• C#使用RabbitMq队列(Sample,Work,Fanout,Direct等模式的简单使用)


    1:RabbitMQ是个啥?(专业术语参考自网络)

         RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。

      RabbitMQ服务器是用Erlang语言编写的,Erlang是专门为高并发而生的语言,而集群和故障转移是构建在开发电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库

    2:使用RabbitMQ有啥好处?

    RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。
    AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
    AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
    RabbitMQ的可靠性是非常好的,数据能够保证百分之百的不丢失。可以使用镜像队列,它的稳定性非常好。所以说在我们互联网的金融行业。

    对数据的稳定性和可靠性要求都非常高的情况下,我们都会选择RabbitMQ。当然没有kafka性能好,但是要比AvtiveMQ性能要好很多。也可以自己做一些性能的优化。

    RabbitMQ可以构建异地双活架构,包括每一个节点存储方式可以采用磁盘或者内存的方式,

    3:RabbitMq的安装以及环境搭建等:

       网络上有很多关于怎么搭建配置RabbitMq服务环境的详细文章,也比较简单,这里不再说明,本人是Docker上面的pull RabbitMq 镜像来安装的!

    3.1:运行容器的命令如下:

    docker run -d --hostname Log --restart=always --name rabbitmq -p 5672:5672 -p 15672:15672 -e RABBITMQ_DEFAULT_USER=log_user -e RABBITMQ_DEFAULT_PASS=331QQFEG123 rabbitmq:3-management

    4:RabbitMq的使用场景主要有哪些,啥时候用或者不用?

    4.1什么时候使用MQ?

    1)数据驱动的任务依赖

    2)上游不关心多下游执行结果

    3)异步返回执行时间长

    4.2什么时候不使用MQ?

    需要实时关注执行结果 (eg:同步调用)

    5:具体C#怎么使用RabbitMq?下面直接上code和测试截图了(Demo环境是.NetCore3.1控制台+Docker上的RabbitMQ容器来进行的)

    6:sample模式,就是简单地队列模式,一进一出的效果差不多,测试截图:

     

    Code:

     1 //简单生产端 ui调用者
     2 
     3 using System;
     4 namespace RabbitMqPublishDemo
     5 {
     6     using MyRabbitMqService;
     7     using System.Runtime.CompilerServices;
     8 
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13                 //就是简单的队列,生产者
    14                 Console.WriteLine("====RabbitMqPublishDemo====");
    15                 for (int i = 0; i < 500; i++)
    16                 {
    17                     ZrfRabbitMqHelper.PublishSampleMsg("smapleMsg", $"nihaifengge:{i}");
    18                 }
    19                 Console.WriteLine("生成完毕!");
    20                 Console.ReadLine();
    21         }
    22     }
    23 }
    24 
    25 /// <summary>
    26 /// 简单生产者 逻辑
    27 /// </summary>
    28 /// <param name="queueName"></param>
    29 /// <param name="msg"></param>
    30 public static void PublishSampleMsg(string queueName, string msg)
    31 {
    32 
    33     using (IConnection conn = connectionFactory.CreateConnection())
    34     {
    35         using (IModel channel = conn.CreateModel())
    36         {
    37             channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
    38             var msgBody = Encoding.UTF8.GetBytes(msg);
    39             channel.BasicPublish(exchange: "", routingKey: queueName, basicProperties: null, body: msgBody);
    40         }
    41     }
    42 }
    43         
    44 
    45 //简单消费端
    46 using System;
    47 
    48 namespace RabbitMqConsumerDemo
    49 {
    50     using MyRabbitMqService;
    51     using System.Runtime.InteropServices;
    52 
    53     class Program
    54     {
    55         static void Main(string[] args)
    56         {
    57             Console.WriteLine("====RabbitMqConsumerDemo====");
    58             ZrfRabbitMqHelper.ConsumeSampleMsg("smapleMsg", isBasicNack: true, handleMsgStr: handleMsgStr =>
    59             {
    60                 Console.WriteLine($"订阅到消息:{DateTime.Now}:{handleMsgStr}");
    61             });
    62             Console.ReadLine();
    63         }
    64     }
    65 }
    66 
    67      #region 简单生产者后端逻辑
    68         /// <summary>
    69         /// 简单消费者
    70         /// </summary>
    71         /// <param name="queueName">队列名称</param>
    72         /// <param name="isBasicNack">失败后是否自动放到队列</param>
    73         /// <param name="handleMsgStr">有就自己对字符串的处理,如果要存储到数据库请自行扩展</param>
    74         public static void ConsumeSampleMsg(string queueName, bool isBasicNack = false, Action<string> handleMsgStr = null)// bool ifBasicReject = false, 
    75         {
    76             Console.WriteLine("ConsumeSampleMsg Waiting for messages....");
    77             IConnection conn = connectionFactory.CreateConnection();
    78             IModel channel = conn.CreateModel();
    79             channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
    80             var consumer = new EventingBasicConsumer(channel);
    81             consumer.Received += (sender, ea) =>
    82             {
    83                 byte[] bymsg = ea.Body.ToArray();
    84                 string msg = Encoding.UTF8.GetString(bymsg);
    85                 if (handleMsgStr != null)
    86                 {
    87                     handleMsgStr.Invoke(msg);
    88                 }
    89                 else
    90                 {
    91                     Console.WriteLine($"{DateTime.Now}->收到消息:{msg}");
    92                 }
    93             };
    94             channel.BasicConsume(queueName, autoAck: true, consumer);
    95         }
    96         #endregion
    97         
    98         

    7:Work模式

     1 //就如下的code, 多次生产,3个消费者都可以自动开始消费
     2 
     3 //生产者
     4 using System;
     5 namespace RabbitMqPublishDemo
     6 {
     7     using MyRabbitMqService;
     8     using System.Runtime.CompilerServices;
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             for (int i = 0; i < 500; i++)
    14             {
    15                 ZrfRabbitMqHelper.PublishWorkQueueModel("workqueue", $" :发布消息成功{i}");
    16             }
    17             Console.WriteLine("工作队列模式 生成完毕......!");          
    18             Console.ReadLine();
    19         }
    20     }
    21 }
    22 
    23 //生产者后端逻辑
    24 public static void PublishWorkQueueModel(string queueName, string msg)
    25         {
    26             using (var connection = connectionFactory.CreateConnection())
    27             using (var channel = connection.CreateModel())
    28             {
    29                 channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    30                 var body = Encoding.UTF8.GetBytes(msg);
    31                 var properties = channel.CreateBasicProperties();
    32                 properties.Persistent = true;
    33 
    34                 channel.BasicPublish(exchange: "", routingKey: queueName, basicProperties: properties, body: body);
    35                 Console.WriteLine($"{DateTime.Now},SentMsg: {msg}");
    36             }
    37         }
    38 
    39 //work消费端
    40 using System;
    41 
    42 namespace RabbitMqConsumerDemo
    43 {
    44     using MyRabbitMqService;
    45     using System.Runtime.InteropServices;
    46     class Program
    47     {
    48         static void Main(string[] args)
    49         {
    50             Console.WriteLine("====Work模式开启了====");
    51             ZrfRabbitMqHelper.ConsumeWorkQueueModel("workqueue", handserMsg: msg =>
    52             {
    53                 Console.WriteLine($"work模式获取到消息{msg}");
    54             });
    55             Console.ReadLine();
    56         }
    57     }
    58 }
    59 
    60 //work后端逻辑
    61        public static void ConsumeWorkQueueModel(string queueName, int sleepHmao = 90, Action<string> handserMsg = null)
    62         {
    63             var connection = connectionFactory.CreateConnection();
    64             var channel = connection.CreateModel();
    65 
    66             channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
    67             channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
    68 
    69             var consumer = new EventingBasicConsumer(channel);
    70             Console.WriteLine(" ConsumeWorkQueueModel Waiting for messages....");
    71 
    72             consumer.Received += (sender, ea) =>
    73             {
    74                 var body = ea.Body.ToArray();
    75                 var message = Encoding.UTF8.GetString(body);
    76                 if (handserMsg != null)
    77                 {
    78                     if (!string.IsNullOrEmpty(message))
    79                     {
    80                         handserMsg.Invoke(message);
    81                     }
    82                 }
    83                 channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
    84             };
    85             channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
    86         }

    8:Fanout

     Code:

     1 //同一个消息会被多个订阅者消费
     2 
     3 //发布者
     4 using System;
     5 
     6 namespace RabbitMqPublishDemo
     7 {
     8     using MyRabbitMqService;
     9     using System.Runtime.CompilerServices;
    10 
    11     class Program
    12     {
    13         static void Main(string[] args)
    14         {
    15 
    16             #region 发布订阅模式,带上了exchange
    17             for (int i = 0; i < 500; i++)
    18             {
    19                 ZrfRabbitMqHelper.PublishExchangeModel("exchangemodel", $"发布的消息是:{i}");
    20             }
    21             Console.WriteLine("发布ok!");
    22             #endregion
    23             Console.ReadLine();
    24         }
    25     }
    26 }
    27 //发布者的后端逻辑 我在这里选择了扇形: ExchangeType.Fanout
    28    public static void PublishExchangeModel(string exchangeName, string message)
    29         {
    30             using (var connection = connectionFactory.CreateConnection())
    31             using (var channel = connection.CreateModel())
    32             {
    33                 channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Fanout);
    34                 var body = Encoding.UTF8.GetBytes(message);
    35                 channel.BasicPublish(exchange: exchangeName, routingKey: "", basicProperties: null, body: body);
    36                 Console.WriteLine($" Sent {message}");
    37             }
    38         }
    39 
    40 
    41 //订阅者
    42 using System;
    43 namespace RabbitMqConsumerDemo
    44 {
    45     using MyRabbitMqService;
    46     using System.Runtime.InteropServices;
    47     class Program
    48     {
    49         static void Main(string[] args)
    50         {
    51 
    52             #region 发布订阅模式 Exchange
    53             ZrfRabbitMqHelper.SubscriberExchangeModel("exchangemodel", msg =>
    54             {
    55                 Console.WriteLine($"订阅到消息:{msg}");
    56             });
    57             #endregion
    58             Console.ReadLine();
    59         }
    60     }
    61 }
    62 
    63 //订阅者后端的逻辑
    64  public static void SubscriberExchangeModel(string exchangeName, Action<string> handlerMsg = null)
    65         {
    66             var connection = connectionFactory.CreateConnection();
    67             var channel = connection.CreateModel();
    68 
    69             channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Fanout);//Fanout 扇形分叉
    70 
    71             var queueName = channel.QueueDeclare().QueueName;
    72             channel.QueueBind(queue: queueName,
    73                               exchange: exchangeName,
    74                               routingKey: "");
    75 
    76             Console.WriteLine(" Waiting for msg....");
    77 
    78             var consumer = new EventingBasicConsumer(channel);
    79             consumer.Received += (model, ea) =>
    80             {
    81                 var body = ea.Body.ToArray();
    82                 var message = Encoding.UTF8.GetString(body);
    83                 if (handlerMsg != null)
    84                 {
    85                     if (!string.IsNullOrEmpty(message))
    86                     {
    87                         handlerMsg.Invoke(message);
    88                     }
    89                 }
    90                 else
    91                 {
    92                     Console.WriteLine($"订阅到消息:{message}");
    93                 }
    94             };
    95             channel.BasicConsume(queue: queueName,  autoAck: true, consumer: consumer);
    96         }

    9:Direct

     

    Code:

      1 //发布者
      2 using System;
      3 
      4 namespace RabbitMqPublishDemo
      5 {
      6     using MyRabbitMqService;
      7     using System.Runtime.CompilerServices;
      8 
      9     class Program
     10     {
     11         static void Main(string[] args)
     12         {
     13             #region 发布订阅 交换机路由模式 Direct
     14             string routerKeyValue = args[0].Split("=")[1];//如 abc.exe --name='qq'
     15             Console.WriteLine("开始发布中。。。");
     16             for (int i = 0; i < 20; i++)
     17             {
     18                 string msg = $"小明有{i}只宝剑";
     19                 ZrfRabbitMqHelper.ExchangeRoutersByDirectModelPublish(msg, routerKey: routerKeyValue);
     20 
     21                 //下面的为固定的写法
     22                 //ZrfRabbitMqHelper.ExchangeRoutersByDirectModelPublish(msg);
     23                 //ZrfRabbitMqHelper.ExchangeRoutersByDirectModelPublish($"你好我好大家好{i}", routerKey:"onlylog");
     24             }
     25             Console.WriteLine("这次发布完毕。。。");
     26             #endregion
     27             Console.ReadLine();
     28         }
     29     }
     30 }
     31 
     32 //发布者后端逻辑 发布订阅的路由模式 Direct
     33         /// <summary>
     34         /// 发布 Direct 路由模式 Direct
     35         /// </summary>
     36         /// <param name="message"></param>
     37         /// <param name="exchangeName"></param>
     38         /// <param name="routerKey"></param>
     39         public static void ExchangeRoutersByDirectModelPublish(string message, string exchangeName = "qqai", string routerKey = "insertToStudent")
     40         {
     41             using (IConnection connection = connectionFactory.CreateConnection())
     42             {
     43                 using (IModel channelmodel = connection.CreateModel())
     44                 {
     45                     channelmodel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct);
     46                     byte[] bymsg = Encoding.UTF8.GetBytes(message);
     47                     channelmodel.BasicPublish(exchange: exchangeName, routingKey: routerKey, body: bymsg);
     48 
     49                     // ​byte[] bytemsg = Encoding.UTF8.GetBytes(message);
     50                     //  ​channelmodel.BasicPublish(exchange: exchangeName,routingKey: routerKey,basicProperties: null,body: bytemsg);
     51                 }
     52             }
     53         }
     54         
     55 //订阅者 Exchange Router路由 Director
     56 using System;
     57 
     58 namespace RabbitMqConsumerDemo
     59 {
     60     using MyRabbitMqService;
     61     using System.Runtime.InteropServices;
     62 
     63     class Program
     64     {
     65         static void Main(string[] args)
     66         {
     67             Console.WriteLine("开始消费中。。!");
     68             if (args.Length > 0)
     69             {
     70                 string routerKeyValue = args[0].Split("=")[1];
     71                 Console.WriteLine($"routerKey=>{routerKeyValue}");
     72                 if (!string.IsNullOrEmpty(routerKeyValue))
     73                     ZrfRabbitMqHelper.ExchangeRoutersByDirectModelConsumer(routerKey: routerKeyValue, handler: msg =>
     74                     {
     75                         Console.WriteLine($"拿到消息:{msg}");
     76                     });
     77                 else
     78                     Console.WriteLine("没有获取到routerKey !");
     79             }
     80             //else
     81             //{
     82             //    ZrfRabbitMqHelper.ExchangeRoutersByDirectModelConsumer(handler: msg =>
     83             //    {
     84             //        Console.WriteLine($"拿到消息:{msg}");
     85             //    });
     86             //}
     87             Console.ReadLine();
     88         }
     89     }
     90 }
     91 
     92 //订阅者 Exchange Router路由 Director 后端逻辑
     93        public static void ExchangeRoutersByDirectModelConsumer(string exchangeName = "qqai", string routerKey = "insertToStudent", Action<string> handler = null)
     94         {
     95             var connection = connectionFactory.CreateConnection();
     96             var channel = connection.CreateModel();
     97             channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct);
     98             var queueName = channel.QueueDeclare().QueueName;
     99             channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routerKey);
    100 
    101             Console.WriteLine("wating for message...!");
    102             var consumer = new EventingBasicConsumer(channel);
    103             //(object sender, BasicDeliverEventArgs e)
    104             consumer.Received += (sender, e) =>
    105             {
    106                 var bytedata = e.Body.ToArray();
    107                 var getRoutekey = e.RoutingKey;
    108                 string msg = Encoding.UTF8.GetString(bytedata);
    109                 if (handler != null)
    110                     handler.Invoke(msg);
    111                 else
    112                     Console.WriteLine($"路由{getRoutekey},订阅到消息{msg}!");
    113             };
    114             channel.BasicConsume(queue: queueName, autoAck: true, consumer);
    115         }
    116 

     需要完整的code,可以留言获取!

  • 相关阅读:
    Difference (第k大(二分)+双指针+ST表)+(很多小细节!!!!!) (MINIEYE杯十六届)
    electronvue实现自定义区域拖拽窗口
    PHP 发送短信
    C#VS2017快捷操作(查看方法重载)
    bootstrapdatetimepicker源代码分析
    Linux下的dstat命令详解以及部分参数说明
    《金字塔原理》
    三年职业生涯回顾
    C++_02_类型转换
    C++_03_动态内存与智能指针
  • 原文地址:https://www.cnblogs.com/Fengge518/p/13826983.html
Copyright © 2020-2023  润新知