ZeroMQ / 0MQ推/拉存储器和路由问题

时间:2012-04-20 05:35:19

标签: c# sockets tcp messaging zeromq

我和ZeroMQ玩了一段时间,并提出了几个问题/问题。如果ZeroMQ的任何贡献者可以插入或使用或当前使用该库的任何人,将不胜感激。

* 假设我有一个路由器/转发器和2个不同的客户端(c1,c2)。我想通过路由设备将消息从client1推送到client2。路由器从任何客户端(此处为client1)提取消息,并将其发布到任何订阅的客户端(此处为client2)。我目前将这些消息路由到适当的客户端的唯一方法是通过pub / sub,但是,a)我想通过发送routingTo标记和消息体来决定如何在运行时路由,b)我想使用push / pull转发到客户端,而不是pub / sub,因为我想在设置高水位标记属性时实现阻塞功能,c)我想让c1和c2连接正好1个端口用于推送,1个端口用于订阅。我可以以某种方式在路由器端进行更改,以便不必使用pub / sub或pub / sub是路由到客户端的唯一方法,即使我知道在路由端应该将消息转发到哪里?当队列大小超过我不想要的hwm时,我读到了pub / sub drop消息。我也不想实现请求/回复模式,因为它增加了不必要的开销,因为我不需要回复。

* 在运行下面的代码(推/拉 - >发布/订阅)并发送所有消息并收到所有消息的确认后,推送消息的客户端仍显示大量内存足迹,显然在Push套接字队列中仍有大量消息。为什么这样做,我该怎么做才能解决这个问题?

这是我的代码:

ROUTER:

class Program
{
    static void Main(string[] args)
    {
        using (var context = new Context(1))
        {
            using (Socket socketIn = context.Socket(SocketType.PULL), socketOut = context.Socket(SocketType.XPUB))
            {
                socketIn.HWM = 10000;
                socketOut.Bind("tcp://*:5560"); //forwards on this port
                socketIn.Bind("tcp://*:5559"); //listens on this port

                Console.WriteLine("Router started and running...");

                while (true)
                {
                    //Receive Message
                    byte[] address = socketIn.Recv();
                    byte[] body = socketIn.Recv();

                    //Forward Message
                    socketOut.SendMore(address);
                    socketOut.Send(body);
                }
            }
        }
    }
}

CLIENT 1:

class Program
{
    static void Main(string[] args)
    {
        using (var context = new Context(1))
        {
            using (Socket socketIn = context.Socket(SocketType.SUB), socketOut= context.Socket(SocketType.PUSH))
            {
                byte[] iAM = Encoding.Unicode.GetBytes("Client1");
                byte[] youAre = Encoding.Unicode.GetBytes("Client2");
                byte[] msgBody = new byte[16];

                socketOut.HWM = 10000;
                socketOut.Connect("tcp://localhost:5559");
                socketIn.Connect("tcp://localhost:5560");
                socketIn.Subscribe(iAM);

                Console.WriteLine("Press key to kick off Test Client1 Sending Routine");
                Console.ReadLine();

                for (int counter = 1; counter <= 10000000; counter++)
                {
                    //Send Message
                    socketOut.SendMore(youAre);
                    socketOut.Send(msgBody);
                }

                Console.WriteLine("Client1: Finished Sending");
                Console.ReadLine();
            }
        }
    }
}

CLIENT 2:

class Program
{
    public static int msgCounter;

    static void Main(string[] args)
    {
        msgCounter = 0;

        using (var context = new Context(1))
        {
            using (Socket socketIn = context.Socket(SocketType.SUB), socketOut = context.Socket(SocketType.PUSH))
            {
                byte[] iAM = Encoding.Unicode.GetBytes("Client2");

                socketOut.Connect("tcp://localhost:5559");
                socketIn.Connect("tcp://localhost:5560");
                socketIn.Subscribe(iAM);

                Console.WriteLine("Client2: Started Listening");

                //Receive First Message
                byte[] address = socketIn.Recv();
                byte[] body = socketIn.Recv();
                msgCounter += 1;

                Console.WriteLine("Received first message");

                Stopwatch watch = new Stopwatch();
                watch.Start();

                while (msgCounter < 10000000)
                {
                    //Receive Message
                    address = socketIn.Recv();
                    body = socketIn.Recv();
                    msgCounter += 1;
                }

                watch.Stop();
                Console.WriteLine("Elapsed Time: " + watch.ElapsedMilliseconds + "ms");
                Console.ReadLine();
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我建议你的架构可能有点偏离。

1)如果您只需要一个PUSH和一个PULL,请从中间移除设备。设备被明确添加到体系结构中以管理多个使用者,这样您每次添加节点时都不必更新生成器。当/如果你到达了需要多个消费者和/或生产者的地方,你将需要连接到你设备上的每个节点 - 这就是它们的工作方式。在这种情况下,听起来好像设备使解决方案过于复杂。

2)拥有“路由到”标签的想法真的令人难以置信。选择消息传递优于其他集成选项的最大原因可能是将您的生产者和消费者分离,以便双方都不必知道关于另一方的任何事情(除了在无经纪人设计的情况下发送消息的位置)。将路由信息直接添加到逻辑中会破坏这一点。

至于开销,我从来没有经历过这个。但是之后,我以前从未使用过.Net驱动程序用于ZeroMQ,所以未经教育的猜测就是查看.Net驱动程序本身。