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

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

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

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

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

那,真正做过读写分离方案的,到底有多少?
7560 次点击
所在节点    程序员
44 条回复
wentaoliang
2019-04-19 11:51:50 +08:00
@huadi 理解一下 cap 理论就知道,按目前分区无法完全保证的情况下,强一致性和高可用只能满足一个。所有从理论层面告诉你,你的只能在业务层面控制
yanaraika
2019-04-19 12:12:59 +08:00
首先,CAP 定理了解一下,要 C+P 必然会牺牲可用。实际中是要检测延时的,这也是不推荐在公有云上自己搭数据库集群的原因:网络没有专有网络稳定。

现在也有一些利用 RDMA 提升 RSM 复制的方案。

另一点是:吞吐和延时也是不可兼得的,要使用 batching 等方式提升 replicate 的吞吐就会牺牲延时。

一种折中方案是 写 + 读确认节点 > N。一般写少读多的话成功写入 3/4 N 节点返回,成功读到 1/4N + 1 节点返回。

顺带一提,当你需要读写分离的时候再折腾 MySQL 读写分离主从之类的基本就是收效最小的方案,之后主不可用、一致性太弱等问题会让你很头疼,最后层层 patch 后会发现自己造了一个已有的轮子。建议一步到位上无中心化的方案如 Cassandra/NewSQL 等。

@lhx2008 这几个方案都有很多缺陷,最简单的就是客户端时钟不可靠
lhx2008
2019-04-19 12:20:43 +08:00
@yanaraika 这个确实是一个折中的方法,但是实现的复杂度也非常高了。当然 NoSQL 的经过验证的分布式的主从架构更加可靠。至于时钟问题,确实是一个存在的因素,我没有过多研究,不过 Redis 作者在说 RedLock 的时候,没有认为这是一个主要问题。"well, you can assume your clock is mostly correct though!"
guyujiezi
2019-04-19 12:28:10 +08:00
@huadi 如果你的业务代码写得正确,那是不会发生你所说的问题的。因为这个分布式模型是可以实现最终一致性的

我猜你的意思可能是:往从库里取得商品库存,由于数据没有同步,所以从库中的库存数量多余实际数量,然后程序因此创建了本不应该创建的订单。是这样吧?

然而你这个代码本身就是错误的呀
alvin666
2019-04-19 12:28:24 +08:00
我们做的主从是直接走的云服务商的内网,内网要是再波动了,就算不做主从也会受影响
yanaraika
2019-04-19 12:35:53 +08:00
@lhx2008 http://antirez.com/news/101 这个问题非常复杂。我个人是不喜欢 redlock 这种对时间源一个外界因素有依赖的方案的
yanaraika
2019-04-19 12:46:59 +08:00
@alvin666 主要是延时没 SoA 保证…而且延时低到一定程度后 gc 等因素也无法忽略
calpes
2019-04-19 12:56:35 +08:00
@huadi 最简单的例子。。。你确认写入成功后不再次读库,直接将你写入的数据返回给用户,这就是一种很常见的操作,主从分离这个事某种意义上是无法做到对开发者透明的,而且这里你有一个钻牛角尖的思路,就是主从之间的网络可能一抖抖个一分钟啥的,需要业务代码来容错,如果把这些东西加到研发成本里,基本上是没法接受的。OP 角度上来讲每个服务都是有他的可用性指标的,五个 9 以上我觉得这种抖动很难感知到,而如果你的业务在主从分离的场景下由于 db 的可用性指标不够导致业务上大面积的出问题,我建议你们换个更专业的 DB 和 OP,毕竟服务可用性他是一个系统性工程。
idblife
2019-04-19 13:22:56 +08:00
楼主土鳖而已
哪家互联网公司不做读写分离能扛得住?
wangxiaoaer
2019-04-19 13:39:59 +08:00
@jimrok #5 即使多个实例机器,那么同一个数据库的某张表你打算放到几台机器呢?如果 1 台,势必会有瓶颈,如果多台,不还是主从复制吗
passerbytiny
2019-04-19 13:43:00 +08:00
读写分离是抽象,分库分表是技术实现,啥时候被当成解决问题的两种方式了。人家文章的意思其实是:一般你用分库分表这种简单实现方式凑合以下就行了,要是扛不住,你得从根本的抽象上去寻找解决方案,比如说读写分离;至于具体是什么,限于篇幅无法细说(其实我也只知道个标题)。

读写分离这种标题很容易理解但内容很复杂的高级抽象,网上你就只能找到标题,想系统的学习,还是要买书。推荐你一本书《实现领域驱动设计》,里面“架构”、“事件”等章节有关于读写分离架构的描述。
jimrok
2019-04-19 14:03:22 +08:00
@wangxiaoaer 你这个问题,要结合业务场景来讲。就说订单这个东西,如果你的用户少,可以不做拆表处理的。当用户购买商品后,去查询订单,这个请求是个读请求,而且查询可能根据时间,状态过滤。这个列表数据是不容易做 memcahced 缓存的,所以,必须将这部分查询请求放在从库上执行。这样主库的压力就会降下来,放几台要根据你的 qps 量进行估算。如果每秒有 2w 笔查询,那你单台能支撑的是 5000qps,你就需要准备至少 4 台服务器。如果你再能在应用层将请求分割开,那么每台的 mysql 可能只负责某个区域的用户查询请求,那么 mysql 的 buffcache 就可能非常高效。
jimrok
2019-04-19 14:14:08 +08:00
@huadi 主从复制不是解决强一致性问题的,通常情况下的应用,不用害怕这个延迟。在运维层面来讲,通常有一个读写分离的 proxy,有这个 proxy 来代理 sql 端的请求。这个代理也同事负责监控主从库的监控状况,如果从库失败,这个代理会把 select 的语句发给主库执行的。如果你用过阿里云的 RDS,他们会给你一个 readonly 的 mysql 地址,还有一个读写分离的地址,你不需要考虑后端是否可用,这个 proxy 已经管理了后端的群集。
CRVV
2019-04-19 14:20:56 +08:00
如果一个数据库 instance 搞不定所有的读写请求,那么你可以使用多个 instance 来搞
有不同的方案来使用多个 instance,读写分离是其中的一个
或者说你也不一样要完全读写分离,只要把一部分读请求分走,也许就能好了

> 如果是异步同步,可以保证写主库成功之后返回,但保证不了延迟。比如写完马上读就会有问题

是会有问题,但有的业务可以接受有这个问题,或者用另外的手段处理这个问题。
或者你可以只把不需要强一致性的读请求分走。

> 如果等待同步从库成功后再返回,实际就是双写。那么故障几率就更大了,可用性就会降低

出故障的概率会变大,但是数据出错的概率会变小。某些情况下可以接受系统挂掉但是不能接受丢数据。

而且这么干的前提是你用一个 instance 搞不定,搞不定的事情就没有可用性,现在能搞定了才有了可用性。
这里不应该说可用性降低了。
Raymon111111
2019-04-19 14:22:51 +08:00
读写分离太多了

我们目前单库写入 qps 3000 (分库分表 5 个库), 读写分离框架用的很顺利

你说的主从延迟的问题, 绝大多数情况下都能控制在 100ms 内. 也就是说主库写入后从库很短时间内就可以读到, 能够满足绝大多数的使用场景

有一些很特殊的场景会采用强制读主库的方案, 但是这种一般控制量, 主库读影响写入性能

至于监控, 产品也很多, 最快的学习方法是进一个大公司, 一般这些东西很成熟, 你一看就明白了
tairan2006
2019-04-19 16:13:12 +08:00
喷了,用缓存本质上就是读写分离吧。网络分区下高可用和一致性是矛盾的,这不就是 CAP 定理么,楼主自己瞎琢磨啥呢。
zzzzzzZ
2019-04-19 16:54:34 +08:00
读写分离是标配,不是大招,不是人云亦云,是一个稍微水平正常的开发都能做的标配架构

如果你还卡在你第一个"如果",那就是你代码写的烂,别玩架构了
如果你出现了你第二个"如果",那就是你架构搭的烂,别玩架构了

你要的所谓的“中间件”,数据库层面的是 Mycat,就是 @jimrok #32 做的事
代码层面的纯代码就能解决,想不明白怎么敲代码,就别来纸上谈兵的学一些架构的东西,架构从来都是实践出来的
janxin
2019-04-19 17:45:43 +08:00
我觉得其实楼主你应该实操一下?空想很容易钻牛角尖。

另外一个,基本上根据 CAP 去牺牲某一个,根据业务需求再去考虑牺牲哪一个。

即便加上缓存,也是根据具体的业务需求,决定缓存 miss 和脏缓存的接受程度。

毕竟,没有银弹嘛。
phx13ye
2019-04-19 19:22:14 +08:00
借楼问问各位大佬,多对多关系的的中间表一般怎么分库分表。是要双向查的,只能冗余两份各自 sharding 吗?。例如我给哪些文章点赞了,文章被谁点赞。学生选修哪些课程,课程有哪些学生选修。
bringyou
2019-04-19 20:33:29 +08:00
分库分表限制了一些业务实现,比如说表之间的 join。一般业务场景下,对于数据的读取是多于写入(更新),所以为了那些特性,很多场景下都只是先读写分离了。而且一般的规模下这个也足够了。至于主从同步的延迟,阿里云 rds 是 1 毫秒级别的,很少超过 10ms,动辄 100ms 甚至 1min 的延迟,我觉得还是先招些专门的网络运维人员,先优化网络链路来的实在一些,因为网络慢不只是影响数据库主从同步,正常的业务应用也会受到影响。

如果对于 1ms 级别的延迟不能接受的话,可以向前面老哥提到的,再次查询写库,这个重复的工作可以通过 aop 或者中间件来做,自己不用重复的。

同步模型可以看看 mysql 的异步同步、半同步和组同步。

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

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

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

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

© 2021 V2EX