问题描述:最近一个项目集成了kafka,今天上了生产环境,运维看了日志消息的消费日志只有一个服务在打印。
环境是这样的kafka是集群三个节点,应用部署了三个节点,按照理想情况三个服务节点都应该在消费消息。
除了kafka配置,消费者和生产者代码如下
生产者:
@Component
public class KafkaPrducer {
private static final Logger log = LoggerFactory.getLogger(KafkaPrducer.class);
public static final String TOPIC_TEST = "tj_test_1";
@Autowired
private KafkaTemplate<String,String> kafkaTemplate;
@Autowired
AdminClient adminClient;
public void send(Object obj) {
String obj2String = JSONObject.toJSONString(obj);
log.info("准备发送消息为:{}", obj2String);
//发送消息
String key = UUID.randomUUID().toString();
ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(TOPIC_TEST,null, obj2String);
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
@Override
public void onFailure(Throwable throwable) {
//发送失败的处理
log.info(TOPIC_TEST + " - 生产者 发送消息失败:" + throwable.getMessage());
}
@Override
public void onSuccess(SendResult<String, String> stringObjectSendResult) {
//成功的处理
log.info(TOPIC_TEST + " - 生产者 发送消息成功:" + stringObjectSendResult.toString());
}
});
DescribeTopicsResult describeTopicsResult = adminClient.describeTopics(Arrays.asList(TOPIC_TEST));
System.out.println(describeTopicsResult);
}
消费者:
public class KafkaConsumer {
private static final Logger log = LoggerFactory.getLogger(KafkaConsumer.class);
@KafkaListener(topics = "tj_test_1")
public void consumerMsg(ConsumerRecord<String, String> record){
log.info("key:{}",record.key());
log.info("value:{}",record.value());
String value = record.value();
record.headers();
Person p = JSONObject.parseObject(value, Person.class);
record.partition();
log.info(p.toString());
}
}
排查思路
- 是不是生产消息只有一个服务节点在生产,接口的负载均衡有问题,接口全都映射到了一个节点
在生产者主体加了日志,发现三个服务器均在生产日志,排除此问题。生产者写入分区策略关键代码
public interface Partitioner extends Configurable, Closeable {
// 分区写入策略就是这个接口的实现类了。
int partition(String var1, Object var2, byte[] var3, Object var4, byte[] var5, Cluster var6);
void close();
default void onNewBatch(String topic, Cluster cluster, int prevPartition) {
}
-
是不是可利用的分区只有一个
在消费消费的时候打印了分区名称(record.partition()),发现都是读取的partion 0 ,并且确定了生产200条消息,也消费了200条消息,说明生产消息的时候,全是写到额一个分区 -
代码写法问题,需要指定分区数量吗
百度了好几篇文章终于找到了,配置topic时候需要指定分区数量,配置之后就好了
@Bean
public NewTopic topicinfo() {
// 创建topic,需要指定创建的topic的"名称"、"分区数"、"副本数量(副本数数目的值要小于等于Broker数量)"
return new NewTopic(KafkaPrducer.TOPIC_TEST.toString(), 3, (short) 1);
}