主从同步、读写分离、分库分表及Sharding Sphere

1. 主从同步

Mysql 5.0以后,支持通过binary log(二进制日志)以支持主从复制。复制允许将来自一个MySQL数据库服务器(master)的数据复制到一个或多个其他MySQL数据库服务器(slave),以实现热备份、读写分离、水平扩展、统计分析、远程数据分发等功能。二进制日志中存储的内容称之为事件,每一个数据库更新操作(Insert、Update、Delete,不包括Select)等都对应一个事件

                                  SouthEast

                                                  图-MySQL基于binlog主从复制

主要分为3个步骤:
第一步:master在每次准备提交事务完成数据更新前,将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log event,简称event)
第二步:slave启动一个I/O线程来读取主库上binary log中的事件,并记录到slave自己的中继日志(relay log)中;
第三步:slave还会起动一个SQL线程,该线程从relay log中读取事件并在备库执行,从而实现备库数据的更新。

1.1 主从同步需要解决的问题

1.1.1 主从延迟问题

由于网络延迟、机器性能、大事务、锁、MySQL参数设置等存在的问题,可能使得主从数据存在延迟,需要考虑好应该在什么场景下来用MySQL主从同步,建议是一般在读远远多于写,而且读的时候一般对数据时效性要求没有那么高,采用主从同步。解决的具体做法有:优化MySQL配置参数、分库、并行复制、强一致性业务强制路由主库。具体做法可以参考:简书-mysql读写分离和解决主从同步延时问题掘金-mysql同步(复制)延迟的原因及解决方案CSDN-彻底终结MySQL同步延迟问题

1.1.2 主库数据丢失问题

MySQL复制默认是异步的,主库写入事务在生成Events并写入到Binlog文件之后,写入线程是不等待的,或者可以说主库并不知道从库是不是已经收到或处理了这些Binlog。在这种情况下,如果主库挂了,有可能没有任何一个从库可以收到已经在主库提交的事务,而此时如果高可用架构将业务从主库切换到了从库,则可能会导致从库丢失主库上面发生的很多修改。

如何解决?可以采用半同步复制策略,是介于全同步复制与全异步复制之间的一种,主库只需要等待至少一个从库节点收到Flush Binlog到Relay Log文件即可,主库不需要等待所有从库给主库反馈,同时这里只是一个收到的反馈,而不是已经完全执行并且提交的反馈,这样就节省了很多时间。具体过程可以参考:高效开发运维-MySQL半同步复制

2. 读写分离

通过数据冗余将数据库读写操作分散到不同的节点上,数据库主机通过主从同步将数据复制到从机,每台数据库服务器都存储了所有的业务数据,其中主机负责写操作,从机负责读操作。适合并发量大,读远大于写的场景,数据实时性不那么严格的业务。一般通过上述binlog复制来实现,因此存在上述延迟问题。

如何将读写操作区分开来,然后访问不同的数据库服务器?一般有客户端代码封装实现,如Sharding-JDBC、TDDL和服务端中间件封装如Cobar、MyCat两种。具体分析可以参考:芋道源码-浅谈高性能数据库集群——读写分离

3. 分库分表

常见的做法有以下几种:

  • 垂直分表,即“大表拆小表”,拆分是基于关系型数据库中的“列”(字段)进行的。通常情况,某个表中的字段比较多,可以新建立一张“扩展表”,将不经常使用或者长度较大的字段拆分出去放到“扩展表”中,可以避免跨页造成的额外性能开销;
  • 垂直分库,基本的思路就是按照业务模块来划分出不同的数据库,而不是像早期一样将所有的数据表都放到同一个数据库中;
  • 水平分表,横向分表,就是将表中不同的数据行按照一定规律分布到不同的数据库表中(这些表保存在同一个数据库中),这样来降低单表数据量,优化查询性能,最常见的方式就是通过主键或者时间等字段进行Hash和取模后拆分。
  • 水平分库分表,水平分库分表与上面讲到的水平分表的思想相同,唯一不同的就是将这些拆分出来的表保存在不同的数据中。“冷热数据分离”(将一些使用较少的历史数据迁移到其他的数据库中,而在业务功能上,通常默认只提供热点数据的查询)也是类似的实践。分库分表能够有效缓解单机和单库的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。

3.1 何时分库分表

数据库记录数达到多少量级需要考虑分库分表?阿里巴巴《Java开发手册》推荐“单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表,如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表”。事实上该数值的评估与MySQL的配置以及机器的硬件有关。具体分析可以参考:占小狼的博客-MySQL单表数据不要超过500万行:是经验数值,还是?

3.2 分库分表需要解决的问题

3.2.1 跨库join的问题

拆分后,数据库可能是分布式在不同实例和不同的主机上,join将变得非常麻烦。而且基于架构规范,性能,安全性等方面考虑,一般是禁止跨库join的。那该怎么解决?

  • 全局表

所谓全局表,就是有可能系统中所有模块都可能会依赖到的一些表。比较类似我们理解的“数据字典”。为了避免跨库join查询,我们可以将这类表在其他每个数据库中均保存一份。同时,这类数据通常也很少发生修改(甚至几乎不会),所以也不用太担心“一致性”问题。

  • 字段冗余

这是一种典型的反范式设计,在互联网行业中比较常见,通常是为了性能来避免join查询。字段冗余能带来便利,是一种“空间换时间”的体现。但其适用场景也比较有限,比较适合依赖字段较少的情况。最复杂的还是数据一致性问题,这点很难保证,可以借助数据库中的触发器或者在业务代码层面去保证。

  • 数据同步

例如A库中的tab_a表和B库中tbl_b有关联,可以定时将指定的表做同步。当然同步本来会对数据库带来一定的影响,需要性能影响和数据时效性中取得一个平衡,这样来避免复杂的跨库查询,可以通过ETL工具来实施。

  • 系统层组装

在系统层面,通过调用不同模块的组件或者服务,获取到数据并进行字段拼装。简单字段组装的情况下,我们只需要先获取“主表”数据,然后再根据关联关系,调用其他模块的组件或服务来获取依赖的其他字段(如例中依赖的用户信息),最后将数据进行组装。通常,我们都会通过批量查询以及缓存来避免频繁RPC通信和数据库查询的开销。

3.2.2 跨库事务(分布式事务)的问题

按业务拆分数据库之后,不可避免的就是“分布式事务”的问题。以往在代码中通过spring注解简单配置就能实现事务的,现在则需要花很大的成本去保证一致性。具体解决方案参考:分布式事务

3.2.3 数据迁移的问题

可以参考:美团技术团队-大众点评订单系统分库分表实践闲鱼技术-21世纪了还愚公移山?数据库这么迁移更稳定!程序猿DD-推荐一个不错的分库分表实践!

3.3 分库分表实践总结

可以参考:

InfoQ-分库分表的几种常见形式以及可能遇到的难题

程序猿DD-推荐一个不错的分库分表实践!

4. Sharding Sphere分布式数据库中间件

田守枝的技术博客-数据库中间件详解

Hollis-SpringBoot 2.x ShardingSphere分库分表实战

ShardingSphere官网

参考资料

匠心零度-MySQL binlog原来可以这样用?各种场景和原理剖析!

田守枝的技术博客-异地多活场景下的数据同步之道

开源中国-sharding-jdbc 事务支持部分观后感

转载于:https://my.oschina.net/u/2939155/blog/3096811

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值