关于MSMQ(System.Messaging.MessageQueue)安装及在.NET Framework框架下的简单应用实现,以解决大并发请求问题


前言

提示:大并发请求队列处理及实时聊天消息也可参考本文自行实现

随着大数据的不断发展,我们实际开发的项目也开始逐渐接触到大数据大并发造成的一些问题,由于近期项目需求要满足2000并发量,经过压测发现原项目中编写的正常逻辑读写程序很卡顿,服务器环境Windows Server 2019 32G16核,响应时间需要1-2分钟,造成程序无法正常使用;为解决这一问题,我研究了各种消息队列中间件及缓存队列,Redis、MSMQ、RabbitMQ等,最终选择了微软Windows系统自带的组件“消息队列”(以下简称:MSMQ)快速解决了此问题,本文主要讲述MSMQ的简单应用。

注意:MSMQ只支持Windows操作系统,其他操作系统暂不支持!!!


一、MSMQ是什么?

MicroSoft Message Queuing(微软消息队列)是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于相连的网络空间中的任一位置。它的实现原理是:消息的发送者把自己想要发送的信息放入一个容器中(我们称之为Message),然后把它保存至一个系统公用空间的消息队列(Message Queue)中;本地或者是异地的消息接收程序再从该队列中取出发给它的消息进行处理。详细描述请参考此链接

二、安装步骤

1.Windows系统

1)首先找到:开始》控制面板》程序》程序和功能》启用或关闭Windows功能。点击打开,如下图:
图1
2)勾选好下图圈出功能,点击确定安装。
图2
3)安装完成后,可打开计算机管理功能(cmd命令打开方式:compmgmt.msc)查看是否安装成功,安装成功则如下图出现“消息队列”栏,也可在系统服务(cmd命令打开方式:services.msc)中查看是否有名称为“消息队列(Message Queuing)”服务正在运行。
图3
图4

2.Windows Server系统

1)首先打开:服务器管理器,找到 管理》添加角色和功能》功能》消息队列,全选“消息队列”下所有功能,“下一页”》“安装”,如下图:
图21
图22
2)安装完成后,可打开计算机管理功能(cmd命令打开方式:compmgmt.msc)查看是否安装成功,安装成功则如下图出现“消息队列”栏,也可在系统服务(cmd命令打开方式:services.msc)中查看是否有名称为“Message Queuing(消息队列)”服务正在运行(同上面Windows操作方式)。
图23
图24

三、使用步骤

1.引入库

首先新建类“MessageHandle”,搜索并引用系统dll程序集:System.Messaging,如下图:
图31

2.封装读写消息类

插入以下封装好的代码到刚建的类“MessageHandle”:

	/// <summary>
    /// 消息处理类
    /// </summary>
    public class MessageHandle
    {
        /// <summary>
        /// 判断队列是否存在
        /// </summary>
        /// <param name="name">队列名称</param>
        public static bool ExistsQueue(string name)
        {
            if (System.Messaging.MessageQueue.Exists(".\\private$\\" + name))//检查是否已经存在同名的消息队列
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 创建队列
        /// </summary>
        /// <param name="name">队列名称</param>
        public static string CreateNewQueue(string name)
        {
            if (!ExistsQueue(name))//检查是否已经存在同名的消息队列
            {
                System.Messaging.MessageQueue mq = System.Messaging.MessageQueue.Create(".\\private$\\" + name);
                mq.Label = name;
                return name + " 创建成功";
            }
            else
            {
                return "已经存在";
            }
        }

        /// <summary>
        /// 删除队列
        /// </summary>
        /// <param name="name">队列名称</param>
        public static string DeleteQueue(string name)
        {
            if (ExistsQueue(name))//检查是否已经存在同名的消息队列
            {
                System.Messaging.MessageQueue.Delete(".\\private$\\" + name);
                return name + " 删除成功";
            }
            else
            {
                return "不存在,无需删除";
            }
        }

        /// <summary>
        /// 同步发送消息
        /// </summary>
        /// <param name="input">发送的内容</param>
        /// <param name="queueName">发送到哪个消息队列中</param>
        public static void SendMsg(string input, string queueName)
        {
            CreateNewQueue(queueName);//先创建队列,避免无此队列时报错
            System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(".\\private$\\" + queueName);
            System.Messaging.Message message = new System.Messaging.Message();
            message.Body = input;
            message.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });
            mq.Send(message);
        }

        /// <summary>
        /// 同步接收消息
        /// </summary>
        /// <param name="queueName">从哪个消息队列读取消息</param>
        /// <returns>返回读取到的消息内容字符串</returns>
        public static string ReceiveMsg(string queueName)
        {
            System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(".\\private$\\" + queueName);
            if (mq.GetAllMessages().Length == 0)//判断是否还有消息,如果没有消息的话Receive方法会一直独占进程直到有消息为止,所以必须判断
            {
                return null;
            }
            else
            {
                System.Messaging.Message m = mq.Receive();
                m.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) });
                return m.Body.ToString();
            }
        }
    }

其他用法及扩展请参考微软官方示例:点击进入 MessageQueue 类

3.发送业务消息数据到队列

1)根据自己业务需求,如果业务有多字段内容时可封装消息内容到实体(如下代码类),后续再把实体对象转换为json字符串发送到队列;如果业务只有一个字段,可直接使用string,无需封装实体。

	/// <summary>
    /// 消息队列使用的消息内容类(可自行封装其他业务类或直接用字符串)
    /// </summary>
    public class MQ_msgdata
    {
        /// <summary>
        /// 用户id
        /// </summary>
        public int UserId { get; set; }
        /// <summary>
        /// 数据内容
        /// </summary>
        public string Msg{ get; set; }
    }

2)组装消息内容发送到“TestMQ”队列,如下代码:

#region 添加业务请求内容到消息队列异步处理
#region 组装消息内容实体
	MQ_msgdata mQMsg = new MQ_msgdata();
	mQMsg.UserId = 1;
	mQMsg.Msg= "测试消息内容";
#endregion

	string mqMsg = Newtonsoft.Json.JsonConvert.SerializeObject(mQMsg);//转json字符串(此处不一定要封装到对象再转json字符串存储,可根据业务需要直接存储字符串内容,如下一行注释代码)
	//string mqMsg = "测试消息内容";//字符串内容
	string qname = "TestMQ";//队列名称(可自行定义队列命名规则)
	MessageHandle.SendMsg(mqMsg, qname);//发送消息(内部已有创建队列逻辑)
#endregion

4.接收队列中的业务消息数据并处理

1)创建一个控制台应用程序(也可是其他定时任务程序,可根据自己业务需求选择),配置好自己业务需要的其他配置,此处就不讲解了(如数据库连接、缓存、公用库等),然后打开Program.cs类。
注意:这个程序要引用之前封装的消息处理类“MessageHandle”,或能调用此类,或直接拷贝此类到这个新建程序里,供使用!
图41
2)拷贝以下代码到Main入口,以接收前面业务程序发送到队列“TestMQ”的消息。
注意:HandleData需要自己根据自己业务需求写自己的业务处理逻辑代码,前面的msg即为业务发送的消息内容字符串,如果是json字符串则需要解析成实体对象。

	//控制台程序入口
	static void Main(string[] args)
        {
            Console.WriteLine("消息队列处理已启动");
            string _qname = "TestMQ";//队列名称(与前面发送消息创建的队列名称要一致)
            if (!MessageHandle.ExistsQueue(_qname))
            {//判断队列是否存在
                Console.WriteLine("开始创建【" + _qname + "】消息队列");
                MessageHandle.CreateNewQueue(_qname);//创建队列
                Console.WriteLine("【" + _qname + "】创建完成");
            }
            Task.Run(async () =>
            {
                Console.WriteLine("【" + _qname + "】开始接收…");
                while (true)
                {//循环一直接收
                    #region 处理接收数据
                    string msg = MessageHandle.ReceiveMsg(_qname);//获取此队列中的消息
                    if (!string.IsNullOrWhiteSpace(msg))
                    {//空消息过滤
                        Console.WriteLine("【" + _qname + "】在【" + DateTime.Now + "】收到队列消息:{0}", msg);
                    	//MQ_msgdata modelmsg = Newtonsoft.Json.JsonConvert.DeserializeObject<MQ_msgdata>(msg);//json字符串解析为实体对象
                        HandleData(_qname, msg);//处理数据(自行解析msg内容根据业务再处理存库等)
                    }
                    #endregion
                }
            });
            Console.Read();
        }

3)运行上面的控制台程序即可开始实时接收处理前面发送的业务消息了。


总结

注意:消息发送和消息接收是异步的,发送了一条,未接收(消耗)的情况下,消息是一直存在队列中的,直到被接收(消耗)处理。
以上就是今天要讲的内容,本文仅仅简单介绍MSMQ的基本应用,大家可以根据自己的业务需要灵活运用,有不清楚的或不对的可评论留言,看即回!

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值