在阅读了著名的C10k文章并在网上搜索了它编写以来的发展情况后,我想知道今天的标准服务器是否有可能使用每个连接一个线程来处理10000个并发连接(可能借助线程池来避免创建/终止过程)。
可能影响问题解决方法的一些细节:
- 输入、中间处理和输出
- 每个连接的长度
- 服务器的技术规范(核心、处理器、RAM等)
- 将该系统与AIO、轮询、绿色线程等替代技术相结合
显然,我不是这方面的专家,所以任何意见或建议都将不胜感激:)
当然。使用每个连接有一个线程的模型,标准服务器可以处理超过10K的并发连接。我已经构建了这样一个应用程序,五年前,它在标准Linux服务器上以每个进程超过5万个并发连接的方式运行。如今,应该可以在当前硬件上运行具有超过250K并发连接的同一应用程序。
只有几件事需要记住:
- 通过使用线程池来重用线程。如果不使用线程,就没有必要终止线程,因为资源使用应该针对峰值负载进行优化
- 堆栈大小:默认情况下,每个Linux线程为其堆栈保留8MB。10K线程的总容量为80 GB。您应该将默认堆栈大小设置为64k到512k之间的某个值,这不是问题,因为大多数应用程序不需要更深的调用堆栈
- 如果连接是短暂的,请使用选项
SO_REUSEPORT
在同一个端点上创建多个套接字,以优化新连接 - 增加用户限制:
open files
(默认1.024)、max user processes
- 增加系统限制,例如
/proc/sys/kernel/pid_max
(默认32K)、/proc/sys/kernel/threads-max
和/proc/sys/vm/max_map_count
(默认65K)
上面提到的应用程序最初设计为只处理2K个并发连接。然而,随着使用量的增长,我们不必为了扩展到5万个连接而对代码进行重大更改。
您可能喜欢最近关于这个主题的后续文章:1000万并发连接的秘密-内核是问题,而不是解决方案。
服务器的常用方法是:(a)每个连接有线程(通常带有线程池),或(b)具有异步IO的单线程(通常具有epoll或kqueue)。我的想法是,这些方法中的一些元素可以而且经常应该组合使用异步IO(带有epoll或kqueue),然后将连接请求交给线程池进行处理。这种方法将异步IO的高效调度与线程池提供的并行性相结合。
我写了这样一个有趣的服务器(用C++),它在Linux上使用epoll,在FreeBSD和OSX上使用kqueue以及线程池。我只需要运行它进行大量测试,做一些代码清理,然后把它扔到github上(希望很快)。