.Net消息生产端、消费端开发,耗时操作并发处理

生产者端代码

首先用Visual Studio 2015 创建一个控制台程序,添加如下代码 

        ConnectionFactory factory = new ConnectionFactory()
            {
                HostName = "192.168.3.101",
                VirtualHost = "/",
                UserName = "admin",
                Password = "admin"
            };
            using (var conn = factory.CreateConnection())
            {
                using (IModel channel = conn.CreateModel())
                {
                    //声名交换
                    channel.ExchangeDeclare("textexchange", ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
                    //声名队列
                    channel.QueueDeclare("testqueue", durable: true, exclusive: false, autoDelete: false, arguments: null);
                    //绑定队列
                    channel.QueueBind("testqueue", "textexchange", routingKey: "routekey");
                    var prop = channel.CreateBasicProperties();
                    //2.表示持久化消息
                    prop.DeliveryMode = 2;
                    var body = Encoding.UTF8.GetBytes("生产第一条消息");
                    channel.BasicPublish(exchange: "textexchange", routingKey: "routekey", basicProperties: prop, body: body);
                }
            }

  

消费者端代码

 消费者端我们采用订阅获取消息模式,首先创建Window服务,创建服务过程不在赘述。

    public partial class MQService : ServiceBase
    {
        private static ILog log = LogManager.GetLogger(typeof(MQService));
        IConnection conn;
        IModel channel;
        private const ushort qosCount = 100;
        public MQService()
        {
            InitializeComponent();
        }
        protected override void OnStart(string[] args)
        {           
            StartRabbitMQ();     
        }

        private bool StartRabbitMQ()
        {
            try
            {
                ConnectionFactory factory = new ConnectionFactory()
                {
                    HostName = "192.168.3.101",
                    VirtualHost = "/",
                    UserName = "admin",
                    Password = "admin",
                    RequestedHeartbeat = 60,                 //健康检查时间间隔
                    AutomaticRecoveryEnabled = true,            //是否开启自动重连
                    NetworkRecoveryInterval = TimeSpan.FromSeconds(20)  //网络恢复时间间隔
                };
                conn = factory.CreateConnection();
                channel = conn.CreateModel();

                channel.ExchangeDeclare("textexchange", ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
                channel.QueueDeclare("testqueue", durable: true, exclusive: false, autoDelete: false, arguments: null);
                channel.QueueBind("testqueue", "textexchange", "routekey");

                channel.BasicQos(0, qosCount, false);
                var consumer = new EventingBasicConsumer(channel);
                channel.BasicConsume("testqueue", noAck: false, consumer: consumer);
                consumer.Received += Consumer_Received;
                return true;
            }
            catch (Exception ex)
            {
                CloseConnection();
                log.Error("工作队列声名失败:" + ex.Message + "|" + ex.StackTrace);
                return false;
            }
        }
        private void Consumer_Received(object sender, BasicDeliverEventArgs e)
        {
            Task.Run(() => SendMessage(e));
        }
        public void SendMessage(BasicDeliverEventArgs e)
        {
            var message = Encoding.UTF8.GetString(e.Body);
            MessageSub sub = null;
            try
            {
                sub = JsonConvert.DeserializeObject<MessageSub>(message);
            }
            catch (Exception ex)
            {
                channel.BasicAck(e.DeliveryTag, false);
                log.Error("消息反序列化失败:" + ex.Message + "|" + message);
                return;
            }

            try
            {
                //currentService.Push(sub); 这里写业务逻辑

                channel.BasicAck(e.DeliveryTag, false);
                log.Info("消费成功");
            }
            catch (Exception ex)
            {
                channel.BasicAck(e.DeliveryTag, false);
                log.Error("消息发送失败" + ex.Message);
            }
        }
        protected override void OnStop()
        {
            CloseConnection();
            log.Info("服务关闭");
        }
        private void CloseConnection()
        {
            if (channel != null)
            {
                if (channel.IsOpen)
                {
                    channel.Close();
                }
                channel.Dispose();
            }

            if (conn != null)
            {
                if (conn.IsOpen)
                {
                    conn.Close();
                }
                conn.Dispose();
            }

            channel = null;
            conn = null;
        }
    }

  

注意事项

1、消息持久化必须将exchange、queue和message全部设置为持久化,否则服务器重启消息会丢失。

2、因为本程序使用Window服务来处理消息,遇到问题时排查不太方便所以一定要多记录一些日志,以便快速的解决问题,本程序日志框架使用Log4net。

3、BasicQos为流量控制,在开启消费端确认消息的情况下,根据当前消费端的处理能力来设置大小。

4、本程序推送消息使用Task.Run()方法实现多线程推送,由于是demo程序,并没有控制线程数量,如果需要控制线程数量,可以使用TaskScheduler任务调度类实现。

耗时操作

假如用MQ推送邮件的情况下,发一份邮件很有可能耗时1至2秒钟,这种情况单消费端来发送邮件很明显效率低下,所以我们应该使用多个消费端,并且每个消费端可以多任务并行发送,可以有效的提高推送效率。如下图

-------------------------------------------------

 技术交流QQ群:588273396

 -------------------------------------------------

转载于:https://www.cnblogs.com/xiaobai888/p/7705349.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值