Pulsar-subscription types-官方文档中文翻译

翻译结果可能存在错误,欢迎指正 , 原文地址.
请注意文档版本为3.2.x

Subscriptions

Pulsar订阅是一个确定消息如何传递给消费者的命名的配置规则。它是由一组消费者对Topic(主题)建立的的使用权利。Pulsar中有四种订阅类型:

  • 独占(exclusive)
  • 共享(shared)
  • 故障转移(failover)
  • 键共享(key_shared)
    这些类型在下图中有所说明。

在这里插入图片描述

提示
在Pulsar中,您可以灵活使用不同的订阅。

  • 如果您想在消费者之间实现传统的“发布-订阅”消息传递,请为每个消费者指定唯一的订阅名称。这是独占订阅类型。
  • 如果您想在消费者之间实现“消息队列”,请在多个消费者之间共享相同的订阅名称(共享,故障转移,键共享)。
  • 如果您想同时实现这两种效果,请将独占订阅类型与其他订阅类型结合起来为消费者使用。

Subscription types

当一个订阅没有消费者时,其订阅类型是未定义的。订阅的类型在有消费者连接时定义,并且可以通过以不同的配置重新启动所有消费者来更改类型。

Exclusive

独占类型是一种订阅类型,只允许单个消费者连接到订阅。如果多个消费者使用相同的订阅订阅主题,则会发生错误。请注意,如果主题被分区,所有分区将由允许连接到订阅的单个消费者消耗。

在下图中,只有消费者 A 被允许消费消息。

独占是默认的订阅类型。

Exclusive

Failover

故障转移类型是一种允许多个消费者连接到同一个订阅的订阅类型。
对于非分区主题或分区主题的每个分区,都会选择一个主要消费者来接收消息。
当主要消费者断开连接时,所有(未确认的和后续的)消息将传递给下一个排队的消费者。

在某些情况下,一个分区可能会有一个较旧的活动消费者处理消息,同时一个新切换的活动消费者开始接收新消息。这可能导致消息重复或顺序错乱。

Failover | Partitioned topics

对于分区Topic,代理按照消费者的优先级和消费者名称的词典顺序对消费者进行排序。
代理尝试将分区均匀地分配给优先级最高的消费者。
通过对模块运算mod(分区索引,消费者索引)来选择消费者。

  • 如果分区主题中的分区数量少于消费者数量:
    例如,在下图中,这个分区主题有2个分区,有4个消费者。
    每个分区有1个活动消费者和3个备用消费者。
    • 对于P0,消费者A是主要的消费者,而消费者B、消费者C和消费者D将是接收消息的下一个消费者,如果消费者A断开连接的话。
    • 对于P1,消费者B是主要的消费者,而消费者A、消费者C和消费者D将是接收消息的下一个消费者,如果消费者B断开连接的话。
    • 此外,如果消费者A和消费者B都断开连接,那么
      • 对于P0:消费者C是活动消费者,消费者D是备用消费者。
      • 对于P1:消费者D是活动消费者,消费者C是备用消费者。

Failover | Partitioned topics

  • 如果分区主题中的分区数量大于消费者数量:
    例如,在下图中,这个分区主题有9个分区和3个消费者。
    • P0、P3和P6分配给消费者A。消费者A是它们的活动消费者。消费者B和消费者C是它们的备用消费者。
    • P1、P4和P7分配给消费者B。消费者B是它们的活动消费者。消费者A和消费者C是它们的备用消费者。
    • P2、P5和P8分配给消费者C。消费者C是它们的活动消费者。消费者A和消费者B是它们的备用消费者。

分区主题中的分区数量大于消费者数量

Failover | Non-partitioned topics
  • 如果有一个非分区主题。 代理按照它们订阅非分区主题的顺序选择消费者。
    例如,在下图中,这个非分区主题有1个主题,有2个消费者。
    该主题有1个活动消费者和1个备用消费者。
    消费者A是主要消费者,如果消费者A断开连接,消费者B将是接收消息的下一个消费者。

非分区主题

  • 如果有多个非分区主题,消费者的选择基于消费者名称哈希主题名称哈希。客户端使用相同的消费者名称订阅所有主题。
    例如,在下面的图表中,有4个非分区主题和2个消费者。
    • 非分区主题1和非分区主题4分配给消费者B。消费者A是它们的备用消费者。
    • 非分区主题2和非分区主题3分配给消费者A。消费者B是它们的备用消费者。

Shared

Pulsar中的共享订阅类型允许多个消费者连接到同一个订阅。消息按照循环分发的方式分配给消费者,并且任何给定的消息只会发送给一个消费者。当一个消费者断开连接时,所有发送给它但未被确认的消息将被重新安排发送给剩余的消费者。

在下图中,消费者A消费者B消费者C都能订阅这个主题。

共享订阅不保证消息的顺序或支持累积确认。

Shared

Key_Shared

Pulsar中的Key_Shared订阅类型允许多个消费者连接到同一个订阅。但与共享类型不同,Key_Shared类型的消息在多个消费者之间进行分发,并且具有相同的键或相同的排序键的消息只会发送到一个消费者。无论消息重新发送多少次,它都会发送到同一个消费者。

Key_Shared

如果有一个新的活跃消费者接管,它将从旧的不活动消费者确认的位置开始读取消息。
例如,如果P0被分配给消费者A。消费者A是活跃消费者,消费者B是备用消费者。

  • 如果消费者A在没有读取任何消息的情况下断开连接,则当添加消费者C并成为新的活跃消费者时,消费者C将直接从P0开始读取消息。
  • 如果消费者A在读取消息(0,1,2,3)后断开连接,则当添加消费者C并成为活跃消费者时,消费者C将从P0读取消息(4,5,6,7)开始。

有三种类型的映射算法决定了如何为给定的消息键(或排序键)选择消费者:

  • 自动分割哈希范围(Auto-split Hash Range)
  • 自动分割一致性哈希(Auto-split Consistent Hashing)
  • Sticky

所有映射算法的步骤如下:

  1. 消息键(或排序键)被传递给哈希函数(例如,Murmur3 32位),产生一个32位整数哈希。
  2. 该哈希数被提供给算法,从已连接的消费者中选择一个消费者。
                      +--------------+                              +-----------+
Message Key ----->  / Hash Function / ----- hash (32-bit) -------> / Algorithm / ----> Consumer
                   +---------------+                               +----------+

当新消费者连接并因此被添加到已连接消费者列表时,算法会重新调整映射,以便将一些当前映射到现有消费者的键映射到新添加的消费者上。当消费者断开连接,因此从已连接消费者列表中移除时,映射到该消费者的键将被映射到其他消费者上。以下各节将解释如何针对每种算法给定消息哈希时选择消费者,以及在连接新消费者或现有消费者断开连接时如何调整映射。

Auto-split Hash Range

自动分割哈希范围算法假定每个消费者被映射到一个数字范围中的单个区域,范围从0到2^16(65,536)。因此,所有映射的区域覆盖整个范围,并且区域之间没有重叠。对于给定的键,通过对消息哈希值使用模运算,将哈希值除以范围大小(65,536)。得到的数字(0 <= i < 65,536)包含在单个区域内。映射到该区域的消费者是被选择的消费者。

例如
如果我们有4个消费者(C1、C2、C3和C4),那么:

 0               16,384            32,768           49,152             65,536
 |------- C3 ------|------- C2 ------|------- C1 ------|------- C4 ------|

根据给定的消息键 Order-3459134,其哈希值为 murmur32("Order-3459134") = 3112179635,其在范围内的索引为 3112179635 mod 65536 = 6067。这个索引位于区间 [0, 16384) 内,因此消费者 C3 将被映射到这个消息键。

当新的消费者连接时,会选择最大的区域,然后将其一分为二:较低的一半将被映射到新添加的消费者,而较高的一半将被映射到拥有该区域的消费者。以下是从1到4个消费者的情况:

C1 连接后:
|---------------------------------- C1 ---------------------------------|

C2 连接后:
|--------------- C2 ----------------|---------------- C1 ---------------|

C3 连接后:
|------- C3 ------|------- C2 ------|---------------- C1 ---------------|

C4 连接后:
|------- C3 ------|------- C2 ------|------- C4 ------|------- C1 ------|

当消费者断开连接时,其区域将合并到其右侧的区域。以下是示例:

C4 断开连接:

|------- C3 ------|------- C2 ------|---------------- C1 ---------------|

C1断开连接

|------- C3 ------|-------------------------- C2 -----------------------|

这种算法的优点是在添加/删除消费者时只影响单个现有消费者,但代价是区域大小不均匀。这意味着一些消费者会比其他消费者获得更多Key。下一个算法做法相反。

Auto-split Consistent Hashing

自动拆分一致性Hash算法假设每个消费者都被映射到一个哈希环中。这是一个从0到MAX_INT(32位)的数字范围,在这个范围内遍历时,当达到MAX_INT时,下一个数字会变为零。就好像你从0开始到MAX_INT结束,然后将其弯曲成一个圆环,以便末尾与起始处相接。


 MAX_INT -----++--------- 0
              ||
         , - ~ ~ ~ - ,
     , '               ' ,
   ,                       ,
  ,                         ,
 ,                           ,
 ,                           ,
 ,                           ,
  ,                         ,
   ,                       ,
     ,                  , '
       ' - , _ _ _ ,  '

当添加一个消费者时,我们在该圆环上标记100个点,并将它们与新添加的消费者关联起来。对于1到100之间的每个数字,我们将该数字与消费者名称连接起来,然后对其运行哈希函数,以获取在圆环上标记的点的位置。例如,如果消费者名称是"orders-aggregator-pod-2345-consumer",那么我们将在该圆环上标记100个点:

    murmur32("orders-aggregator-pod-2345-consumer1") = 1003084738
    murmur32("orders-aggregator-pod-2345-consumer2") = 373317202
    ...
    murmur32("orders-aggregator-pod-2345-consumer100") = 320276078

由于哈希函数具有均匀分布的特性,这些点将均匀分布在整个圆环上。

    C1-100
         , - ~ ~ ~ - ,   C1-1
     , '               ' ,
   ,                       ,
  ,                         , C1-2
 ,                           ,
 ,                           ,
 ,                           ,
  ,                         ,  C1-3
   ,                       ,
     ,                  , '
       ' - , _ _ _ ,  '      ...

对于给定的消息键,通过将其哈希值放在圆环上,然后顺时针在圆环上继续,直到达到一个标记点来选择消费者。该点可能有多个消费者(哈希函数可能会发生冲突),因此,我们运行以下操作以获取该点消费者列表中的位置,然后取该位置上的消费者:哈希值 % 消费者列表大小 = 索引

当添加一个消费者时,我们如前所述在圆环上添加100个标记点。由于哈希函数的均匀分布特性,这100个点的作用就好像新的消费者从每个现有消费者那里拿走了一小部分键。这样就保持了均匀分布,但代价是影响了所有现有的消费者。这段youtube视频很好地解释了一致性哈希的概念(唯一的区别在于在 Pulsar 的情况下,我们使用了 K 个点而不是 K 个哈希函数,如注释中所述)。

Sticky

"Sticky"算法假设每个消费者被映射到从0到2^16(65,536)的多个区域,并且这些区域之间没有重叠。通过将消息哈希值通过对范围大小(65,536)取模的操作,从中选择一个消费者。接收到的数字(0 <= i < 65,536)位于单个区域内。被映射到该区域的消费者将被选中。

在这个算法中,您拥有完全的控制权。每个新添加的消费者都可以使用消费者API指定它希望被映射到的范围。当构造消费者对象时,您可以指定区域列表。您有责任确保没有重叠,并且所有区域都被覆盖。

例如
假设我们有2个消费者(C1和C2),每个消费者都指定了它们的范围,那么:

C1 = [0, 16384), [32768, 49152)
C2 = [16384, 32768), [49152, 65536)

 0               16,384            32,768           49,152             65,536
 |------- C1 ------|------- C2 ------|------- C1 ------|------- C2 ------|

给定消息Key Order-3459134,其哈希值为murmur32("Order-3459134") = 3112179635,它在范围内的索引为3112179635 mod 65536 = 6067。该索引位于[0, 16384)范围内,因此消费者C1将映射到此消息密钥。

如果新连接的消费者未提供其范围,或者它们与现有消费者范围重叠,则会断开连接,从消费者列表中删除,并恢复为从未尝试连接的状态。

使用上述提及的映射算法,您可以在构建消费者时指定键共享模式:

如何使用?

使用上述提及的映射算法,您可以在构建消费者时指定键共享模式:
AUTO_SPLIT - 自动分割哈希范围
STICKY

如果broker配置subscriptionKeySharedUseConsistentHashing是启用状态,将使用一致性哈希代替哈希范围进行自动分割。

保留处理顺序

Key Shared订阅类型保证一个键在任何给定时间只会由单个消费者处理。当新的消费者连接时,一些键将从现有消费者映射到新的消费者。一旦连接建立,代理将记录当前的读取位置,并将其与新的消费者关联。读取位置是一个标记,指示消息已经分派给消费者直到此时,之后还未分派消息。代理将仅在所有消息直到读取位置的消息都被确认后,才开始将消息传递给新的消费者。这将确保某个特定键在任何给定时间只由单个消费者处理。其中的折衷是,如果现有消费者中的一个卡住了并且未定义超时时间(确认时间),则新的消费者将不会接收任何消息,直到卡住的消费者恢复或断开连接。

通过Consumer API启用allowOutOfOrderDelivery可以放宽这个要求。如果在新的消费者上设置了此选项,则当其连接时,代理将允许其接收消息,即使在该时刻该键的某些消息可能仍在其他消费者中处理,因此可能会影响顺序,在添加新的消费者时,这种影响仅在短时间内会发生。

Batching for Key Shared Subscriptions

当消费者使用Key_Shared订阅类型时,您需要禁用批处理或使用基于键的批处理来进行生产者操作。

Key_Shared订阅类型需要使用基于键的批处理有两个原因:

代理根据消息的键来分派消息,但默认的批处理方法可能无法将具有相同键的消息打包到同一批次中。
由于是消费者而不是代理从批次中分派消息,因此一个批次中第一条消息的键被视为该批次中所有消息的键,从而导致上下文错误。
基于键的批处理旨在解决上述问题。该批处理方法确保生产者将具有相同键的消息打包到同一批次中。没有键的消息被打包到一个批次中,并且该批次没有键。当代理从此批次中分派消息时,它使用NON_KEY作为键。此外,每个消费者仅与一个键相关联,应仅接收连接键的一个消息批次。默认情况下,您可以通过配置允许生产者发送的消息数量来限制批处理。

以下是在Key_Shared订阅类型下启用基于键的批处理的示例,其中client是您创建的Pulsar客户端。
java

Producer<byte[]> producer = client.newProducer()
        .topic("my-topic")
        .batcherBuilder(BatcherBuilder.KEY_BASED)
        .create();

C++

ProducerConfiguration producerConfig;
producerConfig.setBatchingType(ProducerConfiguration::BatchingType::KeyBasedBatching);
Producer producer;
client.createProducer("my-topic", producerConfig, producer);

python

producer = client.create_producer(topic='my-topic', batching_type=pulsar.BatchingType.KeyBased)

当您使用Key_Shared订阅时,请注意:

  • 您需要为消息指定一个键或排序键。
  • 您不能使用累积确认。
  • 当主题中最新消息的位置为X时,连接到相同订阅并连接到主题的key_shared消费者将不会收到任何消息,直到所有位于X之前的消息都被确认。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值