kafka
消息队列介绍
异步的方式,减少上游时间,提高吞吐量。在分布式系统中,利用分布式事务保证最终的一致性。
常见消息队列中间件:rabbitMQ rocketMQ kafka zeroMQ
消息队列的类型:
有broker
重topic:根据topic进行消息转发(kafka)
轻topic:topic这是一种方式
无broker:不需要broker,类似于socket通信(zeroMQ)
kafka基本概念
kafka就是解决通信问题的,底层封装了数据是如何发送的。
producer:发布消息到broker
broker:依据topic将消息发布
topic:实现消息的分类,不同消费者订阅不同topic
consumer:获取消息
安装
分布式发布/订阅消息系统
# vim server.properties
listeners=PLAINTEXT://192.168.43.33:9092
zookeeper.connect=192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181
log.dirs=/tmp/kafka-logs
# vim zookeeper.properties
dataDir=/tmp/zookeeper
maxClientCnxns=100
tickTimes=2000
initLimit=10
syncLimit=5
admin.enableServer=false
./kafka-server-start.sh -daemon /usr/local/src/kafka/config/server.properties
验证方式
# ./zkCli.sh查看对应brokerid即可
消息的发布与订阅
创建主题topic
创建主题名为"test"的topic,1个分区,1个副本
# ./kafka-topics.sh --create --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181 -replication-factor 1 --partitions 1 --topic test
Created topic test.
查看当前kafka的topic
# ./kafka-topics.sh --list --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181
test
--zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181
发送消息
kafka自带了一个producer命令客户端,可以从本地文件中读取内容或命令行输入内容,并将这些内容以消息的形式发送到kafka集群中。
使用Kafka指定的客户端,要发送到kafka的服务器和topic上
# ./kafka-console-producer.sh --broker-list 192.168.43.33:9092 --topic test
消费消息
kafka自带了一个consumer命令客户端,会将获取到的内容展示出来,默认消费最新的消息
方式1:最后一条消息偏移量+1
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092 --topic test
方式2:从头开始消费
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092 --from-beginning --topic test
注意:
消息是顺序存储的,可以从特定偏移量开始消费
producer将消息发送给broker,broker会将消息保存在kafka上
消息保存在/tmp/kafka-logs/主题-分区/00000000000000000000.log中
单播消息
如果多个消费者在一个消费组中,只能有一个消费者能收到topic的消息
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092 --consumer-property group.id=Group1 --topic test
多播消息
不同的消费组中的消费者都能收到同一个topic中的消息
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092 --consumer-property group.id=Group1 --topic test
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092 --consumer-property group.id=Group2 --topic test
消费组
查看消费组
# ./kafka-consumer-groups.sh --bootstrap-server 192.168.43.33:9092 --list
Group1
Group2
testGroup1
描述组信息
# ./kafka-consumer-groups.sh --bootstrap-server 192.168.43.33:9092 --describe --group testGroup1
Consumer group 'testGroup1' has no active members.
TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
test 0 8 12 4 - - -
已经消费8条,还有4条未消费,共12条消息
主题与分区
创建分区
topic:kafka消息的一种划分
由于消息会被保存在log文件中(容量非常大),所以分区出现
分区存储优点:
1、解决统一存储文件过大问题
2、分布式存储,并行写
查看当前kafka的topic
# ./kafka-topics.sh --list --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181
创建分区
# ./kafka-topics.sh --create --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181 -replication-factor 1 --partitions 2 --topic test2
描述test
# ./kafka-topics.sh --describe --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181 --topic test
副本
副本概念
创建主题为my-replicated-topic 有两个分区,三个副本
# ./kafka-topics.sh --create --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181 -replication-factor 3 --partitions 2 --topic my-replicated-topic
描述 my-replicated-topic
# ./kafka-topics.sh --describe --zookeeper 192.168.43.30:2181,192.168.43.31:2181,192.168.43.32:2181 --topic my-replicated-topic
多个副本在kafka集群中的多个broker中,只有一个leader(leader负责读写),follower负责同步数据
Leader:2表示Partition:0的leader为broker-2
Leader:0表示Partition:0的leader为broker-1
Replicas: 2,0,1表示副本所在的broker节点
Isr表示可以同步的节点、已经同步的节点(当节点性能较差时,会被踢出Isr)
因此broker、主题、分区、副本、isr等概念完整了
消息日志文件中保存的内容
消息存放文件,文件过大时利用索引能快速查找需要的消息。
kafka自带了50个主题-分区
__consumer_offsets-0
__consumer_offsets-1
...
...
__consumer_offsets-49
key:消费组+主题+分区号
value:当前offset值
每次消费后都会将消费的主题的偏移量上报给kafka,默认给了50个分区(默认保存7天)
集群消息消费
查看消费组
# ./kafka-consumer-groups.sh --bootstrap-server 192.168.43.33:9092,192.168.43.34:9092,192.168.43.35:9092 --list
描述消费组
# ./kafka-consumer-groups.sh --bootstrap-server 192.168.43.33:9092,192.168.43.34:9092,192.168.43.35:9092 --describe --group testGroup1
向集群中发送消息
# ./kafka-console-consumer.sh --bootstrap-server 192.168.43.33:9092,192.168.43.34:9092,192.168.43.35:9092 --from-beginning --consumer-property group.id=testGruop1 --topic my-replicated-topic
rebalance机制
前提:消费者未指定分区消费
当消费者和分区的关系发送变化,就会触发rebalance机制
触发rebalance机制之前,消费者消费分区有三种策略
range(公式计算)、轮询、sticky(触发rebalance机制后,在原来消费分区的基础上进行调整)
HW和LEO
LEO是某个副本最后消息的位置,HW是已完成同步的位置。(每个broker都有自己维护的HW和LEO值)
只有消息在写入broker且完成同步后,HW才会发生改变,在这之前LEO所在的位置的消息是不能被消费的。
kafka性能调优
1、防止消息丢失
使用同步发送
设置ack=1或all
设置同步的分区数>=2
2、防止消息的重复消费
幂等:多次访问结果是一样的
1、数据库中创建联合主键,防止相同主键创建多条记录
2、使用分布式锁,保证只有一条记录被创建
3、关闭重试(不建议)
3、顺序消费
ack不为0、同步发送、关闭重试----->在上游保证消息顺序写入broker
消费者:主题只能有一个分区,消费组只能有一个消费者(牺牲了性能)------>使用场景不多
4、消息积压问题
生产者发送消息的速度远大于消费者消费消息的速度,导致kafka集群性能变慢,导致其它消费者访问的速度也变慢
1、消费者使用多线程,充分利用机器性能
2、创建多个消费组、多个消费者部署在其它机器上,提高消费者的消费速度
3、创建一个消费者,这个消费者创建新的topic并配置多个分区,多个分区配置多个消费者。利用创建的消费者poll消息然后放到新topic中。保证了新topic的多个分区被多个消费者消费
4、通过业务的架构设计,提升业务层面的消费性能
5、延时队列
例子:在创建订单30分钟后还未付款,自动删除订单
kafka中创建相应的主题
消费者轮询消费该主题的消息
当时间大于30分钟,消费者将数据库中的订单改为已取消
当时间小于30分钟,消费者记录offset值,并间隔1分钟poll消息,直到订单完成