【RabbitMQ.Clinet笔记】六种消息模型

RabbitMQ六种消息模型


Hello World


最简单的消息模型,图中没有交换器,实际使用的是默认交换器,默认交换器的类型是Direct,默认'binding key'和队列名同名
发送消息时交换器名传空字符串,binding key传队列名

//======================发消息======================
using (var channel = connection.CreateModel())
{
    channel.QueueDeclare(queue: "hello",
                         durable: true,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);
    channel.BasicPublish(exchange: "",
                                 routingKey: "hello",
                                 basicProperties: null,
                                 body: Encoding.UTF8.GetBytes("Hello World!"));//默认交换机的名字就是""
}

//======================收消息======================
using (var channel = connection.CreateModel())
{
    channel.QueueDeclare(queue: "hello",
                         durable: true,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);
    var result = channel.BasicGet("hello", true);
    string msg = Encoding.UTF8.GetString(result.Body);
}

Worker


Worker模型中也只有一个工作队列。但它是一种竞争消费模式。可以看到同一个队列我们绑定上了多个消费者,消费者争抢着消费消息,这可以有效的避免消息堆积。
比如对于短信微服务集群来说就可以使用这种消息模型,来了请求大家抢着消费掉。
如何实现这种架构:对于上面的HelloWorld这其实就是相同的服务我们启动了多次罢了,自然就是这种架构。

Publish/Subscribe(订阅模型)

订阅之Fanout模型

交换器类型设置为fanout,发送消息时不需要routing keyfanout交换器不处理routing key,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被转发到与该交换器绑定的所有队列上。很像子网广播

Routing


交换器类型设置为direct
向Exchange发送消息时,指定一个routing key。
Exchange接收生产者的消息,然后把消息递交给 与routing key完全匹配的binding key绑定指向的队列

private void Send()
{
    string exchangeName = "myexchange1";
    string queueName_logElse = "log_else";
    string queueName_logError = "log_error";

    //2:创建channel
    using (var channel = connection.CreateModel())
    {
        //创建交换机
        channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, true, false, null);
        //创建队列
        channel.QueueDeclare(queueName_logElse, true, false, false, null);
        channel.QueueDeclare(queueName_logError, true, false, false, null);
        //绑定
        channel.QueueBind(queueName_logElse, exchangeName, "info", null);
        channel.QueueBind(queueName_logElse, exchangeName, "debug", null);
        channel.QueueBind(queueName_logElse, exchangeName, "warn", null);
        channel.QueueBind(queueName_logError, exchangeName, "error", null);

      //发布info消息
        var msg = Encoding.UTF8.GetBytes($"haha-info");
        channel.BasicPublish(exchangeName, "info", null, msg);
      //发布debug消息
        msg = Encoding.UTF8.GetBytes($"haha-debug");
        channel.BasicPublish(exchangeName, "debug", null, msg);
      //发布warn消息
        msg = Encoding.UTF8.GetBytes($"haha-warn");
        channel.BasicPublish(exchangeName, "warn", null, msg);
      //发布error消息
         msg = Encoding.UTF8.GetBytes($"haha-error");
        channel.BasicPublish(exchangeName, "error", null, msg);
    }
}

Topics


类似于Direct模型。区别是Topic的Routing Key支持通配符。

private void btnTopicPublish_Click(object sender, EventArgs e)
{
    string exchangeName = "myTopicExchange1";
    string queueName1 = "topic_queue1";
    string queueName2 = "topic_queue2";

    using (var channel = connection.CreateModel())
    {
        channel.ExchangeDeclare("myTopicExchange1", ExchangeType.Topic, true, false, null);
        channel.QueueDeclare(queueName1, true, false, false, null);
        channel.QueueDeclare(queueName2, true, false, false, null);
        channel.QueueBind(queueName1, exchangeName, "#.cn", null);
        channel.QueueBind(queueName2, exchangeName, "*.cn", null);

        //发布info消息(消息会发送到两个队列,因为都匹配)
        var msg = Encoding.UTF8.GetBytes($"{i}:haha");
        channel.BasicPublish(exchangeName, "fan.cn", null, msg);
    }
}

RPC

MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)。
但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC。

RabbitMQ中实现RPC的机制是:

客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14种properties,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)
服务器端收到消息并处理
服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性
客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理

posted @ 2020-07-23 22:49  .Neterr  阅读(195)  评论(0编辑  收藏  举报