最近在使用kafkajs 做kafka 生产者和消费者客户端的时候,遇到一些问题,不同的生产者客户端(kafka版本是一致的:2.2.4)生产相同的key 消息的时候,将消息发送到了不同分区。本文是记录这个问题的解决过程。
问题复现
环境
- node v18
- kafkajs v2.2.4
- kafka broker v2.4
kafka 客户端
生产者客户端1
const {Kafka, Partitioners} = require('kafkajs')
const kafka = new Kafka({
clientId: 'my-app',
brokers: ['kafka1:9092', 'kafka2:9092'],
})
const producer = kafka.producer({
createPartitioner: Partitioners.DefaultPartitioner,
allowAutoTopicCreation: false,
})
await producer.connect()
await producer.send({
topic: 'test-topic',
messages: [
{key: "10000", value: 'Hello KafkaJS user!'},
],
})
await producer.disconnect()
生产者客户端2
const {Kafka, Partitioners} = require('kafkajs')
const kafka = new Kafka({
clientId: 'my-app',
brokers: ['kafka1:9092', 'kafka2:9092'],
})
const producer = kafka.producer({
createPartitioner: Partitioners.LegacyPartitioner,
allowAutoTopicCreation: false,
})
await producer.connect()
await producer.send({
topic: 'test-topic',
messages: [
{key: "10000", value: 'Hello KafkaJS user!'},
],
})
await producer.disconnect()
消费者(启动多个进程)
const {Kafka} = require('kafkajs')
const kafka = new Kafka({
clientId: 'my-app',
brokers: ['kafka1:9092', 'kafka2:9092'],
})
const consumer = kafka.consumer({groupId: 'test-group'})
await consumer.connect()
await consumer.subscribe({topic: 'test-topic', fromBeginning: true})
await consumer.run({
eachMessage: async ({topic, partition, message}) => {
console.log({
key: message.key.toString(),
value: message.value.toString(),
})
},
})
kafka 服务器 配置 test-topic N(N>1)个分区,M(M>1)个副本
当启动进程后相同key放在不同的分区去消费。
kakfa生产者客户端的区别就是分区算法DefaultPartitioner/LegacyPartitioner
源码解读
当生产的消息存在key时,分区算法会对key 做一次hash运算,保证不同的key尽可能分布在不同的partition
源码分析1
2个不同的目录代表2种不同的分区算法。
- DefaultPartitioner v2版本新增的算法,是默认算法。采用long类型的数值hash运算。
- LegacyPartitioner 之前版本的分区算法,采用number类型的数值进行hash运算。
hash算法基础是 murmur2(算法最新版本是murmur3)
DefaultPartitioner murmur2源码
/* eslint-disable */
const Long = require('../../../utils/long')
// Based on the kafka client 0.10.2 murmur2 implementation
// https://github.com/apache/kafka/blob/0.10.2/clients/src/main/java/org/apache/kafka/common/utils/Utils.java#L364
const SEED = Long.fromValue(0x9747b28c)
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
const M = Long.fromValue(0x5bd1e995)
const R = Long.fromValue(24)
module.exports = key => {
const data = Buffer.isBuffer(key) ? key : Buffer.from(String(key))
const length = data.length
// Initialize the hash to a random value
let h = Long.fromValue(SEED.xor(length))
let length4 = Math.floor(length / 4)
for (let i = 0; i < length4; i++) {
const i4 = i * 4
let k =
(data[i4 + 0] & 0xff) +
((data[i4 + 1] & 0xff) << 8) +
((data[i4 + 2] & 0xff) << 16) +
((data[i4 + 3] & 0xff) << 24)
k = Long.fromValue(k)
k = k.multiply(M)
k = k.xor(k.toInt() >>> R)
k = Long.fromValue(k).multiply(M)
h = h.multiply(M)
h = h.xor(k)
}
// Handle the last few bytes of the input array
switch (length % 4) {
case 3:
h = h.xor((data[(length & ~3) + 2] & 0xff) << 16)
case 2:
h = h.xor((data[(length & ~3) + 1] & 0xff) << 8)
case 1:
h = h.xor(data[length & ~3] & 0xff)
h = h.multiply(M)
}
h = h.xor(h.toInt() >>> 13)
h = h.multiply(M)
h = h.xor(h.toInt() >>> 15)
return h.toInt()
}
LegacyPartitioner murmur2源码
/* eslint-disable */
// Based on the kafka client 0.10.2 murmur2 implementation
// https://github.com/apache/kafka/blob/0.10.2/clients/src/main/java/org/apache/kafka/common/utils/Utils.java#L364
const SEED = 0x9747b28c
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
const M = 0x5bd1e995
const R = 24
module.exports = key => {
const data = Buffer.isBuffer(key) ? key : Buffer.from(String(key))
const length = data.length
// Initialize the hash to a random value
let h = SEED ^ length
let length4 = length / 4
for (let i = 0; i < length4; i++) {
const i4 = i * 4
let k =
(data[i4 + 0] & 0xff) +
((data[i4 + 1] & 0xff) << 8) +
((data[i4 + 2] & 0xff) << 16) +
((data[i4 + 3] & 0xff) << 24)
k *= M
k ^= k >>> R
k *= M
h *= M
h ^= k
}
// Handle the last few bytes of the input array
switch (length % 4) {
case 3:
h ^= (data[(length & ~3) + 2] & 0xff) << 16
case 2:
h ^= (data[(length & ~3) + 1] & 0xff) << 8
case 1:
h ^= data[length & ~3] & 0xff
h *= M
}
h ^= h >>> 13
h *= M
h ^= h >>> 15
return h
}
测试 代码地址 gitee.com/edodo/jsmur…
key: 10000 murmur2legacy: 1652631299 murmur2default: 19210356
key: 10001 murmur2legacy: 618469818 murmur2default: -62124129
key: 10002 murmur2legacy: -1237937297 murmur2default: 1280536182
key: 10003 murmur2legacy: 1183573782 murmur2default: -1446901933
key: 10004 murmur2legacy: -39996104 murmur2default: -1678027407
key: 10005 murmur2legacy: 1071593662 murmur2default: -1731916815
key: 10006 murmur2legacy: -2067389554 murmur2default: 830042206
key: 10007 murmur2legacy: -1777399396 murmur2default: 1131852762
key: 10008 murmur2legacy: -1790118757 murmur2default: 713771282
key: 10009 murmur2legacy: 1536669998 murmur2default: 2011010072
key: 10010 murmur2legacy: 1342801554 murmur2default: 2093165943
key: 10011 murmur2legacy: -1982759520 murmur2default: -1626827470
key: 10012 murmur2legacy: -725135859 murmur2default: 1412292251
key: 10013 murmur2legacy: 187243346 murmur2default: -1234513182
key: 10014 murmur2legacy: 1274942141 murmur2default: -1225482186
key: 10015 murmur2legacy: -153469769 murmur2default: 1320086528
key: 10016 murmur2legacy: 1449990875 murmur2default: -854288048
key: 10017 murmur2legacy: 1246139276 murmur2default: 159315029
key: 10018 murmur2legacy: -1959287187 murmur2default: -2059259591
key: 10019 murmur2legacy: -685278131 murmur2default: 1859884381
key: 10020 murmur2legacy: 1608403645 murmur2default: -841897444
key: 10021 murmur2legacy: 1597622386 murmur2default: -1100689363
key: 10022 murmur2legacy: 1362787957 murmur2default: 181208127
key: 10023 murmur2legacy: 900607836 murmur2default: 1979662630
key: 10024 murmur2legacy: 1931764809 murmur2default: 359417849
key: 10025 murmur2legacy: 486478334 murmur2default: -1282029111
key: 10026 murmur2legacy: -140617609 murmur2default: 272383078
key: 10027 murmur2legacy: -518262732 murmur2default: -400266993
key: 10028 murmur2legacy: -14876870 murmur2default: 270044867
key: 10029 murmur2legacy: -1969771523 murmur2default: 1984814214
key: 10030 murmur2legacy: 1857446381 murmur2default: 1630765241
key: 10031 murmur2legacy: -451889374 murmur2default: 196299064
key: 10032 murmur2legacy: -35932748 murmur2default: -305708214
key: 10033 murmur2legacy: -220304961 murmur2default: 62092989
key: 10034 murmur2legacy: 1740812164 murmur2default: 513148526
key: 10035 murmur2legacy: 582849915 murmur2default: 1383509756
key: 10036 murmur2legacy: -659505310 murmur2default: -1441733386
key: 10037 murmur2legacy: 361674653 murmur2default: -365185288
key: 10038 murmur2legacy: 225868524 murmur2default: -2114772043
key: 10039 murmur2legacy: -471203113 murmur2default: -2103950001
key: 10040 murmur2legacy: 1255203232 murmur2default: -1009802442
key: 10041 murmur2legacy: 571483680 murmur2default: 76170860
key: 10042 murmur2legacy: 279446864 murmur2default: 304051539
key: 10043 murmur2legacy: -150079464 murmur2default: 1008760609
key: 10044 murmur2legacy: 867810163 murmur2default: -882672830
key: 10045 murmur2legacy: 1438846343 murmur2default: -33672948
key: 10046 murmur2legacy: -1238163868 murmur2default: 360437549
key: 10047 murmur2legacy: -1301978360 murmur2default: 1680825220
key: 10048 murmur2legacy: -496980286 murmur2default: 1322857464
key: 10049 murmur2legacy: 1149953812 murmur2default: 1066304863
key: 10050 murmur2legacy: -1393905449 murmur2default: 1804877743
key: 10051 murmur2legacy: -1942724502 murmur2default: 993290080
key: 10052 murmur2legacy: -624970116 murmur2default: -2118344603
key: 10053 murmur2legacy: -846130911 murmur2default: 1674397892
key: 10054 murmur2legacy: 1997835432 murmur2default: -1646322339
key: 10055 murmur2legacy: -1682357584 murmur2default: -262728904
key: 10056 murmur2legacy: -1556522128 murmur2default: -176056435
key: 10057 murmur2legacy: -2115477294 murmur2default: -1213779819
key: 10058 murmur2legacy: -1546642782 murmur2default: 399144595
key: 10059 murmur2legacy: -1962000866 murmur2default: 1858752531
key: 10060 murmur2legacy: -903962562 murmur2default: -186466498
key: 10061 murmur2legacy: 541698963 murmur2default: -2042299038
key: 10062 murmur2legacy: 462805291 murmur2default: -1056973035
key: 10063 murmur2legacy: 786762186 murmur2default: -421099533
key: 10064 murmur2legacy: -921247122 murmur2default: 420648318
key: 10065 murmur2legacy: -1057070081 murmur2default: -908562188
key: 10066 murmur2legacy: 251770371 murmur2default: 793435697
key: 10067 murmur2legacy: 1484614395 murmur2default: 2017984404
key: 10068 murmur2legacy: -1562405955 murmur2default: 38430594
key: 10069 murmur2legacy: 456162400 murmur2default: -1759122343
key: 10070 murmur2legacy: -1291287501 murmur2default: -301168529
key: 10071 murmur2legacy: 1514219203 murmur2default: 2087884856
key: 10072 murmur2legacy: 1163519410 murmur2default: -1729430034
key: 10073 murmur2legacy: 1622627183 murmur2default: -1124672206
key: 10074 murmur2legacy: 403609885 murmur2default: -159997051
key: 10075 murmur2legacy: -1188505005 murmur2default: 1771543385
key: 10076 murmur2legacy: -345723702 murmur2default: 1822040411
key: 10077 murmur2legacy: -1019478924 murmur2default: 2019664338
key: 10078 murmur2legacy: -1629323722 murmur2default: 924525977
key: 10079 murmur2legacy: 1520782059 murmur2default: 1083950221
key: 10080 murmur2legacy: -1278245731 murmur2default: 1622573222
key: 10081 murmur2legacy: -479626543 murmur2default: 573481222
key: 10082 murmur2legacy: 1347040069 murmur2default: -1004348380
key: 10083 murmur2legacy: 988144331 murmur2default: 1235157515
key: 10084 murmur2legacy: 614462271 murmur2default: 80886365
key: 10085 murmur2legacy: 1165536496 murmur2default: -1504206243
key: 10086 murmur2legacy: 1382915146 murmur2default: -1924047115
key: 10087 murmur2legacy: 1988218626 murmur2default: -916418453
key: 10088 murmur2legacy: 2051370123 murmur2default: 2108860640
key: 10089 murmur2legacy: -1575369799 murmur2default: -796870384
key: 10090 murmur2legacy: -468819425 murmur2default: -326564793
key: 10091 murmur2legacy: -1853518967 murmur2default: -2000414038
key: 10092 murmur2legacy: 413962585 murmur2default: 1162386446
key: 10093 murmur2legacy: 1258975765 murmur2default: 180755019
key: 10094 murmur2legacy: -75708166 murmur2default: 1231106808
key: 10095 murmur2legacy: -218820119 murmur2default: 1199365919
key: 10096 murmur2legacy: -1601182435 murmur2default: -591059619
key: 10097 murmur2legacy: 1696251956 murmur2default: -1183758518
key: 10098 murmur2legacy: 1281946320 murmur2default: -1816448453
key: 10099 murmur2legacy: -1793854299 murmur2default: 394481488