如何实现单服务器300万个长连接的?-来自知乎的经典问答
2016-05-03 17:09
513 查看
看到一篇文章说“最终我们采用了多消息循环、异步非阻塞的模型,在一台双核、24G内存的服务器上,实现峰值
维持超过300万个长连接。”
很疑惑,这是吹牛还是真的做到了?
什么是“多消息循环、异步非阻塞”?有什么特点?
用单台服务器实现高连接数,和使用多台服务器实现高连接数,哪种成本更高?修改
这……我能说也不怎么困难咩?实际在去年操作过一次,并且看过一篇文章(研究eurasia socket内存使用量的时
候翻到的最后会单独列出),我的成果是2G内存双核18W左右的并发连接。
1. 事件驱动,这个只是为了IO和CPU异步,让CPU从IO等待中解放出来,这样就能在CPU循环中往死里accept连接了
,nginx就靠这个把apache玩死的,nodejs的快不仅仅因为这个,语言层的magic就扯远了。
2. 利用双核,2个核就2个进程,一个进程一个事件驱动核(epoll,select啥的),增加链接吞吐。
3. 参数调优,这才是最重要的一步,一个Socket连接默认是有内存消耗的,我不记得Python的Socket占用是4M还
是多少来着了,当然这个也可以调优,eurasia的作者沈大侠说过可以搞到2M来着?当然这对于一个24G的服务器来
说300w还是搞不定的,但是就送TCP本身来分析的话,tcp_rmem/tcp_wmem,这2个系统tcp读写缓存默认都很高,拉
低到4k,然后把tcp_mem也得改下,这个说起来太麻烦,man一下就有了,总的来说就是得拉高High值
4. 网卡要给力,端口给足,句柄加高。
参考文献:100万并发连接服务器笔记之1M并发连接目标达成
从我的测试和此文的结论来看,他在7.5G左右实现了1M并发,24G到3M差不多,我那么挫的水平2G 18W,24G怎么说
也能上2M啊,而且如果仅仅是推送,业务层逻辑复杂度不强,等于就是个Proxy所以恩。
至于单台和多台之间的选择,追求技术的,单台你屌你牛逼,追求稳妥Crash也不会造成太大影响还想在推送一层
玩点花样用点动态语言的,多台不二选择。
不是吹牛,理论上完全可以达到。
(以下参考值皆是Linux平台上)
1,Linux单个进程可以维持的连接数(fd)理论值是通过ulimit -a设置,或在server内使用setrlimit()设置,具体
最大是多少?我看我的64机上是64bits的一个数值,所以,权且认为理论上是2^64-1。 anyway,几百万不是问题
。
2,TCP连接数。因为是Server端,不用向系统申请临时端口,只占fd资源。所以tcp连接数不受限制。
3,维持连接当然需要内存消耗,假如每个连接(fd),我们为其分配5k字节(应该足够了,就存放一些用户信息
之类的)。这样是5k*3000000=15G。 文中有24G内存,应该也足够了。
================================
下面我们说下文中提及的 多消息循环、异步非阻塞。
先说异步和非阻塞吧。权且认为这俩是一个概念。都是指的IO的异步和非阻塞。
1,异步+非阻塞的话,Linux上必然是epoll了。
原理上简而言之吧,异步就是基于事件的读写,epoll同时监听所有的tcp连接(fd),当有哪些连接上有了事件(
读、写、错误),就返回有事件的连接集合,然后处理这个集合里的需要处理的连接事件。这儿就是基于事件的异
步IO。
非阻塞。 在得到有事件的tcp连接集合之后,逐一进行读(写)。分开来说,需要读的fd,其实数据已经到OS的
tcp buffer里了,读完直接返回,CPU不等待。(返回EAGAIN,其实就进行了几次memcpy); 需要写的连接,同样
,其实是把数据写到了OS的tcp buffer里,写满为止。。不会等待对方发来ACK再返回。这样,其实这里CPU基本上
只进行了一些memcpy的操作。。即便同时几十万连接有事件,也是瞬间处理完的事。。。然后,CPU再进行异步io
等待(epoll_wait())。
当然这儿要充分利用多核,最好将io线程和work线程分开。
2,多消息循环。。这个应该是他们内部的概念。我个人猜测是异步的消息协议。
举例子,传统的TCP连接是一问一答,如HTTP。
如图,客户端在发送A和发送B之间,CPU就纯等待。服务器在回复A之后,也是纯等待B包的到来。。这样的话。TCP
吞吐量很低。
异步协议就是读写完全分开,无需等待(当然,在包内需要自行对应包的ID来识别对应请求包和回复包)。如图
这样的话,双方在任一时刻,都尽最大努力的发包。充分利用tcp连接。使单条TCP连接吞量直线上升。而且,如果
其中有一个包处理的极慢,丝豪不影响其他包的回包。
大体推算一下流量,因为300万的客户端均是手机客户端,,假如每个人每天平均收到500条push信息。300万
*500=1500000000, 1500000000 /一天86400=17361。一个封装的不错的server每秒进行2W次IO是很轻松的事。
最后说单台Hold大量和多台Hold小量的区别。
成本上肯定是多台的硬件本高了。。但是,这个量级,从架构上,绝对是多台更加合理。我们假如,每个连接有一
个用户认证的过程 ,用户认证时要去数据库(或其他类似db)查询用户信息,当你升级服务重启时,300万用户瞬
间断开,客户端会重连;再次启动之后,300万用户同时连接,同时请求库。。然后,杯具了。。。
刚好搜索长连接的时候看到这个问题,就来回答一下,算做是知乎的处女答。
首先理解多消息循环、异步非阻塞从程序设计角度来说是两个层次的东西。
1.多消息循环指的就是利用到epoll或者select来做的IO多路复用机制
2.异步非阻塞是指利用到下层的IO多路复用做的基于事件触发方式的一种设计方式
其实现在的异步模型大同小异,大致过程如下(分三层,一二层就是上面所说的两个层次):
1.(最重要的)维护一个事件反应堆,用epoll或者select或者kqueue来做,反应堆的作用就是用同步的方式处理
异步问题,在反应堆上注册好事件后如果相应的事件发生,就调用其回调函数,一般情况下反应堆是一个进程内全
局唯一的。
2.上层的buffer,维护一系列的buffer用于管理每一个连接的数据,可以把buffer看做是一个对象。一般在一个连
接到达的时候分配一个buffer对象,然后上层的连接注册事件的时候是注册到buffer上,buffer再注册到反应堆中
。
3.就是一个个的连接对象,把每一个来自外部的连接都抽象为一个具体的对象,用于管理每一个连接,其中这个对
象就包含了上面所说的buffer对象和其他一些状态。
处理并发的过程就是这样的:
1.为监听套接口在反应堆注册一个事件,此事件发生调用对应的回调,一般情况是accept这个连接,然后为这个连
接创建连接对象,统一管理。
2.为此连接创建buffer对象,并注册对应的读写错误事件的回调(上层对于buffer的读写事件回调都是业务层来控
制的了).
3.在加入监听队列后是离散的,准确来说epoll中是由一颗红黑树维护的,每一个事件的先后顺序跟它达到的顺序
有关。
4.维护了众多的连接对象,也就是这里的并发情况了,如果有事件发生会调用回调来处理,理论上无阻塞情况减少
了很多CPU的wait,这部分时间用于处理真正的业务,所以异步模型能够带来很高的CPU处理能力,减少等待,单位
时间处理的事件越多,从外部来看并发就很高,实际上也是一个串行的工作状态,但是串行过程没有等待。
若水、槐槐、管显笋 等人赞同
不说清楚具体每秒收发包数量以及包大小就是耍流氓!300万静态连接纯吃内存谁都搞得来,3000连接每秒10000请
求和300万连接每秒100请求你说谁消耗大?同样每秒100请求,每个请求广播给10个客户端和广播给100客户端你说
哪个消耗大?关键数据不说,还分析啥?
这个模型现在被 nginx/node.js 采用,建议你仔细研究一下相关文档、代码。
单机高连接数好与不好跟业务有一定的相关性,当然跟“钱”也有关系。
如果内存可以更多,还可以维持更多的连接数,无需吹牛。
2013年11月4日更新:
这两天发现还有不少朋友对这个话题有兴趣,再细说一点。
消息循环。前面提到过 nginx/node.js 都是采用的 IO 事件触发的消息循环,如果不了解可以直接看代码。
多消息循环。在多核 CPU 的服务器,是一个 IO 口上的事件用多个进程处理,充分利用多核的运算能力。每个进
程运行一下独立的消息循环,一般来说,进程数据与 CPU 核数相同。
异步非阻塞 就更容易理解了。CPU 不同步读写 IO,减少 CPU 等待时间。在业务层面的通讯也全部采用异步模型
。
正如我前面提到的,这些模型,在 nginx 上几乎都能找到代码。最近比较流行的 node.js 也有大量异步模型。
2014/06/19 更新:
最近我们用 Erlang 实现了了一个版本,维持长连接的效果也很好,开发时间成本低。
内存足够多,文件描述符限制足够大即可。不需要啥高端技术。
1. IO多路复用技术:使用一个线程来检查多个文件描述符的就绪状态
2.长连接
3.异步接收和发送:异步双工,就是开启两个线程分别处理读、写
4.参数调优(我还木有查到QAQ)
维持超过300万个长连接。”
很疑惑,这是吹牛还是真的做到了?
什么是“多消息循环、异步非阻塞”?有什么特点?
用单台服务器实现高连接数,和使用多台服务器实现高连接数,哪种成本更高?修改
这……我能说也不怎么困难咩?实际在去年操作过一次,并且看过一篇文章(研究eurasia socket内存使用量的时
候翻到的最后会单独列出),我的成果是2G内存双核18W左右的并发连接。
1. 事件驱动,这个只是为了IO和CPU异步,让CPU从IO等待中解放出来,这样就能在CPU循环中往死里accept连接了
,nginx就靠这个把apache玩死的,nodejs的快不仅仅因为这个,语言层的magic就扯远了。
2. 利用双核,2个核就2个进程,一个进程一个事件驱动核(epoll,select啥的),增加链接吞吐。
3. 参数调优,这才是最重要的一步,一个Socket连接默认是有内存消耗的,我不记得Python的Socket占用是4M还
是多少来着了,当然这个也可以调优,eurasia的作者沈大侠说过可以搞到2M来着?当然这对于一个24G的服务器来
说300w还是搞不定的,但是就送TCP本身来分析的话,tcp_rmem/tcp_wmem,这2个系统tcp读写缓存默认都很高,拉
低到4k,然后把tcp_mem也得改下,这个说起来太麻烦,man一下就有了,总的来说就是得拉高High值
4. 网卡要给力,端口给足,句柄加高。
参考文献:100万并发连接服务器笔记之1M并发连接目标达成
从我的测试和此文的结论来看,他在7.5G左右实现了1M并发,24G到3M差不多,我那么挫的水平2G 18W,24G怎么说
也能上2M啊,而且如果仅仅是推送,业务层逻辑复杂度不强,等于就是个Proxy所以恩。
至于单台和多台之间的选择,追求技术的,单台你屌你牛逼,追求稳妥Crash也不会造成太大影响还想在推送一层
玩点花样用点动态语言的,多台不二选择。
不是吹牛,理论上完全可以达到。
(以下参考值皆是Linux平台上)
1,Linux单个进程可以维持的连接数(fd)理论值是通过ulimit -a设置,或在server内使用setrlimit()设置,具体
最大是多少?我看我的64机上是64bits的一个数值,所以,权且认为理论上是2^64-1。 anyway,几百万不是问题
。
2,TCP连接数。因为是Server端,不用向系统申请临时端口,只占fd资源。所以tcp连接数不受限制。
3,维持连接当然需要内存消耗,假如每个连接(fd),我们为其分配5k字节(应该足够了,就存放一些用户信息
之类的)。这样是5k*3000000=15G。 文中有24G内存,应该也足够了。
================================
下面我们说下文中提及的 多消息循环、异步非阻塞。
先说异步和非阻塞吧。权且认为这俩是一个概念。都是指的IO的异步和非阻塞。
1,异步+非阻塞的话,Linux上必然是epoll了。
原理上简而言之吧,异步就是基于事件的读写,epoll同时监听所有的tcp连接(fd),当有哪些连接上有了事件(
读、写、错误),就返回有事件的连接集合,然后处理这个集合里的需要处理的连接事件。这儿就是基于事件的异
步IO。
非阻塞。 在得到有事件的tcp连接集合之后,逐一进行读(写)。分开来说,需要读的fd,其实数据已经到OS的
tcp buffer里了,读完直接返回,CPU不等待。(返回EAGAIN,其实就进行了几次memcpy); 需要写的连接,同样
,其实是把数据写到了OS的tcp buffer里,写满为止。。不会等待对方发来ACK再返回。这样,其实这里CPU基本上
只进行了一些memcpy的操作。。即便同时几十万连接有事件,也是瞬间处理完的事。。。然后,CPU再进行异步io
等待(epoll_wait())。
当然这儿要充分利用多核,最好将io线程和work线程分开。
2,多消息循环。。这个应该是他们内部的概念。我个人猜测是异步的消息协议。
举例子,传统的TCP连接是一问一答,如HTTP。
如图,客户端在发送A和发送B之间,CPU就纯等待。服务器在回复A之后,也是纯等待B包的到来。。这样的话。TCP
吞吐量很低。
异步协议就是读写完全分开,无需等待(当然,在包内需要自行对应包的ID来识别对应请求包和回复包)。如图
这样的话,双方在任一时刻,都尽最大努力的发包。充分利用tcp连接。使单条TCP连接吞量直线上升。而且,如果
其中有一个包处理的极慢,丝豪不影响其他包的回包。
大体推算一下流量,因为300万的客户端均是手机客户端,,假如每个人每天平均收到500条push信息。300万
*500=1500000000, 1500000000 /一天86400=17361。一个封装的不错的server每秒进行2W次IO是很轻松的事。
最后说单台Hold大量和多台Hold小量的区别。
成本上肯定是多台的硬件本高了。。但是,这个量级,从架构上,绝对是多台更加合理。我们假如,每个连接有一
个用户认证的过程 ,用户认证时要去数据库(或其他类似db)查询用户信息,当你升级服务重启时,300万用户瞬
间断开,客户端会重连;再次启动之后,300万用户同时连接,同时请求库。。然后,杯具了。。。
刚好搜索长连接的时候看到这个问题,就来回答一下,算做是知乎的处女答。
首先理解多消息循环、异步非阻塞从程序设计角度来说是两个层次的东西。
1.多消息循环指的就是利用到epoll或者select来做的IO多路复用机制
2.异步非阻塞是指利用到下层的IO多路复用做的基于事件触发方式的一种设计方式
其实现在的异步模型大同小异,大致过程如下(分三层,一二层就是上面所说的两个层次):
1.(最重要的)维护一个事件反应堆,用epoll或者select或者kqueue来做,反应堆的作用就是用同步的方式处理
异步问题,在反应堆上注册好事件后如果相应的事件发生,就调用其回调函数,一般情况下反应堆是一个进程内全
局唯一的。
2.上层的buffer,维护一系列的buffer用于管理每一个连接的数据,可以把buffer看做是一个对象。一般在一个连
接到达的时候分配一个buffer对象,然后上层的连接注册事件的时候是注册到buffer上,buffer再注册到反应堆中
。
3.就是一个个的连接对象,把每一个来自外部的连接都抽象为一个具体的对象,用于管理每一个连接,其中这个对
象就包含了上面所说的buffer对象和其他一些状态。
处理并发的过程就是这样的:
1.为监听套接口在反应堆注册一个事件,此事件发生调用对应的回调,一般情况是accept这个连接,然后为这个连
接创建连接对象,统一管理。
2.为此连接创建buffer对象,并注册对应的读写错误事件的回调(上层对于buffer的读写事件回调都是业务层来控
制的了).
3.在加入监听队列后是离散的,准确来说epoll中是由一颗红黑树维护的,每一个事件的先后顺序跟它达到的顺序
有关。
4.维护了众多的连接对象,也就是这里的并发情况了,如果有事件发生会调用回调来处理,理论上无阻塞情况减少
了很多CPU的wait,这部分时间用于处理真正的业务,所以异步模型能够带来很高的CPU处理能力,减少等待,单位
时间处理的事件越多,从外部来看并发就很高,实际上也是一个串行的工作状态,但是串行过程没有等待。
若水、槐槐、管显笋 等人赞同
不说清楚具体每秒收发包数量以及包大小就是耍流氓!300万静态连接纯吃内存谁都搞得来,3000连接每秒10000请
求和300万连接每秒100请求你说谁消耗大?同样每秒100请求,每个请求广播给10个客户端和广播给100客户端你说
哪个消耗大?关键数据不说,还分析啥?
这个模型现在被 nginx/node.js 采用,建议你仔细研究一下相关文档、代码。
单机高连接数好与不好跟业务有一定的相关性,当然跟“钱”也有关系。
如果内存可以更多,还可以维持更多的连接数,无需吹牛。
2013年11月4日更新:
这两天发现还有不少朋友对这个话题有兴趣,再细说一点。
消息循环。前面提到过 nginx/node.js 都是采用的 IO 事件触发的消息循环,如果不了解可以直接看代码。
多消息循环。在多核 CPU 的服务器,是一个 IO 口上的事件用多个进程处理,充分利用多核的运算能力。每个进
程运行一下独立的消息循环,一般来说,进程数据与 CPU 核数相同。
异步非阻塞 就更容易理解了。CPU 不同步读写 IO,减少 CPU 等待时间。在业务层面的通讯也全部采用异步模型
。
正如我前面提到的,这些模型,在 nginx 上几乎都能找到代码。最近比较流行的 node.js 也有大量异步模型。
2014/06/19 更新:
最近我们用 Erlang 实现了了一个版本,维持长连接的效果也很好,开发时间成本低。
内存足够多,文件描述符限制足够大即可。不需要啥高端技术。
1. IO多路复用技术:使用一个线程来检查多个文件描述符的就绪状态
2.长连接
3.异步接收和发送:异步双工,就是开启两个线程分别处理读、写
4.参数调优(我还木有查到QAQ)
相关文章推荐
- java-模拟tomcat服务器
- Linux socket 初步
- 小心服务器内存居高不下的元凶--WebAPI服务
- 运维入门
- 「Linux 中国」2018 微信文章排行榜
- 利用开源软件打造自己的全功能远程工具
- Linux5.9无人值守安装
- 数据中心和云未来的十二大趋势
- 用vsftp快速搭建ftp服务器
- Linux快速构建apache web服务器
- 服务器监控策略浅谈
- java socket 注意的地方
- java socket 注意的地方
- 企业批量部署RealVNC远程控制软件
- 如何降低服务器采购成本 原理分析
- 建议的服务器分区办法
- 服务器托管六大优势分析
- Erlang实现的一个Web服务器代码实例
- 服务器技术全面解析