Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET AMQP消息传递模式问题_C#_Events_Rabbitmq_Messaging_Eai - Fatal编程技术网

C# .NET AMQP消息传递模式问题

C# .NET AMQP消息传递模式问题,c#,events,rabbitmq,messaging,eai,C#,Events,Rabbitmq,Messaging,Eai,我使用RabbitMQ创建了一个小类,它在主题交换上实现了发布/订阅消息传递模式。在此发布/订阅之上,我有以下方法和属性: void Send(Message,Subject)-将消息发布到目标主题,供任何订阅者处理 MessageReceivedEvent-订阅此消息传递实例上收到的消息事件(消息传递实例在创建时绑定到所需的订阅主题) SendWaitReply(消息,主题)-发送消息并阻止,直到收到相关id与已发送消息id(或超时)匹配的回复消息。这本质上是发布/订阅模式之上的请求/回复或R

我使用RabbitMQ创建了一个小类,它在主题交换上实现了发布/订阅消息传递模式。在此发布/订阅之上,我有以下方法和属性:

  • void Send(Message,Subject)-将消息发布到目标主题,供任何订阅者处理

  • MessageReceivedEvent-订阅此消息传递实例上收到的消息事件(消息传递实例在创建时绑定到所需的订阅主题)

  • SendWaitReply(消息,主题)-发送消息并阻止,直到收到相关id与已发送消息id(或超时)匹配的回复消息。这本质上是发布/订阅模式之上的请求/回复或RPC机制

  • 由于系统的设计方式,我选择的消息传递模式有点一成不变。我意识到我可以使用回复队列来缓解SendWaitReply的潜在问题,但这打破了一些要求

    现在我的问题是:

    • 对于侦听事件,当侦听器在单个线程中运行时,通过事件订阅服务器同步处理消息。这会在处理大量消息时(即,在使用web api事件的后端进程中)导致一些严重的性能问题。我正在考虑传入回调函数,而不是订阅事件,然后使用Task或Threadpool并行调度回调集合。线程安全现在显然是调用方关心的问题。我不确定这是不是一个正确的方法

    • 对于SendWaitReply事件,我构建了一个看似黑客的解决方案,它从消息侦听器循环获取所有入站消息,如果它们包含非空的关联guid,则将它们放在ConcurrentDictionary中。然后,在SendWaitReply方法中,我轮询ConcurrentDictionary以查找包含与所发送消息的Id匹配的密钥的消息(或在特定时间段后超时)。如果有更快/更好的方法,我真的很想调查一下。也许有一种方法可以向所有当前被阻止的SendWaitReply方法发出信号,表明新消息可用,并且它们都应该检查自己的ID,而不是连续轮询


    更新日期:2014年10月15日 经过大量详尽的研究后,我得出结论,在RabbitMQ或AMQP的范围内,没有“官方”机制/助手/库来直接处理我在上面为SendWaitReply介绍的特定用例。目前,我将坚持使用当前的解决方案(并研究更健壮的实现)。有人建议我使用提供的RPC功能,但不幸的是,这只适用于您希望在每个请求的基础上使用独占回调队列的情况。这打破了我的主要要求之一,即在同一主题交换中显示所有的消息(请求和回复)

    为了进一步澄清,SendWaitReply请求的典型消息对的格式为:

    • 主题交换。服务A=>一些命令=>主题交换。服务B
    • Topic\u-Exchange.Service\u-B=>some\u-command\u-reply=>Topic\u-Exchange.Service\u-A
    这为我提供了一种强大的调试和日志记录技术,我只需在主题交换上设置一个侦听器。#就可以查看所有系统流量,以便通过各种服务跟踪非常深入的“调用堆栈”

    TL;DR-下面是当前的问题
    从体系结构级别后退—我仍然存在消息侦听器循环的问题。我试过EventingBasicConsumer,但仍然看到一个区块。我的类的工作方式是调用方订阅类实例提供的委托。消息循环触发该委托上的事件,然后这些订阅者处理该消息。似乎我需要一种不同的方式将消息事件处理程序传递到实例中,这样它们就不会全部位于一个强制执行同步处理的委托后面。

    很难说为什么代码在没有示例的情况下会阻塞,但为了防止在使用时阻塞,您应该使用EventBasicConsumer

    var consumer = new EventingBasicConsumer;
    consumer.Received += (s, delivery) => { /* do stuff here */ };
    channel.BasicConsume(queue, false, consumer);
    
    一个警告是,如果您使用的是autoAck=false(正如我所做的),那么您需要确保在执行channel.BasicAck时锁定通道,否则您可能会遇到.NET库中的并发问题

    对于SendWaitReply,如果您只使用RabbitMQ客户机库中包含的SimpleRpcClient,您的运气可能会更好:

    var props = channel.CreateBasicProperties();
    // Set your properties
    var client = new RabbitMQ.Client.MessagePatterns.SimpleRpcClient(channel, exchange, ExchangeType.Direct, routingKey);
    IBasicProperties replyProps;
    byte[] response = client.Call(props, body, out replyProps);
    
    SimpleRpcClient将处理创建临时队列、关联ID等,而不是构建自己的队列。如果你发现你想做一些更高级的事情,这也是一个很好的参考