如何使用ServiceBus EventData Offset Value

时间:2018-06-05 07:36:30

标签: c# azure azure-eventhub .net-4.7

我有一些代码使用Service Bus Event Data,我怀疑我需要使用offset属性,因为目前我的程序正在(或似乎)重新运行相同的事件中心数据。再一次。

我的代码如下:

public class EventHubListener : IEventProcessor
{
    private static EventHubClient _eventHubClient;        
    private const string EhConnectionStringNoPath = "Endpoint=...";
    private const string EhConnectionString = EhConnectionStringNoPath + ";...";
    private const string EhEntityPath = "...";        

    public void Start()
    {
        _eventHubClient = EventHubClient.CreateFromConnectionString(EhConnectionString);
        EventHubConsumerGroup defaultConsumerGroup = _eventHubClient.GetDefaultConsumerGroup();            
        EventHubDescription eventHub = NamespaceManager.CreateFromConnectionString(EhConnectionStringNoPath).GetEventHub(EhEntityPath);

        foreach (string partitionId in eventHub.PartitionIds)
        {
            defaultConsumerGroup.RegisterProcessor<EventHubListener>(new Lease
            {
                PartitionId = partitionId
            }, new EventProcessorCheckpointManager());

            Console.WriteLine("Processing : " + partitionId);
        }
    }

    public Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
    {
        foreach (EventData eventData in messages)
        {                
            string bytes = Encoding.UTF8.GetString(eventData.GetBytes());
            MyData data = JsonConvert.DeserializeObject<MyData>(bytes);

当我一遍又一遍地收到相同的消息时,我怀疑我需要做这样的事情:

string bytes = Encoding.UTF8.GetString(eventData.GetBytes(), eventData.Offset, eventData.SerializedSizeInBytes - eventData.Offset);

但是,Offset是一个字符串,即使它似乎是一个数值(&#34; 12345&#34;例如)。 context.CheckPointAsync()上的文档似乎可能就是答案;但是,在循环结束时发出它似乎没有任何区别。

所以,我有两个问题:

  1. 什么是抵消?它是我认为的(即流中某个点的数字标记),如果是,为什么它是一个字符串?
  2. 为什么我会再次收到相同的消息?据我了解事件中心,虽然他们至少保证一次,但一旦检查点出现问题,我就不应该收到相同的消息。
  3. 编辑:

    经过一段时间的捣乱,我提出了一些避免这个问题的东西;但是,我当然不会声称它是一个解决方案:

    var filteredMessages =
                messages.Where(a => a.EnqueuedTimeUtc >= _startDate)
                .OrderBy(a => a.EnqueuedTimeUtc);
    

    使用EventProcessorHost似乎实际上使问题变得更糟;也就是说,不仅历史事件被重播,而且它们似乎以随机顺序重播。

    编辑:

    我在@Mikhail看到了this优秀的文章,这似乎确实解决了我的确切问题。然而;并且可能是我问题的根源(或者其中之一,假设这是正确的,那么我不确定为什么使用EventProcessorHost并不是开箱即用,因为@Mikhail说自己在评论)。但是,ICheckpointManager的ServiceBus版本只有一个接口方法:

    namespace Microsoft.ServiceBus.Messaging
    {
    
        public interface ICheckpointManager
        {
            Task CheckpointAsync(Lease lease, string offset, long sequenceNumber);
        }
    }
    

2 个答案:

答案 0 :(得分:0)

您的标题应该是事件中心,而不是服务总线。对于您的问题:

  1. 尽管事件中心的设计与Kafka类似,但最大的不同是您应该自己管理偏移。事件中心经纪人完全不知道您的消费群体的抵消额。
  2. 因此事件中心sdk提供了一些帮助类来将偏移量存储在存储帐户中,但是在处理消息后,您仍然需要手动调用检查点。

答案 1 :(得分:0)

  1. 什么是偏移量?它是我认为的那样吗(即流中某个点的数字标记),如果是,为什么它是一个字符串?

    偏移量是流中的指针。当消息保留策略失效时,事件的偏移量会随着事件从事件中心中删除而发生变化。因此,曾经在偏移量 10 处的消息,可能在几天后在偏移量 0 处,因为较旧的消息已从流中删除。这有一个很好的图表:Event Hubs: Stream Offsets

  2. 为什么我会再次收到相同的消息?据我了解,事件中心虽然至少保证一次,但一旦检查点出现问题,我就不应该收到相同的消息。

    如果您使用低级 EventReceiver offset,您可能会再次收到相同的消息,因为消息在消息保留策略失效时(即默认为 1 天)从事件中心过期。 Sequence number 是一个更好的利用领域,因为它不会改变。

    当检查点成功时,它告诉我们成功处理的最后一个事件,所以你不应该得到相同的事件,因为当客户端启动时,它会创建一个流到事件流中的一个位置 之后 那个事件。您可以在 GitHub 上提交问题。

EventProcessorHost 很有帮助,因为它尝试在运行的实例数量之间平衡分区的处理。 (即。考虑一个 6 分区的事件中心。如果你有 2 个 EventProcessorHosts 连接到同一个事件中心读取与相同的消费者组,他们最终会平衡这些分区的处理,每个分区有 3 个。)当有时它也会重新连接网络丢失等暂时性故障。

它支持对持久存储(如 Azure 存储 Blob)的检查点。这是一个示例:Process Events using an EventProcessorClient