第2章通用的高并发架构设计——2.2 高并发读场景方案1:数据库读/写分离

第2章通用的高并发架构设计——2.2 高并发读场景方案1:数据库读/写分离
John Yaml大部分互联网应用都是读多写少的,比如刷帖的请求永远比发帖的请求多,浏览商品的请求永远比下单购买商品的请求多。数据库承受的高并发请求压力,主要来自读请求。
我们可以把数据库按照读/写请求分成两类:
- 专门负责处理写请求的数据库(写库)
- 专门负责处理读请求的数据库(读库)
让所有的写请求都落到写库,写库将写请求处理后的最新数据同步到读库,所有的读请求都从读库中读取数据。这就是数据库读/写分离的思路。
数据库读/写分离使大量的读请求从数据库中分离出来,减少了数据库访问压力,缩短了请求响应时间。
2.2.1 读/写分离架构
我们通常使用数据库主从复制技术实现读/写分离架构,将数据库主节点Master作为“写库”,将数据库从节点Slave作为“读库”,一个Master可以与多个Slave连接,如图2-2所示。
市面上各主流数据库都实现了主从复制技术,参见1.7.3节介绍的MySQL数据库的主从复制原理。
2.2.2 读/写请求路由方式
在数据库读/写分离架构下,把写请求交给Master处理,而把读请求交给Slave处理。那么由什么角色来执行这样的读/写请求路由呢?一般可以采用如下两种方式。
- 基于数据库Proxy代理的方式
- 基于应用内嵌的方式
(1)基于数据库Proxy代理的方式
在业务服务和数据库服务器之间增加数据库Proxy代理节点(下文简称Proxy)。
- 业务服务对数据库的一切操作都需要经过Proxy转发。
- Proxy收到业务服务的数据库操作请求后,根据请求中的SQL语句进行归类。
- 将属于写操作的请求(如insert/delete/update语句)转发到数据库Master。
- 将属于读操作的请求(如select语句)转发到数据库任意一个Slave,完成读/写分离的路由。
开源项目如中心化代理形式的MySQL-Proxy和MyCat,以及本地代理形式的MySQL-Router等都实现了读/写分离功能。
(2)基于应用内嵌的方式
基于应用内嵌的方式与基于数据库Proxy代理的方式的主要区别是,它在业务服务进程内进行请求读/写分离。数据库连接框架开源项目如gorm、shardingjdbc等都实现了此形式的读/写分离功能。
2.2.3 主从延迟与解决方案
数据库读/写分离架构依赖数据库主从复制技术,而数据库主从复制存在数据复制延迟(主从延迟),因此会导致在数据复制延迟期间主从数据的不一致,Slave获取不到最新数据。针对主从延迟问题有如下三种解决方案。
- 同步数据复制
- 强制读主
- 会话分离
(1)同步数据复制
数据库主从复制默认是异步模式,Master在写完数据后就返回成功了,而不管Slave是否收到此数据。我们可以将主从复制配置为同步模式,Master在写完数据后,要等到全部Slave都收到此数据后才返回成功。
这种方案可以保证数据库每次写操作成功后,Master和Slave都能读取到最新数据。这种方案相对简单,将数据库主从复制修改为同步模式即可,无须改造业务服务。
但是由于在处理业务写请求时,Master要等到全部Slave都收到数据后才能返回成功,写请求的延迟将大大增加,数据库的吞吐量也会有明显的下滑。这种方案的实用价值较低,仅适合在低并发请求的业务场景中使用。
(2)强制读主
不同的业务场景对主从延迟的容忍性不一样。举个例子:
- 用户A刚刚发布了一条状态,他浏览个人主页时应该展示这条状态,这个场景不太能容忍主从延迟;
- 而好友用户B此时浏览用户A的个人主页时,可以暂时看不到用户A最新发布的状态,这个场景可以容忍主从延迟。
我们可以对业务场景按照主从延迟容忍性的高低进行划分:
- 对于主从延迟容忍性高的场景,执行正常的读/写分离逻辑;
- 对于主从延迟容忍性低的场景,强制将读请求路由到数据库Master,即强制读主。
(3)会话分离
比如某会话在数据库中执行了写操作,那么在接下来极短的一段时间内,此会话的读请求暂时被强制路由到数据库Master,与“强制读主”方案中的例子很像,保证每个用户的写操作立刻对自己可见。暂时强制读主的时间可以被设定为略高于数据库完成主从数据复制的延迟时间,尽量使强制读主的时间段覆盖主从数据复制的实际延迟时间。
总结
数据库按照读/写请求可以分成哪两类?
- 专门负责处理写请求的数据库(写库)
- 专门负责处理读请求的数据库(读库)
数据库读/写分离的思路?
- 让所有的写请求都落到写库,写库将写请求处理后的最新数据同步到读库,所有的读请求都从读库中读取数据。
如何实现数据库读/写分离架构?
- 通过数据库主从复制技术
由什么角色来执行这样的读/写请求路由呢?
- 基于数据库Proxy代理的方式
- 基于应用内嵌的方式
主从延迟的解决方案?
- 同步数据复制
- 强制读主
- 会话分离