【问题标题】:ZeroMQ subscriber fails to initialize using 1000+ publishersZeroMQ 订阅者无法使用 1000 多个发布者进行初始化
【发布时间】:2012-12-03 13:22:29
【问题描述】:

我正在尝试评估 ZeroMQ 以获得更大的监控和数据收集系统。在较小的规模上一切都很好,但增加负载和规模似乎有点棘手。

现在我正在使用 C# 包装器(clrzmq,3.0.0-rc1)来创建发布者和订阅者应用程序。我将发布者套接字(1 个套接字,1 个上下文)绑定到 1000 个端点(本地主机 + 一系列端口),并让订阅者应用程序套接字(同样是 1 个套接字,1 个上下文)绑定到发布者端点。

这有时有效,有时无效(我猜这与进程以某种方式处理的最大套接字数有关)。这似乎取决于我启动应用程序的顺序,但我无法确定。我唯一看到的是讨厌的 SEHExceptions,根本不包含任何细节。如果我创建简单的控制台应用程序,我有时会看到低级 C++ 断言,例如:

  • 断言失败:fds.size ()
  • 断言失败:权限被拒绝 (......\src\signaler.cpp:281)
  • 断言失败:对等方重置连接 (......\src\signaler.cpp:124)

对我帮助不大。在 C# 包装器中,上下文创建失败。它甚至没有机会开始连接甚至创建套接字。我希望通过抛出异常来处理低级别的 ZeroMQ 错误,也许我只是还没有理解如何处理错误。

我现在的问题是:

  • 如何创建(有点)真实的测试设置来模拟单台机器上的 1000 个单独的发布者(在现实世界中 1 个发布者 = 1 台机器)和另一台机器上的几个订阅者,所有这些都使用 C#。这可能吗?
  • 更重要的是,我如何在 C# 代码中捕获 ZeroMQ 错误以便能够了解问题所在?

由于 ZeroMQ 看起来相当稳定和成熟,我很难相信 1000 个发布者应该是一个需要处理的问题。但是,为了在 C# 上使用 ZeroMQ,我需要比目前可用的更好的错误支持(除非我在这里完全遗漏了一些东西)。

更新:

在深入挖掘源代码后,我最终得到了一个 zmq_assert(...) 导致 RaiseException (0x40000015, EXCEPTION_NONCONTINUABLE, 1, extra_info);。这将在将原始断言语句转储到控制台后突然终止应用程序。这似乎有点苛刻,但考虑到它确实无法恢复,这可能是最好的选择。但是,更好的错误消息不会受到伤害。不是每个人都知道fds.size () <= FD_SETSIZE 是什么意思。源代码中的评论提供了一些线索,如果在错误消息中包含该评论会很好。无论如何,鉴于我的应用程序不是控制台应用程序,这只会给我留下一个未处理的 SEHException,它似乎甚至不包含断言语句或行/文件信息。我想知道我将创建多少其他错误会导致其他类似的神秘错误。

【问题讨论】:

标签: c# .net zeromq


【解决方案1】:

进一步研究后,似乎默认套接字数设置为 1024。C# 包装器在 Context 对象上有一个属性,应该能够更改此设置,但它不起作用,在至少不像预期的那样。还有,原生的zmqlib在上下文对象上也没有这个设置。

运行描述中的设置似乎是不可能的,至少不使用clrzmq C# ZeroMQ 包装器。我通过在一台单独的机器上运行 500 个发布者并在另一台机器上运行另外 500 个加 1000 个订阅者来解决它。这很好用,没有任何错误。

另一个话题也有点让人失望。当达到最大套接字数时,ZeroMQ 会简单地抛出一个无法捕获的异常,导致应用程序突然崩溃。这是一种快速失败的方法,可以避免任何进一步的数据/状态损坏,但不幸的是,对于导致应用程序死机的原因也几乎没有留下任何线索。从其他帖子来看,当这种情况发生时,似乎很难为事后收集数据。在 C# 代码中捕获异常似乎是不可能或非常困难的,并且挂钩到标准输出以捕获打印的断言似乎也很难实现(如果我们不是从命令提示符运行,在这种情况下,断言消息会在之前打印应用程序死亡)。

总而言之,当 ZeroMQ 通过 zmq_assert(...) 调用终止时,这使得在非控制台 C# 设置中进行低级故障排除和事后分析非常困难。希望这是一个极端的例子。并非所有故障模式似乎都会以这种突然的方式导致终止。

【讨论】:

    【解决方案2】:

    默认 FD_SETSIZE 为 1024(在 MSVC libzmq 项目中定义),因此您将在测试用例的中途遇到此问题。其他断言由此而跌落。

    在您的 libzmq 项目中将其增加到 4K 或 8K,这样会更好。

    至于 assert() 调用,它在 Windows 上确实太残酷了。在 Linux 上,这提供了一个不错的堆栈转储和足够的信息来跟踪问题。随意改进 assert 宏,使其做一些更智能的事情,例如启动调试器。无论如何,如果您遇到断言,您将无法合理地继续。

    当 FD 集已满时断言,这可以更好地处理。如果您对 C/C++ 有所了解,请随时查看代码。我们确实依赖于人们的补丁。

    另外,如果您觉得 1024 太小,请随时在项目中提出这个问题并将补丁发送给我们。

    【讨论】:

      【解决方案3】:

      对该问题的快速而肮脏的调查表明您为您的计算机创建了太多的套接字连接。查看来自 MSDN 的 link on the max number of sockets。您看到的错误看起来与此相关的可疑程度足以成为您的错误的可能来源。

      说实话,拥有 1000 个独立的发布者似乎您在使用 zmq 时处理的问题有点不正确。为什么不拥有 1 个发布者并使用“命名空间”并让订阅者订阅它需要拆分订阅者获得的消息的内容。

      【讨论】:

      • 是的,1000 Publishers on a single box 仅用于开发和模拟。尽管我想在开发中使用这样的设置,但它很可能会失败。然而,更大的问题是缺乏良好的错误处理/报告。到目前为止,当达到套接字限制时,应用程序只是在没有太多额外信息的情况下崩溃。我期待一些更有用的东西。
      • IMO,我宁愿应用程序崩溃也不愿静默失败。您是否将在生产环境中拥有 1000 个发布者(意味着 1000 个单独的盒子/cpus/heads)?您有什么理由不能按照我的建议将整个数字减少到 1 或仅几个并实施一些智能过滤?
      • 同意,我想要崩溃,但有更多线索可以说明哪里出了问题。日志记录、异常、错误代码等等。在生产环境中,我们将有多达 1000 个单独的盒子,每个发布数据,由一个或多个服务器(使用订阅套接字)收集,所以很遗憾我不能将它减少到单个发布者。至少不适用于缩放测试。但对我来说主要问题是现在缺少错误细节,剩下的只是方便。
      • Jakob,我认为 Windows 上的 assert 宏可以改进,以满足您的需求。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-27
      • 1970-01-01
      相关资源
      最近更新 更多