Kafka 集群/高性能讲解

一、ZooKeeper 集群搭建

ZooKeeper 节点端口:2181/2182/2183

cp -r 复制zk节点

修改配置zoo.cfg

#客户端端口,三台分别为2181、2182、2183
clientPort=2181

#数据存储路径,三台分别为/tmp/zookeeper/2181,/tmp/zookeeper/2182,/tmp/zookeeper/2183
dataDir=/tmp/zookeeper/2181 ​

#修改AdminServer的端口,三台分别为8881、8882、8883
admin.serverPort=8881

dataDir对应目录下分别创建myid文件,内容对应1、2、3

cd /tmp/zookeeper/2181
echo 1 > myid

配置集群

# server.服务器id=服务器IP地址:服务器直接通信端口:服务器之间选举投票端口
​
server.1=127.0.0.1:2881:3881
server.2=127.0.0.1:2882:3882
server.3=127.0.0.1:2883:3883

启动命令:进入bin目录

#启动zk
./zkServer.sh  start
​
#查看节点状态
./zkServer.sh status
​
#停止节点
./zkServer.sh stop

二、Kafka 集群搭建

Kafka 节点端口:9092/9093/9094

cp -r 复制 Kafka 节点

修改配置server.properties

#内网中使用,内网部署 kafka 集群只需要用到 listeners,内外网需要作区分时 才需要用到advertised.listeners
listeners=PLAINTEXT://172.18.123.229:9092
​
advertised.listeners=PLAINTEXT://112.74.55.160:9092#每个节点编号1、23
broker.id=1#端口
port=9092#配置3个
log.dirs=/tmp/kafka-logs/9092#zk地址
zookeeper.connect=localhost:2181,localhost:2182,localhost:2183

三、Kafka日志数据清理

Kafka 将数据持久化到了硬盘上,为了控制磁盘容量,需要对过去的消息进行清理

问题:如果让你去设计这个日志删除策略,你会怎么设计?【原理思想】很重要的体现,下面是 kafka 答案

  • 内部有个定时任务检测删除日志,默认是5分钟 log.retention.check.interval.ms
  • 支持配置策略对数据清理
  • 根据segment单位进行定期清理

启用cleaner

  • log.cleaner.enable=true
  • log.cleaner.threads = 2 (清理线程数配置)

日志删除

  • log.cleanup.policy=delete
#清理超过指定时间的消息,默认是168小时,7天,
#还有log.retention.ms, log.retention.minutes, log.retention.hours,优先级高到低
log.retention.hours=168
​
#超过指定大小后,删除旧的消息,下面是1G的字节数,-1就是没限制
log.retention.bytes=1073741824
​
还有基于日志起始位移(log start offset),未来社区还有更多
  • 基于【时间删除】 日志说明
配置了7天后删除,那7天如何确定呢?
​
每个日志段文件都维护一个最大时间戳字段,每次日志段写入新的消息时,都会更新该字段
​
一个日志段segment写满了被切分之后,就不再接收任何新的消息,最大时间戳字段的值也将保持不变
​
kafka通过将当前时间与该最大时间戳字段进行比较,从而来判定是否过期
  • 基于【大小超过阈值】 删除日志 说明
假设日志段大小是500MB,当前分区共有4个日志段文件,大小分别是500MB,500MB,500MB和10MB
​
10MB那个文件就是active日志段。
​
此时该分区总的日志大小是3*500MB+10MB=1500MB+10MB
​
如果阈值设置为1500MB,那么超出阈值的部分就是10MB,小于日志段大小500MB,故Kafka不会执行任何删除操作,即使总大小已经超过了阈值;
​
如果阈值设置为1000MB,那么超过阈值的部分就是500MB+10MB > 500MB,此时Kafka会删除最老的那个日志段文件
​
注意:超过阈值的部分必须要大于一个日志段的大小

注意:log.retention.bytes 和 log.retention.minutes 任意一个达到要求,都会执行删除

日志压缩

  • log.cleanup.policy=compact 启用压缩策略
  • 按照消息 key 进行整理,有相同 key 不同 value 值,只保留最后一个

四、Kafka 零拷贝 ZeroCopy

例子:将一个 File 读取并发送出去(Linux 有两个上下文:内核态、用户态)

  • File 文件的经历了4次copy

    • 调用 read,将文件拷贝到了 kernel 内核态
    • CPU 控制 kernel 态的数据 copy 到用户态
    • 调用 write 时,user 态下的内容会 copy 到内核态的 socket 的 buffer 中
    • 最后将内核态 socket buffer 的数据 copy 到网卡设备中传送
  • 缺点:增加了上下文切换、浪费了2次无效拷贝(即步骤2和3)

ZeroCopy

  • 请求 kernel 直接把 disk 的 data 传输给 socket,而不是通过应用程序传输。Zero copy 大大提高了应用程序的性能,减少不必要的内核缓冲区跟用户缓冲区间的拷贝,从而减少 CPU的开销和减少了 kernel 和 user 模式的上下文切换,达到性能的提升
  • 对应零拷贝技术有 mmap 及 sendfile
    • mmap:小文件传输快
    • sendfile:大文件传输比 mmap 快
  • 应用:Kafka、Netty、RocketMQ等都采用了零拷贝技术

五、Kafka 高性能原因总结

  • 存储模型,Topic 多分区,每个分区多 segment 段

  • index 索引文件查找,利用分段和稀疏索引

  • 磁盘顺序写入

  • 异步操作少阻塞 sender 和 main 线程,批量操作(batch)

  • 页缓存Page cache,没利用 JVM 内存,因为 JVM 容易 GC 影响性能

  • 零拷贝ZeroCopy(SendFile)

posted @ 2021-05-27 16:26  认真对待世界的小白  阅读(170)  评论(0编辑  收藏  举报