读写分离到底是大招还是人云亦云 ?真正做过的人有多少?

2019-04-19 10:16:12 +08:00
 huadi
大部分所谓架构文章都会先介绍分库分表,再扛不住就读写分离对吧。

但没人往下讲细节了。
如果是异步同步,可以保证写主库成功之后返回,但保证不了延迟。比如写完马上读就会有问题。
如果等待同步从库成功后再返回,实际就是双写。那么故障几率就更大了,可用性就会降低。

好吧我知道还有所谓“具体业务具体分析”,但实际上哪有那么多具体业务能忍受可用性降低或者同步延迟。就比如订单,钱不能算错,库存也不能错,但没听说过谁说用可用性来做 trade off 的。

我始终认为,提升系统容量,要有一套能撑得住的运维体系,然后一直分库分表就好了。所谓主从同步,是一个“高可用”方案,在主库挂掉的时候从库顶上。而不是 scale out 方案。

那,真正做过读写分离方案的,到底有多少?
7544 次点击
所在节点    程序员
44 条回复
LinInV2
2019-04-19 10:41:54 +08:00
互联网公司标配吧。
保证高可用性的啊
wentaoliang
2019-04-19 10:46:26 +08:00
这个理解就不对了。主从除了高可用,另外一个作用就是负载均衡,你想想如果访问到数据库的 qps 有几 w,你再怎么分库分表,单机都不可能承受的住
tiedan
2019-04-19 10:47:59 +08:00
读写的同步延迟间隙可以用缓存覆盖掉
guyujiezi
2019-04-19 10:48:10 +08:00
你用过 memcache 或 redis 缓存吗?缓存就是一种读写分离
jimrok
2019-04-19 10:49:18 +08:00
大部分的查询请求,其实不用那么实时,例如订单完成之后,可以不用变化。而且 mysql 的复制还是非常快的,100 毫秒上下,这样主库就可以把 cpu 剩下来提高写入的 ops。
huadi
2019-04-19 10:50:24 +08:00
@wentaoliang 分库又不是只能在单台机器上分,跑在多台机器上的多个实例也叫分库。
关键是纸上谈兵的文章太多了,深入细节就没人讲。
那么,我原文问的的两个如果怎么破?
expkzb
2019-04-19 10:50:26 +08:00
虽然我不是搞后端的,但我知道磁盘也是有 io 瓶颈的。一般业务都是读多写少的。
zhengyongtao
2019-04-19 10:51:59 +08:00
读写分离是为了负载均衡,单机性能同时做读写撑不了多少 qps,另外一般订单这种都会使用缓存和队列,而不是直接入库,什么都等入库黄花菜都凉了。
gaius
2019-04-19 10:54:21 +08:00
多数据源,具体方法上加自定义注解结合 aop 选折具体数据源,这样讲是不是细节了一点。
tiedan
2019-04-19 10:55:26 +08:00
读写分离的情况下,无实时性要求的业务读从,高实时性的业务强制读主。
wentaoliang
2019-04-19 10:55:28 +08:00
@huadi 比如你是一个库的某个表请求几 w,你就只能读写分离了,对于读写同步延迟的。就不应该在同一个请求中写完立马就读,如果非得这么做,让第二次强制读主库
huadi
2019-04-19 10:59:25 +08:00
@guyujiezi 缓存和两个 db 双写还是不一样的。
缓存很快。
缓存不是持久化方案,可以采用 db+缓存双写而不降低可用性。
缓存和 db 的一致性,仍然是问题。
huadi
2019-04-19 11:05:33 +08:00
@wentaoliang 分库分表最大的问题是数据倾斜和运维水平。比如按 userId 分,可能有某个 user 的请求很多。或者 db 特别多。否则无论如何我都可以降低 QPS。
强制读主库确实是个好方法。但我不知道怎么控制这个时间阈值,因为同步延迟很难保证。网络抖动这个天灾就受不了。
vmskipper
2019-04-19 11:06:00 +08:00
根据自己的 qps tps 而定 链接过多或者活动事务过多 就弄呗 读压力过大就加缓存 写压力过大就分片 每天 2000 万的记录 消息几亿 总量百亿 现在就这么弄的
guyujiezi
2019-04-19 11:11:58 +08:00
@huadi 主从架构不能叫“双写”,这样说法会有歧义的,两主才叫双写。

主从同步一般都是异步的,这叫最终一致性,同步写入那就变成两阶段提( 2PC )交了
whileFalse
2019-04-19 11:22:40 +08:00
“写完马上读就会有问题”

没错。所以要从业务层弥补。
当如果写和读属于两个无关业务,比如用户 A 刚更新了自己的头像,用户 B 立即去拿结果拿到了旧的;这种情况通常是可忍受的。因为如果用户 B 的这个请求早发送 1s,那么他看到的肯定就是旧的;两个业务之前不存在因果关系。

如果写读属于同一个业务,比如更改用户单张借记卡的余额,然后显示用户所有卡的总余额;这种情况要不将两个数据库操作合并为同一个操作,要不从业务层将两个独立的请求合并为一个请求,要不强制读主库;要不告诉用户”更新可能延迟“之类的。

总之,上读写分离是和业务相关的,无法做到对开发透明。在业务理解并做针对性优化的情况下,可用性不会是问题。
huadi
2019-04-19 11:27:08 +08:00
@guyujiezi 我的原始问题是原文的两个如果。
如果不双写,做异步同步,这没问题的。那我的疑问是怎么处理延迟。
主从延迟很低是没错,但关键是这个延迟是无法保证的。也就是说平常 100ms 之内,但网络一抖动,分钟级别的延迟都有可能发生。这个时候从库是没办法提供服务的,怎么处理这种问题呢?
huadi
2019-04-19 11:35:55 +08:00
@whileFalse 想请问下,合并两个请求有什么思路么?现在大部分应用都是 HTTP,有什么工具或者链接能分享下?
glfpes
2019-04-19 11:40:21 +08:00
你举的例子就是那种“读写分离不太合适”的情况。订单系统这种强一致性的场景不多且一般都是关键场景,花更多的资源有价值。
实际上很多场景,不需要强一致性。当读写不均衡的情况下,比如读的 qps 比写高几个数量级,读写分离还是很常见的做法。比如用户画像。其实用到本地缓存的地方都可以搞读写分离。
lhx2008
2019-04-19 11:46:20 +08:00
分布式系统最大的问题就是很难保证强一致性,对于普通业务,主要通过逻辑弥补。对于敏感的业务,主写从读会出问题。

逻辑弥补有很多方法 (来自李运华的文章)
1. 业务可以接受,系统不优化
2. 写操作后的 n 秒内读操作指定发给数据库主服务器
3. 读从机失败后再读一次主机
4. 关键业务只走主机,可接受延迟的业务走从机
5. 走缓存,先更新缓存,缓存过期肯定已经刷入从机了

楼主看的“所谓架构文章”,怕不是 CSDN 上面的?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/556677

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX