消息队列
生产者产生消息,将消息放到MQ中,消费者从MQ中获取消息进行消费
消息队列的作用
- 异步处理
- 将一些耗时的操作请求传输给MQ,直接给用户返回成功的结果。其他系统可以消费MQ中的消息
- 降低耦合
- 两个服务之间本身要通过某些接口进行通讯,直接调用接口的耦合度很高(如果任何一方修改了接口的参数或者返回值会导致接口的不可用)。
- 一个服务可以将请求发送给MQ,另一个服务可以从MQ中消费请求。原先的直接耦合变成了处理MQ中的消息。两个系统都只要面对MQ编程即可。
- 流量削峰
- MQ可以应对大量并发,有助于控制和优化数据流金国系统的速度。
解决生产消息和消费消息处理速度不一致的问题
- MQ可以应对大量并发,有助于控制和优化数据流金国系统的速度。
- 日志处理
- 可以使用MQ来作为临时的存储,或者是一种通信管道来传输数据。
消息队列的两种模式
点对点模式
- 生产者生产消息到MQ,消费者从MQ中消费消息。消费后消息就直接删除消息队列中的数据
- 每个消息只有一个接收者
- 消费者是否消费了消息都不会影响生产者生产新的消息
- 消费者消费消息后向MQ发送成功应答,MQ将消息删除
生产订阅模式
- 每个消息由多个订阅者和多个topic主题
- 发布者和订阅者有时间上的依赖性。超过一定的时间就不能够再消费对应的消息。但是这个时间内,订阅者消费完数据后并不会删除这个数据。
- 每个订阅者是相互独立的
- 每个消息都有一个主题,该主题有订阅者以后,才能够消费该消息
- 订阅者需要提前订阅角色主体,并且保持在线的状态
kafka
- 发布和订阅数据流
- 能够以容错的持久化方式存储数据
- 处理数据流
kafka基础架构
- 为了方便扩展和提高吞吐量,一个topic被切割成多个partition(分区)
- 配合分区的设计,提出了消费者组的概念,每个消费者组内的消费者并行消费
- 为了保证数据可靠性,每个partition增加若干副本
- kafka中的副本有leader和follower的区别,消费者只针对leader这个副本进行生产消费
- follower这个副本是在当leader挂了以后,follower就会成为新的leader,后续的消费者就来找这个follower进行生产消费了
- kafka中还有一部分内容是存储在zookeeper中的,记录服务器节点的运行状态,以及每一个副本的leader相关信息
- kafka2.8.0之后的配置就可以不依赖于zookeeper
- broker:代表对应的分布式服务器
kafka相关脚本
kafka-topic命令
-
参数
参数 描述 –bootstrap-server 连接kafka broker主机名称和端口 –topic 需要操作的topic名称 –create 创建对应的主题 –delete 删除对应的主题 –alter 修改对应的主题 –list 查看所有的主题列表 –describe 查看对应主题的详细描述 –partitions 设置分区数 –replication-factor 设置分区副本数 –config 更新系统默认的配置 要注意分区数只能改大不能改小
生产者脚本命令
使用的脚本./bin/kafka-console-producer.sh
参数 | 描述 |
---|---|
–bootstrap-server | 连接kafka broker主机名称和端口 |
–topic | 选择需要连接的集群 |
启动该脚本后,就可以通过在客户端中输入数据作为生产者数据
消费者脚本命令
在生产者启动之后,如果生产者端产生了数据,就需要通过消费者将生产者生产的数据取出来
启动消费者的脚本./bin/kafka-console-consumer.sh
消费者从最早的生产的消息开始获取,启动脚本中加上--from-beginning
kafka生产者发送原理
- 首先创建一个
main
线程 - 调用
send
方法,数据到达拦截器(可选,一般会使用flume的拦截器) - 到达序列化器(Serializer),大数据的数据量较大,不需要额外的再使用Java的序列化器去序列化
- 到达分区器,决定数据应该被发送到哪一个分区。
- 对应一个分区,会创建一个队列。队列是被放在内存里的,默认的内存大小是32M,一个batch的大小是16k
- 创建一个sender线程,
- 当缓冲队列区中的一个batch达到
batch.size
之后,sender才会开始读取数据 - 如果缓冲区中的数据始终没能达到
batch.size
,那么sender会等待linger.ms
所涉这的时间再发送单位是ms,默认是0ms,表示没有延迟
- 当缓冲队列区中的一个batch达到
- 以每一个broker节点为key,对应的value为该broker中所需要的请求,将这些内容组成一个队列,最多每个broker节点可以缓存5个请求
- 通过selector,连接缓存队列和kafka集群,让后续的请求能够通过这个selector发送给kafka集群
- kafka收到相应的数据后,会进行一个副本的同步,同时会产生一个应答acks有三种应答级别
- 0:表示生产者发送的数据,不需要等到数据落盘之后应答,生产者只管发
- 1:生产者发送的数据需要在leader收到数据后发送应答
- -1(all):生产者发送的数据要等leader以及ISR(follower)队列中所有的节点都收齐数据之后再进行应答
- 如果返回的acks是成功,则将缓存中的相关数据清理掉。如果失败了则会重试,重新发送该请求,默认的retry次数是无限(重试直到成功)
异步发送和同步发送
异步发送就是外部的数据可以不用等缓存队列中的数据发送完了再被载入缓存队列,只要其中还是空的就可以一直往里面放
同步发送是需要等待一批的数据发送完了,才会开始加载下一批次的数据
带有回调的异步发送
在调用send方法的时候,当数据被发送到队列中的时候,就会返回相应的主题、分区等信息
同步发送
必须等每个队列都处理完成再开始发送下一波数据
生产者分区
分区的意义
- 便于合理使用存储资源:每个partition在一个broker上进行存储,可以把海量数据按照分区切割成一块一块数据存储在不同的服务器上。通过合理控制分区,可以实现负载均衡
- 能够生产者向broker集群发送数据的并行度。生产者可以以分区为单位发送数据,消费者可以以分区为单位消费数据。
分区策略
- 如果指定分区,则按照指定分区来进行分区
- 如果没有指定分区,但是指定了key,那么就按照key值的hash值进行分区,将key的hash值与topic的分区数进行取模,得到分区数
- 如果也没有指定key,使用粘性分区,会随机选择一个分区,并尽可能一直使用该分区,直到这个分区的batch数满了或者该分区的内容已完成,再随机选择一个分区,同时保证这个分区与之前的分区不同。即同一个batch的数据同属于一个分区中
- 在生产环境中,如果要将同一个表中的数据分配到同一个分区中,一般使用的是指定key这种方法,将表名作为key,对key进行hash取值就可以分配到相同的分区中
自定义分区去
重写Partitioner
中的partition
方法
数据可靠性
数据可靠性主要针对数据落盘问题,你发送的数据是否能在kafka集群的broker上能够正确落盘
主要是和应答模式有关
- 0:broker数据收到后就应答,不需要确定数据落盘。
最不可靠,效率高
,这个过程中如果leader挂了,那么数据就会丢失了 - 1:broker确保leader收到数据并落盘后再进行应答,
可靠性较高,效率中等
。如果应答完成了,leader还没向其他的broker开始进行数据副本的同步就挂了,那么也会造成数据的丢失。虽然会选举产生新的leader,但是此时因为应答已经完成了,所以已经发过的数据就不会再向新的leader上再进行分发了。 - -1: 确保所有的ISR集合中的broker和leader都收到数据并落盘后再应答,
可靠性最高,但是相应的消耗的时间最长
。如果过程中有节点挂了,那么就会应答失败,导致leader长时间无法进行应答。- 为了解决这个问题,kafka维护了一个动态的ISR(in-sync replica set),表示和leader保持同步的follower和leader集合。
- 如果某一个follower长时间未向leader发送通信请求或者进行数据同步,那么这个follower就会被踢出ISR
- 这个时间阈值有
replica.lag.time.max.ms
这个参数进行设定,默认是30s
,注意单位是ms - 例如leader:0,follower:1,2。那么ISR={0,1,2}。如果2号broker长时间没有回应,那么维护ISR={0,1}。这样只需要确保ISR队列中的所有broker都进行数据落盘后就能够进行应答,避免了长时间无应答的问题。
- 如果分区的副本数设为1个,或者ISR中应答的最小副本数为1(
min.insync.replicas
,默认为1),也就是只有一个leader在ISR中,那么和应答模式为1的时候没有区别,同样也有丢数的风险 - 数据重复性问题:如果之前一个信息同步了一半,leader挂了,那么会重新对ISR队列中的节点进行数据同步。如果之前有一个节点已经进行过同步了,那么就会产生数据重复的问题。
数据完全可靠条件=ACK应答级别为-1 + 分区副本数大于等于2 + ISR队列中应答最小副本数量大于等于2
- 在生产环境中
- 一般不使用ack=0的模式
- 如果只是传输普通的日志,允许部分数据的丢失,那么可以使用ack=1
- 如果传输的数据很重要,例如交易金融等内容,对可靠性要求较高,那么需要使用ack=-1
数据重复性
- 至少一次 At least Once = ACK应答级别为-1 + 分区副本数大于等于2 + ISR队列中应答最小副本数量大于等于2
- 最多一次 At Most Once = ACK应答级别为0
- 精确一次 Exactly Once =
幂等性
+ ACK应答级别为-1 + 分区副本数大于等于2 + ISR队列中应答最小副本数量大于等于2
幂等性
无论Producer向broker发送多少次重复数据,Broker端只会持久化一条,确保了数据不重复
- 重复数据的判断标准:具有
<PID,Partition,SeqNumber>
相同主键- PID:每次kafka重启都会分配一个新的
- Partition:分区号
- Sequence Number:单调递增
- 幂等性确保的是在单分区单会话中无重复数据
- 开启幂等性:
enable.idempotence
设置为true,默认为true
生产者事务
开启事务,必须开启幂等性
- 每个broker节点都有一个事务协调器,同时会有一个
_transaction_state-分区-leader
主题,用于存储事务信息的特殊主题。 - 在这个主题中,默认有
50
个分区。每个分区负责一部分事务。事务划分是根据transactional.id
的hash值%50,从而计算出该事务是属于哪一个分区的。 - 该分区所在的broker节点,就是这个
transaction.id
对应的主事务协调器节点。由这个事务协调器负责该分区中事务的管理。 - 生产者在使用事务功能之前,必须先自定义一个唯一的transactional.id。有了这个事务id之后,哪怕客户端挂了,重启之后也能继续处理未完成的事务。
事务过程
- producer向事务协调器请求Producer id (PID)
- 事务协调器返回PID
- Producer将消息发送到topicA
- producer向事务协调器请求commit
- 事务协调器向
transaction_state
主题持久化commit请求 - 事务协调器向Producer返回成功
- 事务协调器后台向TopicA发送commit请求,判断消息是否完成持久化
kafka broker
可以安装prettyzoo这个软件查看zookeeper中的内容
zookeeper中存储的kafka相关的信息
/kafka/brokers/ids
记录有哪些服务器/fkag/brokers/topics/first/partitions/0/state
记录每个主题下每个分区的leader和ISR
{
"controller_epoch" : 26,
"leader" : 2,
"version" : 1,
"leader_epoch" : 39,
"isr" : [ 2, 1 ]
}
/kafka/controller
辅助选举leader,谁先把brokerid放进去谁优先成为Controller,由Controller来辅助leader的选举
broker总体工作流程
- broker启动后,向zk进行注册,向
ids
节点中添加id - controller谁先进行注册,谁就会成为Controller
- 由选举产生的Controller去监听
ids
节点中broker节点的变化 - Controller决定leader的选举
- 以在ISR中存活为前提,按照AR排在前面的优先。
- AR:kafka分区中所有副本的统称
AR=ISR+OSR
- OSR:未与leader进行同步的节点
- Controller将leader和ISR的信息上传到zk的
state
节点中 - 其他节点会从zk
state
节点中同步信息 - producer开始向leader发送消息,broker通过Log的方式进行写入
- Log方式:将数据分割成1G大小的Segment,在这个segment中通过
.log
文件和.index
文件来进行数据的存储
- Log方式:将数据分割成1G大小的Segment,在这个segment中通过
- broker向producer进行应答
- 假设broker1中的leader挂了,Controller中能够监控到leader的状态
- Controller根据
state
节点中的ISR信息,重新进行leader的选举 - Controller更新
state
中Leader和ISR的信息
kafka 副本
基本信息
- 副本作用:提高数据的可靠性
- 默认副本1个,生产环境中一般会配置两个。太多的副本数会占据大量磁盘空间,增加传输数据,降低效率。
- 副本分为leader和follower,生产者只会将数据发给leader,然后follower会找到leader进行数据同步。
- 分区中所有的副本统称未AR
- AR = ISR + OSR
- ISR :与leader保持同步的Follower集合
- OSR:与leader进行同步时延迟过高,超时的副本
follower和leader故障处理细节
-
LEO (Log End Offset) :每个副本的最后一个offset
- LEO就是副本的最大offset+1
-
HW (High Watermark): 所有副本中最小的LEO
-
消费者能够见到的最大的offset就是这个HW,因为只有主副本都将数据落盘之后,数据才会对消费者可见
follower发生故障
- follower故障后会被临时提出ISR
- 期间Leader和Follower会继续接受数据,LEO和HW继续发生变化
- Follower恢复之后,会读取本地磁盘上的HW,将log文件高于HW的部分截取掉,从HW开始重新和Leader进行同步。
举例:
- 假设原先F3的LEO是7,在F3挂掉之前的HW是4。
- 此时F3挂掉,剩余的ISR会继续进行数据同步,此时F3的LEO还是7,F3的HW还是3,集群的HW已经进行到8了
- F3恢复,会读取本地的HW,本地读取到的HW是4,F3会将自己LEO7到原HW4之间的数据截取掉,从4开始与leader同步,直到最新的HW8
- 追上HW后,F3重新进入ISR
Leader故障处理
- 从ISR中选出一个新的leader
- 所有的follower此时会将自己的数据中高于HW的部分截取掉,从新的leader处同步数据。
- leader故障后只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复
分区副本分配
为保证负载均衡,会尽量均匀的分配
kafka文件
文件存储机制
- topic是一个逻辑上的概念,而partition是一个物理上的概念。每个partition对应于一个log文件,producer生产的数据会被不断的被追加到该log文件的末尾。
- log文件可能过大导致数据的定位效率低下,从而kafka采用了
分片
和索引
机制。这个log文件也是一个逻辑上的概念,实际上没有这个.log
文件,而是被分割成了多个segment - 将每个partition分割成多个segment,每个segment包含有
.index
,.log
,,timeindex
等文件。这些segment文件存储在datas
文件夹下。同一个segment处于同一个文件夹下,命名规则为topic+分区号:test-0
。每个segment默认大小为1G .index
偏移量索引文件,记录数据在哪.timeindex
时间戳索引文件 记录数据生产的时间,超过7天的数据会被删除- index和log文件以当前的segment的第一条信息的offset命名的。
- 如果要查看其中的log、index这些文件,需要通过
kafka-run-class.sh kafka.tools.DumpLogSegments --files 文件名
log和index文件
- index是稀疏索引,没往log中写入4kb的数据,会往index中写入一条索引。
- index写入的大小由
log.index.intercal.bytes
控制,默认4kb - index中保存的offset是相对offset,即在本segment中的offset,从而确保能控制index中的offset值所占用的空间不会过大
- 查找offset为某个值的record
- 首先根据offset定位segment
- 找到绝对offset小于等于目标offset的最大offset对应的索引项
- 根据index中的position定位到log文件中的record
- 向下遍历log直到目标record
文件清理策略
kafka默认文件保存7天,七天后删除,可以通过修改以下参数
log.retention.hours
最低优先级log.retention.minutes
log.retention.ms
最高优先级log.retention.check.interval.ms
检查周期,默认5分钟
kakfa的删除方式
- delete 删除
log.cleanup.policy=delete
- 默认基于时间,以segment中所有记录中的最大时间戳作为该文件的时间戳
- 默认关闭基于大小的开关。对于超过设置大小的所用日志总大小,会删除最早的segment。
log.retention.bytes
这个是基于大小的设置值,默认为-1,代表无穷大
- compact 压缩
-
对于相同key的不同value值,只保留最后一个版本
-
log.cleanup.policy=compact
对所有数据启用压缩策略 -
-
这种方式只适用于一些特殊的场景,例如用户资料的更新,保证消息队列中只存储了所有用户最新的资料
-
broker高效的读取数据
- 本身就是分布式集群,采用分区技术,并行度高
- 读取数据时采用稀疏索引,能够快速定位到目标数据
- 按照顺序写入磁盘,写的过程直接追加到log文件的末端
- 顺序写比随机读写的速度要快很多,因为省去了大量磁头寻址的时间。
- 页缓存+零拷贝
- 零拷贝:数据加工处理操作交给生产者和消费者去处理。Broker的应用层不关心存储的数据,不走应用层,传输效率高
- pageCache页缓存:上层有写操作的时候,os只将数据写入到页缓存中。当有读操作的时候,kafka会优先从页缓存中查找,如果找不到,再去从磁盘中读取。页缓存是把尽可能多的空闲内存当作是磁盘缓存来使用。
- kafka在页缓存中查找数据,如果没有就从磁盘中读取数据到页缓存中,然后直接将数据通过网卡发送给消费者。不需要通过应用层调用socket
消费者
消费方式
- pull:consumer从broker中主动拉取数据。
- 能够根据consumer自身的情况,自行决定消费者的消费速率
- 如果kakfa中没有数据,消费者可能陷入循环中,不停的尝试从broker中拉取数据,造成效率的降低
- push:broker主动将数据发送给consumer,consumer被动接受
- 如果由broker决定消息发送的速率,难以适应所有consumer的速率,速率快的处于闲置状态,速率慢的来不及处理消息
总体工作流程
- 一个消费者可以消费多个分区的数据,多个独立的消费者之间互相不影响
- 如果存在消费者组,每个分区中的数据只能由消费者组中的一个消费者消费。把一个consumer组当成一个独立consumer,其中的conumser只是这个独立消费者的组件,每个负责一个分区的数据。
- 每个消费者的offset是由消费者提交到
__consumer_offsets
这个系统topic中进行存储的。
消费者组工作原理(Consumer Group CG)
- consumer group 概念
- 一个consumer group 由多个consumer组成。
- 形成一个group的条件是这个group中的所有消费者的group id相同。
- 同一组中的每个consumer负责消费不同分区的数据,一个分区只能被一个组内的consumer所消费。
- 消费者组之间互相不影响。所有的consumer同属于某个group,消费者组是在逻辑上可以当成一个独立的consumer
- 如果CG中的消费者数量比主题分区的数量还要多的时候,就会有一部分的消费者处于闲置状态,不会主动接受任何消息。
- CG的初始化流程
0. coordinator:辅助实现消费者组的初始化和分区的分配,coordinator=hash(groupid)%50(__consumer_offset的分区数量)
,计算出的coordinator值就是对应的节点id- 每个consumer都会向coordinator节点发送一个
JoinGroup
的请求 - coordinator选择一个CG中的consumner作为leader
- coordinator把需要消费的topic情况发送给leader消费者
- leader会制定一个消费方案
- leader将这个消费方案发送给coordinator
- coordinator将该消费方案发送给CG中的各个消费者
- 每个consumer和coordinator都会保持一个心跳连接
默认3s
,一旦超时session.timeout.ms=45s
,该消费者就会被移除。同时,如果消费者处理消息的时间过长,超过max.poll.interval.ms=5mins
,也会将这个消费者移除。当有消费者被移除时,就会触发GC的再平衡。其他组内的消费者来接替这个consumer,再平衡会影响kafka的工作性能
- 每个consumer都会向coordinator节点发送一个
- 详细消费流程
- 首先创建一个
ConsumerNetworkClient
,CG的leader会向CNC发送一个消费请求,此时CNC会进行初始化Fetch.min.bytes
每批次最小抓取大小,默认1字节Fetch.max.wait.ms
一批数据最大未到达的超时时间,默认500ms- 最小大小和超时时间只要有一个达成,CNCN就会拉取数据
Fetch.max.bytes
每批最大抓取大小,默认50m
- CNC调用
send
方法,向broker中对应的分区副本发送请求 - broker回调
onSuccess
方法,将对应的结果拉取到completedFetches
队列中 - 消费者从
completedFetches
中拉取数据,一次拉取最大Max.poll.records=500
条信息 - 拉取到的数据首先要进行反序列化,然后通过拦截器对数据进行一定的处理和监控
- 首先创建一个
消费者组实操
- 在通过API的方式配置CG时,必须要指定好对应的group id。在通过命令行启动的时候不需要这个id,会自动填写随机的id
offset保存位置
之前有说过,同一个CG中的每一个consumer在消费的时候,会将自己消费到的offset位置维护在系统中一个__consumer_offset
的topic中。
在该topic中,采用一种kv型的数据结构存储数据,key为group_id+topic+分区号
,value为当前的offset值。
每隔一段时间,kafka内部就会对这个topic进行compact,确保其中维护的是最新的数据,删除掉过时的数据
如果需要查看这个topic,需要修改config.consumer.properties
文件,在其中添加exclude.internal.topics=false
,该参数默认为true,通过修改来查看系统主题。
自动offset提交
enable.auto.commit
:是否开启自动提交offset功能,默认为trueauto.commit.interval.ms
:自动提交offset的时间间隔,默认是5s- 工作原理
- consumer从broker中不断的拉取数据
- consumer每隔5s提交当前的offset到系统topic
手动提交offset
自动提交offset虽然方便,但是因为基于时间提交,故较难把握offset提交的时机。提交的方式分为同步提交和异步提交。 两者都是会把本batch中最大的offset值提交。
- 同步提交(commitSync):阻塞当前的线程,反复重试直到提交成功。必须等待offset提交成功,才会开始消费下一batch的数据。
- 异步提交(commitAsync):没有失败重试机制,可能会提交失败。发送完提交offset的请求后,就会开始消费下一批的数据了
在生产环境中,主要是通过异步提交的方式较多
指定offset消费
通过修改参数auto.offset.reset=earliest|latest|none
来指定offset的位置。默认是latest
earliest
:自动将offset重置为最早的offsetlatest
:将offset重置为最新的offsetnone
:如果没有找到CG之前的偏移量,向消费者抛出异常。
这一块在写代码的时候需要注意,创建消费者组的时候会有一个分区分配策略的决策过程,如果这个时候直接去获取分区信息,很有可能获取到的分区信息是空的。
重复消费和漏消费
- 重复消费:已经消费了数据,但是offset没有提交
- 漏消费:先提交了offset再消费,可能造成数据的漏消费
重复消费
由offset自动提交引起的。
在自动提交完offset后,过了2s consumer挂了,那么已经消费过的offset就没有被提交
漏消费
手动提交offset时,offset已经被提交了,但是数据还在内存中没有落盘,此时因为某些原因,consumer的线程被kill了,那么offset已经提交了,但是对应的数据还没有写到位置上,导致内存中的这些数据丢失了。
解决方案: 消费者事务
需要将消费过程和提交offset做原子绑定。
如果需要做到精准的一次性消费,需要确保下游的消费者同样支持事务,确保数据写入的过程也是具有原子性的。
kafka中的事务由之前的幂等性保证
kafka-egale 监控
用于监控kafka集群的状况
如果要使用kafka-egale,需要修改集群的一些硬件参数
修改bin/kafka-server-start.sh
中
export KAFKA_HEAP_OPTS="-server -Xms2G -Xmx2G -XX:PermSize=128 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=5 -XX:InitiatingHeapOccupancyPercent=70"
export JMX_PORT="9999"
kafka-Kraft 模式
架构
之前的kafka需要依赖于zookeeper,但是使用该模式就不再需要使用zookeeper集群了,使用三个controller节点代替zookeeper,元数据保存在controller中,controller直接对kafka集群进行管理。
优点:不再依赖于外部的框架,能够独立运行了
kafka调优
场景: 100w日活,每人每天100条日志,每天日志总数1亿条
- 1150条/秒钟
- 每条日志 0.5k-2k,取1k
- 1mb/s
- 高峰期大约有20倍,23000/s
- 20mb/s
- 平均没什么太大意义,主要要看峰值的状态
硬件选择
- 服务器台数 =
2 * (生产者峰值速率 * 副本数 /100) + 1
= 2 * (20 m/s * 2 / 100) + 1 = 3 台 - 磁盘
- kafka 按照顺序读写,在顺序读写的方面,固态和机械差不多,可以选机械硬盘
- 1 亿 * 1k * 2(副本) * 3(天数) / 0.7 = 1 t
- 三台服务器总的磁盘大小需要>1t
- 内存
- kafka内存 = 堆内存 (kafka内部配置) + 页缓存 (服务器内存)
- 堆内存: 10-15g 就是修改
kafka-server-start.sh
中的配置 - 页缓存 使用segment来存储(1g),一般放25%。
页缓存=分区数 * 1g * 25% / 服务器台数
- 一台机器应该 10-15g + 1-2g
- CPU 选择
num.io.threads=8
负责写磁盘的线程数,占总核数的50%num.replica.fetchers=1
副本拉取线程数 占总核数1/6num.network.threads=3
数据传输线程 占总核数1/3- 还会有很多线程独立在运行中
- 一般建议32个cpu核
- 网络选择
网络带宽 =峰值吞吐量
一般选择千兆网卡
自动创建主题
auto.create.topics.enable
如果没有主题的时候就向其中发送消息,系统会自动创建一个主题,该主题是非预期的,增加了主题管理和维护上的难度,因此该值一般置为false