kafka处理大消息的相关配置

kafka的设计初衷是迅速处理短消息,比如几k或者几十k,当然更小也不合适,一般认为处理10k大小的消息吞吐量性能最好。
但有些情况下,没有办法限制消息的体积或者分割消息,就必须更改kafka的相关配置。

kafka消息的最大值

首先,kafka的一条消息肯定是有一个最大值的,在kafka的数据存储格式中,有一个4个字节的整数值来描述这条消息的大小,也就是说一条消息最大是2147483647字节,接近2个g。

producer端相关参数

max.request.size

Int类型,默认值是1048576,也即是1M,一条消息的最大值,超过后这条消息不会被发送

buffer.memory

Long类型,默认值是33554432,32M,生产者用来缓存等待发送到服务器的消息的内存总字节数

batch.size

int类型,默认值16384,16k,当多个消息要发送到相同分区的时,生产者尝试将消息批量打包在一起,以减少请求交互。我的理解是如果某几条消息可以被打包成一批,就会被限制在这个大小内,但是如果某条消息自身就比这个值大,这条消息还是会发送,除非这条消息的大小超过了max.request.size

request.timeout.ms

int类型,默认值30000,也就是30s,该配置控制客户端等待请求响应的最长时间。如果消息过大的话,显然要增大这个时间。

在这里插入图片描述

例如

Properties props = new Properties();
 props.put("bootstrap.servers", "localhost:9092");
 props.put("acks", "all");
 props.put("retries", 0);
 props.put("batch.size", 16384);
 props.put("linger.ms", 1);
 props.put("buffer.memory", 33554432);
 props.put("max.request.size", 33554432);
 props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
 props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

 Producer<String, String> producer = new KafkaProducer<>(props);
 for(int i = 0; i < 100; i++)
     producer.send(new ProducerRecord<String, String>("my-topic", Integer.toString(i), Integer.toString(i)));

 producer.close();

consumer端相关参数

fetch.max.bytes

int类型,默认值52428800,50M,服务器为获取请求应返回的最大数据量。使用者将批量获取记录,并且如果获取的第一个非空分区中的第一个记录批次大于此值,则仍将返回记录批次以确保使用者可以取得进展。因此,这不是绝对最大值。代理可接受的最大记录批处理大小是通过“ message.max.bytes”(代理配置)或“ max.message.bytes”(主题配置)定义的。请注意,使用者并行执行多个提取。

max.poll.interval.ms

int,300000,也就是300s,根据实际情况增加或减小。使用消费者组管理时poll()调用之间的最大延迟。消费者在获取更多记录之前可以空闲的时间量的上限。如果此超时时间期满之前poll()没有调用,则消费者被视为失败,并且分组将重新平衡,以便将分区重新分配给别的成员。如果报一下错误,可以考虑增大这个参数了。

org.apache.kafka.clients.consumer.internals.ConsumerCoordinator - [Consumer clientId=consumer-1, groupId=hsta.cdcGroup] Asynchronous auto-commit of offsets {hs_ta_channel_Metadata-0=OffsetAndMetadata{offset=22, leaderEpoch=null, metadata=''}} failed: Commit cannot be completed since the group has already rebalanced and assigned the partitions to another member. This means that the time between subsequent calls to poll() was longer than the configured max.poll.interval.ms, which typically implies that the poll loop is spending too much time message processing. You can address this either by increasing max.poll.interval.ms or by reducing the maximum size of batches returned in poll() with max.poll.records.

max.poll.records

int,500,在单次调用poll()中返回的最大记录数。我认为是如果单条消息体积大的话,这个值应该减小,可以根据实际情况先观察。

request.timeout.ms

int, 305000, 配置控制客户端等待请求响应的最长时间。 如果在超时之前未收到响应,客户端将在必要时重新发送请求,如果重试耗尽则客户端将重新发送请求。

session.timeout.ms

int, 10000,用于发现消费者故障的超时时间。消费者周期性的发送心跳到broker,表示其还活着。如果会话超时期满之前没有收到心跳,那么broker将从分组中移除消费者,并启动重新平衡。请注意,该值必须在broker配置的group.min.session.timeout.msgroup.max.session.timeout.ms允许的范围内。

broker端配置

message.max.bytes

int,1000012,接近1M, 服务器可以接收的消息的最大大小

replica.fetch.max.bytes

int,1048576,限制副本拉取消息的大小,在 0.8.2 以前的版本中,如果 replica.fetch.max.bytes < message.max.bytes,就会造成 follower 副本复制不了消息

max.message.bytes(topic级别配置)

int,1000012,和message.max.bytes作用一样,不过是对单个topic生效,好处是不需要重启kafka服务

开启消息压缩

首先要区分kafka的消息压缩和kafka的compact是两种概念,compact是日志清理策略的一种,和delete策略的概念并列。

消息压缩compress

好处:broker的磁盘空间占用减小,网络带宽占用会减小。

设置:

生产者 compression.type,有效的值有 none,gzip,snappy, 或 lz4。其中性能方面lz4>>snappy>gzip

broker可以配置compression.type(主题级别也可以配置),标准的压缩格式有’gzip’, ‘snappy’, lz4。还可以设置’uncompressed’,就是不压缩;设置为’producer’这意味着保留生产者设置的原始压缩编解码。默认值是producer。

消费者端不用配置。

另外,开启压缩之前要评估一下资源情况,cpu资源也是很宝贵的。

总结

为了保证极限情况下消息能被正常发送和接收,要维持下面的数量关系

max.request.size(producer端) < message.max.bytes(broker端) < fetch.max.bytes(consumer端)
或者是
max.request.size(producer端) < max.message.bytes(topic级别) < fetch.max.bytes(consumer端)

视情况调整堆内存:

kafka-server-start.sh:export KAFKA_HEAP_OPTS="-Xmx6G -Xms6G"

如果有总结错的,欢迎指正。

### HAL_TIM_PeriodElapsedCallback 函数功能与用法 #### 1. 功能描述 `HAL_TIM_PeriodElapsedCallback` 是 STM32 HAL 库中的回调函数,用于处理定时器周期结束事件。当定时器的计数值达到设定的最值并触发更新事件时,该回调函数会被调用[^1]。 此函数的主要作用是在中断服务程序中被自动调用,允许用户在不修改底层驱动的情况下实现自定义逻辑。它通常用来响应特定的时间间隔到达后的动作,例如刷新数据、切换状态或其他实时任务调度[^2]。 --- #### 2. 定义形式 以下是 `HAL_TIM_PeriodElapsedCallback` 的典型定义: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // 用户可以在此处编写自己的代码来处理定时器周期溢出事件 } ``` - **参数说明** - `TIM_HandleTypeDef *htim`: 这是一个指向定时器句柄结构体的指针,包含了配置和运行状态的信息。通过这个句柄,可以在回调函数内部访问当前定时器的相关属性或重新设置其行为。 --- #### 3. 使用方法 为了使能这一回调机制,需完成以下几个步骤: 1. 初始化定时器:利用 `HAL_TIM_Base_Init` 或其他初始化接口完成硬件资源分配以及基础参数配置(如预分频系数、计数器周期等)。 2. 启动带中断模式的定时器:调用 `HAL_TIM_Base_Start_IT(htim)` 来开启定时器及其关联的中断请求。这一步会启用相应的中断线,并注册默认的中断服务例程(ISR)[^1]。 3. 实现回调函数:根据实际需求重写 `HAL_TIM_PeriodElapsedCallback` 方法的内容。每当发生一次完整的计数循环后,即进入下一轮计数前,都会跳转到此处执行指定的操作[^3]。 4. 清除标志位/中断挂起比特 (可选): 如果需要手动管理某些特殊类型的干扰信号,则可能还需要借助宏指令如 __HAL_TIM_CLEAR_IT() 对应位置零操作。 --- #### 示例代码片段 下面展示了一个简单的应用案例——每秒钟点亮 LED 一次: ```c #include "stm32f4xx_hal.h" // 假设已正确设置了 GPIO 和 TIM 句柄 htim2 uint8_t led_state = 0; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ if(htim->Instance == TIM2){ // 判断是否来自 TIM2 中断 if(led_state == 0){ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 打开LED led_state = 1; } else { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); // 关闭LED led_state = 0; } } } int main(void){ /* MCU Initialization */ // 配置GPIO PA5作为输出端口 // 设置 TIM2 参数 TIM_HandleTypeDef timHandle; timHandle.Instance = TIM2; timHandle.Init.Prescaler = 8399; // 设定预分频值使得频率接近1KHz timHandle.Init.CounterMode = TIM_COUNTERMODE_UP; timHandle.Init.Period = 9999; // 计数至最值约等于一秒 timHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if(HAL_TIM_Base_Init(&timHandle) != HAL_OK){ Error_Handler(); } // 开启 IT 模式的定时器 HAL_TIM_Base_Start_IT(&timHandle); while(1); } ``` 上述例子展示了如何结合外部设备控制形成规律性的脉冲序列。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值