赞
踩
Borker:
消息中间件处理节点,⼀个Kafka节点就是⼀个broker,⼀个或者多个Broker可以组成⼀个Kafka集群
Topic:
Kafka根据topic对消息进⾏归类,发布到Kafka集群的每条消息都需要指定⼀个topic
Producer:
消息⽣产者,向Broker发送消息的客户端
Consumer:
消息消费者,从Broker读取消息的客户端
ConsumerGroup:
每个Consumer属于⼀个特定的Consumer Group,⼀条消息可以被多个不同的Consumer Group消费,但是⼀个Consumer Group中只能有⼀个Consumer能够消费该消息
Partition:
物理上的概念,⼀个topic可以分为多个partition,每个partition内部消息是有序的
日志收集:
⼀个公司可以⽤Kafka收集各种服务的log,通过kafka以统⼀接⼝服务的⽅式开放给各种consumer,例如hadoop、Hbase、Solr等。
消息系统:
解耦和⽣产者和消费者、缓存消息等。
用户活动跟踪:
Kafka经常被⽤来记录web⽤户或者app⽤户的各种活动,如浏览⽹⻚、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘
运营指标:
Kafka也经常⽤来记录运营监控数据。包括收集各种分布式应⽤的数据,⽣产各种操作的集中反馈,⽐如报警和报告。
rabbitMQ:内部的可玩性(功能性)是⾮常强的
rocketMQ: 阿⾥内部⼀个⼤神,根据kafka的内部执⾏原理,⼿写的⼀个消息队列中间件。性能是与Kafka相⽐肩,除此之外,在功能上封装了更多的功能。
kafka:全球消息处理性能最快的⼀款MQ
zeroMQ
有broke:
重topic:Kafka、RocketMQ、ActiveMQ
整个broker,依据topic来进⾏消息的中转。在重topic的消息队列⾥必然需要topic的存在
轻topic:RabbitMQ
topic只是⼀种中转模式
⽆broker:
在⽣产者和消费者之间没有使⽤broker,例如zeroMQ,直接使⽤socket进⾏通信
发送消息:
把消息发送给broker中的某个topic,打开⼀个kafka发送消息的客户端,然后开始⽤客户端向kafka服务器发送消息
消费消息:
打开⼀个消费消息的客户端,向kafka服务器的某个主题消费消息
⽅式⼀:从当前主题中的最后⼀条消息的offset(偏移量位置)+1开始消费
⽅式⼆:从当前主题中的第⼀条消息开始消费
关于消息的细节:
1、⽣产者将消息发送给broker,broker会将消息保存在本地的⽇志⽂件中
2、消息的保存是有序的,通过offset偏移量来描述消息的有序性
3、消费者消费消息时也是通过offset来描述当前要消费的那条消息的位置
单播消息:
在⼀个kafka的topic中,启动两个消费者,⼀个⽣产者,问:⽣产者发送消息,这条消息是否
同时会被两个消费者消费?
如果多个消费者在同⼀个消费组,那么只有⼀个消费者可以收到订阅的topic中的消息。换⾔
之,同⼀个消费组中只能有⼀个消费者收到⼀个topic中的消息。
多播消息:
不同的消费组订阅同⼀个topic,那么不同的消费组中只有⼀个消费者能收到消息。实际上也
是多个消费组中的多个消费者收到了同⼀个消息。
current-offset:
最后被消费的消息的偏移量
Log-end-offset:
消息总量(最后⼀条消息的偏移量)
Lag:
积压了多少条消息
主题:
topic在kafka中是⼀个逻辑的概念,kafka通过topic将消息进⾏分类。不同的topic会被订阅该topic的消费者消费。
但是有⼀个问题,如果说这个topic中的消息⾮常⾮常多,多到需要⼏T来存,因为消息是会被
保存到log⽇志⽂件中的。为了解决这个⽂件过⼤的问题,kafka提出了Partition分区的概念。
分区:
通过partition将⼀个topic中的消息分区来存储。这样的好处有多个:
1、分区存储,可以解决统⼀存储⽂件过⼤的问题
2、提供了读写的吞吐量:读和写可以同时在多个分区中进行
在创建主题时,除了指明了主题的分区数以外,还指明了副本数,那么副本是⼀个什么概念呢?
副本:
为了为主题中的分区创建多个备份,多个副本在kafka集群的多个broker中,会有⼀个副本作为leader,其他是follower。
leader:
kafka的写和读的操作,都发⽣在leader上。leader负责把数据同步给follower。当leader挂了,经过主从选举,从多个follower中选举产⽣⼀个新的leader
follower:
接收leader的同步的数据
isr:
可以同步和已同步的节点会被存⼊到isr集合中。
这⾥有⼀个细节:如果isr中的节点性能较差,会被提出isr集合。
同步发送消息:
如果⽣产者发送消息没有收到ack,⽣产者会阻塞,阻塞到3s的时间,如果还没有收到消息,会进⾏重试。重试的次数3次。
异步发送消息:
异步发送,⽣产者发送完消息后就可以执⾏之后的业务,broker在收到消息后异步调⽤⽣产者提供的callback回调⽅法。
在同步发送的前提下,⽣产者在获得集群返回的ack之前会⼀直阻塞。那么集群什么时候返回ack呢?此时ack有3个配置:
ack = 0:
kafka-cluster不需要任何的broker收到消息,就⽴即返回ack给⽣产者,最容易丢消息的,效率是最⾼的
ack=1(默认):
多副本之间的leader已经收到消息,并把消息写⼊到本地的log中,才会返回ack给⽣产者,性能和安全性是最均衡的
ack=-1/all:
⾥⾯有默认的配置min.insync.replicas=2(默认为1,推荐配置⼤于等于2),此时就需要leader和⼀个follower同步完后,才会返回ack给⽣产者(此时集群中有2个broker已完成数据的接收),这种⽅式最安全,但性能最差。
kafka默认会创建⼀个消息缓冲区,⽤来存放要发送的消息,缓冲区是32m
kafka本地线程会去缓冲区中⼀次拉16k的数据,发送到broker
如果线程拉不到16k的数据,间隔10ms也会将已拉到的数据发到broker
提交的内容:
消费者⽆论是⾃动提交还是⼿动提交,都需要把所属的消费组+消费的某个主题+消费的某个分区及消费的偏移量,这样的信息提交到集群的_consumer_offsets主题⾥⾯。
自动提交:
消费者poll消息下来以后就会⾃动提交offset
注意:⾃动提交会丢消息。因为消费者在消费前提交offset,有可能提交完后还没消费时消费者挂了。
手动提交:
需要把⾃动提交的配置改成false
⼿动提交⼜分成了两种:
⼿动同步提交:
在消费完消息后调⽤同步提交的⽅法,当集群返回ack前⼀直阻塞,返回ack后表示提交成功,执⾏之后的逻辑
⼿动异步提交:
在消息消费完后提交,不需要等到集群ack,直接执⾏之后的逻辑,可以设置⼀个回调⽅法,供集群调⽤
默认情况下,消费者⼀次会poll500条消息。
代码中设置了⻓轮询的时间是1000毫秒。
意味着:
如果⼀次poll到500条,就直接执⾏for循环
如果这⼀次没有poll到500条。且时间在1秒内,那么⻓轮询继续poll,要么到500条,要么到1s
如果多次poll都没达到500条,且1秒时间到了,那么直接执⾏for循环
如果两次poll的间隔超过30s,集群会认为该消费者的消费能⼒过弱,该消费者被踢出消费组,触发rebalance机制,rebalance机制会造成性能开销。可以通过设置这个参数,让⼀次poll的消息条数少⼀点
新消费组中的消费者在启动以后,默认会从当前分区的最后⼀条消息的offset+1开始消费(消费新消息)。可以通过以下的设置,让新的消费者第⼀次从头开始消费。之后开始消费新消息(最后消费的位置的偏移量+1)
Latest:
默认的,消费新消息
earliest:
第⼀次从头开始消费。之后开始消费新消息(最后消费的位置的偏移量+1)
controller:
集群中谁来充当controller
每个broker启动时会向zk创建⼀个临时序号节点,获得的序号最⼩的那个broker将会作为集群中的controller,负责这么⼏件事:
当集群中有⼀个副本的leader挂掉,需要在集群中选举出⼀个新的leader,选举的规则是从isr集合中最左边获得。
当集群中有broker新增或减少,controller会同步信息给其他broker
当集群中有分区新增或减少,controller会同步信息给其他broker
rebalance机制:
前提:消费组中的消费者没有指明分区来消费
触发的条件:当消费组中的消费者和分区的关系发⽣变化的时候
分区分配的策略:在rebalance之前,分区怎么分配会有这么三种策略
range:根据公示计算得到每个消费消费哪⼏个分区:前⾯的消费者是分区总数/消费者数量+1,之后的消费者是分区总数/消费者数量
轮询:大家轮着来
sticky:粘合策略,如果需要rebalance,会在之前已分配的基础上调整,不会改变之前的分配情况。如果这个策略没有开,那么就要进⾏全部的重新分配。建议开启。
HW和LEO:
LEO是某个副本最后消息的消息位置(log-end-offset)
HW是已完成同步的位置。消息在写⼊broker时,且每个broker完成这条消息的同步后,hw才会变化。在这之前消费者是消费不到这条消息的。在同步完成之后,HW更新之后,消费者才能消费到这条消息,这样的⽬的是防⽌消息的丢失。
⽣产者:
1、使⽤同步发送
2、把ack设成1或者all,并且设置同步的分区数>=2
消费者:
把⾃动提交改成⼿动提交
在防⽌消息丢失的⽅案中,如果⽣产者发送完消息后,因为⽹络抖动,没有收到ack,但实际上broker已经收到了。
此时⽣产者会进⾏重试,于是broker就会收到多条相同的消息,⽽造成消费者的重复消费。
怎么解决:
⽣产者关闭重试:会造成丢消息(不建议)
消费者解决⾮幂等性消费问题:
所谓的幂等性:多次访问的结果是⼀样的。对于rest的请求(get(幂等)、post(⾮幂等)、put(幂等)、delete(幂等))
解决⽅案:
在数据库中创建联合主键,防⽌相同的主键,创建出多条记录
使⽤分布式锁,以业务id为锁。保证只有⼀条记录能够创建成功
⽣产者:
保证消息按顺序消费,且消息不丢失——使⽤同步的发送,ack设置成⾮0的值
消费者:
主题只能设置⼀个分区,消费组中只能有⼀个消费者
kafka的顺序消费使⽤场景不多,因为牺牲掉了性能,但是⽐如rocketmq在这⼀块有专⻔的功能已设计好。
消息积压问题的出现:
消息的消费者的消费速度远赶不上⽣产者的⽣产消息的速度,导致kafka中有⼤量的数据没有被消费。随着没有被消费的数据堆积越多,消费者寻址的性能会越来越差,最后导致整个kafka对外提供的服务的性能很差,从⽽造成其他服务也访问速度变慢,造成服务雪崩。
消息积压的解决方案:
在这个消费者中,使⽤多线程,充分利⽤机器的性能进⾏消费消息。
通过业务的架构设计,提升业务层⾯消费的性能。
创建多个消费组,多个消费者,部署到其他机器上,⼀起消费,提⾼消费者的消费速度
创建⼀个消费者,该消费者在kafka另建⼀个主题,配上多个分区,多个分区再配上多个消费者。该消费者将poll下来的消息,不进⾏消费,直接转发到新建的主题上。此时,新的主题的多个分区的多个消费者就开始⼀起消费了。此方案不常用。
应用场景:
订单创建后,超过30分钟没有⽀付,则需要取消订单,这种场景可以通过延时队列来实现
具体方案:
kafka中创建创建相应的主题
消费者消费该主题的消息(轮询)
消费者消费消息时判断消息的创建时间和当前时间是否超过30分钟(前提是订单没⽀付)
如果是:去数据库中修改订单状态为已取消
如果否:记录当前消息的offset,并不再继续消费之后的消息。等待1分钟后,再次向kafka拉取该offset及之后的消息,继续进⾏判断,以此反复。
千锋教育最新kafka入门到精通教程|kafka原理解析从安装到实战,阿里P7架构师讲解Java必备(附源码)_哔哩哔哩_bilibili
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。