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

~~~ 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。多看看其他框架,服务集群的设计。
但是!!
当你成长后,一切模式、设计,都是扯淡~~!
模式是死的,需求是变动的,人和思维是活的!
只有根据实际需求,具体设计!具体定制!!!
(还记得无字真经吗~~)

(貌似扯远了,已经不是服务器高并发了,而是高并发后端系统集群了。。。-_-! )

你可能感兴趣的:(epoll编程,如何实现高并发服务器开发?)