第8章kafka可靠性探究_第1页
第8章kafka可靠性探究_第2页
第8章kafka可靠性探究_第3页
第8章kafka可靠性探究_第4页
第8章kafka可靠性探究_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8章可靠性探究8.1.5为什么不支持读写分离在Kafka中,生产者写入消息、消费者读取消息的操作都是与leader副本进行交互的,从而实现的是一种主写主读的生产消费模型。数据库、Redis等都具备主写主读的功能,与此同时还支持主写从读的功能,主写从读也就是读写分离,为了与主写主读对应,这里就以主写从读来称呼。Kafka并不支持主写从读,这是为什么呢?从代码层面上来说,虽然增加了代码复杂度,但在Kafka中这种功能完全可以支持。对于这个问题,我们可以从“收益点”这个角度来做具体分析。主写从读可以让从节点去分担主节点的负载压力,预防主节点负载过重而从节点却空闲的情况发生。但是主写从读也有2个很明显的缺点:数据一致性问题。数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中A数据的值都为x,之后将主节点中A的值修改为Y,那么在这个变更通知到从节点之前,应用读取从节点中的A数据的值并不为最新的Y,由此便产生了数据不一致的问题。延时问题。类似Redis这种组件,数据从写入主节点到同步至从节点中的过程需要经历网络一主节点内存一网络一从节点内存这几个阶段,整个过程会耗费一定的时间。而在Kafka中,主从同步会比Redis更加耗时,它需要经历网络一主节点内存一主节点磁盘一网络一从节点内存一从节点磁盘这几个阶段。对延时敏感的应用而言,主写从读的功能并不太适用。现实情况下,很多应用既可以忍受一定程度上的延时,也可以忍受一段时间内的数据不一致的情况,那么对于这种情况,Kafka是否有必要支持主写从读的功能呢?主读从写可以均摊一定的负载却不能做到完全的负载均衡,比如对于数据写压力很大而读压力很小的情况,从节点只能分摊很少的负载压力,而绝大多数压力还是在主节点上。而在Kafka中却可以达到很大程度上的负载均衡,而且这种均衡是在主写主读的架构上实现的。我们来看一下Kafka的生产消费模型,如图8-23所示。如图8-23所示,在Kafka集群中有3个分区,每个分区有3个副本,正好均匀地分布在3第8章可靠性探究I299个broker上,灰色阴影的代表leader副本,非灰色阴影的代表follower副本,虚线表示follower副本从leader副本上拉取消息。当生产者写入消息的时候都写入leader副本,对于图8-23中的情形,每个broker都有消息从生产者流入;当消费者读取消息的时候也是从leader副本中读取的,对于图8-23中的情形,每个broker都有消息流出到消费者。我们很明显地可以看出,每个broker上的读写负载都是一样的,这就说明Kafka可以通过主写主读实现主写从读实现不了的负载均衡。图8-23展示是一种理想的部署情况,有以下几种情况(包含但不仅限于〉会造成一定程度上的负载不均衡:⑴broker端的分区分配不均。当创建主题的时候可能会出现某些broker分配到的分区数多而其他broker分配到的分区数少,那么自然而然地分配到的leader副本也就不均。(2生产者写入消息不均。生产者可能只对某些broker中的leader副本进行大量的写入操作,而对其他broker中的leader副本不闻不问。(3)消费者消费消息不均。消费者可能只对某些broker中的leader副本进行大量的拉取操作,而对其他broker中的leader副本不闻不问。⑷leader副本的切换不均。在实际应用中可能会由于broker岩机而造成主从副本的切换,或者分区副本的重分配等,这些动作都有可能造成各个broker中leader副本的分配不均对此,我们可以做一些防范措施。针对第一种情况,在主题创建的时候尽可能使分区分配得均衡,好在Kafka中相应的分配算法也是在极力地追求这一目标,如果是开发人员自定义的分配,则需要注意这方面的内容。对于第二和第三种情况,主写从读也无法解决。对于第四种情况,Kafka提供了优先副本的选举来达到leader副本的均衡,与此同时,也可以配合相应的监控、告警和运维平台来实现均衡的优化。在实际应用中,配合监控、告警、运维相结合的生态平台,在绝大多数情况下Kafka都能做到很大程度上的负载均衡。总的来说,Kafka只支持主写主读有几个优点:可以简化代码的实现逻辑,减少出错的可能;将负载粒度细化均摊,与主写从读相比,不仅负载效能更好,而且对用户可控;没有延时的影响;在副本稳定的情况下,不会出现数据不一致的情况。为此,Kafka又何必再去实现对它而言毫无收益的主写从读的功能呢?这一切都得益于Kafka优秀的架构设计,从某种意义上来说,主写从读是由于设计上的缺陷而形成的权宣之计。8.2日志同步机制在分布式系统中,日志同步机制既要保证数据的一致性,也要保证数据的顺序性。虽然有许多方式可以实现这些功能,但最简单高效的方式还是从集群中选出一个leader来负责处理数据写入的!I说序性。只要leader还处于存活状态,那么follower只需按照leader中的写入顺序来进行同步即可。300I深入理解Kafka:核心设计与实践原理通常情况下,只要leader不着机我们就不需要关心环llower的同步问题。不过当leader岩机时,我们就要从follower中选举出一个新的leaderfollower的同步状态可能落后leader很多,甚至还可能处于窑机状态,所以必须确保选择具有最新日志消息的follower作为新的leader。日志同步机制的一个基本原则就是:如果告知客户端已经成功提交了某条消息,那么即使leader岩机,也要保证新选举出来的leader中能够包含这条消息。这里就有一个需要权衡(tradeoff)的地方,如果leader在消息被提交前需要等待更多的follower确认,那么在它岩机之后就可以有更多的follower替代它,不过这也会造成性能的下降。对于这种tradeo筐,一种常见的做法是“少数服从多数”,它可以用来负责提交决策和选举决策。虽然Kafka不采用这种方式,但可以拿来探讨和理解tradeoff的艺术。在这种方式下,如果我们有2f+l个副本,那么在提交之前必须保证有轩1个副本同步完消息。同时为了保证能正确选举出新的leader,至少要保证有f+l个副本节点完成日志同步井从同步完成的副本中选举出新的leader节点。并且在不超过f个副本节点失败的情况下,新的leader需要保证不会丢失己经提交过的全部消息。这样在任意组合的f+l个副本中,理论上可以确保至少有一个副本能够包含己提交的全部消息,这个副本的日志拥有最全的消息,因此会有资格被选举为新的leader来对外提供服务。“少数服从多数”的方式有一个很大的优势,系统的延迟取决于最快的几个节点,比如副本数为3,那么延迟就取决于最快的那个follower而不是最慢的那个(除了】eader,只需要另一个follower确认即可〉。不过它也有一些劣势,为了保证leader选举的正常进行,它所能容忍的失败follower数比较少,如果要容忍l个follower失败,那么至少要有3个副本,如果要容忍2个follower失败,必须要有5个副本。也就是说,在生产环境下为了保证较高的容错率,必须要有大量的副本,而大量的副本又会在大数据量下导致性能的急剧下降。这也就是“少数服从多数”的这种Quorum模型常被用作共享集群配置(比如ZooKeeper),而很少用于主流的数据存储中的原因。与“少数服从多数”相关的一致性协议有很多,比如Zab、Raft和ViewstampedReplication等。而Kafka使用的更像是微软的PacificA算法。在Kafka中动态维护着一个ISR集合,处于ISR集合内的节点保持与leader相同的高水位CHW),只有位列其中的副本(unclean.leader.elect工on.enable配置为false)才有资格被选为新的leadera写入消息时只有等到所有ISR集合中的副本都确认收到之后才能被认为已经提交。位于ISR中的任何副本节点都有资格成为leader,选举过程简单(详细内容可以参考6.4.3节〉、开销低,这也是Kafka选用此模型的重要因素。Kafka中包含大量的分区,leader副本的均衡保障了整体负载的均衡,所以这一因素也极大地影响Kafka的性能指标。在采用ISR模型和(f+l)个副本数的配置下,一个Kafka分区能够容忍最大f个节点失败,相比于“少数服从多数”的方式所需的节点数大幅减少。实际上,为了能够容忍f个节点失败,第8章可靠性探究【301“少数服从多数”的方式和ISR的方式都需要相同数量副本的确认信息才能提交消息。比如,为了容忍l个节点失败,“少数服从多数”需要3个副本和l个follower的确认信息,采用ISR的方式需要2个副本和l个follower的确认信息。在需要相同确认信息数的情况下,采用ISR的方式所需要的副本总数变少,复制带来的集群开销也就更低,“少数服从多数”的优势在于它可以绕开最慢副本的确认信息,降低提交的延迟,而对Kafka而言,这种能力可以交由客户端自己去选择。另外,一般的同步策略依赖于稳定的存储系统来做数据恢复,也就是说,在数据恢复时日志文件不可丢失且不能有数据上的冲突。不过它们忽视了两个问题:首先,磁盘故障是会经常发生的,在持久化数据的过程中并不能完全保证数据的完整性;其次,即使不存在硬件级别的故障,我们也不希望在每次写入数据时执行同步刷盘(fsync)的动作来保证数据的完整性,这样会极大地影响性能。而Kafka不需要岩机节点必须从本地数据日志、中进行恢复,Kafka的同步方式允许宿机副本重新加入ISR集合,但在进入ISR之前必须保证自己能够重新同步完leader中的所有数据。8.3可靠性分析很多人问过笔者类似这样的一些问题:怎样可以确保Kafka完全可靠?如果这样做就可以确保消息不丢失了吗?笔者认为:就可靠性本身而言,它并不是一个可以用简单的“是”或“否”来衡量的一个指标,而一般是采用几个9来衡量的。任何东西不可能做到完全的可靠,即使能应付单机故障,也难以应付集群、数据中心等集体故障,即使躲得过天灾也未必躲得过人祸。就可靠性而言,我们可以基于一定的假设前提来做分析。本节要讲述的是:在只考虑Kafka本身使用方式的前提下如何最大程度地提高可靠性。就Kafka而言,越多的副本数越能够保证数据的可靠性,副本数可以在创建主题时配置,也可以在后期修改,不过副本数越多也会引起磁盘、网络带宽的浪费,同时会引起性能的下降。一般而言,设置副本数为3即可满足绝大多数场景对可靠性的要求,而对可靠性要求更高的场景下,可以适当增大这个数值,比如国内部分银行在使用Kafka时就会设置副本数为5。与此同时,如果能够在分配分区副本的时候引入基架信息(broker.rack参数),那么还要应对机架整体岩机的风险。仅依靠副本数来支撑可靠性是远远不够的,大多数人还会想到生产者客户端参数acks。在2.3节中我们就介绍过这个参数:相比于0和Lacks=-1(客户端还可以配置为all,它的含义与一l一样,以下只以1来进行陈述〉可以最大程度地提高消息的可靠性。对于acks=1的配置,生产者将消息发送到leader副本,leader副本在成功写入本地日志之

后会告知生产者己经成功提交,如图8-24所示。如果此时ISR集合的follower副本还没来得及拉取到leader中新写入的消息,leader就看机了,那么此次发迭的消息就会丢失。302I深入理解Kafka:核心设计与实践原理①肖塞目入Iea6ef副本2后,folfcwr胡本宰投取凯夏逢行同步用XMacks-l的阶置情形气〉。Producer写入消恩3加4eaderfollDwerlfoilower?I断厄原加Ik)gr1\HW[LEO2folloMriElog口(oUcwedX并道有旧a如盗学遂RMlowef避没有来得及fetchSleader的At折消息.①肖塞目入Iea6ef副本2后,folfcwr胡本宰投取凯夏逢行同步用XMacks-l的阶置情形气〉。Producer写入消恩3加4eaderfollDwerlfoilower?I断厄原加Ik)gr1\HW[LEO2folloMriElog口(oUcwedX并道有旧a如盗学遂RMlowef避没有来得及fetchSleader的At折消息.电30取就客机了follower?HWJLEO—001122⑤心的VE当览为酷的leader但是此时LE。仍为3,Producer发遥的洛悬电5芸夫对于ack=一l的配置,生产者将消息发送到leader副本,leader副本在成功写入本地日志之后还要等待ISR中的follower副本全部同步完成才能够告知生产者已经成功提交,即使此时leader副本君机,消息也不会丢失,如图8-25所示。®leader宝生名机,再盖从1SR中造翠出一个folio神日成为籍的ledilerhTW昆直当通.消息部不尝丢失国S-25acks--[的配宜情毋(成功)电fdlowodtojtower?HWfLEOHW|L£O00112223334A4③旧10岫普部同辑完成西ffnw坦盘吾户持成功有志在2.1.2节中,我们讨论了消息发送的3种模式,即发后即忘、同步和异步。对于发后即忘的模式,不管消息有没有被成功写入,生产者都不会收到通知,那么即使消息写入失败也无从得知,因此发后即忘的模式不适合高可靠性要求的场景。如果要提升可靠性,那么生产者可以采用同步或异步的模式,在出现异常情况时可以及时获得通知,以便可以做相应的补救措施,比如选择重试发送(可能会引起消息重复)。有些发送异常属于可重试异常,比如NetworkException,这个可能是由瞬时的网络故障而导致的,一般通过重试就可以解决。对于这类异常,如果直接抛给客户端的使用方也未免过于兴师动众,客户端内部本身提供了重试机制来应对这种类型的异常,通过retries参数即可配置。默认情况下,retries参数设置为0,即不进行重试,对于高可靠性要求的场景,需要将这个值设置为大于0的值,在2.3节中也谈到了与retries参数相关的还有一个retry.backoff.ms参数,它用来设定两次重试之间的时间间隔,以此避免无效的频繁重试。在配置retries和retry.backoff.ms之前,最好先估算一下可能的异常恢复时间,这样可以设定总的重试时间大于这个异常恢复时间,以此来避免生产者过早地放弃重试。如果不知道retries参数应该配置为多少,则可以参考KafkaAdminClient,在KafkaAdminClient中retries参数的默认值为5。注意如果配置的retries参数值大于0,则可能引起一些负面的影响。首先同2.3节中谈及的一样,由于默认的max.川.fl工ght.requests.per.connection参数值为5,这样可能会影响消息的顺序性,对此要么放弃客户端内部的重试功能,要么将max.in.flight.requests.per.connection参数设置为l,这样也就放弃了吞吐。其次,有些应用对于时延的要求很高,很多时候都是需要快速失败的,设置retries>0会增加客户端对于异常的反馈时延,如此可能会对应用造成不良的影响。我们回头再来看一下acks=寸的情形,它要求ISR中所有的副本都收到相关的消息之后才304I深入理解Kafka:核心设计与实践原理能够告知生产者己经成功提交。试想一下这样的情形,leader副本的消息流入速度很快,而follower副本的同步速度很慢,在某个临界点时所有的follower副本都被剔除出了ISR集合,那么ISR中只有一个leader副本,最终acks=一】演变为acks=1的情形,如此也就加大了消息丢失的风险。Kafka也考虑到了这种情况,并为此提供了min.insync.replicas参数(默认值为1)来作为辅助(配合acks=-1来使用〉,这个参数指定了ISR集合中最小的副本数,如果不满足条件就会抛出NotEnoughReplicasException或NotEnoughReplicasAfterAppendException在正常的配置下,需要满足副本数〉min.i口sync.replicas参数的值。一个典型的配置方案为:副本数配置为3,min.工nsync.replicas参数值配置为2o注意min.insync.replicas参数在提升可靠性的时候会从侧面影响可用性。试想如果ISR中只有一个leader副本,那么最起码还可以使用,而此时如果配置mXn.insync.replicas>l,则会使消息无法写入。与可靠性和ISR集合有关的还有一个参数一一unclean.leader.election.enable。这个参数的默认值为false,如果设置为true就意味着当leader下线时候可以从非ISR集合中选举出新的leader,这样有可能造成数据的丢失。如果这个参数设置为false,那么也会影响可用性,非ISR集合中的副本虽然没能及时同步所有的消息,但最起码还是存活的可用副本。随着Kafka版本的变更,有的参数被淘汰,也有新的参数加入进来,而传承下来的参数一般都很少会修改既定的默认值,而unclean.leader.election.enable就是这样一个反例,从版本开始,unclean.leader.el

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论