一、读写分离
1.1 何为读写分离?
读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话,就能够小幅提升写性能,大幅提升读性能。
一主多从:也就是一台主数据库负责写,其他的从数据库负责读。主库和从库之间会进行数据同步,以保证从库中数据的准确性。这样的架构实现起来比较简单,并且也符合系统的写少读多的特点。
1.2 读写分离会带来什么问题?如何解决?
主从同步延迟:读写分离对于提升数据库的并发非常有效,但是,主库和从库的数据存在延迟,比如你写完主库之后,主库的数据同步到从库是需要时间的,这个时间差就导致了主库和从库的数据不一致性问题。这也就是我们经常说的 主从同步延迟 。
1.强制将读请求路由到主库处理。
直接从主库读取:会增加主库的压力,Sharding-JDBC 就是采用的这种方案。通过使用 Sharding-JDBC 的 HintManager 分片键值管理器,我们可以强制使用主库。
2.延迟读取。
对于一些对数据比较敏感的场景,你可以在完成写请求之后,避免立即进行请求操作。比如你支付成功之后,跳转到一个支付成功的页面,当你点击返回之后才返回自己的账户。(才开始读)
1.3 如何实现读写分离?
1.3.1 步骤:
- 部署多台数据库,选择其中的一台作为主数据库,其他的一台或者多台作为从数据库。
- 保证主数据库和从数据库之间的数据是实时同步的,这个过程也就是我们常说的主从复制。
- 系统将写请求交给主数据库处理,读请求交给从数据库处理。
1.3.2 落实到项目中:
1.代理方式
在应用和数据中间加了一个代理层。应用程序所有的数据请求都交给代理层处理,代理层负责分离读写请求,将它们路由到对应的数据库中。
2.第三方组件
引入第三方组件来帮助我们读写请求,推荐使用 sharding-jdbc ,直接引入 jar 包即可使用,节约运维成本。
1.4 主从复制原理
数据库日志:MySQL binlog(binary log 即二进制日志文件) 主要记录了 MySQL 数据库中数据的所有变化(数据库执行的所有 DDL 和 DML 语句)。
因此,我们根据主库的 MySQL binlog 日志就能够将主库的数据同步到从库中。
流程(复制、恢复):从库用IO线程请求更新,主库用binlog dump线程发送binlog,让IO线程接收,从库写入relay log,从库SQL线程读取relay log 同步到本地(再执行一遍)
原理拓展:阿里开源Cannal工具可以同步数据源到另外的数据库,底层依赖于binlog,分布式缓存Redis也是通过主从复制实现读写分离。
二、分库分表
分库:就是将数据库中的数据分散到不同的数据库上
- 你将数据库中的用户表和用户订单表分别放在两个不同的数据库。
- 由于用户表数据量太大,你对用户表进行了水平切分,然后将切分后的 2 张用户表分别放在两个不同的数据库。(不要都存在同个库)
分表 就是对单表的数据进行拆分,可以是垂直拆分,也可以是水平拆分。
- 垂直拆分:是对数据表列的拆分,把一张列比较多的表拆分为多张表。
- 水平拆分:将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。(例如时间分表)
2.1 什么情况下需要分库分表?
遇到下面几种场景可以考虑分库分表:
- 单表的数据达到千万级别以上,数据库读写速度比较缓慢(分表)。
- 数据库中的数据占用的空间越来越大,备份时间越来越长(分库)。
- 应用的并发量太大(分库)。
2.2 分库分表会带来什么问题呢
要考虑这个技术能不能满足我们的要求,是否适合当前业务场景,还要重点考虑其带来的成本。
- join 操作 :join不能跨库连接,需要手动封装逻辑,在A查到a数据,根据a去B查b数据。
- 事务问题 :单个操作涉及到多个数据库,那么数据库自带的事务就无法满足我们的要求了(Mapper需要跨越,配置)
- 分布式 id :分库之后, 数据遍布在不同服务器上的数据库,数据库的自增主键已经没办法满足生成的主键唯一了。我们如何为不同的数据节点生成全局唯一主键呢?这个时候,我们就需要为我们的系统引入分布式 id 了。(重新设计表)
- 服务器成本、DBA(Database Administrator,数据库管理员)的参与
2.3 分库分表有没有什么比较推荐的方案?
ShardingSphere 项目(包括 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar)是当当捐入 Apache 的,目前主要由京东数科的一些巨佬维护。
生态完善、社区活跃、除了支持读写分离和分库分表,还提供分布式事务、数据库治理等功能。
2.4 分库分表后,数据怎么迁移呢
将老库(单库单表)的数据迁移到新库(分库分表后的数据库系统)
停机迁移:脚本在人少的时候迁移。
双写方案:(用Canal做增量数据维护,降低运维成本)
- 对老库的更新操作(增删改),同时也要写入新库(双写)。不存在于新库的话,就插入到新库中。
- 手动老库跟新库数据对比。老库没有,新库有,要删除。老库有,新库没有,要插入。
三、总结:
- 将对数据库的读写操作分散到不同的数据库节点上。 这样的话,就能够小幅提升写性能,大幅提升读性能。
- 读写分离基于主从复制,MySQL 主从复制是依赖于 binlog 。
- 分库 就是将数据库中的数据分散到不同的数据库上。分表 就是对单表的数据进行拆分,可以是垂直拆分,也可以是水平拆分。
- 引入分库分表之后,需要系统解决事务、分布式 id、无法 join 操作问题。
- ShardingSphere 绝对可以说是当前分库分表的首选!ShardingSphere 的功能完善,除了支持读写分离和分库分表,还提供分布式事务、数据库治理等功能。另外,ShardingSphere 的生态体系完善,社区活跃,文档完善,更新和发布比较频繁。