Kafka

1.Kafka基本概念

 

Topic :消息根据Topic进行归类
Producer:发送消息者
Consumer:消息接受者
Kafka cluster:kafka集群
broker:每个kafka实例(server)
Zookeeper:依赖集群保存metadata信息

image.png

如上消息生产者使用kafka集群发送消息消息接受者从集群获取消息

1.1 Broker实例

一个kafka实例一个broker

 

1.2 主题Topic

image.pngimage.png

 

1.3 分区Partition

image.png

image.png

1.4 副本(Replication)

image.png

 

 1.数据同步
  kafka 0.8后提供了Replication机制来保证Broker的failover。
  引入Replication之后,同一个Partition可能会有多个Replica,而这时需要在这些Replication之间
   选出一个Leader,Producer和Consumer只与这个Leader交互,其它Replica作为Follower从Leader中
   复制数据。
2.副本放置策略  
 Kafka分配Replica的算法如下(注意!!! 下面的broker、partition副本数这些编号都是从0开始编号的):
 将所有存活的N个Brokers和待分配的Partition排序将第i个Partition分配到第(i mod n)个Broker上,
  这个Partition的第一个Replica存在于这个分配的Broker上,并且会作为partition的优先副本( 这里就
  基本说明了一个topic的partition在集群上的大致分布情况 )将第i个Partition的第j个Replica分配到
  第((i + j) mod n)个Broker上
 
 假设集群一共有4个brokers,一个topic有3个partition,每个Partition有3个副本。下图是每个Broker上的
  副本分配情况。

 

1.5 Metadata

 

Metadata 包含 Topic 和 Partition 和 broker 的映射关系,每一个 Topic 的每一个 partition,需要知道
对应的 broker 列表是什么,Leader 是谁,Follower 是谁。这些信息都是存储在 Metadata 这个类中。

image.png

 

1.6 数据同步

image.png

image.png

1.7 Kafka中ZK的作用

image.png

 

1.broker的集群配置信息 
kafka的每个broker(相当于一个节点,相当于一个机器)在启动时,都会在zk中注册,告诉zk其brokerid,在整
个的集群中,broker.id/brokers/ids,当节点失效时,zk就会删除该节点,就很方便的监控整个集群broker的
变化,及时调整负载均衡。

2.topic和partition信息
在kafka中可以定义很多个topic,每个topic又被分为很多个分区。一般情况下,每个分区独立在存在一个broker
上,所有的这些topic和broker的对应关系都由zk进行维护存放在broker.id/brokers/topics中

3. consumer(消费者)在zk中注册 --现在已经记录在本地
注册新的消费者,当有新的消费者注册到zk中,zk会创建专用的节点来保存相关信息,路径 
/consumers/{group_id}/ [ids,owners,offset],
Ids:记录该消费分组有几个正在消费的消费者,
Owmners:记录该消费分组消费的topic信息,
Offset:记录topic每个分区中的每个offset 

4.监听消费者分组中消费者的变化
 监听/consumers/{group_id}/ids的子节点的变化,一旦发现消费者新增或者减少及时调整消费者的负载均衡。

 

2.高可用性

 

Replication 副本机制 副本个数可以手动指定。 在多个Replication之间选出一个Leader.
Producer和Consumer只与这个Leader交互,其它Replication作为Follower从Leader中复制数据。
在这种情况下及时一个Broker宕机也不会影响集群的可用性。

 

3.集群和容错机制

 

使用broker来作为集群的实现方式,使用Replication 副本机制来容错。为了更好的做负载均衡,Kafka尽量将
所有的Partition均匀分配到整个集群上。一个典型的部署方式是一个Topic的Partition数量大于Broker的数量

 

4.消息持久化

 

无论消息是否被消费,kafka 都会保留所有消息。有两种策略可以删除旧数据:
1、 基于时间:log.retention.hours=168 
2、 基于大小:log.retention.bytes=1073741824"

 

5.延迟/定时发送

 

因为kafka使用的是消费者pull方式获取消费信息(p2p模式),没有实现JMS中的Sub/Pub模式.
所以理论上无法完成延迟和定时发送操作。

 

6.签收机制

image.png

 

上面是什么意思呢:
从数据的一致性来考虑自然是写入到所有的Leader和Flower中才算是数据写入成功,但是由此带来的是分布式下的
不确定下,如果某一台机器无法响应写入的情况下该信息就无法写入,那么系统也就理解为无法工作了.
request.required.acks=0又是另外一种极端,数据只管写入不管有没有完成真实的被Leader和Flower写入,在
发送之后如果出现系统错误那么就会导致数据丢失的情况发生。

Customer消费数据的ack
kafka使用offect来确定消费者消费到哪条数据了,可以使用低级API手工指定offcet来确定消费者的签收信息

 

 

7.如何保证消息幂等性

 

其实无论是那种消息队列,造成重复消费原因其实都是类似的。正常情况下,消费者在消费消息时候,消费完毕后,
会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的
消息队列发送的确认信息形式不同,例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS
成功标志,kafka实际上有个offset的概念就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset
,让消息队列知道自己已经消费过了。那造成重复消费的原因?,就是因为网络传输等等故障,确认信息没有传送到消
息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。

如何解决?这个问题针对业务场景来答分以下几点
  (1)比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复
  消费的情况,就会导致主键冲突,避免数据库出现脏数据。
  (2)再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样
  的,set操作本来就算幂等操作。
  (3)如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局
  id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消
  费记录即可。"           

 

8.如何保证消息可靠传输(不丢失)

 

(1)生产者丢数据
在kafka生产中,基本都有一个leader和多个follwer。follwer会去同步leader的信息。因此,为了避免生产者
丢数据,做如下两点配置:
第一个配置要在producer端设置acks=all。这个配置保证了,follwer同步完成后,才认为消息发送成功
在producer端设置retries=MAX,一旦写入失败,这无限重试

(2)消息队列丢数据
针对消息队列丢数据的情况,无外乎就是,数据还没同步,leader就挂了,这时zookpeer会将其他的follwer切换
为leader,那数据就丢失了。针对这种情况,应该做两个配置。
replication.factor参数,这个值必须大于1,即要求每个partition必须有至少2个副本
min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至少感知到有至少一个follower还跟自己
保持联系这两个配置加上上面生产者的配置联合起来用,基本可确保kafka不丢数据

(3)消费者丢数据
这种情况一般是自动提交了offset,然后你处理程序过程中挂了。kafka以为你处理好了。再强调一次offset是干嘛
的offset:指的是kafka的topic中的每个消费组消费的下标。简单的来说就是一条消息对应一个offset下标,每次
消费数据的时候如果提交offset,那么下次消费就会从提交的offset加一那里开始消费。
比如一个topic中有100条数据,我消费了50条并且提交了,那么此时的kafka服务端记录提交的offset就是49
(offset从0开始),那么下次消费的时候offset就从50开始消费。解决方案也很简单,改成手动提交即可。"

 

9.保证消息顺序性

image.png

 

针对这个问题,通过某种算法,将需要保持先后顺序的消息放到同一个消息队列中(kafka中就是partition,
rabbitMq中就是queue)。然后只用一个消费者去消费该队列。          

 

10.其他特性

posted @ 2020-01-20 10:07  reload  阅读(449)  评论(0编辑  收藏  举报