C: epoll和多线程

14

我需要创建一个专用的HTTP服务器,计划使用epoll系统调用,但是我想要利用多个处理器/核心,我无法想出架构解决方案。 目前我的想法是:创建多个带有自己epoll描述符的线程,主线程接受连接并将它们分配给线程的epoll。 但是否有更好的解决方案?哪些书籍/文章/指南可以让我了解高负载架构?我只看到了C10K文章,但大多数示例链接都已失效 :( ,而且没有深入研究这个主题的书籍。

谢谢回答。

更新:请更具体一些,我需要材料和示例(nginx不是一个示例,因为它过于复杂,并且有多个抽象层来支持多个系统)。


1
嗨,丹尼尔,我想知道这个项目进展如何。我也在研究这个主题,我认为我的事件驱动服务器概念现在可能有点薄弱。据我所知,如果我们有一个事件驱动的后端(比如使用 epoll),每个被调用的函数都必须是非阻塞的...也许是我的设计问题,但是每个请求都会进行数据库调用...如果由于某种原因该调用变慢,同时发出请求的所有其他客户端也会因等待数据库响应而受到影响。我可以创建一个线程...但这违背了初衷。 - Begui
4
实际上它已经完成了,很久以前就使用了libev :) 我的应用程序中仍然有一些函数会阻塞,只是它们的阻塞时间非常短。但是像数据库查询、I/O操作(特别是当它们非常密集时)这样的事情应该是非阻塞的。在我的情况下,我正在使用带有异步驱动程序的mongodb,因此在使用数据库时没有任何阻塞。对于我无法使其异步化的事情(例如ImageMagick图像处理和CSS/JS最小化器),我确实有线程池,但它们通过队列操作,并由epoll(自己的队列实现)进行监控。 - Daniel
3个回答

14

请检查libeventlibev源代码。它们易于阅读,已经是一个很好的基础设施可供使用。

此外,libev的文档提供了许多各种可靠策略的示例。即使您喜欢直接编写epoll(),这些示例也可以带来多种见解。


从我所看到的,libevent是单线程的,但非常高效。目前找不到libevent+多线程的示例,但正在进行谷歌搜索... - Daniel
1
是的,它们都处理多线程,检查多事件循环注释。 - Javier
如果你指的是Steven Grimm在libevent主页上的解释,那么它的服务器已经挂了 :( - Daniel
libev文档 中还有更多内容,它特别提到了如何在多线程应用程序中使用,通常使用“每个线程一个事件循环”的设计。 - Javier
libev 的文档更加详细,我使用 libev + 多线程完成了 15k 次请求。谢谢 :) - Daniel

13

我的想法是:创建多个具有自己epoll描述符的线程,主线程接受连接并将它们分配给线程的epoll。

是的,这是目前最好的方法,也是Nginx的实现方式。线程的数量可以根据负载和/或机器上的物理核数增加或减少。

额外线程(超过物理核心数量)和事件之间的权衡是延迟和吞吐量。线程提高了延迟,因为它们可以预占式执行,但通过上下文切换和线程创建/删除所产生的开销,以牺牲吞吐量。事件提高了吞吐量,但缺点是长时间运行的代码会导致整个线程停止。

第二个最佳方法是Apache2使用阻塞线程池。这里没有事件处理,因此实现更简单,线程池意味着不会不必要地创建和销毁线程,但它无法真正与像您尝试实现的线程/异步混合或Nginx一样良好的实现相竞争。

第三个最佳方法是仅使用异步事件处理,如Lighttpd或Node.js。如果服务器上没有进行大量处理,则很好,但是如前所述,单个长时间运行的while循环会阻塞整个服务器。


-3

除非你有一个太比特的上行连接并计划从单个服务器服务10000个并发连接,否则请忘记epoll。这只是无端的非可移植性;poll或者甚至select同样好用。请记住,到了太比特上行连接等成为标准的时候,你的服务器也会足够快,以至于你仍然不需要epoll

如果您只提供静态内容,请忘记线程并使用Linux的sendfile系统调用。这也是非标准的,但它至少提供了巨大的实际性能优势。

还要注意,其他设计决策(尤其是过度复杂性)将更多地影响您的服务器能处理多少负载。例如,只需看一下谦逊的单线程、单进程thttpd在静态内容上的性能,就可以击败Apache和朋友们——根据我的经验,甚至在传统的cgi动态内容上也是如此!


1
自2005年以来,服务器的速度并没有显著提高。大约4GHz左右似乎是极限。 - slebetman
1
我仍然没有看到epoll的令人信服的论据,只有大量localhost基准测试等内容。而且我已经看到了许多不喜欢它的原因:各种写服务器/应用程序的人使用epoll(因此仅在Linux上工作),而他们只需要处理2-10个文件描述符... - R.. GitHub STOP HELPING ICE
3
说实话,一个人不会使用epoll来监听10个套接字,但是因为它也可以与timerfd和更重要的eventfd一起使用。它使得在POSIX下最愚蠢、设计不良的事情之一变得简单、直接、易于管理。作为额外的好处,epoll比使用fd-set管理宏和模糊限制的select稍微快一些,而且相对不那么笨拙。正如你所说,这可能并不重要,但也不是错误。 - Damon
@Damon:全是伪命题。timerfdeventfd与普通的标准poll同样有效,但如果你正在使用它们,那么你肯定做错了什么。如果您有短暂的文件描述符(因为每个添加/删除都是系统调用而不是简单的内存写入),则epollpoll慢得多。 - R.. GitHub STOP HELPING ICE
直到您达到至少1000个套接字,系统调用的成本才比从用户空间复制poll文件描述符列表更高;对于select,阈值可能更接近10000(但当然,select在其他方面也很糟糕,我建议不要使用select)。我认为您的“不寻常情况”实际上是大多数网络流量的不寻常情况。常见情况是大量瞬态连接(HTTP)或少量持久连接。对于具有大量持久连接的IRC之类的东西,epoll更有意义,而不是通常情况。 - R.. GitHub STOP HELPING ICE
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接