思考一个问题:高并发的场景都喜欢用Kafka做中间件,为什么?
答:消息解耦需要用中间件,Kafka有几点优势:
1. 底层消息传递(FileChannel.transferTo API) 运用到Zero-Copy技术,简单概括就是减少数据从内核空间(Kernel Context)到用户空间(Application Context) 之间转换的次数,从而降低CPU资源的开销;
参考资料:
Efficient data transfer through zero copy
2. 数据持久化到硬盘上,Broker没有内存压力,资源成本低;
3. Topic划分为多个partition,提高parallelism(并行度),支持在线水平扩展;
4. 数据批量发送;
5. 数据压缩(支持Gzip和Snappy压缩协议);
6. 消息自动平衡,防止热点问题。
基于上述几点,Kafka可以支持高并发高吞吐量的场景,比如每秒请求数量在百万级别的应用场景 (例子:8小时点击量最大的文章前100名)。
总结几点可以提高Kafka性能的方法:
当然最简单就是增加broker节点,增加分区数量,提高并行度,除此以外,还有以下一些方法,概括为静态的和动态的配置:
静态配置:
GC相关:
Java 7引进了G1 垃圾回收,使得GC调优变的没那么难。G1主要有两个配置选项来调优:MaxGCPauseMillis 和 InitiatingHeapOccupancyPercent. Kafka的启动脚本不支持G1算法,需要在环境变量中设置:
export KAFKA_HEAP_OPTS="-Xmx8G -Xms8G -Xmn4G -XX:PermSize=64m -XX:MaxPermSize=128m -XX:SurvivorRatio=6 -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly"
OS相关:
1. 因为Kafka数据持久化到硬盘,所以理论上增加磁盘数量,可以增加吞吐量;
server.properties 中的log.dirs来配置多个硬盘,多个存储路径;
2. 增大socket buffer size:
Enabling High Performance Data Transfers
默认值,可以改成4倍大小。
# cat /proc/sys/net/core/rmem_max
124928
# cat /proc/sys/net/core/wmem_max
124928
3. 文件描述符:Kafka会使用大量文件和网络socket,所以,我们需要把file descriptors的默认配置改为100000。
#vi /etc/sysctl.conf
fs.file-max = 32000
#vi /etc/security/limits.conf
yourusersoftnofile10000
youruserhardnofile30000
动态配置:
unclean.leader.election.enable:不严格的leader选举,有助于集群健壮,但是存在数据丢失风险。
max.message.bytes:单条消息的最大长度。如果修改了该值,那么replica.fetch.max.bytes和消费者的fetch.message.max.bytes也要跟着修改。
cleanup.policy:生命周期终结数据的处理,默认删除。
flush.messages:强制刷新写入的最大缓存消息数。
flust.ms:强制刷新写入的最大等待时长。
min.insync.replicas:如果同步状态的副本小于该值,服务器将不再接受request.required.acks为-1或all的写入请求。
▪典型的值:
0: 表示Producer从来不等待来自broker的确认信息。这个选择提供了最小的时延但同时风险最大(因为当server宕机时,数据将会丢失)。
1:表示获得Leader replica已经接收了数据的确认信息。这个选择时延较小同时确保了server确认接收成功。
-1:Producer会获得所有同步replicas都收到数据的确认。同时时延最大,然而,这种方式并没有完全消除丢失消息的风险,因为同步replicas的数量可能是1。如果你想确保某些replicas接收到数据,那么你应该在Topic-level设置中选项min.insync.replicas设置一下。