Kafka核心技术与实战

一. Kafka入门

01. 消息引擎系统

国外名字Messaging System,国内翻译成消息引擎。

消息引擎系统:消息引擎是一组规范,企业利用这组规范在不同系统之间传递语义准确的消息,实现松耦合的一步式消息传递。通俗的讲,就是系统A发送消息给消息引擎系统,系统B从消息引擎系统中读取A发送的消息。

消息引设定具体的传输协议,用什么方法把消息传出去:

  • 点对点模型
  • 发布/订阅模型

Kafka同时支持这两种消息引擎模型。

Kafka引入的优点:

  • 削峰填谷:上游系统不再与下游系统进行交互,Kafka能够将瞬时增加的订单流量全部以消息形式保存在对应的主题中,既不影响上游服务的TPS:Transactions Per Second(每秒传输的事物处理个数),也能够给下游子服务留出充足的时间去消费他们。
  • 松耦合:发送方和接收方的松耦合,在一定程度上简化了应用开发减少了系统间不必要的交互。
02. 一篇文章带你快速搞定Kafka术语

Record(消息):Kafka处理的主要对象

Topic(主题):主题是承载消息的逻辑容器,在实际使用中多用来区分具体的业务。

Partitioning(分区):一个有序不变的消息序列。每个主题下可以有多个分区。

Offset(消息位移):表示分区中每条消息的位置信息,是一个单调递增且不变的值。

Producer(生产者):向主题发布消息的应用程序。

Consumer(消费者):从主题订阅消息的应用程序。

Client(客户端):Producer(生产者)和Consumer(消费者)统称为Client(客户端)。

Broker(服务器端):Kafka的服务端由被称为Broker的服务进程构成,即一个Kafka集群由多个Broker组成,Broker负责接收和处理客户端发送过来的请求,以及对消息进行持久化。

Consumer Offset(消费者位移):表示消费者消费进度,每个消费者都有自己的消费者位移。

Consumer Group(消费者组):多个消费者实例共同组成的一个组,同时消费多个分区以实现高吞吐。

Rebalance(重平衡):消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。

Replica(副本):

  • Leader Replica(领导者副本):对外提供服务,对外服务指的是与客户端进行交互。
  • Follower Replica(追随者副本):被动的追随领导者副本,不能与外界交互。
  • 之前的Master-Slave即现在的Leader-Follower

Kafka三层消息架构

  • 第一层是主题层,每个主题可以配置M个分区,而每个分区又可以配置N个副本。
  • 第二层是分区层,每个分区的N个副本中只能有一个充当领导者角色,对外提供服务,其他N-1个副本是追随者副本,知识提供数据冗余之用。
  • 第三层是消息层,分区中包含若干条消息,每条消息的位移从0开始,依次递增。
  • 最后,客户端程序只能与分区的领导者副本进行交互。

IMG_0478.JPG

03. 我应该选择哪种Kafka?
  • Apache Kafka:社区版本

优势:开发人数最多,掌控高

劣势:仅提供最基础的组件,没有提供任何监控工具和框架

  • Confluent Kafka:Kafka创始人离开Linkedin后创办公司

免费版:比社区版多了Schema注册中心,REST proxy,多种连接器

企业版:跨数据中心备份,集群监控

劣势:相关文档资料不全,没有太多可供参考的范例

  • Cloudera/Hortonworks Kafka

优势:操作简单,节省运维成本

劣势:把控度低,演进速度慢

04. 聊聊Kafka的版本号

Kafka目前总共演进了7个大版本,分别是0.7,0.8,0.9,0.10,0.11,1.0,2.0

0.8:引入了副本机制

0.9:增加了基础的安全认证/权限功能,使用java重写了Producter API,在这个版本中算比较稳定了,不建议使用新版本的Consumer API。引入了Kafka Connet组件

0.10:引入了Kafka Streams,Consumer API算是稳定了,修复了Producter的bug

0.11:提供幂等性Producer API以及事务API;对Kafka消息格式做了重构

1.0 & 2.0:Kafka Streams的各种改进

二. Kafka基本使用

05. kafka线上集群部署方案怎么做?** **

磁盘阵列(RAID)优势:

  • 提供冗余的磁盘存储空间
  • 提供负载均衡**
    **
因素考量点建议
操作系统操作系统I/O模型将Kafka部署在Linux系统上
磁盘磁盘I/O性能普通环境使用机械磁盘,不需要搭建RAID
磁盘容量根据消息数、留存时间预估磁盘容量实际使用中建议预留20%~30%的磁盘空间
带宽根据实际带宽资源和业务SLA预估服务器数量对于千兆网络,建议每台服务器按照700Mbps来计算,避免大流量下的丢包
06. 最重要的集群参数配置(上)
  1. 针对存储相关的参数(Broker端参数)
  • log.dirs:指定的Broker需要使用的若干个文件的目录路径,无默认值
  • log.dir:指定的Broker需要使用的单个文件的目录路径

例如 /home/kafka1,/home/kafka2,/home/kafka3

  1. 针对Kafka与ZooKeeper
  • zookeeper.connect

例如 zk1:2181,zk2:2181,zk3:2181(2181是zookeeper默认的端口)

如果多个Kafka集群使用一个zookeeper集群,这样设置,zk1:2181,zk2:2181,zk3:2181/kafka1和zk1:2181,zk2:2181,zk3:2181/kafka2

  1. 与Broker连接相关的参数
  • listerers(监听器)告诉外部连接者要通过什么协议访问指定主机名和端口开发的Kafka服务
  • advertised.listeners,这组监听器是Broker用于对外发布的
  1. 关于Topic管理的参数
  • auto.create.topics.enable:是否允许自动创建Topic

建议射程false,不允许随便创建topic

  • unclean.leader.election.enable:是否允许unclean leader选举

kafka有多副本策略,设置成false,剑指不能让数据落后太多的副本竞选leader,这样做的后果是这个分区就不可用了,因为没有leader了。反之如果是true,那么kafka允许从那些“跑的慢”的副本中选一个出来当leader,这样做的后果是数据有可能丢失。建议设置成false。

  • auto.leader.rebalance.enable:是否允许定期进行leader选举

建议设置成false。如果设置成true,有可能一段时间leader A被强制换成leader B,换一次leader代价很高的,而且这种换leader本质上没有任何性能收益。

  1. 关于数据留存的参数
  • log.retention.{hours|minutes|ms}:控制一条消息数据被保存多长时间,优先级上来说ms设置最高、minutes辞职、hours最低。
  • log.retention.bytes:指定Broker为消息保存可以占用的磁盘容量大小

这个默认值是-1,表示想在这台Broker保存多少数据都可以

  • message.max.bytes:控制Broker能够接收的最大消息大小

默认值不到1MB,建议根据实际来,可以设置成稍微大一点。

07. 最总要的集群参数配置(下)
  1. Topic级别参数

说起 Topic 级别的参数,你可能会有这样的疑问:如果同时设置了 Topic 级别参数和全局 Broker 参数,到底听谁的呢?哪个说了算呢?答案就是 Topic 级别参数会覆盖全局 Broker 参数的值,而每个 Topic 都能设置自己的参数值,这就是所谓的 Topic 级别参数。

  • retention.ms:规定了该topic消息被保存的时长,默认为7天。
  • retention.bytes:规定了要为该topic预留多大的磁盘空间,默认值为-1,表示可以无限使用磁盘空间。
  • max.message.bytes:它决定了Kafka Broker能够正常接收该Topic的最大消息大小
  1. JVM参数

Kafka 服务器端代码是用 Scala 语言编写的,但终归还是编译成 Class 文件在 JVM 上运行,因此 JVM 参数设置对于 Kafka 集群的重要性不言而喻。另外 Kafka 自 2.0.0 版本开始,已经正式摒弃对 Java 7 的支持了,所以有条件的话至少使用 Java 8 吧。

  • KAFKA_HEAP_OPTS:指定堆大小。JVM 堆大小设置成 6GB 吧,这是目前业界比较公认的一个合理值。

  • KAFKA_JVM_PERFORMANCE_OPTS:指定GC参数

    • GC参数(java7)

如果 Broker 所在机器的 CPU 资源非常充裕,建议使用 CMS 收集器。启用方法是指定–

-XX:+UseCurrentMarkSweepGC。否则,使用吞吐量收集器。开启方法是指定-XX:+UseParallelGC。

    • GC参数(java8)

用默认的 G1 收集器就好了。在没有任何调优的情况下,G1 表现得要比 CMS 出色,主要体现在更少的 Full GC,需要调整的参数更少等,所以使用 G1 就好了。

  1. 操作系统参数
  • 文件描述符限制:通常情况下将它设置成一个超大的值是合理的做法,比如ulimit -n 1000000。通常情况下将它设置成一个超大的值是合理的做法,比如ulimit -n 1000000。
  • 文件系统类型:这里所说的文件系统指的是如 ext3、ext4 或 XFS 这样的日志型文件系统。根据官网的测试报告,XFS 的性能要强于 ext4,所以生产环境最好还是使用 XFS。对了,最近有个 Kafka 使用 ZFS 的数据报告,貌似性能更加强劲。
  • Swappiness:网上很多文章都提到设置其为 0,将 swap 完全禁掉以防止 Kafka 进程使用 swap 空间。我个人反倒觉得还是不要设置成 0 比较好,我们可以设置成一个较小的值。为什么呢?因为一旦设置成 0,当物理内存耗尽时,操作系统会触发 OOM killer 这个组件,它会随机挑选一个进程然后 kill 掉,即根本不给用户任何的预警。但如果设置成一个比较小的值,当开始使用 swap 空间时,你至少能够观测到 Broker 性能开始出现急剧下降,从而给你进一步调优和诊断问题的时间。基于这个考虑,我个人建议将 swappniess 配置成一个接近 0 但不为 0 的值,比如 1。
  • 提交时间:或者说是Flush落盘时间。。向 Kafka 发送数据并不是真要等数据被写入磁盘才会认为成功,而是只要数据被写入到操作系统的页缓存(Page Cache)上就可以了,随后操作系统根据 LRU 算法会定期将页缓存上的“脏”数据落盘到物理磁盘上。这个定期就是由提交时间来确定的,

三. 客户端实践及原理剖析

08. 生产者消息分区机制原理剖析

在使用Apache Kafka生产和消费消息的时候,肯定希望能够将数据均匀地分配到所有服务器上,如果将大数据量均****匀地分配到Kafka的哥哥Broker上,成为一个非常重要的问题。

为什么分区?

其实分区的作用就是提供负载均衡的能力,或者说对数据进行分区的主要原因,就是为了实现系统的高伸缩性(Scalability)。

值得注意的是,不同的分布式系统对分区的叫法也不尽相同,比如在Kafka中叫分区,在MongoDB和Elasticsearch中就叫分片Shard,而在HBase中则叫Region,在Cassandra中又叫vnode。

  • Kafka的消息组织方式实际上是三级结构:主题-分区-消息。主题下的每条消息知乎包存在某一个分区中,而不会在多个分区中保存多份。

C0B68678-7438-4FC7-8DC7-FEA290CB8AF2.jpeg

  • 分区是实现负载均衡及高吞吐量的关键

分区策略有哪些?

分区策略也就是决定生产者将消息发送到哪个分区的算法,分区策略常见分类:

  1. 轮询策略(默认分区策略)

也称Round-robin策略,即顺序分配。如果一个主题下有3个分区,那么第一条消息被发送到分区0,第二条被发送到分区1,第三条被发送到分区2,以此类推。当生产第4条消息又会重新开始,即将其分配到分区0 。

5AC6573B-53D1-44B0-88ED-788450E6DC71.jpeg

  1. 随机策略

也称Randomness策略。所谓随机策略就是我们随意地将消息放知道任意一个分区上。但从实际上来看,它要逊于轮询策略。

BF62A47B-2AB0-4E90-970A-774E22C313B9.jpeg

  1. 按消息键保存策略

也称Key-ordering策略。Kafka允许为每条消息定义消息键,简称为key。由于每个分区下的消息处理都是有顺序的,故这个策略被称为按消息键保存策略。

A4563B58-585C-46AD-8954-38AE9E28929A.jpeg

10. 无消息丢失配置怎么实现?

Kafka在什么情况下才能保证消息不丢失?

Kafka支队"已提交"的消息(committed message)做有限度的持久化保证。

  • 已提交的消息:

当 Kafka 的若干个 Broker 成功地接收到一条消息并写入到日志文件后,它们会告诉生产者程序这条消息已成功提交。此时,这条消息在 Kafka 看来就正式变为“已提交”消息了。

这里的若干个可以设置为只要有一个Broker成功保存该消息就算是已提交,也可以是令所有Broker都车更难过保存该消息才算是已提交。

  • 有限度的持久化保证:

Kafka不丢失消息是有前提条件的,假如你的消息包存在N个Kafka Broker上,前提条件就是这个N个Broker中至少有一个存活。

  1. "消息丢失"情况分类

a. 生产者程序丢失数据

目前 Kafka Producer 是异步发送消息的,也就是说如果你调用的是 producer.send(msg) 这个 API,那么它通常会立即返回,但此时你不能认为消息发送已成功完成。

这种发送方式有个有趣的名字,叫“fire and forget”,翻译一下就是“发射后不管”。如果用这个方式,可能有很多原因导致消息压根久没哟欧发送到Broker端,或者消息本身不合格导致Broker拒绝接收。

实际上,解决此问题的方法非常简单:Producer 永远要使用带有回调通知的发送 API,也就是说不要使用 producer.send(msg),而要使用 producer.send(msg, callback)。

b. 消费者程序丢失数据

消费消息与更新位移的顺序不对。

对抗这种消息丢失,办法很简单:维持先消费消息(阅读),再更新位移(书签)的顺序即可。这样就能最大限度地保证消息不丢失。当然这种方式可能带来的问题是消息的重复处理。

c. 消费端多线程消费消息出现数据丢失

Consumer 程序从 Kafka 获取到消息后开启了多个线程异步处理消息,而 Consumer 程序自动地向前更新位 移。假如其中某个线程运行失败了,它负责的消息没有被成功处理,但位移已经被更新了,因此这条消息对于 Consumer 而言实际上是丢失了。

这个问题的解决方案也很简单:如果是多线程异步处理消费消息,Consumer 程序不要开启自动提交位移,而是要应用程序手动提交位移。

  1. 最佳实践

    1. 不要使用producer.send(msg),而要使用producer. send(msg,callback)
    2. 设置acks=all,acks是producer的一个参数,代表了比对"已提交"消息的定义,如果设置成all,则表明所有副本broker都要接收到消息,该消息才算是"已提交",这是最高等级的"已提交"定义。
    3. 设置retries为一个较大的值,这里的retries同样是producer的参数,对应前面提到的producer的参数,对应前面提到的producer自动重试。当出现网络的瞬间抖动时,消息发送可能会失败,此时配置了retries大于0的producer能够自动重试消息发送,避免消息丢失。
    4. 设置 unclean.leader.election.enable = false。这是 Broker 端的参数,它控制的是哪些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么它一旦成为新的 Leader,必然会造成消息的丢失。故一般都要将该参数设置成 false,即不允许这种情况的发生。
    5. 设置 replication.factor >= 3。这也是 Broker 端的参数。其实这里想表述的是,最好将消息多保存几份,毕竟目前防止消息丢失的主要机制就是冗余。
    6. 设置 min.insync.replicas > 1。这依然是 Broker 端参数,控制的是消息至少要被写入到多少个副本才算是“已提交”。设置成大于 1 可以提升消息持久性。在实际环境中千万不要使用默认值 1。
    7. 确保 replication.factor > min.insync.replicas。如果两者相等,那么只要有一个副本挂机,整个分区就无法正常工作了。我们不仅要改善消息的持久性,防止数据丢失,还要在不降低可用性的基础上完成。推荐设置成 replication.factor = min.insync.replicas + 1。
    8. 确保消息消费完成再提交。Consumer 端有个参数 enable.auto.commit,最好把它设置成 false,并采用手动提交位移的方式。就像前面说的,这对于单 Consumer 多线程处理的场景而言是至关重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值