1.下载/安装
下载地址: Kafka
解压: tar -zxf 文件名3
启动Zookeeper:
bin\windows\zookeeper-server-start.bat config\zookeeper.properties
启动kafka:
bin\windows\kafka-server-start.bat config\server.properties
2.简介
kafka是一个分布式的基于发布/订阅的消息引擎系统
2.1结构图
producer: 消息生产者 ==> 主题发布的服务
consumer: 消息消费者 ==> 主题订阅的服务
Topic: 主题用于区分具体的业务
Record: 消息,kafka处理的消息对象
partition: 分区 ==> 一个有序不变的消息序列
offset: 消息位移 ==> 分区中每条消息的位置
Replica/follower : 副本 ==> kafka用于冗余数据,将partition leader数据备份到多个地方
消费者位移: consumer offset ==> 表示消费者消费进度 (比如每个consumer有多个partition,这个时候用来记录消费到哪个partition)
重平衡: Rebalance ==> 消费者在某个消费挂了之后,其他消费者自动重新分配partition(分区)的过程, Rebalance是kafka消费者端实现高可用的重要手段
2.2参数
topic参数:
auto.create.topics.enable = true(默认) 自动创建topic
auto.leader.rebalance.enable = true(默认) partition自动切回leader ==> 如果leader挂了之后,follower切换为leader,再过一段时间leader恢复之后,leader自动成为 leader partition (主要为了解决多个服务的负载均衡)
3.SpringBoot整合kafka
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>2.7.6</version>
</dependency>
3.1Producer
@Component
public class KafkaProducer {
@Resource
private KafkaTemplate<String,Object> kafkaTemplate;
public void send(String topic,Object record){
ListenableFuture<SendResult<String,Object>> result = kafkaTemplate.send(topic, record);
result.addCallback(new ListenableFutureCallback<SendResult<String, Object>>() {
@Override
public void onFailure(Throwable throwable) {
System.out.println("发送失败");
}
@Override
public void onSuccess(SendResult<String, Object> stringObjectSendResult) {
System.out.println("发送成功");
}
});
}
}
3.2Consumer
@Component
public class KafkaDemoConsumer {
@KafkaListener(topics = "kafka-topic1", groupId = "kafka-topic1-group")
public void topic_test(String msg) {
System.out.println("消费成功 =====> "+msg);
}
}
3.3测试
@Controller
@RequestMapping("/kafka")
public class KafkaController {
@Resource
private KafkaProducer kafkaProducer;
@RequestMapping("/consumer")
@ResponseBody
private String consumer(){
Map map = new HashMap();
map.put("id",2);
map.put("name","ff0");
kafkaProducer.send("kafka-topic1", map.toString());
return "OK";
}
}
4.日志存储
server.properties配置文件中 ==> 日志默认目录: log.dirs=/tmp/kafka-logs
目录名: topic+partion名称
.index文件: 偏移量索引文件
.log文件: 日志文件(消息日志) 默认1G
.timeindex文件: 时间戳索引文件
.snapshot文件: 其他文件
查看index文件:
start kafka-run-class.bat kafka.tools.DumpLogSegments --files E:\tmp\kafka-logs\kafka-topic1-0\00000000000000000000.index
Dumping E:\tmp\kafka-logs\kafka-topic1-0\00000000000000000000.index
offset: 112 position: 4285
offset: 326 position: 11081
offset: 用于记录索引文件中的位置
position: 用于指向log文件中消息的物理地址
查看log文件:
start kafka-run-class.bat kafka.tools.DumpLogSegments --files E:\tmp\kafka-logs\kafka-topic1-0\00000000000000000000.log --print-data-log
5.分区处理
每个topic都对应多个partition(分区),然而kafka在集群的情况下,partition在每个broker节点下都存在Replica(副本),kafka是怎么保证数据的高可用呢
1.副本分为两类: Leader Replica 和 Follower Replica
2.Follower Replica不对外提供服务,所有对外都是由Leader Replica来处理
3.当Leader Replica挂掉的时候,kafka会从ISR中获取Follower Replica来选举为Leader Replica
ISR: 与Leader保持数据同步的副本集合 ==> kafka在启动的时候,自动指定一个Follower和Leader组成ISR
AR: 分区中所有的副本集合
request.ack = 1 (默认) ==> producer只要收到一个分区副本成功写入的通知就认为推送消息成功了。这里有一个地方需要注意,这个副本必须是leader副本。只有leader副本成功写入了,producer才会认为消息发送成功
ack = 0 ==> 不管成功与否,只发送一次
ack = -1 ==> 等到所有的副本都同步完毕之后,说明发送成功
ack = 1时说明我们只能保证Leader中的数据高可用,那么kafka是怎么保证Follower怎么同步的呢
LEO: 每个副本中最后一条消息的下一个位置
HW: ISR中最小的LEO即为HW,俗称高水位,消费者只能拉取高水位的消息
6.Leader切换
当我们partition中的Leader挂掉之后,kafka是怎么从ISR中切换的副本呢
在kafka启动的时候,会在zookeeper注册的实时节点
{
"controller_epoch":2, //
"leader":0, //表示该partition选举leader的brokerId
"version":1, // 版本号
"leader_epoch":0, //leader的选举次数
"isr":[
0
] //ISR ==> 与leader保持同步的副本对应的brokerId集合
}
以上主要讲到kafka的高可靠性,那么kafka是怎么来保证它的高性能呢
1.kafka采用磁盘顺序读写方式,来提升性能
2.高性能页缓存到内存中(不至于每次读写都交互磁盘) ==> 类似Mysql的Buffer Pool
7.Consumer Offsets
{"version":2,"partitions":{"30":[0],"39":[0],"45":[0],"2":[0],"5":[0],"48":[0],"33":[0],"27":[0],"12":[0],"8":[0],"15":[0],"42":[0],"36":[0],"21":[0],"18":[0],"24":[0],"35":[0],"41":[0],"7":[0],"17":[0],"1":[0],"44":[0],"23":[0],"38":[0],"47":[0],"4":[0],"26":[0],"11":[0],"32":[0],"14":[0],"20":[0],"29":[0],"46":[0],"34":[0],"28":[0],"6":[0],"40":[0],"49":[0],"9":[0],"43":[0],"0":[0],"22":[0],"16":[0],"37":[0],"19":[0],"3":[0],"10":[0],"31":[0],"25":[0],"13":[0]},"adding_replicas":{},"removing_replicas":{}}
__consumer_offsets
是 kafka 自行创建的,和普通的 topic 相同
它存在的目的之一就是保存 consumer 提交的位移
eg:"kafka-topic1-group".hashCode()%50=32