文章目录
随着业务的不断发展和数据量的增长,传统的单机关系型数据库已经逐渐不能满足高效存储和快速访问的需求。在这种背景下,分布式数据库存储成为了解决这些问题的重要策略。通过分表分库、主从复制以及数据扩容等技术,分布式数据库可以提高存储的可扩展性、性能和可靠性。接下来,我们将详细介绍这些关键策略及其应用。
一、分表分库
1. 数据分表的必要性与方式
在传统数据库中,随着单表数据量的增加,操作数据库时会产生巨大的开销,导致系统效率降低。例如,在MySQL中,当单表记录数过多时,插入数据时可能会对表加锁,这会导致后续的请求排队等待,从而影响系统的整体性能。为了解决这一问题,通常建议MySQL单表的记录数控制在500万条以内,但实际情况要根据具体的业务需求和硬件配置来决定。
为了应对数据量过大的问题,分表技术应运而生。分表的方式主要有两种:垂直分表和水平分表。
垂直分表:将表中的字段根据业务需求拆分到不同的表中。例如,将不常用的字段或长字段拆分出来,这样可以避免查询时产生“跨页”问题。此方法通常在数据库设计的初期就进行。
水平分表:根据某个关键字段(如ID)进行Hash计算,将数据拆分到多个表中。例如,可以通过对ID取模的方式,将数据分配到不同的表中。除了ID外,还可以按时间、地域等标准进行分表。
然而,分表虽然带来了性能提升,但也引入了跨表数据查询、ID生成和事务处理等新问题。针对这些问题,有以下解决思路:
- 跨表数据的Join:可以在应用层进行多次查询,并合并结果。
- 跨表数据生成ID:可以使用UUID或Sequence表来生成ID,但这些方式的效率和空间利用有时不尽如人意。大厂常用的snowflake算法(由Twitter开源)就是一种高效生成ID的方式。
- 跨表数据的排序和分页:可以先对分表数据进行排序、分页、聚合等操作,再合并数据进行进一步处理,或者先合并数据后再进行这些操作。
- 跨表事务处理:可以通过补偿事务或采用TCC(Try-Confirm-Cancel)模式来保证跨表事务的一致性。
2. 数据分库原则与优势
在分表的基础上,随着数据量和请求量的不断增长,单一数据库的存储能力和访问能力已无法满足需求,这时就需要采用分库技术。分库技术可以将数据库按照一定的规则拆分到多个数据库中,减轻单个数据库的负担。
分库的常见原则有:
- 按业务分库:根据不同的业务模块将数据分到不同的数据库中。例如,订单数据、核算数据和评价数据可以分别存储在不同的数据库中。
- 按冷热数据分库:根据数据访问频率的不同,将高频、中频和低频的数据分库存储。频繁访问的数据存储在高性能数据库中,减少访问延迟。
- 按访问地域或时间范围分库:根据地域或者时间来划分数据存储的数据库。例如,可以将不同地区或不同时间段产生的数据分配到不同的数据库中。
通过分库,将多个数据库组成集群,应用程序通过负载均衡代理来访问这些数据库,实现读写分离,极大地提高了数据库的可用性。同时,分库也便于进行健康监控、熔断、选举等机制的实施,从而保障数据库系统的高可用性。
二、主从复制
1. 读写分离架构设计
在分布式数据库中,为了提高数据库的并发处理能力,通常会采用读写分离的架构。具体来说,数据库的写操作由主库处理,读操作由从库来承担。这样,主库和从库之间就形成了一个分离的架构,从库可以分担主库的读请求压力。当读请求较多时,可以通过增加从库来进一步扩展系统的读性能。
2. 数据复制方式
为了保证主库和从库数据的一致性,需要对主库的数据进行复制。数据复制可以分为同步和异步两种方式:
同步数据复制:主库在进行写操作时,必须先将数据同步到从库,确认从库同步成功后,才会返回给用户。这样做能够确保主从数据的一致性,但也会牺牲部分系统的可用性,因为写操作需要等待同步完成。
异步数据复制:主库在进行写操作后,直接返回结果给用户,数据复制则在后台进行。虽然这样可以提高系统的可用性,但也可能导致主从数据不一致的问题,尤其是在从库还未同步完成时,应用读取到的数据可能存在问题。
3. MySQL实现主从复制
以MySQL为例,MySQL的主从复制过程如下:
- 从库的IO线程连接到主库,获取Binary Log的指定位置和偏移量。
- 主库在数据更新时,将更新信息通知从库。
- 从库IO线程将这些更新信息存入relay Log,并记录日志文件名和位置。
- 从库的SQL线程解析relay Log内容,执行SQL语句,从而完成数据的同步。
MySQL支持两种数据复制方式:Row Level和Statement Level。Row Level复制记录每条数据的修改操作,能够更精确地同步数据,但会增加日志的存储和网络传输负担;而Statement Level复制记录执行的SQL语句,相对节省空间和IO成本,但对主从数据库版本的要求较高,建议主库的版本低于从库版本。
4. MySQL主从复制实践与高可用方案
在实际应用中,为了实现高可用性,除了传统的主从复制,还有主主复制(双主模式)等方案。在主主模式下,两个主服务器之间互为备份,通常会暴露一个虚拟IP(VIP),并根据服务器的健康状态进行切换。也可以通过中间件如MyCat和ZooKeeper实现更高级的高可用性,ZooKeeper提供了选举机制来选择新的主服务器,从而确保系统的高可用性。
如下图:MyCat 通过 ZooKeeper 对主节点 writeHost(负责写入)和从节点 readHost(负责读取)进行心跳检测。接收到请求时,MyCat 依据 SQL 解析结果,将 DML SQL 发往 writeHost,Select SQL 发往 readHost。writeHost 完成写入后与 readHost 进行主从复制。若 writeHost 挂掉,n 次心跳检测未恢复,MyCat 发起选举新 writeHost,原 writeHost 恢复后变为 readHost 接收数据同步。
三、数据扩容
随着数据量和并发量的不断增长,数据库需要不断扩容以满足需求。以主从数据库扩容为例,假设原本有2个数据库集群,在扩容时可以将数据库数量增加到4个。扩容时,需要将原先基于ID取模的分表方式改为新的模4运算,重新分配数据并进行代理配置的调整。扩容后的系统,主库和从库之间可以继续进行复制,进一步提高系统的可用性和性能。
具体操作如下:
- 初始数据分布:在2个数据库集群中,每个集群含主备(M0、S0 和 M1、S1),通过对记录ID进行模2运算,结果为0的数据存于M0和S0所在集群,结果为1的数据存于M1和S1所在集群。主库写入数据后,从库主动同步以保证数据一致。
集群扩展操作:当将2个集群扩展为4个时,将模2运算切换为模4运算,原从库S0和S1变为主库,负载均衡器按ID%4算法将部分数据路由到它们上面,同时S0和S1停止与原主库同步。只需修改代理配置,无需重启服务。之后可通过后台服务删除冗余数据。
保障数据库可用性:扩展到4个主库后进行主从复制,为每个主库建立从库,主库负责写操作,从库负责读操作,后续扩容可参照此方法。
《分布式架构原理与实践-崔皓》