我可以在使用 PartitionSender 发送到 EventHubs 时设置 EventData.PartitionKey 吗?

Can I set EventData.PartitionKey while sending to EventHubs using a PartitionSender?

我目前在 Azure 中设置了一个 EventHub 实例。它有5个分区。我想知道 PartitionKey 是否始终必须是 0n-1 之间的数字,其中 n 是分区数。

我有以下代码:

    private static async Task SendMessagesToEventHub(int numMessagesToSend)
    {
        var sender = eventHubClient.CreatePartitionSender("test1");

        for (var i = 0; i < numMessagesToSend; i++)
        {
            try
            {
                var message = $"Message {i}";
                Console.WriteLine($"Sending message: {message}");
               await  sender.SendAsync(new EventData(Encoding.UTF8.GetBytes(message)));
            }
            catch (Exception exception)
            {
                Console.WriteLine($"{DateTime.Now} > Exception: {exception.Message}");
            }

            await Task.Delay(10);
        }

        Console.WriteLine($"{numMessagesToSend} messages sent.");
    }

这会抛出异常

The specified partition is invalid for an EventHub partition sender or receiver. It should be between 0 and 4.

在 EventHub 的 documentation 中,这是他们对 PartitionKey 的说法:

The EventData class has a PartitionKey property that enables the sender to specify a value that is hashed to produce a partition assignment. Using a partition key ensures that all the events with the same key are sent to the same partition in the Event Hub. Common partition keys include user session IDs and unique sender IDs.

对我来说,这意味着您不限于 int,而是可以使用任何 string。我错过了什么?

回答:

您不能混合使用 PartitionKeyPartitionSender - 它们是 2 个 互斥的 概念。

不要使用 PartitionSender 又名 ehClient.CreatePartitionSender() - API,它旨在发送到特定分区(在这种情况下,EventHub 服务无法使用 PartitionKey to-hash-to 了)。

而是在 c# 中使用此代码段:

EventData myEvent = new EventData(Encoding.UTF8.GetBytes(message));
myEvent.PartitionKey = "test1";
await eventHubClient.SendAsync(myEvent);

我们了解到这让我们的客户有点难以理解 API 然后当我们制作 Java SDK 时,我们 corrected/simplified 我们 API 看看像这样:

EventData myEvent = new EventData(message.getBytes(Charset.defaultCharset()))
eventHubClient.SendSync(myEvent, "test1");

事件中心公开的 3 种发送模式:

当我们开发 EventHubs 服务时——我们希望为我们的用户提供对事件流分区的多层次控制。我们提出了以下 3 种模式(我们的 c# 客户 API 的):

  1. EventHubClient.Send(eventData_Without_PartitionKey) - 当您不想控制数据的分区方式时使用它。 EventHubs 服务将尝试在所有分区之间均匀分布数据(尽力而为,无保证)。因为,您权衡 控制数据分区 - 您在这里获得的是高可用性 .如果您有一个包含 32 个分区的事件中心 - 并且正在使用这种发送到事件中心的方法 - 您的事件将被传送到立即可用且数据最少的 32 个事件中心分区之一。

  2. EventHubClient.Send(eventData_With_PartitionKey) - 当你的数据有 属性 时使用它 - 你想使用它来分区你的数据。 EventHubs 服务将确保所有具有相同 PartitionKeyEventData 将落在相同的 EventHubs partition 上。此处 - 用户通过指定提示来控制分区 - 我们的服务将使用该提示 运行 哈希算法并将其传送到哈希分区。所有具有相同 PartitionKey 的事件都保证落在相同的 Event Hubs partition.

  3. EventHubSender.Send(eventData_Without_PartitionKey) - EventHubPartitionSender 名称更适合这个 - 当你使用这个想要完全控制数据分区 - 当您需要控制时 - EventData 应该放在哪个 EventHubs partition 上。这通常用于 - 当客户拥有自己的专有哈希算法时 - 他们认为对于他们的场景表现更好 - w.r.to。所有 EventHubs partitions.

  4. 负载分配的公平性

你需要的是(2)。

here's some general reading on Event Hubs concepts...

如果您不想要默认的 Round-robin 逻辑并希望使用您的自定义逻辑将消息平均分发到所有分区,您可以使用类似的方式将消息发送到特定的分区 ID,您应该在这种情况下无法为 eventData 分配分区键。

你必须想出一个逻辑来获取 PartitionId 以将你的消息分发到所有分区

    String PartitionId = GetPartitionId(message) 
    EventData eventData = new EventData(Encoding.UTF8.GetBytes(message));     
    EventHubClient.CreatePartitionedSender(PartitionId).SendAsync(eventData)

    private static int GetPartitionId(Message message)
    {
       // Your own custom logic
        var svin = message.vin.Substring(12, 5);
        int partKey;
        if (int.TryParse(svin, out partKey))
        {
            partKey = Convert.ToInt32(svin) % NumberOfPartitions;
        }
        return partKey;
    }

或者您可以为EventData设置Partition key,Eventhub会将其分配到不同的Paritions。但是具有相同分区键的 Eventdata 将转到相同的分区 ID

      string payLoadJson = convertToJson(record);
      EventData eventData = new 
      EventData(Encoding.UTF8.GetBytes(payLoadJson));
      eventData.PartitionKey = record.vin;
      
      await eventHubClient.SendAsync(eventData);