什么是数据库读写分离?大型互联网系统必备的数据层架构
摘要:刷朋友圈、浏览电商商品详情,这些高频访问背后都离不开读写分离架构。本文用通俗案例讲解读写分离是什么、主从复制的工作原理,分析它解决的三大核心问题,同时梳理生产环境下主从延迟、数据不一致等坑点,以及落地实现方案,帮你理解互联网后端数据层的基础架构。前言
“读写分离” 是后端开发非常高频的技术名词,它隐藏在我们日常每一次刷新社交动态、搜索商品、浏览文章的背后。绝大多数互联网业务都具备读多写少的特征:用户查询浏览请求量巨大,新增、修改、删除的数据写入请求占比很低。如果全部请求都压在单一数据库实例上,数据库很容易成为整个系统的性能瓶颈。
读写分离就是为了解决该场景诞生的数据库架构方案。
通俗理解:图书馆的比喻
我们可以把数据库比作一座图书馆,数据库服务器就是图书馆管理员。
[*]读操作:借书、翻阅书籍,对应业务里的查询 SELECT;
[*]写操作:还书、登记新书,对应业务里 INSERT、UPDATE、DELETE。
只有一位管理员的时候,借书、还书、登记全部找他处理。少量访客时运转正常;一旦访问量暴涨,大量人来翻阅书籍,同时夹杂少量还书登记,所有任务堆积在同一个管理员身上,队伍越来越长,整体响应速度急剧下降。
读写分离的思路就是分工处理:保留一个总台(主库 Master,写库),所有还书、登记修改操作必须在这里完成;同时增设多个阅览室(从库 Slave,读库),绝大部分翻阅查询操作分流到各个阅览室。主库发生的数据变更,会同步复制到所有从库,保证阅览室里的书籍信息和总台保持一致腾讯云。
读写分离核心原理:主库写,从库读
读写分离架构核心规则:
[*]主库(写库):承担全部写操作,所有新增、修改、删除业务数据都在主库执行;部分对实时性要求极高的读请求,也会直接访问主库。
[*]从库(读库):专门承接大量查询读请求,多个从库可以做负载均衡,分摊查询压力。
[*]主从复制:主库每一次数据变更,都会记录二进制日志 binlog。从库持续拉取这份日志,按照完全相同的顺序复现主库的变更,以此同步数据,保证从库数据和主库对齐。
注意:复制同步存在时间差。通常是毫秒级,也就是主从延迟。不是真正意义上的完全实时同步。绝大多数业务感知不到,但强实时业务需要特殊处理。举个业务例子:你发布一条朋友圈状态,这条写操作写入主库;主库通过主从复制把这条动态同步到各个从库;其他用户刷朋友圈时,查询请求打到从库,读取到你刚刚发布的动态。
为什么互联网大厂普遍使用读写分离?三大核心价值
1. 突破单库性能瓶颈,低成本横向扩展
单台数据库硬件能力存在天花板,CPU、内存、磁盘 IO 总有上限,单纯升级高配服务器成本高昂。读写分离可以横向增加从库节点来承接海量读请求。读压力暴涨,直接新增一台从库即可分担流量,相比升级单机硬件,成本更低、弹性更强。
同时读写物理隔离,写操作产生的锁机制不会阻塞大量查询请求。如果读写都在同一个库,哪怕少量写入,数据库加锁会让大量查询排队等待,造成接口响应变慢。读写分离之后,写只发生在主库,海量查询跑在从库,互不干扰。
2. 提升系统架构韧性,提高可用性
采用一主多从架构,某一台从库宕机,流量可以快速切换到其余正常从库,主库写入链路完全不受影响,整体服务继续对外提供服务。如果所有读写都在单台数据库,数据库一旦故障,整个业务直接瘫痪。读写分离为高可用打下基础,同时从库天然可以作为数据备份节点,降低数据丢失风险。
3. 风险隔离,保护核心业务链路
业务中经常会有报表统计、大数据分析这类重型查询,这类 SQL 会扫描大量数据,消耗大量 CPU、IO 资源。如果这类重查询跑在主库,会挤占下单、支付等核心业务的数据库资源,直接造成线上业务卡顿。读写分离架构下,可以把统计分析任务单独交给某一台从库执行。即便报表查询把这台从库资源打满,也不会影响主库核心交易链路,实现业务风险隔离。
读写分离绕不开的痛点:主从延迟与读写不一致
主从复制无法做到绝对实时同步,会存在短暂延迟,由此带来经典的读写不一致问题:刚刚提交写入的数据,立刻去从库查询,有可能查不到最新数据。
场景举例:刚发布一篇文章,马上刷新页面,读请求落到尚未完成同步的从库,页面看不到刚发布的内容;下单完成立刻查询订单,从库还没同步订单记录,用户看不到自己的订单。
常见解决方案
[*]关键业务强制读主库:写操作之后立刻读取的场景,不走从库,强制访问主库获取最新数据。比如下单后查询订单、修改个人资料后立刻回显信息。这是生产环境最常用的手段。
[*]缓存层兜底:使用 Redis 等缓存组件,写入数据同时更新缓存,读请求优先读取缓存,掩盖主从延迟带来的数据不一致。
[*]半同步复制:MySQL 提供半同步复制机制,主库提交事务后,等待至少一台从库接收到 binlog 日志再返回成功。可以缩小延迟窗口,但不能完全消除延迟,只能降低不一致概率。
[*]业务层面接受最终一致性:大部分资讯、信息流场景,允许几十毫秒到几百毫秒的短暂数据时差,业务无需特殊处理。
补充:从库不是越多越好,从库数量越多,主库同步压力会上升,一般业务一主 2~4 从是比较常见的配置。
技术落地:如何实现读写分离
业务程序不能自己判断 SQL 该发给主库还是从库,需要方案做 SQL 路由,主流两种实现方式:
方案 1:数据库中间件代理(生产最常用)
代表开源组件:ShardingSphere、MyCat、ProxySQL;云厂商数据库代理也属于这一类。应用程序连接中间件,中间件拦截 SQL 语句做解析判断:
[*]遇到 INSERT / UPDATE / DELETE 写语句,转发到主库;
[*]遇到 SELECT 查询语句,分发到从库集群,同时支持轮询、权重等负载均衡策略。
优点:对业务代码透明,业务不用修改大量代码;支持故障自动切换;新增从库无需改动业务。缺点:中间件本身会带来少量性能损耗,需要维护中间件集群,避免中间件成为新的单点故障。
方案 2:应用层多数据源
在业务代码内部维护两套数据源,写操作使用主库数据源,读操作使用从库数据源,通过 AOP、注解等方式切换数据源。优点:不引入额外中间件组件;缺点:代码侵入强,业务代码需要感知主从;新增从库需要修改配置重启服务,运维灵活性差。
真实业务场景举例
[*]电商平台:商品列表、商品详情、评论查看,海量查询请求全部打到从库;用户下单、扣库存、生成订单的写操作在主库;下单完成立刻查询订单,强制走主库。
[*]社交 APP:刷好友动态、查看用户资料,请求落在从库;发布动态、点赞、发消息写操作落地主库,再同步到从库供其他用户浏览。
[*]内容网站:文章浏览、评论浏览大量走从库;发布文章、编辑内容写入主库。
读写分离的局限性(哪些场景不适合)
读写分离解决的是读多写少场景下,读请求的性能压力,并不能解决所有数据库问题:
[*]如果业务是写多读少,大量高频写入,主库写入会成为瓶颈,读写分离无法解决,需要分库分表。
[*]单表数据量达到千万级别以上,查询本身变慢,单纯读写分离也无法解决,需要配合分库分表。
[*]业务要求所有数据访问强实时一致,完全不能容忍延迟,读写分离会带来额外的处理成本。
总结
读写分离本质是分而治之的架构思想:依靠主从复制,把查询流量卸载到多个从库,主库专注处理数据写入。它带来三大收益:横向扩展读性能、提升系统可用性、隔离重查询风险;同时代价是需要面对主从延迟带来的数据一致性问题,业务需要做适配处理。
在互联网后端体系中,读写分离是理解分布式数据架构的入门钥匙。当看懂读写分离,就能看懂大部分中大型网站数据库层的基础设计思路。
拓展:读写分离 ≠ 分库分表。读写分离解决读写压力;分库分表解决单库单表数据量过大的问题,两者经常搭配使用,但属于完全不同的架构手段。
页:
[1]