在上篇的例子里(【Kafka】《Kafka权威指南》——写数据), ProducerRecord 对象包含了目标主题、键和值。 Kafka 的消息是 一个个 键值对, ProducerRecord对象可以只包含目标主题和值,键可以设置为默认的 null,不过大多数应用程序会用到键。键有两个用途 :可以作为消息的附加信息,也可以用来决定消息该被写到主题的哪个分区。拥有相同键的悄息将被写到同一个分区。 也就是说,如果一个进程只从一个主题的分区读取数据(第 4章会介绍更多细节),那么具有相 同键的所有记录都会被该进程读取。要创建一个包含键值的记录,只需像下面这样创建 ProducerRecord 对象:
如果键值为 null, 井且使用了默认的分区器,那么记录将被随机地发送到主题内各个可用的分区上。分区器使用轮询(Round Robin)算法将消息均衡地分布到各个分区上。
如果键不为空,并且使用了默认的分区器,那么Kafka会对键进行散列(使用 Kafka 自己的散列算法,即使升级Java版本,散列值也不会发生变化),然后根据散列值把消息映射到特定的分区上。这里的关键之处在于 ,同一个键总是被映射到同一个分区上 ,所以在进 行映射时,我们会使用主题所有的分区,而不仅仅是可用的分区 。这也意味着,如果写入数据的分区是不可用的,那么就会发生错误。但这种情况很少发生。我们将在第 6章讨论 Kafka 的复制功能和可用性。
只有在不改变主题分区数量的情况下,键与分区之间的映射才能保持不变 。举个例子,在分区数量保持不变的情况下,可以保证用户 045189 的记录总是被写到分区 34。在从分区读取数据肘,可以进行各种优化。不过,一旦主题增加了新的分区,这些就无法保证 了——旧数据仍然留在分区 34,但新的记录可能被写到其他分区上 。 如果要使用键来映射分区,那么最好在创建主题的时候就把分区规划好,而且永远不要增加新分区。
实现自定义分区策略
我们已经讨论了默认分区器的特点,它是使用次数最多的分区器。不过 ,除了散列分区之 外,有时候也需要对数据进行不一样的分区。假设你是一个 B2B 供应商,你有 一 个大客 户,它是手持设备 Banana 的制造商。 Banana 占据了你整体业务 10% 的份额。如果使用默 认的散列分区算怯, Banana 的账号记录将和其他账号记录一起被分配给相同的分区,导致 这个分区比其他分区要大一些。服务器可能因此出现存储空 间不足、处理缓慢等问题。我 们需要给 Banana 分配单独的分区,然后使用散列分区算住处理其他账号 。
下面是一个自定义分区器的例子 :