高性能架构模式(一):数据库集群如何实现高性能?

2023年 8月 12日 69.5k 0

 在具体的实践过程中,为了更快、更好地设计出的架构,除了掌握一些架构基础知识外,还需要掌握业界已经成熟的各种架构模式。在大部分情况下,我们做架构设计主要都是基于已有的成熟模式,结合业务和团队的具体情况,进行一定的优化或者调整;即使少部分情况我们需要进行较大的创新,前提也是需要对已有的各种架构模式和技术非常熟悉。

一.读写分离 “读写分离”,其本质是将访问压力分散到集群中的多个节点,但是没有分散存储压力;其实现方式可以是一主一从,也可以是一主多从,其中,数据库主机负责读写操作,从机只负责读操作。读写分离的逻辑实现并不是很复杂,但有两个细节,会引入复杂度,分别是:主从复制延迟(网络问题)和分配机制(数据读取问题)。 主从和主备经常被提起,但是这两个概念并不等同:

“主从”:其中的“从”可以理解为“仆从”,仆从是要帮主人干活的,“从机”是需要提供读数据的功能的。“主备”:其中的“备机”一般被认为仅仅提供备份功能,不提供访问功能。

1.主从复制延迟 读写分离主从机制的实现,意味着需要进行数据备份(不同主机间),那么就会存在数据复制延迟的行为(网络传输)。以 MySQL 为例,主从复制延迟可能达到 1 秒、1分钟、甚至更久。如果数据写入主机后,然后去从机读取数据,因为复制延迟,导致读取的数据为空,那么,就可能会影响到业务。

 解决主从复制延迟有几种常见的方法:

业务绑定:写操作后的读操作指定发给数据库主服务器需要和对应的业务进行强关联

二次读取:读从机失败后再读一次主机业务分类:关键业务读写操作全部指向主机,非关键业务采用读写分离

2.分配机制 分配机制主要指的是将读写操作区分开来,然后访问不同的数据库服务器,其实就是如何访问读写分离的数据库集群。其使用方式一般有两种:程序代码封装和中间件封装。 这里并没有介绍这两种方案的具体实现细节,旨在概括总的方向。

(1)程序代码封装 程序代码封装指在代码中抽象一个数据访问层,实现读写操作分离和数据库服务器连接的管理。例如,基于 Hibernate 进行简单封装,就可以实现读写分离。其基本结构表如下:

 该方式实现起来简单,但是每个编程语言都需要自己来实现,没有办法通用,并且,在发生故障情况下,如果发生主从切换,那么可能需要所有系统都修改配置并重启。

(2)中间件封装 中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。其基本结构如下:

 其特点如下:

支持多种编程语言。支持完整的 SQL 语法和数据库服务器的协议。数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都要经过中间件,中间件的性能要求也很高。数据库主从切换对业务服务器无感知。  开源数据库中间件方案:

MySQL 官方提供了 MySQL Proxy(没有正式 GA)MySQL 官方推荐 MySQL Router奇虎 360 公司开源的数据库中间件 Atlas

二.分表分库 “读写分离”,的本质只是将访问压力分散到集群中的多个节点,但是没有分散存储压力;而“分库分表”,既可以分散访问压力,又可以分散存储压力。看着如此强大,却是在引入了复杂度和放弃一定功能的基础上完成的。

1.业务分库 业务分库指的是按照业务模块将数据分散到不同的数据库服务器。这样,每个业务模块都有自己的数据库,而不是所有的模块共用一个数据库,这样,也就降低了数据库的压力,提升了数据库的性能。 在软件架构中,是没有完美的方案的,解决一个问题的同时,有可能会引入新的问题。拿业务分库来说,会引入以下一些问题:

join 问题原本在一个数据库中的数据,现在分散到了多个数据库上,那么,表之间的 join 就无法使用(不同数据库的表之间,是没办法 join 的)。

事物问题MySQL 提供了事物的特性,在同一个数据库中,支持很好。但是数据分库后,就是不同系统间的交互了,也就是引入了分布式事物的问题。虽然数据库厂商提供了一些分布式事务的解决方案(例如,MySQL 的 XA),但性能实在太低,与高性能存储的目标是相违背的。分库后就无法使用数据库事务了,那么就需要业务程序自己来模拟实现事务的功能。

成本问题原来只需要一台服务器就能处理,现在需要多台,成本会增加。这些成本对对于小公司初创业务来说,会表现的更加的严重。

2.分表 分库只是将不同的业务模块,做了拆分,是一种垂直方向拆分的手段。但是,当表的数据超过的千万的时候,就需要考虑分表(水平分表)了,其依据一般是表的大小,而不是表行数据的多少。 单表数据拆分有两种方式:垂直分表和水平分表。示意图如下:

 单表的拆分,并不强制要求切分后的多表必须分散在不同的数据库中,器原因在于,单表切分为多表后,新的表即使在同一个数据库服务器中,也可能带来可观的性能提升,如果性能能够满足业务要求,是可以不拆分到多台数据库服务器的。 分表是可以降低存储压力和性能提升的,但是,和分库一样,依旧会引入复杂度。

(1)垂直分表 垂直分表主要是对表中的字段进行拆分,适合将表中某些不常用且占了大量空间的列拆分出去。其复杂度的体现为:操作表的数量会增加。

(2)水平分表 水平分表适合表行数特别大的表,相对于垂直分表,会引入更多的复杂性,如下所示:

路由数据在进行水平分表时,某条数据具体属于哪个切分后的子表,需要增加路由算法进行计算,这样,在查找的时候,才能更加快速的定位数据。常见的路由算法有:范围路由、Hash 路由、配置路由。(1)范围路由:将某一段范围的值,路由到同一张表中。其优点是数据能够进行平滑的扩充;其缺点是数据可能分布不均匀。(2)Hash 路由:计算某些列的 hash 值,将相同 hash 值的数据,路由到一张表中。其优点是表的数据分布较均匀;其缺点是数据扩充会比较麻烦。可借鉴一致性哈希的方式来优化。(3)配置路由:使用一张路由配置表,来记录数据和分片表的对应关系。其优点是设计简单,扩充表数据也比较容易;其缺点是会增加一次SQL查询,且路由表本身过大的时候,也会降低性能。

join 操作水平分表后,数据分散在多个表中,如果需要与其他表进行 join 查询,需要在业务代码或者数据库中间件中进行多次 join 查询,然后将结果合并。

count() 操作这里的count() 不再是一张表的简单统计,常见方式有两种:count() 相加、记录数表(1)count() 相加:分别对每张表做 count(),然后再汇总返回给客户端。其优点是实现简单;其缺点是性能较差。(2)记录数表:使用一张记录表来专门记录总条数。其优点是性能较好;其缺点是要额外的维护记录数表。

order by 操作水平分表后,数据分散到多个子表中,排序操作无法在数据库中完成,只能由业务代码或者数据库中间件分别查询每个子表中的数据,然后汇总进行排序。

3.实现 不管是分库还是分表,其实现方式都和读写分离类似,可分为“程序代码封装”和“中间件封装”,只是,其实现的复杂度相比读写分离会更高。读写分离实现时只要识别 SQL 操作是读操作还是写操作,而分库分表的实现除了要判断操作类型外,还要判断 SQL 中具体需要操作的表、操作函数(例如 count 函数)、order by、group by 操作等。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论