什么是读写分离?
读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话,就能够小幅提升写性能,大幅提升读性能。
读写分离会带来什么问题?如何解决?
读写分离对于提升数据库的并发非常有效,但是,同时也会引来一个问题:主库和从库的数据存在延迟,比如你写完主库之后,主库的数据同步到从库是需要时间的,这个时间差就导致了主库和从库的数据不一致性问题。这也就是我们经常说的 主从同步延迟 。
1.强制将读请求路由到主库处理。
既然你从库的数据过期了,那我就直接从主库读取嘛!这种方案虽然会增加主库的压力,但是,实现起来比较简单,也是我了解到的使用最多的一种方式。
比如 Sharding-JDBC 就是采用的这种方案。通过使用 Sharding-JDBC 的 HintManager 分片键值管理器,我们可以强制使用主库。
HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
// 继续JDBC操作
对于这种方案,你可以将那些必须获取最新数据的读请求都交给主库处理。
2.延迟读取。
还有一些朋友肯定会想既然主从同步存在延迟,那我就在延迟之后读取啊,比如主从同步延迟 0.5s,那我就 1s 之后再读取数据。这样多方便啊!方便是方便,但是也很扯淡。
不过,如果你是这样设计业务流程就会好很多:对于一些对数据比较敏感的场景,你可以在完成写请求之后,避免立即进行请求操作。比如你支付成功之后,跳转到一个支付成功的页面,当你点击返回之后才返回自己的账户。
3.缓存路由方法
1、写请求发往主库,同时缓存记录操作的 key,缓存的失效时间设置为主从的延时;
2、读请求首先判断缓存是否存在:
2.1、若存在,代表刚发生过写操作,读请求操作主库;
2.2、若不存在,代表近期没发生写操作,读请求操作从库。
如何实现读写分离?
1、部署多台数据库,选择其中的一台作为主数据库,其他的一台或者多台作为从数据库。
2、保证主数据库和从数据库之间的数据是实时同步的,这个过程也就是我们常说的主从复制。
3、系统将写请求交给主数据库处理,读请求交给从数据库处理。
落实到项目本身的话,常用的方式有两种:
1.代理方式:
我们可以在应用和数据中间加了一个代理层。应用程序所有的数据请求都交给代理层处理,代理层负责分离读写请求,将它们路由到对应的数据库中。
提供类似功能的中间件有 MySQL Router(官方)、Atlas(基于 MySQL Proxy)、Maxscale、MyCat。
2.组件方式
在这种方式中,我们可以通过引入第三方组件来帮助我们读写请求。
这也是我比较推荐的一种方式。这种方式目前在各种互联网公司中用的最多的,相关的实际的案例也非常多。如果你要采用这种方式的话,推荐使用 sharding-jdbc ,直接引入 jar 包即可使用,非常方便。同时,也节省了很多运维的成本。
主从复制原理是什么?
MySQL binlog(binary log 即二进制日志文件) 主要记录了 MySQL 数据库中数据的所有变化(数据库执行的所有 DDL 和 DML 语句)。因此,我们根据主库的 MySQL binlog 日志就能够将主库的数据同步到从库中。
1、主库将数据库中数据的变化写入到 binlog
2、从库连接主库
3、从库会创建一个 I/O 线程向主库请求更新的 binlog
4、主库会创建一个 binlog dump 线程来发送 binlog ,从库中的 I/O 线程负责接收
5、从库的 I/O 线程将接收的 binlog 写入到 relay log 中。
6、从库的 SQL 线程读取 relay log 同步数据本地(也就是再执行一遍 SQL )。