Kafka
一、定义:分布式的基于发布订阅模式的消息队列
Partition作用
1)对topic的负载均衡能力
2) 提高读写并发量
3)方便在集群中扩展
Leader:指partition的leader
Follower:leader的备份,副本,数据冗余,follower与leader必定不在同一个broke上,
消息的生产、消费只连接leader,不会连接Follower
一个partition只能被一个consumer group中的一个consumer消费
二、Zookeeper 作用:
1) 集群工作依赖ZK,
2) 0.9版本之前,消费者消费的位置信息会存储在ZK(内存中也会有一份)
3) 0.9版本之后offset存储在kafka系统的固定topic中,也可以存储在ZK中
4) Kafka集群中有一个broker会被选举为controller,负责管理集群broker的上下线,所有topic的分区副本分配和leader选举等工作,Controller的管理工作依赖ZK,controller文件中的brokerid(抢资源)。
三、配置操作
1)Kafka的服务配置文件Server.properties
Broker.id 要求全局唯一整数
2)常用命令
Kafka-topic.sh topic的增删改查
--partitions 定义分区数
--topic topic名
--replication-factor 定义副本数
3)集群日志: server.log
Topic partition的副本数<可用broker数
4)Producer命令
Kafka-console-producer.sh –-topic topic_name –broker-list <broker ip>:9092(broker端口)
5)Consumer命令
(是0.9版本前的命令)Kafka-console-consumer.sh --topic topic_name –-zookeeper <ZK ip>端口
##0.9版本后,offset值不存储在ZK中,故customer直接连接broker
(0.9版本后) Kafka-console-consumer.sh --topic topic_name –-bootstrap-server <broker ip>:9092(端口)
--from-beginning 表示从头消费,不加参数表示实时消费
0.9版本后offset存储在__consumer_offsets这个topic中,50个partitions
6)Procucer生产数据写入partition时默认是轮询写入的
Topic是逻辑上概念,partition是物理上的概念。
Kafka采用分片分区的方式(防止log过大导致数据定位效率下降),每个partition分为多个 segment,每个segment由1个index和log组成
xxx.log 是存放实际数据的 --log.segment.bytes是配置大小的,默认一个日志片段是1G。文件命名为当前文件的最小偏移量
xxx.index 是存放当前log索引(每条消息的偏移量和对应大小),用于快速定位消息位置每个索引长度固定
四、Kafka preducer生产者
1、分区的原因
1) 方便在集群中扩展
2) 可以提高并发
2、生产者写入方法
1) 可以指定发送的partition
2) 不指定partition,有key时,按照key的hash值与topic的partition数取余得到partition的值,再顺序发送
3) 既不指定partition,又无key时,第一次调用时随机生成一个整数,这个值与topic的可用partition数取余得到partition的值,后续递增,即round-robin轮询
3、数据可靠性
1)每个partition(leader)收到producer消息后,向producer发送ack。Producer收到ack后,进行下一轮消息发送
2)副本同步策略
要求全部同步完成,才返回ack,原因:选取新的leader时,容忍n台节点故障,只需要n+1个副本即可,缺点,延时会高些
3)ISR: leader维护了一个动态ISR,即和leader保持同步的follower集合,当ISR中的follower完成数据同步后,leader就会给follower发送ack。如果follower长时间未向leader同步数据,则该follower会被剔除出ISR,时间阈值replica.lag.time.max.ms设置,leader故障后,会从ISR中选取新leader(假设5副本,则ISR中可以有3个follower,即3个副本同步完成后,即发送ack)
4)Acks参数配置
0:producer不等待broker的ack,最低延时,但可能数据丢失
1:producer 只等待leader的ack,不等待follower,如果follower同步完成之前,leader发生故障,会数据丢失
-1(all): producer等待partition的leader和follow(ISR中)全部落盘后返回ack。缺点,同步完成后,broker发送ack之前,leader故障,会有数据重复。{当ISR中只有leader时,leader故障,也会有数据丢失(极端情况)}
5)数据一致性问题(消费、存储的一致性)
LEO(log end offset):每个副本的最后一个offset,即每个副本最大的一个offset
HW:所有副本最小的LEO,即消费者能见到的最大的offset,ISR队列中最小的LEO
HW(high watermark)之前的数据才对consumer可见
Leader故障后,会从ISR选出新的leader,为保证副本之前的数据一致性,其余follower会将各自log文件高于HW的部分截掉,从新的leader同步数据(只能保证数据一致,不能保证数据丢失或者重复)
Follower故障后,会被踢出ISR,待恢复后,follower会读取本地磁盘记录的上次的HW,并将高于HW的log部分截掉,从HW处开始向leader同步,等待follower的LEO大于等于该partition的HW,就可以重新加入ISR
6)Exactly Once语义
即要求数据既不丢失也不重复
Kafka 0.11版本后引入幂等性概念 At Least Once(ACK=-1) + 幂等性=Exaclty Once
启用幂等性 ,将pruducer参数enable.idompotence设备为true,即在broker段会对数据去重
幂等性原理:producer在初始化时会被分配一个PID,发往同一个partition的消息会附带Sequence Number。Broker端会对<PID,partition,SeqNumber>做缓存,当具有相同主键的消息提交时, Broker只会持久化一条
幂等性不足:PID重启会发生变化,同时不同的partition具有不同的主键,所以无法保证跨分区会话的Exactly Once。只能解决单次会话单个分区的数据去重
四、事务(0.11版本后)
保证kafka在Exactly Once语义基础上,生产和消费可以跨分区和会话,要么全部成功,要么全部失败
1) producer事务
引入Transaction ID(客户端提供,全局唯一)并将producer获得的ID与该ID绑定,这样,preducer重启后就可以通过Transaction ID 获取原来producer ID,保证幂等性
引入新的组件Transaction Coordinator,producer通过和该组件交互获取Transaction
ID对应的任务状态。该组件还负责将事务所有写入kafka的一个内部topic,这样即使服务重启,进行中的事务状态可以得到恢复
五、kafka customer 消费者
1、消费方式
采用拉取的方式
不足:如果kafka中没有对应topic数据,customer就会陷入循环中,一直返回空数据。弥补方式:消费者在消费数据时,会传入一个时间参数timeout,如果当前没有数据可消费,customer会间隔一段时间再次返回,减少资源浪费
2、分区分配策略(customer数量发生变化时,就会触发重分配)
1)roundRobin 轮询 (按组划分)
将多个topic当作一个整体对待,构造TopicAndPartition类,通过hash值进行排序,对类进行轮询
优点:customer之间差值分区相差小
缺点:使用时要保证customer group内订阅topic一致
2)Range 范围(默认使用)(按照主题划分)
可能或有消费者数据不对等问题
‘
3、offset维护
组成:group+customer+partition来确定offset
1) ZK中保存
目录结构:customer\group\offset\ partition
2)本地保存(0.9版本后)默认保存在kafka固定topic中(__consumer_offsets中)
要消费该topic,需要先修改配置文件(consumer.properties)
Exclude.internal.topics=false
六、读写
1、顺序读写
2、零复制技术
七,常用命令
1. 查看当前集群Topic列表。
bin/kafka-topics.sh --list --zookeeper <ZooKeeper集群IP:24002/kafka>
2. 查看单个Topic详细信息。
bin/kafka-topics.sh --describe --zookeeper <ZooKeeper集群IP:24002/kafka> --topic
<Topic名称>
3. 删除Topic,由管理员用户操作。
bin/kafka-topics.sh --delete --zookeeper <ZooKeeper集群IP:24002/kafka> --topic
<Topic名称>
4. 创建Topic,由管理员用户操作。
bin/kafka-topics.sh --create --zookeeper <ZooKeeper集群IP:24002/kafka> --partitions 6 --replication-factor 2 --topic <Topic名称>
5. Old Producer API生产数据,服务端“allow.everyone.if.no.acl.found”配置为 “True”。
bin/kafka-console-producer.sh --broker-list <Kafka集群IP:21005> --topic <Topic名
称> --old-producer -sync
6. Old Consumer API消费数据,服务端“allow.everyone.if.no.acl.found”配置为 “True”。
bin/kafka-console-consumer.sh --zookeeper <ZooKeeper集群IP:24002/kafka> --topic
<Topic名称> --from-beginning
7. 赋Consumer权限命令,由管理员用户操作。
bin/kafka-acls.sh --authorizer-properties zookeeper.connect=<ZooKeeper集群IP:
24002/kafka > --add --allow-principal User:<用户名> --consumer --topic <Topic名
称> --group <消费者组名称>
8. 赋Producer权限命令,由管理员用户操作。
bin/kafka-acls.sh --authorizer-properties zookeeper.connect=<ZooKeeper集群IP:
24002/kafka > --add --allow-principal User:<用户名> --producer --topic <Topic名称>
9. New Producer API生产消息,需要拥有该Topic生产者权限。
bin/kafka-console-producer.sh --broker-list <Kafka集群IP:21007> --topic <Topic名称> --producer.config config/producer.properties
10. New Consumer API消费数据,需要拥有该Topic的消费者权限
bin/kafka-console-consumer.sh --topic <Topic名称> --bootstrap-server <Kafka集群IP:21007> --new-consumer --consumer.config config/consumer.properties
分区rebalance需要用
kafka-reassign-partitions.sh --zookeeper 172.16.8.1:24002/kafka --topics-to-move-json-file genrate.json --broker-list "1,2,3,4,5,6,33,34,35,36,37" --generate 重分配
kafka-reassign-partitions.sh --zookeeper 172.16.8.1:24002/kafka --reassignment-json-file reassignment.json --execute
kafka-reassign-partitions.sh --zookeeper 172.16.8.1:24002/kafka --reassignment-json-file reassignment.json --verify
{"partitions":[
{"topic":"PS_4G_TB_HTTP.V003","partition":4,"replicas":[34,35]},
{"topic":"PS_4G_TB_HTTPS.V003","partition":186,"replicas":[5,6]},
{"topic":"PS_4G_TB_IM.V003","partition":20,"replicas":[1,2]},
{"topic":"PS_4G_TB_VISITIP.V003","partition":26,"replicas":[3,4]}
],"version":1}