auto.create.topics.enable=false #关闭自动创建topic
log.retention.bytes=xxx #是设置每个分区最大保留大小,而不是topic维度
# 页面缓存配置
vm.swappiness=1
vm.dirty_ratio=60~80
vm.dirty_background_ratio=5
# 网络配置
net.core.wmem_default=128K #socket写缓冲大小
net.core.rmem_default=128K #socket读缓冲大小
net.core.wmem_max=2M #socket写缓冲最大值
net.core.rmem_max=2M #socket读缓冲最大值
net.ipv4.tcp_wmem=4k 64K 2M #tcp socket配置
net.ipv4.tcp_rmem=4k 64K 2M
net.ipv4.tcp_window_scaling=1 #启动tcp时间窗口
net.ipv4.tcp_max_syn_backlog=1024 #设置并发连接数
net.core.netdev_max_backlog=1000 #设置最大排队等待数
发送消息的三种方式:
如果发送嫌慢,可以采用多线程
如何保证发送不丢失消息:
就是不能不管send的结果就直接返回,要通过get或者添加回调函数来处理失败的情况,失败后记录日志或保存到数据库
client.id
acks=[0 | 1 | all] #0不等待直接返回,1首领节点成功就返回,all全部成功才返回
retries=n #收到服务器的错误,重试次数
retry.backoff.ms=n #重试时间间隔
buffer.memory=n #内存缓冲大小
compression.type=[snappy | gzip | lz4] #snappy占用较少cpu来提高可观的压缩比,gzip占用内存大压缩比高
batch.size=n #一批可发送的最大数量
linger.ms #发送前的等待时间,增加吞吐量,增加延迟
max.in.flight.requests.per.connection=n #生成者在收到服务器响应前可以发送多少条消息,设置为1可以保证顺序写入
max.block.ms #调用send和partitionsFor的最大阻塞时间
max.request.size #一批次发送消息的最大值
send.buffer.bytes=n #设置tcp缓冲大小,-1则使用操作系统的默认值
Kafka的特性之一就是高吞吐率,但是Kafka的消息是保存或缓存在磁盘上的,一般在磁盘上读写数据性能是不高的,但kafka可以轻松支持每秒百万级的写入请求,主要是采用了顺序写入和MMFile(memory mapped files, 内存映射文件, 简称mmap)
因硬盘寻址相对读写耗时, 每次读写都会寻址->写入, 随机I/O(RDB很多都是随机I/O)要比顺序I/O慢很多. 为了提高读写硬盘的速度, kafka就是使用顺序I/O. 这样省去了大量的内存开销(减少jvm垃圾回收)以及节省了IO寻址的时间.
但是单纯的使用顺序写入, kafka的写入性能也不可能和内存(寻址读写速度远远高于硬盘)进行对比, 因此Kafka的数据并不是实时的写入硬盘中
kafka充分利用了操作系统分页存储来利用内存提高I/O效率. mmap称为内存映射文件, 在64位操作系统中一般可以表示20G的数据文件
它的工作原理是直接利用操作系统的pagecache实现磁盘文件到物理内存的直接映射. 完成MMP映射后, 用户对内存的所有操作会被操作系统自动的刷新到磁盘上,极大地降低了IO使用率. (用户将不直接把数据写入磁盘, 而是写入内存(pagecache)中, pagecache数据会被系统定时(间隔由系统参数配置)刷写进磁盘)
直接写入硬盘, 速度慢, 但安全; 使用pagecache, 速度快, 但操作系统宕机(断电)会丢失数据(应用(用户态)挂掉不影响, pagecache是内核态, 数据依然会被操作系统刷入硬盘)
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
consumer.wakeup();
}
});
List partitionInfoList = consumer.partitionsFor(ProducerTest.topic);
List topicPartitionList = partitionInfoList.stream()
.map(item -> new TopicPartition(item.topic(), item.partition()))
.collect(Collectors.toList());
consumer.assign(topicPartitionList);
while(true) {
ConsumerRecords poll = consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord record : poll) {
System.out.printf("topic:%s,partition:%d,key:%s,content:%s\n",
record.topic(),
record.partition(),
record.key(),
record.value());
}
consumer.commitSync();
}
fetch.min.bytes=x #返回的数据大小至少xx,否则阻塞等待到有这么多数据
fetch.max.wait.ms=x #指定最大阻塞等待时间,默认500ms
max.partition.fetch.bytes=x #一次poll,从一个分区能拉取的最大大小
session.timeout.ms=x #会话过期时间,如果过期就被认定为消费者挂掉了
auto.offset.reset=[latest | earliest] #在没有偏移量的情况,指定消费其实位置(最前或者最后)
enable.auto.commit=true #是否自动提交偏移量
auto.commit.interval.ms=100 #设置自动提交偏移量的频率
max.poll.records=n #单次poll最大的返回最大记录数
receive.buffer.bytes=n #设置tcp缓冲大小,-1则使用操作系统的默认值
kafka服务器在响应客户端读取时, 使用ZeroCopy技术, 直接将需要读取的数据从内核空间的磁盘中传递输出, 而无需将数据读取并拷贝到用户空间, 再进行传输
何为分区:就是一个topic的数据,分散存储在多个broker中,这样就可以避免一个topic把broker给占满的情况,同时分区可以提高吞吐量,比如一个客户端的消费速度是50M/S,要达到每秒1G/S的吞吐量,就需要1000/50=20个分区
默认采用轮询broker(round-robin)的方式,先分主分区,再分副本分区;分区数=2为例: 第1条去0分区, 第2条去1分区, 第3条去0分区, 仅仅达到负载均衡
hash, 每条record根据key的hash值对分区数取模(去哪个分区= hash(record的key) % 分区数 ), 决定该record存放哪个分区
kafka-topics.sh --zookeeper zkStr --create --topic test --replication-factor 2 --partitions 8 #如果放置存在报错,可以加--if-not-exists
只能增加分区,不能减少分区,因为减少分区会出现消息乱序,如果一定要减少分区,只能删除整个topic
kafka-topics.sh --zookeeper zkStr --alter --topic test --partition 16
删除topic必须broker的delete.topic.enable=true,否则删除请求将被忽略
kafka-topics.sh --zookeeper zkStr --delete --topic test
kafka-topics.sh --zookeeper zkStr --list
kafka-topics.sh --zookeeper zkStr --describe
--topics-with-overrides #只列出有不同于默认配置的topic
--under-replicated-partitions #列出包含不同步副本分区
--unavailable-partitions #列出没有leader的分区
在旧版本中,消费者群组信息保存在zk上面,用–zookeeper指定;
在新版本中,消费者群组信息保存在broker上面,用–bootstrap-server指定;
在旧版本可以删除消费者群组和偏移量信息,新的不行。
kafka-consumer-groups.sh --zookeeper zkStr --list
kafka-consumer-groups.sh --zookeeper zkStr --describe --group testGroup
字段 | 描述 |
---|---|
group | 分组名字 |
topic | 分区名字 |
partition | 分区名字 |
current-offset | 这个群组读取的位置 |
log-end-offset | 高水位位置 |
log | current-offset和log-end-offset的差距 |
owner | 消费者id |
kafka-configs.sh --zookeeper zkStr --alter --entity-type [topics | clients] --entity-name xxxx --add-config key=value[,key=value...]
kafka-configs.sh --zookeeper zkStr --describe --entity-type [topics | clients] --entity-name xxxx
kafka-configs.sh --zookeeper zkStr --alter --entity-type [topics | clients] --entity-name xxxx --delete-config key[,key...]
kafka-console-consumer.sh --zookeeper zkStr --topic topicName [--from-begin] [--max-messages] [--partition] [--formatter] [--property]
kafka-console-producer
--broker-list ip:port[,ip:port]
--topic topicName [--key-serializer]
[--value-serializer]
[--compression-codec [none | gzip | snappy | lz4]] #压缩方式
[--sync] #是否同步发送
请求与相应:一个请求对应一个响应,响应时长在亚秒和毫秒级
批处理:处理周期为分钟、小时、天、周、月、年等等
流式处理:流式处理范式介于上面两种范式中间,不要求在亚秒级响应,但也不能容忍第二天才返回结果。流式处理是持续的,输入的数据一直持续进行,返回的结果也是持续进行。有持续性和非阻塞特性。
事件时间:表示追踪时间的发生时间或者创建时间
日志追加时间:事件保存到broker的时间,这个时间一般和流式计算没有关系,除非事件没有记录事件时间,这时可以使用日志追加时间模糊代表事件时间
处理时间:指应用程序在收到事件之后开始对其进行处理的时间。因为从产生事件到处理事件中间时间不确定,所以这个时间更不可靠,尽量避免使用它
本地状态:只有当前应用程序能访问,一般使用内嵌的数据库保存,优点访问速度快,不受内存大小限制
外部状态:使用外部的数据存储系统,一般是NoSQL,优势是没有容量限制,但是延迟高。大部分流式处理应该避免使用外部存储
表只关注于数据的当前状态,而流表示了数据的整个变化过程,比如,mysql的binlog就是一个事件流。大部分的数据库都提供了CDC方案(Change Data Capture)
窗口的大小:是统计5分钟还是10分钟内的数据
窗口的移动间隔:统计5分钟的数据,可以每1秒钟统计一次,也可以每1分钟统计一次。如果窗口大小和移动间隔相等叫做“滚动窗口”,如果窗口随每一条数据移动,这种叫做“滑动窗口”
窗口的可更新时长:有些数据可能由于网络或者服务器重启导致数据姗姗来迟,这些数据在允许的时间范围可以更新统计结果,否则忽略他们
Kafka Streams在流式计算领域应用的很少,主要在于只能处理Kafka的数据,对于其他数据源和Sink的数据只能干瞪眼。而且部署上也没有优势。