读写分离

读写分离:将对数据库的读写操作分散到不同的数据库节点上,可以小幅提升写性能,大幅提升读性能。

MySQL里通常是基于主从复制实现的:

  • 主库(Master):负责处理写操作(INSERT、UPDATE、DELETE)
  • 从库(Slave):负责处理读操作(SELECT)
  • 应用层或中间件做路由

一般都是一主多从,主库和从库之间会进行数据同步

实现读写分离有两种常见方式:

  • 代理方式
  • 组件方式

代理方式

代理方式:在应用和数据库之间引入一个代理层,这个代理负责将读写请求路由到正确的数据库节点。

常见的代理工具有:

  • MySQL Router(官方,MySQL Proxy的替代方案)
  • Atlas(基于MySQL Proxy的开源项目)
  • MaxScale
  • MyCat

组件方式

组件方式:在应用层直接使用支持读写分离的数据库连接池或ORM框架。

推荐使用:sharding-jdbc(阿里巴巴开源的分库分表组件)


主从复制原理

MySQL的主从复制基于二进制日志(binlog)实现,binlog主要记录了MySQL数据库中数据的所有变化(数据库执行的所有DDL和DML语句)。

详细过程:

  1. 主库将数据库中数据的变化写入到binlog中
  2. 从库连接主库
  3. 从库会创建一个I/O线程向主库请求更新的binlog
  4. 主库会创建一个binlog dump线程,将binlog发送给从库,从库中的I/O线程负责接收
  5. 从库的I/O线程将接收的binlog写入到从库的中继日志(relay log)中
  6. 从库的SQL线程读取中继日志,并执行其中的SQL语句,从而实现数据同步

如何避免主从延迟

强制将读请求路由到主库处理:

例如:

  • 用户下单
  • 紧接着查订单状态

这种场景必须读主库

比如通过Sharding-JDBCHintManager分片键值管理器,我们可以强制使用主库:

1
2
3
HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
//继续JDBC操作

延迟读取

比如:
主从同步延迟0.5s,那就1s后再读从库。