kafka总结

一、为什么需要消息系统

  1. 解耦:允许你独立的扩展或修改两边的处理过程
  2. 扩展性:因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可
  3. 冗余:消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险
  4. 灵活性和峰值处理能力
  5. 可恢复性:即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理
  6. 顺序保证
  7. 缓冲:有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况
  8. 异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制

二、RabbitMq、ActiveMq、ZeroMq、kafka比较

  1. TPS(每秒事务处理量)比较:Kafka最高,RabbitMq 次之, ActiveMq 最差
  2. 吞吐量对比:kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度。rabbitMQ在吞吐量方面稍逊于kafka,不支持批量的操作;存储可以采用内存或者硬盘
  3. 负载均衡方面比较:kafka采用zookeeper对集群进行管理。 rabbitMQ的负载均衡需要单独的loadbalancer进行支持
  4. 在架构模型方面:kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,producer通过push数据到broker,consumer从broker上批量pull数据;      RabbitMQ遵循AMQP协议,RabbitMQ的broker由Exchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。rabbitMQ以broker为中心;          
  5. ZeroMq不支持持久化。activemq实现了JMS规范,支持持久化到数据库,对队列数较多的情况支持不好

三、kafka介绍

    是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需求场景:比如基于hadoop的批处理系统、低延迟的实时系统、storm/Spark流式处理引擎,web/nginx日志、访问日志,消息服务等等,用scala语言编写

四、kafka特性

  • 高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒
  • 高并发:支持数千个客户端同时读写
  • 可扩展性:kafka集群支持热扩展
  • 持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
  • 容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)

五、Kafka的使用场景

  1. 消息系统:解耦和生产者和消费者、缓存消息等。
  2. 日志收集:通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
  3. 用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
  4. 运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
  5. 流式处理:比如spark streaming和storm

六、基本概念

  1. broker:kafka 集群中包含的服务器
  2. controller:kafka 集群中的其中一个服务器,用来进行 leader election 以及 各种 failover。
  3. producer:消息生产者,发布消息到 kafka 集群的终端或服务。
  4. consumer:从 kafka 集群中消费消息的终端或服务。
  5. Consumer group:high-level consumer API 中,每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 中的一个 Consumer 消费,但可以被多个 consumer group 消费。
  6. topic:Topic相当于传统消息系统MQ中的一个队列queue,producer端发送的message必须指定是发送到哪个topic。
  7. partition:一个topic会分成一个或多个partition,每个partiton相当于是一个子queue。kafka 分配的单位是 partition。
  8. replica:partition 的副本,保障 partition 的高可用。
  9. leader:replica 中的一个角色, producer 和 consumer 只跟 leader 交互。
  10. follower:replica 中的一个角色,从 leader 中复制数据。

七、Producer 生产消息

   7.1 生产方式

     producer 采用 push 模式将消息发布到 broker;producer不用维护offsite信息,offsite就相当于一个自增id

   7.2 消息路由

1、轮询;           
2、hash(message) % [broker数量]

   7.3 发布消息过程

  1. producer 先从 zookeeper 的 "/brokers/.../state" 节点找到该 partition 的 leader
  2. producer 将消息发送给该 leader
  3. leader 将消息写入本地 log
  4. followers 从 leader pull 消息,向leader 发送 ACK后写入本地 log
  5. leader 收到所有 ISR 中的 replica 的 ACK 后,增加 offset, 并向 producer 发送 ACK

    为了提高性能,每个Follower在接收到数据后就立马向Leader发送ACK,而非等到数据写入Log中。因此,对于已经commit的消息,Kafka只能保证它被存于多个Replica的内存中,而不能保证它们被持久化到磁盘中,也就不能完全保证异常发生后该条消息一定能被Consumer消费

  7.4 Producer消息传输保证

1、At most once 消息可能会丢,但绝不会重复传输
2、At least one 消息绝不会丢,但可能会重复传输
3、Exactly once 每条消息肯定会被传输一次且仅传输一次,很多时候这是用户所想要的。

     当 producer 向 broker 发送消息时,一旦这条消息被 commit,由于 replication 的存在,它就不会丢。但是如果 producer 发送数据给 broker 后,遇到网络问题而造成通信中断,那 Producer 就无法判断该条消息是否已经 commit。虽然 Kafka 无法确定网络故障期间发生了什么,但是 producer 可以生成一种类似于主键的东西,发生故障时幂等性的重试多次,这样就做到了 Exactly once,但目前还并未实现。所以目前默认情况下一条消息从 producer 到 broker 是确保了 At least once,可通过设置 producer 异步发送实现At most once。

  7.5 ACK机制

     1)为了保证生产者数据的不丢失。在producer发送数据的时候,每次发送消息都会有一个确认反馈机制,确保消息正常的能够被收到。

通过参数request.required.acks设置
0:producer不等待broker返回ack确认信息
1:producer等待topic中某个partition leader保存成功的状态反馈
-1:producer等待topic中某个partition 所有副本都保存成功的状态反馈

   2)在向Producer发送ACK前需要保证有多少个Replica已经收到该消息:根据ack配的个数而定 。

   3)怎样处理某个Replica不工作的情况:

  1. 如果这个replica不在ack列表中,就是producer在发送消息到partition leader上,partition leader向partition follower发送message没有响应而已,这个不会影响。
  2. 如果这个replica在ack列表中的话,producer发送的message的时候会等待这个不工作的partition replca写message成功,但是会等到time out,然后返回失败,此时kafka会自动的把这个不工作的partition replica从ack列表中移除

   4)怎样处理Failed Replica恢复回来的情况

  1. 如果这个partition replica之前不在ack列表中,那么启动后重新受Zookeeper管理即可,之后producer发送message的时候,partition leader会继续发送message到这个partition follower上。
  2. 如果这个partition replica之前在ack列表中,此时重启后,需要把这个partition replica再手动加到ack列表中。

  7.6 Producer同步异步

   producer同步和异步的发送数据通过“producer.type”参数指定,值为sync/async,默认sync同步。如果设置成async异步的模式,可以运行生产者以批量的形式push数据,这样会极大的提高broker的性能,但是这样会增加丢失数据的风险。

一般配置
对于sync的发送方式: 
producer.type=sync 
request.required.acks=1

对于async的发送方式: 
producer.type=async 
request.required.acks=1 
queue.buffering.max.ms=5000         //producer缓存消息的时间,可以极大的增加broker吞吐量,但会造成时效性的降低
queue.buffering.max.messages=10000  //producer缓存队列里最大缓存的消息数量,如果超过这个值,producer就会阻塞或者丢掉消息
queue.enqueue.timeout.ms = -1       //当达到上面参数时producer会阻塞等待的时间。如果设置为0,buffer队列满时producer不会
                                    阻塞,消息直接被丢掉;若设置为-1,producer会被阻塞,不会丢消息
batch.num.messages=200              //每次批量发送的数量。达到这个数值时,producer才会发送消息

当满足以下其中一个条件的时候就触发发送
batch.num.messages 异步发送 每次批量发送的条目 
queue.buffering.max.ms 异步发送的时候 发送时间间隔 单位是毫秒

八、Broker保存消息

8.1 文件存储

     物理上把 topic 分成一个或多个 patition(对应 server.properties 中的 num.partitions=3 配置),每个 patition 物理上对应一个文件夹(该文件夹存储该 patition 的所有消息和索引文件),文件夹命名是[topicname]_[partition]_[序号]

      一个Topic的Partition数量大于等于Broker的数量,可以提高吞吐率。同一个Partition的Replica尽量分散到不同的机器,高可用,存replica副本的方式是按照kafka broker的顺序存存储。副本数目不能大于kafka broker节点的数目,否则报错

8.3 旧数据删除策略

1、基于时间:log.retention.hours=168 
2、基于大小:log.retention.bytes=1073741824

    无论消息是否被消费,kafka 都会保留所有消息。可以设定消息的过期时间,只有过期的数据才会被自动清除以释放磁盘空间。需要注意的是,因为Kafka读取特定消息的时间复杂度为O(1),即与文件大小无关,所以这里删除过期文件与提高 Kafka 性能无关

九、Consumer 消费消息 

   9.1 消费方式

      Consumer 采用 pull 模式从 broker 中读取数据。原因:push 模式很难适应消费速率不同的消费者,因为消息发送速率是由 broker 决定的。它的目标是尽可能以最快速度传递消息,但是这样很容易造成 consumer 来不及处理消息,典型的表现就是拒绝服务以及网络拥塞。而 pull 模式则可以根据 consumer 的消费能力以适当的速率消费消息

   9.2 顺序消费

  1. Consumer处理partition里面的message的时候是o(1)顺序读取的。所以必须维护着上一次读到哪里的offsite信息。high level API,offset存于Zookeeper中,low level API的offset由自己维护。一般来说都是使用high level api的。AMQ采用悲观锁并发处理message
  2. partition中的message只能被Consumer group中的一个consumer消费,如果一个partition的message可以被多个consumer消费的话,那么这些consumer必须在不同的Consumer group。
  3. 一般情况下,一个consumer group处理一个topic的message,consumer group下面的所有consumer 一定会消费topic下的全部partition。最优方法是这个consumer group里面consumer的数量等于topic里面partition的数量,这样效率是最高的,一个consumer 处理一个partition。如果这个consumer group里面consumer的数量小于topic里面partition的数量,就会有consumer同时处理多个partition。如果这个consumer group里面consumer的数量大于topic里面partition的数量,多出的consumer thread就会闲着啥也不干,剩下的是一个consumer thread处理一个partition,这就造成了资源的浪费,因为一个partition不可能被两个consumer去处理
  4. 如果producer的流量增大,当前的topic的parition数量=consumer数量,这时候的应对方式就是很想扩展:增加topic下的partition,同时增加这个consumer group下的consumer

   9.3 consumer消息传递保证

      1.读完消息先 commit 再处理消息。
            默认方式。这种模式下,如果 consumer 在 commit 后还没来得及处理消息就 crash 了,下次重新开始工作后就无法读到刚刚已提交而未处理的消息,这就对应于 At most once
      2.读完消息先处理再 commit。
            这种模式下,如果在处理完消息之后 commit 之前 consumer crash 了,下次重新开始工作时还会处理刚刚未 commit 的消息,实际上该消息已经被处理过了。这就对应于 At least once。
      3.如果一定要做到 Exactly once,就需要协调 offset 和实际操作的输出。
            精典的做法是引入两阶段提交。如果能让 offset 和操作输入存在同一个地方,会更简洁和通用。这种方式可能更好,因为许多输出系统可能不支持两阶段提交。比如,consumer 拿到数据后可能把数据放到 HDFS,如果把最新的 offset 和数据本身一起写到 HDFS,那就可以保证数据的输出和 offset 的更新要么都完成,要么都不完成,间接实现 Exactly once。(目前就 high-level API而言,offset 是存于Zookeeper 中的,无法存于HDFS,而SimpleConsuemr API的 offset 是由自己去维护的,可以将之存于 HDFS 中)

       总之,Kafka 默认保证 At least once,并且允许通过设置 producer 异步提交来实现 At most once

   9.4 Consumer Rebalance的触发条件

(1)Consumer增加或删除
(2)Broker的增加或者减少

   为了保证整个consumer group 的一致性,当一个 consumer 触发了 rebalance 时,该 consumer group 内的其它所有其它 consumer 也应该同时触发 rebalance。这会导致以下几个问题 :

1.群体效应:任何 broker 或者 consumer 的增减都会触发所有的 consumer 的 rebalance
2.脑裂问题:每个 consumer 分别单独通过 zookeeper 判断哪些 broker 和 consumer 宕机了,那么不同 consumer在同一时刻
           从 zookeeper 看到的 view 就可能不一样,这是由 zookeeper 的特性决定的,这就会造成不正确的 reblance 尝试。
3.调整结果不可控:所有的 consumer 都并不知道其它 consumer 的 rebalance 是否成功,这可能会导致 kafka 工作在
                一个不正确的状态。

  基于以上问题,kafka 设计者考虑在0.9.*版本开始使用中心 coordinator 来控制 consumer rebalance 

十、Kafka HA(高可用)

  10.1 Broker failover            

     当controller宕机时,原先在zookeeper的临时节点会消失,然后重启发起leader选举。

     leader选举:Kakfa Broker集群受Zookeeper管理。所有的Kafka Broker节点一起去Zookeeper上注册一个临时节点,因为只有一个Kafka Broker会注册成功,其他的都会失败,所以这个成功在Zookeeper上注册临时节点的这个Kafka Broker会成为Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。Controller会在ZooKeeper注册Watch。监听其他的Kafka Broker的所有信息

     当监听到非controller中的一个broker宕机时,这个kafka broker controller会读取该宕机broker上所有的partition在zookeeper上的状态,并选取ISR列表中的一个replica作为partition leader(如果ISR列表中的replica全挂,选一个幸存的replica作为leader; 如果该partition的所有的replica都宕机了,则将新的leader设置为-1,等待恢复,等待ISR中的任一个Replica“活”过来,并且选它作为Leader;或选择第一个“活”过来的Replica(不一定是ISR中的)作为Leader),这个broker宕机的事情,kafka controller也会通知zookeeper,zookeeper就会通知其他的kafka broker 

    Kafka判断一个节点是否活着有两个条件:

  1. 节点必须可以维持和ZooKeeper的连接,Zookeeper通过心跳机制检查每个节点的连接。
  2. 如果节点是个follower,他必须能及时的同步leader的写操作,延时不能太久。

符合以上条件的节点准确的说是同步中的(in sync)。Leader会追踪所有“同步中”的节点,一旦一个down掉了,或是卡住了,或是延时太久,leader就会把它移除。

replica.lag.time.max.ms =10000

replicas响应partition leader的最长等待时间,若是超过这个时间,就将replicas从ISR列表剔除

replica.lag.max.messages =4000

如果follower落后与leader太多,将会认为此relicas已经失效

##通常,在follower与leader通讯时,因为网络延迟或者链接断开,总会导致replicas中消息同步滞后

##如果消息之后太多,leader将认为此follower网络延迟较大或者消息吞吐能力有限,将会把此replicas迁移

##到其他follower中.

##在broker数量较少,或者网络不足的环境中,建议提高此值.

 10.2 partition leader failover 

   当 partition 对应的 leader 宕机时,需要从 follower 中选举出新 leader。在选举新leader时,一个基本的原则是,新的 leader 必须拥有旧 leader commit 过的所有消息

    kafka 在 zookeeper 中(/brokers/.../state)动态维护了一个 ISR(in-sync replicas),只有 ISR 里面的成员才能选为 leader。对于 f+1 个 replica,一个 partition 可以在容忍 f 个 replica 失效的情况下保证消息不丢失。

当所有 replica 都不工作时,有两种可行的方案:

1. 等待 ISR 中的任一个 replica 活过来,并选它作为 leader。可保障数据不丢失,但时间可能相对较长。
2. 选择第一个活过来的 replica(不一定是 ISR 成员)作为 leader。无法保障数据不丢失,但相对不可用时间较短。

10.3 replication

      同一个 partition 可能会有多个 replica(对应 server.properties 配置中的 default.replication.factor=N)。没有 replica 的情况下,一旦 broker 宕机,其上所有 patition 的数据都不可被消费,同时 producer 也不能再将数据存于其上的 patition

 Kafka 分配 Replica 的算法如下:

1. 将所有 broker(假设共 n 个 broker)和待分配的 partition 排序
2. 将第 i 个 partition 分配到第(i mod n)个 broker 上
3. 将第 i 个 partition 的第 j 个 replica 分配到第((i + j) mode n)个 broker上

十一、性能优化

 11.1 减少磁盘IO

      kafka使用文件存储消息(append only log),这就直接决定kafka在性能上严重依赖文件系统的本身特性。通过文件缓存/直接内存映射等是常用的手段。因为kafka是对日志文件进行append操作,因此磁盘检索的开支是较小的;同时为了减少磁盘写入的次数,broker会将消息暂时buffer起来,当消息的个数(或尺寸)达到一定阀值时,再flush到磁盘,这样减少了磁盘IO调用的次数.对于kafka而言,较高性能的磁盘,将会带来更加直接的性能提升

 11.2 减少网络IO

  1.  对于producer端,可以将消息buffer起来,当消息的条数达到一定阀值时,批量发送给broker;对于consumer端也是一样,批量fetch多条消息.不过消息量的大小可以通过配置文件来指定
  2. 启用消息压缩机制是一个良好的策略;压缩需要消耗少量的CPU资源。kafka支持gzip/snappy等多种压缩方式

 11.3 zero copy(零拷贝)

一般将数据从文件发送到socket的数据流向:

  1. 操作系统把数据从文件拷贝到内核中的页面缓存中
  2. 应用程序将数据从页面缓存拷贝到自己的内存缓存中
  3. 应用程序将数据从自己内存中写入到内核中socket缓存中
  4. 操作系统将数据从socket缓存中拷贝到网卡接口缓存,从这里发送到网络上。

这显然是低效率的,有4次拷贝和2次系统调用。在linux中Sendfile通过直接将数据从页面缓存发送网卡接口缓存,避免了重复拷贝,大大的优化了性能

问题总结

1、producer 无法发送消息的问题

   没有抛错。首先查看iptables有没开放端口,然后修改server.properties 配置

1. listeners=PLAINTEXT://121.10.26.XXX:9092
2. advertised.listeners=PLAINTEXT://121.10.26.XXX:9092

修改后重启服务

   advertised.listeners 是 broker 给 producer 和 consumer 连接使用的,如果没有设置,就使用 listeners,而如果 host_name 没有设置的话,就使用 java.net.InetAddress.getCanonicalHostName() 方法返回的主机名

2、如何保证kafka消费者消费数据是全局有序的

     如果要全局有序的,必须保证生产有序,存储有序,消费有序。由于生产可以做集群,存储可以分片,消费可以设置为一个consumerGroup,要保证全局有序,就需要保证每个环节都有序。只有一个可能,就是一个生产者,一个partition,一个消费者。这种场景和大数据应用场景相悖。

3、Kafka服务器能接收到的最大信息是多少?

    Kafka服务器可以接收到的消息的最大大小是1000000字节

4、可以在没有Zookeeper的情况下使用Kafka吗?

      不可能越过Zookeeper,直接联系Kafka broker。一旦Zookeeper停止工作,它就不能服务客户端请求。 Zookeeper主要用于在集群中不同节点之间进行通信 在Kafka中,它被用于提交偏移量,因此如果节点在任何情况下都失败了,它都可以从之前提交的偏移量中获取 除此之外,它还执行其他活动,如: leader检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。
   

猜你喜欢

转载自blog.csdn.net/qq_33314107/article/details/81488230
今日推荐