kafka?
kafka示例代码
生产者:
const { Kafka, Partitioners } = require("kafkajs");
(async () => {
const kafka = new Kafka({
clientId: "test-app",
brokers: ['1.14.217.220:9094'],
});
const producer = kafka.producer({
createPartitioner: Partitioners.LegacyPartitioner,
});
await producer.connect();
for (let i = 0; i < 10; i++) {
await producer.send({
topic: "test-topic",
messages: [{ value: "test msg" + i }],
});
console.log('发送:', "test msg" + i);
}
await producer.disconnect();
})();
消费者
const { Kafka } = require("kafkajs");
(async () => {
const kafka = new Kafka({
clientId: "test-app",
brokers: ['1.14.217.220:9094'],
});
const consumer = kafka.consumer({ groupId: "test-group1" });
await consumer.connect();
await consumer.subscribe({ topic: "test-topic", fromBeginning: true });
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
console.log({
value: message.value.toString(),
});
},
});
})();
kafka中消费者之间的关系
消费者有一个group的概念,用创建消费者时的groupId
参数区分。同一个group中的消费者消费来自同一个topic的消息时取决于broker中分区的数量,具体规则如下。
- 当分区数大于消费者数量时,每一个消费者会被分配来自一个以上的分区的消息,以保证所有分区的消息都有地方消费
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MoumZCLx-1661006356982)(/api/project/10755416/files/28624151/imagePreview)] - 当分区数量等于消费者数量时,一个消费者对应一个分区
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vEoQX3I-1661006356982)(/api/project/10755416/files/28624154/imagePreview)] - 当分区数量小于消费者数量时,可能有消费者会被闲置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbdYWhGx-1661006356982)(/api/project/10755416/files/28624164/imagePreview)]
总之就是确保每一个分区的消息都有消费者消费,但是不保证每一个消费者都有活干。
并且kafka有一个机制,每当有新的消费者加入既有的group时,就会分配一个leader
。由leader
来按照上述规则分配哪个消费者对应哪个分区。
我们目前搭建的kafka只有一个分区,并且目前采取的是点到点的形式,所以编写代码的时候一个话题只需要一个消费者就好了,消费者多了也会闲置掉。
关于更多的消费者的信息可以看看这两篇文章
杂项
订阅模式解决项目
消费者自身队列
使用队列解决
多消费者互锁
用一个读写锁给version,然后消费者看某条数据的读写锁,锁住了就跳过;没锁就加锁,然后查看version是不是比获取的时候新,如果是也跳过;若version保持一致就更新version,然后再跟broke声明已消费该条数据,解锁,继续往下一topic塞
生产者生产问题
未收到broke响应产生重复数据
尚未有实际思路,考虑消费重复消息后,最终的结果是一样的。(即冥等)
如何保证消息发送的幂等性
produce – > broke
每个producer会分配一个唯一 的PID,发往同一个broker的消息会附带一个Sequence Number,broker端会对<PID,partitionId,Sequence Number>做一个缓存,当具有相同主键的消息提交时,Kafka只会持久化一条。
注意:PID 会随着生产者重启而发生变化,并且不同的partition对应的partitionId也不相同。