线程、事件循环和大量连接和并发
Posted
技术标签:
【中文标题】线程、事件循环和大量连接和并发【英文标题】:Threading, event loops and large amounts of connections and concurrency 【发布时间】:2015-12-06 10:23:48 【问题描述】:全部。我试图找出以最佳方式处理大量并发连接(超过 800k)的最佳方法。我决定使用 libevent 来处理套接字上的读/写,并将在后端使用一个端口并将 fd 交给非阻塞套接字。我的问题在哪里发挥作用:
1) 关于事件库的 libevent - 例如,如果我要为每个内核运行一个线程,每个线程都有自己的 libevent 库,侦听单个 fd 以获取传入连接,libevent 将如何处理触发的多个事件库在那个单一的fd上?这个想法是然后接受该传入连接,接受它并基于特定于该连接的新 fd 启动一个新事件。或者,是像我过去那样做的适当方法 - 在主程序线程中运行主事件库并将传入连接推送到工作线程以处理接受,然后为每个事件创建一个新的事件库那么连接呢?
2) 每个连接的线程数...是,还是否?在过去的实现中,我为每个接受的连接建立了 1:1 线程模型。最终结果显然是连接了 500 个客户端、500 个线程以及我用作工作队列的任何线程。但是,我担心一旦我接触到数十万个标记连接,这可能会造成问题......有人可以确认吗?我也觉得在使用诸如 libevent 之类的异步 IO 的东西时拥有这么多线程是不必要的,而且只会增加比所需更多的开销......但我可能是错的。
这是我第一次不得不编写能够支持如此高的用户负载的东西,我更希望能够从可靠的概念设计从头开始编写它,以此作为充分理解一切的手段正在上映。显然,我可以深入研究 UnrealIRCD 或 nginx 的源代码并提出解决方案,但我真的更愿意从了解我正在写的内容以及我为什么这样写的情况下来做。因此,我们将不胜感激。
【问题讨论】:
如果您尝试启动 800k 线程,您几乎肯定会遇到问题;您可以使用测试用例来证明这一点。一般的想法是,您应该从程序可用的 CPU 内核数中得出线程数,以降低为每个线程分配上下文和在内核之间切换上下文的成本。多线程是一种优化,与许多其他优化一样,如果将其发挥到极致,不仅会失去好处,还会将其他优化排除在外。首先编写程序以使用单线程,然后将其扩展... 另外,我能给出的三个最明智的话是:使用分析器... 【参考方案1】:我相信您可能会混淆两种不同的编程范式。如果你使用 libevent,每个线程将处理成百上千个连接。有关从哪里开始开发高容量/并发服务器搜索 C10K 问题的更多信息。这是一个开始的页面:
http://www.kegel.com/c10k.html
顺便说一句,如果您想扩展到 800K 并发连接,则不应使用“每个连接线程”模型。
【讨论】:
感谢您的反馈。在对 libevent2 进行了大量挖掘之后,我提出了以下模型: 用户指定在程序开始时预加载的“事件基线程”计数。每个“事件基线程”都有一个与之关联的事件基并启动事件循环。当连接进入时,我将连接事件库旋转到线程上的每个线程/事件库。这似乎工作得很好。我用“每个连接的线程”进行了测试,在大约 20k 连接之后它太可怕了。从那以后,我实现了一个带有代理的调度程序来处理所有事件。以上是关于线程、事件循环和大量连接和并发的主要内容,如果未能解决你的问题,请参考以下文章