您的位置:首页 > 编程语言

epoll编程,如何实现高并发服务器开发?

2017-10-27 15:14 211 查看
转载地址:https://www.zhihu.com/question/21516827

1、本系统处理的业务为多客户端接入,一旦接入基本超过8个小时的长连接,但是登陆以后客户端基本不怎么活动,只有客户端触发相关设定事件才会产生活跃通信。
2、查了很多资料,单单多进程是不现实的,但是多线程开发linux系统在线程的数量上是有上限的,如何解决?
3、QQ、SKYPE等的多客户端登陆软件,服务器一般是如何设计开发的?
4、客户端接入时间随机,系统运行初期不会存在同一时间成千上万用户登陆的情况,但是用户一旦接入服务器就会长时间不会断开。
5、能否使用epoll技术跟多线程技术配合开发?HOW?
6、系统开发使用TCP协议。
7、希望大家能给个详细开发框架。





swxlion

分布式架构师,性能优化和高伸缩性系统架构设计

145 人赞同了该回答

~~~ 2017-09-24 增加~~~
评论区里有不少干货,有兴趣的同学可以看看。鉴于我很懒,就不再编辑更新原始回答了。
看了一下,上次编辑是15年7月份,没想到这么长时间了,还有人关注这个问题 :)
以下是原始回答。

~~~ 15年最初的原始回答 ~~~

闲答。
按重要性和基础程度,打乱下顺序吧~~

先回问题,然后说怎么实现。
注:以下数据,均基于亚马逊AWS c3.xlarge 机型。

虚拟CPU:4

内存:7.5 GB

c3.xlarge 配置和价格:
AWS | Amazon EC2
~~~~~~~~~~ 分割线 ~~~~~~~~~~

2、查了很多资料,单单多进程是不现实的,但是多线程开发linux系统在线程的数量上是有上限的,如何解决?

多线程数量限制?有!但这重要吗?想着开着无限的线程,每个线程都在跑?
线程调度是有系统资源开销的!!!!

线程调度是有系统资源开销的!!!!

线程调度是有系统资源开销的!!!!
重要的事情说三遍~~!!!

理论上,如果没有I/O等待等让CPU idle的事情,线程数最好等于CPU核心数目。

线程数最好等于CPU核心数目!!!

线程数最好等于CPU核心数目!!!

线程数最好等于CPU核心数目!!!
重要的事情再说三遍。
举个实际的栗子:

本人负责公司网络框架的架构设计和开发。在4核的 c3.xlarge 虚拟机上,压测框架时,2000 worker 线程的QPS(这里理解为TPS问题也不大)远远低于4个worker线程的QPS!

4个worker线程,再加其他辅助线程,QPS最大每秒35万。2000 worker线程,加同样的辅助线程,QPS最大每秒15万~~!
大部分的时间和其他系统资源都消耗在了线程的切换上~~!这就是为什么单线程的程序在某些情况下比多线程的程序要快~~!(单线程模拟多线程的线程库,不妨参考 state thread:http://state-threads.sourceforge.net。足够简单。)

1、本系统处理的业务为多客户端接入,一旦接入基本超过8个小时的长连接,但是登陆以后客户端基本不怎么活动,只有客户端触发相关设定事件才会产生活跃通信。

6、系统开发使用TCP协议。
目前开的框架,TCP长链接,最大压测链接108万,总 QPS 6万。

服务器也是c3.xlarge。开了18台机器做客户端压,每台机器6万链接(记得要修改 /proc/sys/net/ipv4/ip_local_port_range,不然一台机器出不了这么多链接)。

4、客户端接入时间随机,系统运行初期不会存在同一时间成千上万用户登陆的情况,但是用户一旦接入服务器就会长时间不会断开。

压测,每批次新加6万链接。

5、能否使用epoll技术跟多线程技术配合开发?HOW?

Linux上,必须的!!!

3、QQ、SKYPE等的多客户端登陆软件,服务器一般是如何设计开发的?

没有一般,都是根据具体需求实际定制!!!

没有一般,都是根据具体需求实际定制!!!

没有一般,都是根据具体需求实际定制!!!
但分布式、去中心化、无状态化、一致性哈希、……,都是必须的~~~!

但分布式、去中心化、无状态化、一致性哈希、……,都是必须的~~~!

但分布式、去中心化、无状态化、一致性哈希、……,都是必须的~~~!
(说了好几个三遍,累死了~~~喝点水~~)

不妨上网搜搜,将网络架构,服务器架构的演化。中小型公司按那些套路来,基本都能搞定。图太多,说起来太罗嗦。都是重复劳动,我就不写了,请自己搜。
你问大公司?请参考第一句话:没有一般,都是根据具体需求实际定制!!!

补充一点:网上搜的,都会对memcached、redis 等有很大的依赖。但我上家公司,也用,很重要,但只是给PHP端用。后端服务集群全用专用缓存~!!

专用缓存~~!含逻辑~~!自己开发~~!

专用缓存~~!含逻辑~~!自己开发~~!

专用缓存~~!含逻辑~~!自己开发~~!

又说三遍。

撑住1.6亿注册用户。

7、希望大家能给个详细开发框架。

框架?是参考架构设计吧?
框架有很多,比如ICE,Facebook Thrift、Apache Thrift 等~~

注意,后两个thrift不完全相同~~!!!
然后怎么做:

没有固定的套路!!!只有要注意的要点!!!

没有固定的套路!!!只有要注意的要点!!!

没有固定的套路!!!只有要注意的要点!!!
又是三遍。
要点:

尽量少的线程切换

尽量少的共享冲突

尽量无锁

工作中的线程数尽量等于CPU核心数

尽量没有等待时间片的线程

逻辑尽量简化,避免不必要的封装和转发

工程不是学术,OOP要给简单易用高性能好维护让道~~!

(就是ICE概念多,太复杂,上家公司才开发了自己的框架。就是因为Facebook Thrift 太罗嗦,一个异步都要绕好几道弯,链接还和CPU核心绑定(如果就一个链接,10万QPS,你会发现就一个核忙得要死,其他核心都在吃干饭~),现在公司才决定自己开发网络框架。)

EPOLL:Edge Trigger、OneShot!!!

不要在epoll_wait()线程中用太长时间处理非epoll_wait()的事情。

能用atomic的就不要用mutex(这是C++11的事了)
上面就不三遍了,太多太啰嗦~~~
~~~~~~~~~~~~~ 7月3日追加 ~~~~~~~~~~~~~~
感谢
Irons Du曾凌恒每天不吃冰淇淋 的评论,涉及到一些昨天忘了的事情。

PS:今次不三遍了~~:)
追加要点:
A. 数据库

数据库一定要分布。

如果有好的数据路由中间层服务,或者好的集群管理器,或者好的Sharding服务,是MongoDB还是MySQL完全不重要~~~!

如果使用MongoDB,需要注意查询 API 的where处理(自定义Javascript查询条件)。C API的 where 处理非常非常低效(至少去年还是这样。今年因项目的关系,没有跟进)

数据库一定要分库分表。

分表强烈建议使用Hash分表,尽量避免按区段分表。

Hash分表设计好了,要扩容也非常容易。区段分表貌似扩容很容易,但时间长了,你的热点数据分布就极其不均匀了。

分库分表,尽量异步并发查询(靠你的数据路由中间件了。当前两家公司都是自己开发的,外面的吹得太凶,不实用。)

除支付业务外,严格禁止联合查询、复合查询、事务操作!!!!

(支付一会单说)

分库分表,表都不在一台机器上了,联合查询、复合查询、事务操作必然失败~~~!

联合查询、复合查询、事务相关的操作请由中间层服务配合完成!!!

PS:MySQL等,联合查询、复合查询、事务操作,效率极低~~极低~~~!!!还会因为锁表时间过长而阻塞其他查询~~!!

支付的逻辑设计并分解好了,可以不用事务完成。要用事务,请确定相关的表均部署在同一台数据库实例上!!!
B. 去中心化、无状态:

高弹性架构这是必须的。

尽量将状态剥离成一个单独的状态服务(也是分布式集群),其他业务逻辑全部变成无状态的。状态信息请通过状态服务处理。

无状态的一般去中心化都很简单。无外乎一致性哈希、随机、轮转等等。

去中心化也是确保无单点故障!!!

如果非要有中心,请尽量选折以下两个方案:

1. 中心如果很简单,请确保在崩溃/杀死后,1秒钟内能立刻复活启动~~~

2. 中心改为管理集群,自动选举主核心。当原主核心失效后,新的核心自动接管当前集群网络。
C. 协议:

不要使用XML!!!这都不想说了,让我看到就是千万只神兽在胸中蹦腾~~!!!

如果文本,请使用JSON。如果二进制,请使用JSON对应的二进制化协议。BSON嘛~~持保留态度。

如果需要协议的灰度升级,如果在协议灰度升级时不想实现两套不同版本的接口,请远离使用IDL的协议/框架!!!

这也是这两家公司弃用 ICE和Facebook Thrift 的原因之一。
最后,如果你是初入行者,不妨多看看前面其他大拿推荐的资料,看看Reactor模式,看看Proactor。多看看其他框架,服务集群的设计。

但是!!

当你成长后,一切模式、设计,都是扯淡~~!

模式是死的,需求是变动的,人和思维是活的!

只有根据实际需求,具体设计!具体定制!!!

(还记得无字真经吗~~)
(貌似扯远了,已经不是服务器高并发了,而是高并发后端系统集群了。。。-_-! )
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: