Kafka 简记

引言

接触一门新的开源项目,最关键就是了解其特性和理解中间的设计原理。但在面对庞大的设计官档或者源码的并且又没人指导的时候,总是会让人望而却步,加之网上资料太过冗长。结合翻阅的资料和查看官档后进行了一些简单介绍和总结,只针对Kafka 0.9.0.1版本。

原理

Kakfa之所以快,是因为它基于文件系统,通过page cache实现了io顺序读写达到高速吞吐的性能。kafka通过os缓存替换了Java缓存,在减少了gc的情况,防止缓存多份的情况下也降低了维护难度。 

名词

  • Topic:用于划分Message的逻辑概念,一个Topic可以分布在多个Broker上。
  • Partition:是Kafka中横向扩展和一切并行化的基础,每个Topic都至少被切分为1个Partition。
  • Offset:消息在Partition中的编号,编号顺序不跨Partition。
  • Consumer:用于从Broker中取出/消费Message。
  • Producer:用于往Broker中发送/生产Message。
  • Replication:Kafka支持以Partition为单位对Message进行冗余备份,每个* Partition都可以配置至少1个Replication(当仅1个Replication时即仅该Partition本身)。
  • Leader:每个Replication集合中的Partition都会选出一个唯一的Leader,所有的读写请求都由Leader处理。其他Replicas从Leader处把数据更新同步到本地,过程类似大家熟悉的MySQL中的Binlog同步。
  • Broker:Kafka中使用Broker来接受Producer和Consumer的请求,并把Message持久化到本地磁盘。每个Cluster当中会选举出一个Broker来担任Controller,负责处理Partition的Leader选举,协调Partition迁移等工作。
  • ISR(In-Sync Replica):是Replicas的一个子集,表示目前Alive且与Leader能够“Catch-up”的Replicas集合。由于读写都是首先落到Leader上,所以一般来说通过同步机制从Leader上拉取数据的Replica都会和Leader有一些延迟(包括了延迟时间和延迟条数两个维度),任意一个超过阈值都会把该Replica踢出ISR。每个Partition都有它自己独立的ISR。

优势

  • 文本系统io顺序流读写,速度快。
  • 0.8以上版本添加了ack机制,进一步防止数据丢失。
  • (zero-copy)调用系统级别函数sendfile(直接把硬盘数据从kernel buffer拷贝到kernel socket buffer,减少了user mode和kernel mode的上下文切换),从而提高性能。

特性

  • offset:0.82版本之前存储在zk里面,但是由于使用zk client频繁写入是一个低效的操作,所以在0.82以后的版本引入了native offset storage,利用了kafka的compacted topic,在内存中维护offset,达到快速存取的效果,同时也会生成checkpoint到log目录用以恢复offset。
  • partition:一旦某个client连接到几个partition后,不管你消不消费,这个partition都被这个client占据着,没法被别的client消费了,rebalancing后才会重新分配partition。
  • consumer在同一个group中只能消费一次

技巧

  • 因为相同consumer同一个group只能消费一次,那么使用相同group.id相当于传统mq的点对点,不同group.id的时候相当于订阅发布。
  • 由于一个partition同时只能被一个consumer消费,所以consumer数不要大于partition数,最优的方案是consumer数和partition数保持一致。

遇到问题

1、出现消息重复消费

Kafka是使用poll()(长轮询)拉取消息,流程可以简单理解为: 拉取消息->向kafka broker发送心跳->提交 offset。当消费者处理过慢(session timeout为30s)没有向kafka broker发送心跳,而且没有提交 offset,broker就会发起rebalancing,这个分区就会分配给其他消费者重复消费。最坏的情况是一直在 rebalancing,新的消息都不会被消费。

解决方法:
增大session.timeout.ms的心跳间隔时间,减少max.partition.fetch.bytes每次从分区拉取的消息量,以降低这种reblancing的情况。另一种方法就是poll出来的数据丢入线程池进行额外消费,快递吞吐消息,弊端就是宕机的时候会导致部分消息丢失。(PS:第二种方法只适应于只追求性能速度,无所谓数据丢失的场景)

2、Kafka 0.9.0.1 server.properties配置bug

advertised.host.name理论上应该按照下面的策略进行,但是因为存在bug,不生效

Hostname the broker will advertise to producers and consumers. 
If not set, it uses the value for "host.name" if configured.    

Otherwise, it will use the value returned from
java.net.InetAddress.getCanonicalHostName().

解决方法:
同时设置advertised.host.name和host.name为相应的ip即可。

 

 

 

 

猜你喜欢

转载自mdxdjh2.iteye.com/blog/2334080