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

1. 主从同步

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

                                  â€œMySQL基于binlog主从复制”的图片搜索结果

                                                  图-MySQL基于binlog主从复制mysql

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

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

1.1.1 主从延迟问题

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

1.1.2 主库数据丢失问题

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

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

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 事务支持部分观后感

相关文章
相关标签/搜索