Linux 的最大进程数大多是 32768,那么以 Linux 构建的服务器是使用哪些技术同时处理百万级的传入连接的呢?
RT。比如说一个工作在最前端的 web 服务器,总是需要有一个进程去监听一个固定端口的(比如 80 端口)。为了提高整个服务器的健壮度,服务器 accept 了一个连接之后,可以立刻 fork 出子进程来处理这个连接。
但是大型服务总有高并发的需求的,仅仅是简单的 fork 轻而易举就可以超过 32768 个进程了,求解?各个服务器在底层原理上,实际上是如何如理传入连接的呢?
BTW:我知道可以使用单个或者少量进程然后简单进行 I/O 复用来处理服务,但是……嗯,我了解到的一切大型网站并不是这么简单处理的……但是我也找不出个具体的所以然来……
170724-22:31 问题补充:
我的希望了解的是作为最底层的socket连接上第一个IP之后(通常是DNS第一层解析得到的IP),发生了什么事情呢?
因为不论上层理论是怎么样的,在所有的实现中,总会有第一个 TCP socket 连接到一个 IP,而这个 IP 应该是一个现实存在的操作系统上的一个进程。
总会存在一个可能,就是同时有大量连接访问这个进程的(假设这个进程称为A
),那么这个进程要怎么处理高并发呢?
我只了解一种方案,就是使用 I/O 复用。而基础的 I/O 复用是基于单一进程的,这样的服务器架构,对软件设计要求很高,因为单进程,一旦有一处地方崩溃,就会导致该进程上所有服务挂掉。
比较安全的做法,是 I/O 服用加上进程分流,也就是进程A
调用accept()
接受了一个 TCP socket 之后,立刻通过 fork()
创建新的进程,将这个连接分流出去。
想到了这个思路之后呢,我就遇到题目中提到的这个问题了:Linux 进程数是有限制的啊!
于是就有了我的这个问题——这要怎么解决呢?
170726-0913 感谢:
感谢各位大大的回答!协程、线程池、异步 I/O 都是本人熟悉的领域。不过负载均衡就不是了。看起来我要从这个方面去学习,特别是了解一下 nginx 的原理吧~~~
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
线程,协程/(go,lua,tornado,erlang),事件驱动(epoll,kqueue),NIO(netty),异步(nodejs)
以上概念有重叠/层级关系,但是都是为了解决高并发问题,而且除了线程,基本都能很好的解决并发问题。
百万级连接,我默认你说的是TCP连接,而且必须是单机百万连接。
C10K problem
为了解决早期服务器单机1万个并发连接的问题。
百万级连接可以说是C1M,但是为了搜索方便,以下统称C10K,你也可以去搜一下C100K,C1M,C10M等相关资料。C10K的资料最多,参考价值最小。
协程:
协程就是相当轻量级的线程。
以linux为例,以前的tcp服务器收到一个连接,一般是开两个线程,一个只用于读取数据,一个只用于写入数据。高级点的,搞个线程池。
那么这就简单了,erlang,go语言层面支持开启协程进行处理,于是一些服务器只能开65535个线程(参考资料:
/proc/sys/kernel/threads-max
),但是换成协程瞬间上百万。有协程的语言就很简单了,,一般限制协程数的因素是:文件描述符(决定)> 内存(大) > CPU(小)
很简单,以Go为例,一个协程消耗4K内存。(仿佛已经改到了2K)。C10K下只是协程本身就要消耗40M*2=80M内存。还有其他杂七杂八的消耗,除非你的业务非常消耗CPU,不然瓶颈是内存。
不过,如果你的瓶颈在CPU的话,那应该考虑proxy支持高并发,或者采用其他负载均衡手段解决了。这个东西80%的锅可以丢给负载均衡和proxy了。
吹了这么久,其实决定性因素是文件描述符。
文件描述符只有10000个的时候,是不可能同时对10001个连接提供服务的,用之前需要修改文件描述符。
事件驱动
epoll是这里的代表。
nginx能打翻apache的垄断很大程度可以归功于epoll。
同时nginx自身还有其他手段,例如线程池等。
NIO
非阻塞IO也是解决高并发的杀手锏,但是实际上,我们看到的NIO,包括java的netty(java.nio)和nodejs的NIO,其实后台其实还是epoll。
对,java也能支撑百万并发,但是你得用netty或者mima。
异步
与其说异步是个方案,不如说异步更像是个方法,异步IO(NIO)等都是异步。
proxy
proxy本身就是个解决方案,包括硬件F5,软件LVS以以及许许多多的proxy等,有些proxy非常薄,只管转发,鉴权什么的一概没有。
道理很简单,任何一种方法,都很容易实现C10K。我后端实现10K,proxy层稍微做一下,或者用lvs,都能很轻松实现这个问题。
百万连接的根本目的是实现服务用户,proxy本身的目的就是能把复杂问题抽象成只用简简单单加机器就能解决的问题。
其他
有些奇奇怪怪的hook。
有些人提出了,性能还能提升XX倍,但是内核得背锅。
内核表示:你要你行,那我背呗,于是就有了dpdk。
补充
如果你说的百万级连接是http连接,那么第一我似乎没见过这个说法,第二推荐研究负载均衡去……
首先现在的大型网站肯定是分布式的,背后是有N个集群的。不可能只靠一台机器来扛很大的流量。
而且题主说的多进程的并发模型是最最原始的,以现在比较常用的nginx来说,nginx的进程数是固定的,通过I/O多路复用来实现高并发。
多级负载均衡,从解析到硬件到分布式,比如 cdn,dns解析,lvm,nginx代理等等。其中lvm和交换机或者路由等硬件可以做到分配远远大于 linux 对进程数和文件数的限制。
最前端不是web服务器,而且一些类似负载均衡或者智能DNS的服务,主要用于分流处理
我印象中64位系统可打开文件描述符的最大个数是65536 再有任何服务器都是有负载均衡的 提高并发的根本是扩相同型号的机器而不是看单一的机器的性能