如何使用Confluent Kafka处理消费者端的消息处理失败?

时间:2017-05-05 18:24:23

标签: c# apache-kafka confluent confluent-kafka

我正在从基于JMS的系统转移到Kafka,后者负责同步新旧系统之间的事务。订户/消费者必须成功处理新系统发布的每条消息。我不必担心消息的顺序。由于遗留系统中的一些设计问题(悲观锁定),偶尔,当消息到达时,很少有事务可能会失败,在这种情况下,我希望该消息在一段延迟后返回。我想弄清楚如何用卡夫卡处理这种情况。

我的源和目标应用程序在.NET 4.6.1和c#中。我正在使用Confluent.Kafka v0.9.5客户端库。 Kafka版本为0.10。

对于使用者应用程序,我已禁用自动提交并显式调用commitAsync方法以在成功处理消息后提交偏移量。以下是我创建消费者的方式。

var config = new Dictionary<string, object>()
                {
                    {"group.id", GroupId},
                    {"client.id", ClientId},
                    {"enable.auto.commit", false},
                    {"bootstrap.servers", _consumerConnectionConfig.BrokerUrl},
                    {
                        "default.topic.config", new Dictionary<string, object>()
                        {
                            {"auto.offset.reset", "latest"}
                        }
                    }
                };
var consumer = new Consumer<string, string>(config, new StringDeserializer(Encoding.UTF8), new StringDeserializer(Encoding.UTF8));

这是如何设置轮询的。

consumer.Subscribe(topics);

while (!SubscriberCancellationToken.IsCancellationRequested)
{
      consumer.Poll(TimeSpan.FromMilliseconds(1000));
}

这是负责处理消息的OnMessage事件

consumer.OnMessage += (sender, message) => {
   try
   {
     var payload = GetPayload(message);
     if (_messageHandlerService.ProcessMessage(payload))
     {                 
      consumer.CommitAsync(message).Wait(SubscriberCancellationToken);   
     }
     else
     {
         //(case 1) Now what should I do?????
     }
   }
   catch(Exception ex)
   { 
        Log.Error("Unable to process xyz messages", ex);
        throw; //??? (Case 2) should I throw the exception or should I not?
   }
};

如果消息可以成功处理,我会调用commitAsync,它就像一个魅力。现在我的问题是,当我无法处理消息(案例1)或发生某些异常(案例2)时,我该怎么办。我有什么选择来处理这两种情况?

在JMS世界中,对于(案例1),我应用了延迟重新发布策略。基本上我等待1分钟,然后将消息重新发布到同一主题并提交当前消息,以便重新发布的消息将再次返回。出于某种原因,如果我无法重新发布,我只是继续重试,直到我可以或直到该过程重新开始。如果在重新发布之前重新启动进程,则会返回未提交的消息,并且循环将重新开始。

一旦重新发布成功,如果有其他消息已在等待主题,他们现在将开始移动直到火车进入一个圆圈,直到所有内容都被处理完毕。每次我都无法像处理案例1那样处理消息时,我会记录错误,根据它生成适当的警报,以便应用程序支持团队可以采取一些操作,以防他们必须修复遗留系统中的某些数据。在此之前,消息一直处于失败状态,然后重新发布。

对于案例2,我正在记录详细信息并在JMS实现中抛出异常。我现在想知道我应该像案例1那样处理。

现在我的问题是我应该如何处理卡夫卡世界的这两种情况?还有更好的选择吗?

2 个答案:

答案 0 :(得分:1)

几个选项

一个是将这些消息推送到另一个Kafka主题,让专门的消费者处理它,或者,

在您的消费者中重试,直到处理完特定消息或达到某个阈值。这可以通过在您的使用者上调用pause方法来暂时停止消息消耗来完成(我从Java消费者的角度来看,请与C#客户端确认),运行您的重试逻辑。请确保您也继续调用轮询(否则消费者将被踢出组,其分区将被重新平衡)。一旦你重新尝试,请调用resume方法继续处理 - 现在poll方法将从Kafka返回记录

答案 1 :(得分:0)

错误处理可以更直接,使用更高级别的库,例如“我的”Silverback(https://github.com/BEagle1984/silverback 可以帮助您处理它们。

它实现了错误策略的概念,您可以使用该概念来配置消费者在出现错误时的行为方式(重试/跳过/将消息移动到另一个主题)。

text-overflow: ellipsis

https://silverback-messaging.net/concepts/broker/inbound.html#error-handling

(Silverback 建立在 Confluent.Kafka 之上。)