达梦数据库集群
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.2.1 读写分离架构

在介绍读写分离架构之前,首先要了解多节点集群架构出现的初衷是备份和容灾,即提高系统的可用性。这是因为,数据库的性能需求是随着业务量的增加而不断增加的,但备份和容灾却是任何一个系统最基本的需求。最初的多节点集群架构,也是比较简单的、易于部署的主备架构或主从架构。然而,从狭义角度讲,很多时候我们在谈论数据库集群时,主备架构和主从架构不属于数据库集群的范畴,因为它们结构单一,还无法上升到集群的覆盖程度。但从数据库集群的广义概念角度来看,这两种架构应该是最初级的数据库集群架构,或者说满足数据库集群架构的基本需求。基于主从架构设定数据库读操作和写操作的分配机制,构成了读写分离架构。

下面从架构部署、读写分配策略、读写分配机制3个方面进行介绍。

1. 架构部署

主备架构是最基础的数据库多节点架构。一般而言,只要数据库支持数据主备复制功能,就能够部署主备架构,最基础的主备架构如图1-1所示。

图1-1 最基础的主备架构

下面结合实际部署情况对主备架构各项指标进行分析。

(1)一致性:数据读、写都由主库控制,不存在数据一致性问题。

(2)性能:读、写都通过操作主库进行,备库只用于数据备份,无法利用其计算性能,因此系统整体资源利用率为50%。

(3)高可用性:系统检测到主库崩溃后(如通过心跳报文),可以将业务访问流量切换到备库。如果没有设置切换过程,则需要通过人工方式切换主备库,或者在业务系统中通过程序中间件实现主备库自动切换。

(4)可扩展性:无法通过增加备库来扩展读性能,无法提高架构性能。

(5)部署难度:部署操作简单,但由于在整体性能和可扩展性方面没有优势,应用场景比较单一。

为充分利用备库的计算资源,提高系统的各项性能指标,一般采用主从架构部署数据库集群。主从架构采用主库和从库的架构,和主备架构相比,从库不仅可以当作数据备份节点,还可以提供系统访问功能。

当从库也需要响应业务系统的访问请求时,主从架构将客户端的读操作和写操作请求分配到不同的节点中,如主库执行写操作,从库执行读操作。在这种场景下,主从架构也被称为读写分离架构,如图1-2所示。

由于在当前业务需求中,读操作请求比较多而写操作请求比较少,因此读写分离架构在实际部署过程中得到了广泛应用。注意,主从架构的说法是从服务器设备的协同分工角度来考虑的,读写分离架构是从用户访问模式的流量划分角度来考虑的,两者之间存在概念上的重叠。

图1-2 读写分离架构

在读写分离架构中,主库节点数量通常为一个,从库节点数量可以有一个或多个。主库将数据同步到从库上,从库需要随时感知主库状态,并在主库发生故障时实现自动切换。这里的切换机制,需要数据库软件的特定进程参与实现,或者通过第三方软件实现,如著名的分布式协调程序ZooKeeper,就能实现节点状态监测,并在必要时进行主从切换。在读写分离架构中,写操作通常在主节点执行,读操作既可以在从节点执行,也可以在主节点执行,主节点的数据按照数据同步规则更新到从节点。

下面结合实际部署情况对主从架构各项指标进行分析。

(1)一致性:存在数据一致性问题,需要结合实际业务需求采用不同的数据一致性策略。

(2)性能:大部分业务系统应用读多写少,读会先成为瓶颈,进而影响整体性能。引入多个从库节点能够增加系统读数据性能,进而提高数据库整体性能。

(3)高可用性:主库单节点故障将导致系统无法实现写操作,甚至导致整个系统不可用,但从库单节点故障不会出问题,因此从库具备高可用性。

(4)可扩展性:增加从库节点能够快速提高系统读性能。这里需要注意的是,从库节点数量越多,数据库整体读数据性能越高,但同时需要同步数据的从库节点也越多,此时配置不当可能会影响主库性能。主节点写性能的可扩展性不高,增加写功能的主节点会引入新的访问逻辑。

(5)部署难度:部署易于实现,但需要重点考虑数据的一致性问题,不同的一致性策略决定了不同的部署难度。

2. 读写分配策略

在读写分离架构中,主库处理所有写操作,从库处理所有读操作,这种分配方式是最简单的,也是最易于实现的。为了合理分配主从节点的读操作和写操作,一般会设置不同的分配策略,这些不同的读写分配策略主要是一致性策略,即考虑数据同步的时延对业务需求的影响。任何两个数据库节点之间在进行数据同步时,数据时延是肯定存在的,只是时延大小不同而已。对于银行、金融等领域,数据的访问必须要求强一致性,因而数据库架构要求在数据写入后,优先保证所有节点的数据实时同步,在数据同步之后,才允许数据访问。这种强一致性需求在实现时,一般要求数据提交更新且主从节点实现同步之后才最终表明数据更新成功。为了不影响数据实时响应,强一致性要求主从节点之间通过高速网络连接,一般要求同机房部署,从而在硬件设置上减小主库与从库之间的数据传输时延。这种场景对数据库硬件部署网络有要求,也对数据库部署位置有要求。按照这种部署策略,读写分配策略只需要在主从节点上进行简单的切分即可,一般不需要设置复杂的读写分配策略。

如果不考虑主库、从库同步的强一致性需求,则在主库数据写操作完成后再考虑从库同步问题,在这种情况下,主从节点在数据同步过程中必然存在不一致性。对于这种瞬时的不一致性,不同业务需求的容忍度是不一样的,需要根据实际业务来考虑是否处理或避免数据的不一致性问题。如果主库与从库数据同步时延较长,则会影响实际业务体验。

对于无法满足强一致性需求的场景,下面列出几种可供考虑的读写分配策略。

1)写操作后的读操作全部发送给主库

以新用户注册为例,用户注册后立刻登录系统,如果此时主库新写入的注册信息还没有同步到从库,那么此时用户无法登录,这将极大影响客户的使用体验。在这种情况下,除非能够确保主从节点间的同步时延控制在某个较短时间内,否则系统必须对这类写操作之后的读操作进行特殊处理。这类操作很常见,如用户在给系统更新数据后,都会要求能够立刻查看最新数据。然而,如何区分这些写操作之后紧跟的读操作是一个比较麻烦的问题。一方面,可以根据用户的会话或源地址进行流量切分,一旦用户执行了写操作,就将其后续会话操作全部导向主节点,从而保障其读写的一致性;另一方面,也可以考虑在业务代码层进行设计,将写操作之后的读操作引入主节点,这种方式对业务侵入性较强,尤其是在系统研发和系统兼容方面需要谨慎考虑。

2)从库读操作失败后继续读主库

上面的读写分配策略需要介入业务层面,为了减少业务代码修改,一种更简单的方式是在从库读操作失败后继续读主库。在写操作之后,如果从库没有及时同步最新数据,则用户在无法访问最新数据时就会去主库读取数据,因而能够有效规避某些业务对数据同步的时延需求。这种方式不需要修改代码,只需要对主库开放读写功能且对从库开放读功能,即在从库上实现二次读取功能就可以实现对最新数据的读取,实现方式比较简单,不需要对系统架构进行改动。然而,这种方式存在弊端,如果从库中存在大量读取失败的访问,则无论是业务需要还是用户恶意访问等,都将为主库带来较大的访问压力。

3)关键业务与非关键业务相互剥离

针对不同业务设置不同的分配策略,将关键业务与非关键业务相互剥离,从而实现主库、从库对读写需求的业务划分。例如,用户注册成功之后马上进行登录的场景、用户更新数据后需要立即显示的场景,都可以设置为关键业务。一种可行的分配策略如下:将关键业务的读写请求指向主库,非关键业务则按照主从节点读写分离的通用方式部署。这种方式也会对业务有一定程度的侵入,即需要显式区分关键业务与非关键业务。这种分配策略也可以结合上述第二种读写分配策略一起运用,如在正常读写分配策略下,对关键业务实现二次读取,即只对关键业务实现上述第二种分配策略,从而可以减小主库的二次访问压力,但对于关键业务的恶意访问仍然无法有效避免,一般需要针对恶意访问行为进行分析,从而采取进一步的处理措施。

3. 读写分配机制

对于不同的数据库软件产品,在建立读写分离模式的数据库集群时,有不同的实现方式。商业数据库软件和开源软件在这方面的实现方式也不相同。下面将从3个方面对其进行介绍。

1)商业数据库软件

商业数据库软件由于面向商业市场,其对稳定性和性能的要求较高,对数据库系统的功能和应用场景也有特定要求,因而一般会提供数据库系列软件实现集群功能,而这些软件一般以后台进程方式或守护进程方式来监控各个数据库节点,从而实现读写分离架构。在部署过程中,用户可直接按照官方使用说明快速部署数据库集群。

对于不具备自主研发能力、不具备专业化运维管理能力的企业,采用商业数据库软件是最直接、最高效的部署方式。

2)自研式程序封装

自研式程序封装指的是在构建业务层代码时,抽象一个数据访问层,实现对数据库服务器连接的管理,从而实现读写操作分离的功能。例如,基于Hibernate的封装可以实现读写分离,或者通过其他数据库连接封装程序进行自主研发。

这种程序封装方式具有以下特点。

(1)实现简单,能够根据业务实现定制化的功能。

(2)程序封装的方式与编程语言紧耦合,无法做到通用,如果一个业务包含多个编程语言实现的多个子系统,则重复开发的工作量比较大。

(3)在故障情况下,如果发生主从切换,则可能需要所有系统都修改配置并重启。

在目前的开源实现方案中,以淘宝的TDDL(Taobao Distributed Data Layer)为例,它是一个通用数据访问层,所有功能封装在Jar包中提供给业务代码调用,其基于集中式配置的JDBC Datasource实现,具有主备、读写分离、动态数据库配置等功能。

3)第三方中间件

中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接管理。第三方中间件对业务服务器提供SQL兼容的协议,业务服务器无须自己进行读写分离。对于业务服务器来说,访问中间件和访问数据库没有区别,事实上,从业务服务器角度看,第三方中间件就是一个数据库服务器。

采用数据库中间件方式具有以下特点。

(1)能够支持多种编程语言,因为数据库中间件对业务服务器提供的是标准SQL接口。

(2)数据库中间件要支持完整的SQL语法和数据库服务器协议。

(3)数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都经过数据库中间件,这对数据库中间件的性能要求比较高。

(4)数据库主从切换对业务服务器无感知,数据库中间件可以探测数据库服务器的主从状态。

例如,向某个测试表写入一条数据,成功的就是主机,失败的就是从机。由于数据库中间件的复杂度要比程序代码封装高很多,在一般情况下建议采用程序语言封装,或者使用成熟的开源数据库中间件。

如果是大公司,则可以投入人力去实现数据库中间件,因为这个系统一旦做好,介入的业务系统越多,则节省的程序开发投入就越多,价值也就越高。