前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >说说常见数据库及中间件的主从设计

说说常见数据库及中间件的主从设计

作者头像
用户5166556
发布2023-03-18 14:00:43
3060
发布2023-03-18 14:00:43
举报

前不久在工作过程中用到了kafka中间件,简单来说是个消息队列,除了支持高吞吐量、发布订阅等功能外,它还支持回放,我可以通过修改偏移量重新获取数据,这个功能是一个非常常见的使用场景,也是我选择kafka的一个重要原因。

但kafka追随者副本不对外提供服务,乍看起来,令人百思不得其解,MySQL、redis都可以使用通过读从节点从而分摊主节点的压力。

为什么kafka不这样设计呢?

究其原因它的设计思路是读自己的写以及单调读,这种做法就不会因为读取follower的数据而导致的数据不一致。相信我们在使用MySQL或者redis的时候就经常碰到一个问题就是在从多个从节点查询数据时,某条数据一会存在一会不存在的问题,当然MySQL和redis也是有对应的解决方案,这个我们后面在说。

kafka的从节点的存在有什么意义?

毫无疑问提供数据冗余、主从切换。kafka的follower自动从leader拉取消息,kafka会把符合时间间隔标准的follower添加到ISR同步集合中。

当leader宕机后,就会从ISR集合中选举一个follower升级为leader。那么到底以什么标准进行选举呢?

这个标准就是Broker端参数replica.lag.time.max.ms参数值。这个参数的含义是Follower副本能够落后Leader副本的最长时间间隔,当前默认值是10秒。这就是说,只要一个Follower副本落后Leader副本的时间不连续超过10秒,那么Kafka就认为该Follower副本与Leader同步的,即使此时Follower副本中保存的消息明显少于Leader副本中的消息。我们在前面说过,Follower副本唯一的工作就是不断地从Leader副本拉取消息,然后写入到自己的提交日志中。如果这个同步过程的速度持续慢于Leader副本的消息写入速度,那么在replica.lag.time.max.ms时间后,此Follower副本就会被认为是与Leader副本不同步的,因此不能再放入ISR中。此时,Kafka会自动收缩ISR集合,将该副本踢出ISR。值得注意的是,倘若该副本后面慢慢地追上了Leader的进度,那么它是能够重新被加回ISR的。这也表明,ISR是一个动态调整的集合,而非静态不变的。

可能我们第一感觉总是当然是根据消息的落后数量了,但是其实不是的,其主要原因是时间这个参数很难给出一个合适的值,比如以默认值4000为例,如果我的tps是10,那么这个值就没有任何参考意义,因为太大了;如果tps是2000,那么一定会引起ISR集合的频繁变动,所以kafka从0.9x废弃了该参数。如果所有的副本延时都比较大,ISR集合中没有一个副本,该怎么办?其实我们可以通过配置至少存在一个副本或者开启Unclean选举。

Kafka如何保证leader和Follower之间的数据一致性呢?

其实Kafka producer的ack有3中机制,初始化producer时的producerconfig可以通过配置request.required.acks不同的值来实现。依次是0:完全异步、1:leader确认、-1:follower确认。数据吞吐量逐渐递减,数据健壮性依次增强。可以根据具体使用场景进行配置。

MySQL是如何保证主从之间的数据一致性?

如下图所示,默认情况下MySQL的主从同步流程是客户端把写请求到主库binlog、提交事务并返回写入成功,每个从库启动一个复制线程拉取binlog并写入到中继日志中,最后给主库返回写入成功。当然从库中还有其它线程去回放中继日志,最终持久化到从库存储引擎中。

看到这里不禁产生了深深的怀疑,这不就是典型的异步复制吧?根本不能保证主从数据的一致性?其实MySQL提供了三种同步模式,分别是同步复制、异步复制、半同步复制。其中同步和异步比较好理解,同步指的就是当生产者把一个消息提交到MySQL主节点时,MySQL主节点必须等待从节点返回后才能告诉客户端数据提交成功,这种性能相对较差,但是能够保证数据一致性;异步复制指的就是主节点不用等待从节点的确认,性能较好,但是不能保证数据的一致性,MySQL主从默认就是这种模式;这个半同步是什么呢?半同步指的是当主节点收到一个或者多个从节点的确认即可返回。MySQL采用的是收到其中一个从节点的确认,即响应客户端操作完成。这种技术既不会对性能产生过多的损耗,还可以实现对数据更好的保护。所以如果你想兼顾性能和数据的一致性就可以考虑使用MySQL的半同步复制,简单来说就是一主多从的模式。

有心思的同学可能会想到比MySQL更强大的Oracle是如何解决主从之间的数据一致性呢?首先Oracle采用了最大保护模式(对应于半同步复制)、最大性能模式(对应于异步复制)、最大可用模式(默认情况下采用最大保护模式,如果主从出现问题则切换为最大性能模式)。

redis是如何保证主从之间的数据一致性?

如下图所示,可以看出redis使用的异步的数据复制方式,通过主库一次传输数据到从库,其它从库之间的数据复制则从其它从库同步数据,从而减轻主库的压力。

只不过在异步复制的过程中又进行了细分,在第一次主从同步的时候会通过内存快照rdb进行全量备份,后续会通过主从之间建立长连接进行数据增量同步,为了降低主库的压力,redis本身采用了主-从-从的方式进行其它从节点之间的数据复制,即一个从节点拉取主节点的数据,其它从节点则从这个从节点进行数据的增量同步。在并发非常大的场景下,redis主从模式首先保证的是可用性,很难保证数据的一致性。所以回头谁在问你,让你设计一个对一致性要求非常高分布式系统(或分布式锁)就不要在提redis了,那应该用什么呢?

基于一致性的数据同步方案是什么呢?

可以考虑使用Zookeeper或者etcd,首先ZK采用了ZAB协议的半同步复制方案,写请求必须在主节点处理,并且有大多数从节点同意后写操作才可以成功,所以ZK可以保证节点之间的数据顺序一致性。另外基于raft算法的etcd也是采用了半同步复制方案,需要半数以上的节点同意后写操作才可以成功,所以它也可以保证数据之间的一致性。

总结

综合来说,基本上常见的基于主从的存储系统都是基于同步、异步、半同步这三种方式实现的,其中同步和异步比较简单,半同步相当于在同步和异步之间做了一个折衷,适用于大多数对一致性并且对性能有要求的大规模分布式场景。当然本文只是简单介绍了数据同步方式,但是它是如何保证数据的可靠性呢?MySQL的快照和binlog、kafka的WAL预写日志、redis的快照和AOF、ES的translog...你可以看到基本上所有的分布式存储系统的可靠性都是根据快照和日志的方式解决的,这个下次再聊!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术爱好者社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么kafka不这样设计呢?
  • kafka的从节点的存在有什么意义?
  • Kafka如何保证leader和Follower之间的数据一致性呢?
  • MySQL是如何保证主从之间的数据一致性?
  • redis是如何保证主从之间的数据一致性?
  • 基于一致性的数据同步方案是什么呢?
  • 总结
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档