簡體   English   中英

將 kafka-streams 與自定義分區器一起使用

[英]Using kafka-streams with custom partitioner

我想加入帶有 KTable 的 KStream。 兩者都有不同的鍵,但使用自定義分區器共同分區。 但是,連接不會產生和結果。

KStream具有以下結構
- 關鍵:房子 - 組
- 值:用戶
KTable具有以下結構
- 鍵:用戶 - 組
- 值:地址

為了確保每個插入的主題都按插入順序處理,我使用了一個自定義分區器,我使用每個鍵的 Group 部分對兩個主題進行分區。

我想最終得到以下結構的流:
- 關鍵:房子 - 組
- 值:用戶 - 地址

為此,我正在執行以下操作:

val streamsBuilder = streamBuilderHolder.streamsBuilder
val houseToUser = streamsBuilder.stream<HouseGroup, User>("houseToUser")
val userToAddress = streamsBuilder.table<UserGroup, Address>("userToAddress")
val result: KStream<HouseGroup, UserWithAddress> = houseToUser
        .map { k: HouseGroup, v: User ->
            val newKey = UserGroup(v, k.group)
            val newVal = UserHouse(v, k.house)
            KeyValue(newKey, newVal)
        }
        .join(userToAddress) { v1: UserHouse, v2: Address ->
            UserHouseWithAddress(v1, v2)
        }
        .map{k: UserGroup, v: UserHouseWithAddress ->
            val newKey = HouseGroup(v.house, k.group)
            val newVal = UserWithAddress(k.user, v.address)
            KeyValue(newKey, newVal)
        }

這需要匹配的連接,但這不起作用。

我想顯而易見的解決方案是加入一個全局表並放棄自定義分區器。 但是,我仍然不明白為什么上述方法不起作用。

我認為缺少匹配是因為使用了不同的分區器。

對於您的輸入主題,使用CustomPartitioner Kafka Streams 默認使用org.apache.kafka.clients.producer.internals.DefaultPartitioner

KStream::join之前的代碼中,您調用了KStream::map KStream::map函數在KStream::join之前強制重新分區。 $AppName-KSTREAM-MAP-000000000X-repartition期間,消息會刷新到 Kafka( $AppName-KSTREAM-MAP-000000000X-repartition主題)。 為了傳播消息,Kafka Streams 使用定義的分區器(屬性: ProducerConfig.PARTITIONER_CLASS_CONFIG )。 總結:使用相同的密鑰信息可能是在“重新分配的話題”不同的分區和“KTable主題

您的解決方案將在您的 Kafka Streams 應用程序的屬性中設置您的自定義分區( props.put(ProducerConfig.PARTITIONER_CLASS_CONFIG, "com.example.CustomPartitioner"

對於調試,您可以檢查重新分區主題( $AppName-KSTREAM-MAP-000000000X-repartition )。 具有相同鍵(如輸入主題)的消息可能位於不同的分區(不同的編號)

關於Join 共同分區要求的文檔

試試這個,對我有用。

static async System.Threading.Tasks.Task Main(string[] args)
        {
 
            int count = 0;
            string line = null;

            var appConfig = getAppConfig(Enviroment.Dev);
            var schemaRegistrConfig = getSchemmaRegistryConfig(appConfig);
            var registry = new CachedSchemaRegistryClient(schemaRegistrConfig);
            var serializer = new AvroSerializer<YourAvroSchemaClass>(registry);

            var adminClient = new AdminClientBuilder(new AdminClientConfig( getClientConfig(appConfig))).Build();
            var topics = new List<TopicSpecification>(){ new TopicSpecification { Name = appConfig.OutputTopic, NumPartitions = 11}};

            await adminClient.CreateTopicsAsync(topics);

            var producerConfig = getProducerConfig(appConfig);

            var producer = new ProducerBuilder<string, byte[]>(producerConfig)
                .SetPartitioner(appConfig.OutputTopic, (string topicName, int partitionCount, ReadOnlySpan<byte> keyData, bool keyIsNull) =>
             {
                 var keyValueInInt = Convert.ToInt32(System.Text.UTF8Encoding.UTF8.GetString(keyData.ToArray()));
                 return (Partition)Math.Floor((double)(keyValueInInt % partitionCount));
             }).Build();

            using (producer)
            {
                Console.WriteLine($"Start to load data from : {appConfig.DataFileName}: { DateTime.Now} ");
                var watch = new Stopwatch();
                watch.Start();
                try
                {
                    var stream = new StreamReader(appConfig.DataFileName);
                    while ((line = stream.ReadLine()) != null)
                    {
                        var message = parseLine(line);
                        var data = await serializer.SerializeAsync(message.Value, new SerializationContext(MessageComponentType.Value, appConfig.OutputTopic));
                        producer.Produce(appConfig.OutputTopic, new Message<string, byte[]> { Key = message.Key, Value = data });
 
                        if (count++ % 1000 == 0)
                        {
                            producer.Flush();
                            Console.WriteLine($"Write ... {count} in {watch.Elapsed.TotalSeconds} seconds");
                        }
                    }
                    producer.Flush();
                }
                catch (ProduceException<Null, string> e)
                {
                    Console.WriteLine($"Line: {line}");
                    Console.WriteLine($"Delivery failed: {e.Error.Reason}");
                    System.Environment.Exit(101);
                }
        finally
        {
            producer.Flush();
           
                }
            }
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM