zoukankan      html  css  js  c++  java
  • RabbitMQ随笔

    不管是官方还是能搜到的文章,使用MQ的基本思路都是这样:

            static void Main(string[] args)
            {
               //通过工厂建立连接
                using (IConnection connection = factory.CreateConnection())
                {
                    //通过连接创建会话,这里还有可能是Channel
                    using (ISession session = connection.CreateSession())
                    {
                        while (true)或者一个for 循环发送100万个消息
                        {
                              //创建一个msg
                          string  message = "Hello World";
                             //发送
                           xxx.Send(message);
                        }
                    }
                }
            }

    那么问题来了:

    这个"Hello World"怎么传进去?如何对外提供服务?

    然后会发现有些客户端SDK是这么处理的:

           public static void SendMsg()
            {
                MQAPI("Hello World");
            }
    
            private static void MQAPI(string message)
            {
                IConnectionFactory factory;
                //通过工厂建立连接
                using (IConnection connection = factory.CreateConnection())
                {
                    //通过连接创建Session会话
                    using (ISession session = connection.CreateSession())
                    {
                           //创建一个msg
                          string  message = message;
    
                          //发送
                          xxx.Send(message);
                    }
                }
            }

    去公开一个接口调用SendMsg吧。

    看起来似乎解决了这个问题,但是实际测试下会吓一跳:后者的QPS仅为前者的40%左右,这是不能容忍的。

    那么接下来大家肯定会从SQLConnection的经验得出一个解决方案:

    将connection抽出来,那么session或者Channel呢?

    我们通过研究RabbitMQ的链接客户端和服务端链接过程(这个过程较为复杂,写了几遍都删了)得出如下结论:

    1. 先建立Connection链接,这个链接就是一个TCP链接,Producer和Consumer都是通过TCP连接到RabbitMQ Server 的。经过connection.start -> connection.start_ok -> connection.secure -> connection.secure_ok -> connection.tune -> connection.tune_ok(这时rabbit会建立一个心跳进程)-> connection.open -> connection.open_ok后,客户端与rabbit之间就认为已经建立 了连接。
    2. 再建立Channels: 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。可以多路复用,1~65535为可用的channel编号,channel的索引不为0时(0是全局链接),rabbit认为这些数据从属于某个 channel。如果该channel进程不 存在,则会创建一个channel进程,并由此进程负责该channel上 的所有数据。根据AMQP协议,经过channel.open -> channel.open_ok后,客户端就可以开始在该channel上发送数据了。

    那么,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理 高并发的能力。但是,在TCP连接中建立 Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个 Channel进行 Publish或者Receive。

    然而我研究了RabbitMQ.Client代码之后发现其并未维护一个连接池:

                    if (AutomaticRecoveryEnabled)
                    {
                        var autorecoveringConnection = new AutorecoveringConnection(this, clientProvidedName);
                        autorecoveringConnection.Init(endpointResolver);
                        conn = autorecoveringConnection;
                    }
                    else
                    {
                        IProtocol protocol = Protocols.DefaultProtocol;
                        conn = protocol.CreateConnection(this, false, endpointResolver.SelectOne(this.CreateFrameHandler), clientProvidedName);
                    }

    只是有一个自动恢复功能,需要设置为true建立长TCP链接,然后根据在请求的时候再创建Channel。

  • 相关阅读:
    写给所有的IT民工们
    如何不重启系统加载.SYS文件
    六十八个经典故事
    利用C#重启远程计算机
    无为无不为
    男人心里到底藏着哪些秘密?
    Microsoft好员工的十个标准
    javascript版的日期输入控件
    书写NDIS过滤钩子驱动实现ip包过滤
    男人25岁前的忠告#必阅
  • 原文地址:https://www.cnblogs.com/madyina/p/6322689.html
Copyright © 2011-2022 走看看