Kafka_集群特性

  1. 集群概述
    Kafka集群具有横向扩展、变态快,大吞吐量、内置分区、副本、故障转移等特点。同时,Kafka是一个非常高性能的存储系统。写入到kafka的数据将直接写到磁盘并复制到集群中保证容错性。并允许生产者等待消息应答,直到消息完全写入。client来控制读取数据的位置。可以认为kafka是一种专用于高性能,低延迟,提交日志存储,复制,和传播特殊用途的分布式文件系统。kafka集群最好部署在相同局域网的环境里,不要部署在不同的网络环境里。

  2. 应用
    ① 作为消息中间件,以队列(组内消费)、发布订阅(组间消费)两种方式构建流数据管道
    ②可构建实时流应用程序,对数据流进行转换或反应

  3. 分布式
    ①broker 的部署是一种 no central master 的概念,并且每个节点都是同等的,节点的增加和减少都不需要改变任何配置。
    ②producer 和 consumer 通过 zookeeper 去发现 topic,并且通过 zookeeper 来协调生产和消费的过程。
    ②producer、consumer 和 broker 均采用 TCP 连接,通信基于 NIO 实现。Producer 和 consumer 能自动检测 broker 的增加和减少
    整个Kafka中使用的NIO模型可以归结为下图:
    这里写图片描述
    socketServer 中引用 Acceptor 处理多个 client 过来的 connector,并为每个 connection 创建出一个processor 去单独处理,每个 processor 中均引用独立的 selector。

  4. 操作系统
    调升文件描述符的数量,因为我们有很多话题和大量的连接。
    调升最大套接字缓冲区大小,使这里介绍的数据中心之间获得高性能的数据传输。

  5. Linux冲洗(写磁盘)行为
    在Linux中,写入文件系统的数据保存在页缓存,直到它必须被写入到磁盘(由应用程序级fsync或系统自己的冲洗策略)。数据的冲洗是通过一组后台线程调用pdflush完成的。
    Pdflush可通过配置策略来控制多少脏数据可以保存在缓存和多长时间之前必须写回到磁盘。当Pdflush无法跟上数据写入的速率时,它最终会导致写入进程块引起数据延迟累积变慢。
    可以通过执行以下命令看到操作系统的内存使用情况:

    cat /proc/meminfo

    页缓存有一个进程内缓存,用于存储将被写入到磁盘的数据 有几个优点:
    ·I/O调度器将连续的小写入一起打包成更大的物理写,从而提高吞吐量。
    ·I/O调度器尝试重新排列写入顺序,尽量减少磁头运动从而提高吞吐量。
    ·它会自动使用计算机上的所有可用的内存

  6. 应用系统与操作系统的冲洗管理
    Kafka一直都是立即把所有数据写入文件系统,并支持使用冲洗功能将数据从操作系统缓存冲洗到磁盘。这个冲洗策略可控制在“一段时间之后”或“消息到一定数量之后”强制数据写入磁盘
    Kafka最终必须调用fsync直到数据被刷新。 当从崩溃中恢复任何未知fsync的日志段时,Kafka将通过检查每个消息的CRC来检查每个消息的完整性,并且还将重新生成伴随的offset索引文件,作为启动时执行的恢复过程的一部分。
    注意,kafka的耐久性不需要同步数据到磁盘,因为失败的节点会从它的副本恢复。
    推荐使用默认的设置,完全禁用fsync。这意味着依赖操作系统和kafka自己的后台冲洗,最适合大多数使用:无需调整,大吞吐量和延迟,以及全面恢复保证,通过副本提供的保证比同步到本地磁盘更强
    使用应用程序级别刷新设置的缺点是它的磁盘使用模式效率较低(它给操作系统减少了重新排序写操作的余地),并且可能引入延迟,因为fsync在大多数Linux文件系统中阻塞写入文件,而后台刷新进行更细粒度的页面级锁定。

  7. Ext4文件系统
    EXT4可供Kafka数据目录文件系统选择。要获得最佳的性能将需要几个挂载选择。这些选项在故障情况下通常是不安全的。并将导致更多的数据丢失和损坏。对单个broker故障,无需担心,可以擦除磁盘,并从集群重建副本。在多故障情况下,如断电,这可能意味着底层文件系统(数据)损坏,这是不容易恢复的。 可以调整以下选项:
    ·data=writeback: 默认Ext4为data=ordered(对一些写入设置强顺序写入)。Kafka不需要,因为kafka的数据在所有未冲洗的日志上恢复。此设置删除了排序约束,并且显著地减少了延迟。
    ·禁用日志记录:日志是一个权衡,它使服务器崩溃后重启更快,但它引入了大量的额外的锁定,这增加了写性能的差异。如果不关心重启时间,想减少写入高峰延迟,可以完全关闭日志记录。
    ·mmit=num_secs:调整ext4提交到其元数据日志的频率。将此值设置的较低可减少崩溃期间未冲洗数据的丢失。设置的越高将提高吞吐量。
    ·nobh:此设置是当使用data=writeback时,控制额外的排序保证。这应该于kafka是安全的,因为我们不依赖写入顺序,并提高吞吐量和延迟。
    ·delalloc: 延迟分配意味着文件系统避免分配任何块,直到物理写入发生。这允许ext4分配很大程度上代替小的页面并确保数据按顺序写入。这一特性非常适合吞吐量,它涉及在文件系统中增加了一些延迟差异锁(似乎)。

  8. sendfile系统调用
    数据从文件传输到socket的公共数据路径:
    ·操作系统将数据从磁盘读入到内核空间的页缓存
    ·应用程序将数据从内核空间读入到用户空间缓存中
    ·应用程序将数据写到到socket缓存中
    ·操作系统将数据从socket缓冲区复制到网卡缓冲区,将数据经网络发出
    如果使用sendfile,再次拷贝可以被避免:允许操作系统将数据直接从页缓存发送到网络上。所以在这个优化的路径中,只有最后一步将数据拷贝到网卡缓存中是需要的。
    页缓存和sendfile组合,意味着Kafka集群的消费者大多数都完全从缓存消费消息,而磁盘没有任何读取活动。

  9. 一个流处理平台应该具有三个关键能力:
    ·发布和订阅消息
    ·以容错的方式存储消息
    ·在消息流发生时处理它们

  10. Kafka的保证
    ·生产者发送到一个特定的Topic的分区上,消息将会按照它们发送的顺序依次加入并写入日志
    ·消费者收到的消息也是此顺序
    ·如果一个Topic配置了复制因子N, 那么可以允许N-1台服务器宕机而不丢失任何已经提交的消息
    kafka默认是保证“至少一次”传递,并允许用户通过禁止生产者重试和处理一批消息前提交它的偏移量来实现 “最多一次”传递。而“正好一次”传递需要与目标存储系统合作,但kafka提供了偏移量,所以实现这个很简单。

  11. Kafka的实现依赖了哪些元素
    ①硬件上,kafka通过线性存储直接读写硬盘
    ②kafka 没有使用内存作为缓存。
    ③Liner writer/reader:拥有 O(1)的操作,而且读写不会相互影响。同时,解耦了数据规模的问题。用廉价的存储就可以达到很高的性价比。
    ④Zero-copy:Zero-copy 减少了 IO 的操作步骤。
    ⑤GZIP and Snappy compression:考虑到传输最大的瓶颈就在于网络,kafka 提供了对数据压缩的各种协议。
    ⑥事务机制:虽然 kafka 对事务的处理比较薄弱,但是在 message 的分发上还是做了一定的策略来保证数据递送的准确性。

  12. Kafka实时流处理
    流处理持续获取输入topic的数据,进行处理加工,然后写入输出topic。
    可以直接使用producer和consumer API进行简单的处理。对于复杂的转换,Kafka提供了更强大的Streams API。可构建聚合计算或连接流到一起的复杂应用程序。
    Sterams API在Kafka中的核心:使用producer和consumer API作为输入,利用Kafka做状态存储,使用相同的组机制在stream处理器实例之间进行容错保障。

  13. 偏移量设计
    Kafka集群保持所有的消息,直到它们过期。消费者仅有的元数据就是偏移量,即消费者在这个log中的位置。消费者消费消息时,偏移量线性增加。消费者也可以将偏移量重置为更老的一个偏移量,重新读取消息。

  14. 分区设计
    ①可以处理更多的消息,不受单台服务器的限制,Topic拥有多个分区意味着它可以不受限的处理更多的数据
    ②第二,分区可以作为并行处理的单元

    这里写图片描述

    Log的分区被分布到集群中的多个服务器上,每个分区还可以复制到其它服务器作为备份容错。每个分区有一个leader,零或多个follower。Leader处理此分区的所有读写请求,follower被动的复制数据。leader宕机,其它follower会推举新leader。一台服务器可能同时是一个分区的leader,另一个分区的follower。这样可以平衡负载,避免所有的请求都只让一台或者某几台服务器处理。

  15. 持久化设计
    在对消息进行存储和缓存时,Kafka严重地依赖于文件系统。线性读取和写入是所有使用模式中最具可预计的一种方式,因而操作系统采用预读和后写技术对磁盘读写进行探测并优化。预读就是提前将一个比较大的磁盘块中内容读入内存,后写是将一些较小的逻辑写入操作合并起来组成比较大的物理写入操作。在某些情况下,顺序磁盘访问能够比随机内存访问还要快!

    所有现代的操作系统都会乐于将所有空闲内存转做磁盘缓存,即使回收这些内存会付出一些性能方面的代价。所有的磁盘读写操作都需要经过这个统一的缓存。因此,对于一个进程而言,即使它在进程内的缓存中保存了一份数据,这份数据也可能在OS 的页面缓存(pagecache)中有重复的一份,结果就成了一份数据保存了两次。

    更进一步讲,我们是在 JVM 的基础上开发的系统:
    ① Java对象的内存开销非常大,往往是对象中存储的数据所占内存的两倍还多
    ② Java中内存垃圾回收会随着堆内数据不断增长而变得越来越不明确,回收所花费的代价也会越来越大。

    由于这些因素,使用文件系统并依赖于页面缓存要优于自己在内存中维护一个缓存或者什么别的结构 —— 通过对所有空闲内存自动拥有访问权,我们至少将可用的缓存大小翻了一倍,然后通过保存压缩后的字节结构而非单个对象,缓存可用大小接着可能又翻了一倍。而且,这种缓存即使在服务重启之后会依然保持有效,而不像进程内缓存,进程重启后还需要在内存中进行缓存重建(10G的缓存重建时间可能需要10分钟),否则就需要以一个全空的缓存开始运行(这么做它的初始性能会非常糟糕)。这还大大简化了代码,因为对缓存和文件系统之间的一致性进行维护的所有逻辑现在都是在OS 中实现的。如果你使用磁盘的方式更倾向于线性读取操作,那么随着每次磁盘读取操作,预读就能非常高效使用随后准能用得着的数据填充缓存。

    这就让人联想到一个非常简单的设计方案:不是要在内存中保存尽可能多的数据并在需要时将这些数据flush到文件系统,而是做完全相反的事情。所有数据都要立即写入文件系统持久化的日志中但不进行对新数据的任何调用。意味着,数据被传输到OS 内核的页面缓存中了,OS 随后会将这些数据刷新到磁盘的。此外我们添加了一条基于配置的刷新策略,允许用户对把数据刷新到物理磁盘的频率进行控刢(每当接收到 N条消息或者每过M秒),从而可以为系统硬件崩溃时“处于危险之中”的数据在量上加个上限

    为了将数据从页面缓存直接传送给socket,现代的Unix操作系统提供了一个高度优化的代码路径。在Linux中是通过sendfile这个系统调用实现的。通过Java中的API,FileChannel.transferTo,由它来简洁的调用上述系统调用。

  16. 副本和leader选举
    kafka集群在各个服务器上备份topic分区中的日志(ps:就是备份我们的消息,称为副本)。当集群中某个服务器发生故障时,自动切换到这些副本,从而保障故障时消息仍然可用。

    副本以topic的分区为单位。正常情况下,kafka每个分区都有一个单独的leader,0个或多个follower。副本的总数包括leader。读取和写入到该分区的leader。通常,分区数比broker多,leader均匀分布在broker。follower的日志完全等同于leader的日志 — 相同的顺序相同的偏移量和消息(当然,在任何一个时间点上,leader比follower多几条消息,尚未同步到follower)

    Followers作为普通的消费者从leader中消费消息并应用到自己的日志中。并允许follower从leader拉取批量日志应用到自己的日志

    和大多数分布式系统一样,自动处理失败的节点。需要精确的定义什么样的节点是“活着”的,对于kafka的节点活着有2个条件:
    ·一个节点必须能维持与zookeeper的会话(通过zookeeper的心跳机制)
    ·如果它是一个slave,它必须复制leader并且不能落后”太多”
    leader跟踪“同步”节点。如果一个follower死掉,卡住,或落后,leader 将从同步副本列表中移除它。落后是通过replica.lag.max.messages配置 控制,卡住是通过replica.lag.time.max.ms配置控制的。

  17. 日志压缩
    旧的数据保留一段固定的时间,或当日志达到规定的大小后丢弃。日志压缩提供了更精细的保留机制,至少保留每个主键的最后一次更新。这意味着下游消费者可以获得最终的状态而无需拿到所有的变化的消息信息。
    可以为每个topic设置保存策略,可以通过大小或时间,以及通过其他的压缩方式保存。
    这里写图片描述
    压缩也允许删除。通过消息的key和空负载来标识该消息可从日志中删除。
    压缩是在后台通过定期重新复制日志段来完成的。清洗不会阻塞读,可以限流I/O吞吐量(是可配置),以避免影响生产者和消费者。
    这里写图片描述
    日志压缩提供什么保障:
    ·滞留在日志head中的消费者能看到写入的所有消息;这些消息是有序的 offset。topic使用min.compaction.lag.ms用来保障消息写入之前须经过 的最小时间长度,才能被压缩。提供了消息保留在head(未压缩)的最少时间。
    ·始终保持消息的排序。压缩永远不会重新排序消息,只是删除了一些。
    ·消息的偏移量永远不会改变。消息在日志中的位置将永久保存。
    ·从日志开始消费的所有消费者将至少看到其按顺序写入的最终状态的消息。 此外,假如消费者在小于topic的delete.retention.ms设置的时间段到达 日志的head。将会看到所有已删除消息的删除标记。换句话说:由于删除日 志与读取同时发生,消费者将优于删除。

    日志压缩的细节:
    日志cleaner处理日志压缩,后台线程池重新复制日志段文件,移除在日志head中出现的消息。每个压缩线程工作方式如下:
    ·选择log head(日志头)到log tail(日志尾)比率最高的日志。
    ·在head日志中为每个key的最后offset创建一个简单概要。
    ·它从日志的开始到结束,删除那些在日志中最新出现的key,新的,干净 的段将立刻交换到日志中。因此,所需的额外磁盘空间只是一个额外的日志 段(不是日志的完整副本)。
    ·日志head的概要本质上是一个空间密集型的哈希表,每个entry使用固 定的24byte。这样8GB的cleaner buffer一次迭代可清理大约366GB的日 志(假设消息1K)。
    配置log cleaner:

    log.cleanup.policy=compact
    

    可以在创建topic时或使用alter topic命令指定。设置压缩延迟时间:

    log.cleaner.min.compaction.lag.ms
    

    消息在一个最小消息时间绝不会被压缩。如果不设置,除了最新的段,其他 所有的段都是可以压缩的,即,当前正在写入的那个。

  18. 配额
    Kafka集群有能力对请求进行配额来控制客户端使用的broker资源:
    ·通过配额定义网络带宽的字节率阈值
    ·请求率配额将CPU的利用率阈值定义为网络和I/O线程的百分比
    为什么需要配额:
    生产者和消费者可能生产/消费大量的数据,从而垄断broker的资源,引起网络饱和,配额可防止这个问题。其中有一小部分不良行为的用户将被降权。事实上,当kafka作为服务运行时,可以根据约定好的协议执行API限制。

  19. Kafka设计元素
    ①通常来说,kafka 的使用是为了消息的持久化
    ②吞吐量是 kafka 设计的主要目标
    ③关于消费的状态被记录为 consumer 的一部分,而不是 server。这点稍微解释下,这里的 server 还是指broker,谁消费了多少数据都记录在消费者自己手中,不存在 broker 中
    ③Kafka 的分布式可以表现在 producer、broker、consumer 都可以分布在多台机器上。

  20. 端到端的批量压缩
    多数情况下系统的瓶颈是网络而不是CPU。高效压缩需要将多条消息一起进行压缩而不是分别压缩每条消息。Kafka对这种压缩方式提供了支持,一批消息可以打包并一起进行压缩,然后以这种形式发送给服务器。这批消息都会被发送给同一个消息使用者,并会在到达使用者那里之前一直保持为被压缩的形式。
    Kafka支持GZIP和Snappy 压缩协议

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值