内容梗概
- 从简单到复杂,推演后台服务的底层通信框架的进化过程,包括网络IO模型、多线程模型的选择和组合。
- 推演的最基础模型是IO同步阻塞+单线程模型,然后逐步进化。推动网络框架进化的3个因素是,每秒请求量的增大,并发量的增大,逻辑计算量的增大。
- 本文使用的底层通信协议以TCP为基础,因此所有推演方案不考虑适用于UDP的信号驱动模型和适用于于文件操作的异步IO模型。
- 只考虑同步阻塞、同步非阻塞、IO多路复用。
- 本文不讨论多进程和多线程的区别,在提高cpu利用率上,这两个模型的作用是一致的,因此本文只选择多线程模型进行讨论。
- 本文主要讨论单机网络通信框架的设计演化,不考虑分布式场景下。本文各项性能对比指标也仅指单台服务器的性能。
推演之前,需要一些系统相关数据支撑。
现有的硬件条件,2017年:
- 单台服务器处理网络连接请求数,每秒约10W量级。
- 单机并发处理网络长连接数上限在10W左右(C100K)。
- CPU 单核,3000MHz,一台服务器以24核计,单核每秒亿次运算。
- 抛离单次请求的网络处理过程,单核每秒处理每个请求的业务计算量在0-10000W之间。
最简单的网络通信模型, 同步IO阻塞+单线程
此模型是我们推演的基础模型。
适用场景,最简单的网络请求、处理和返回。每秒处理请求量低,并发处理请求数只有1,计算量小。系统硬件、网络IO都不会构成瓶颈。
实例,各类demo、模拟后台服务的测试服务、大型系统中开发的调试接口、数据接口、监控接口。
开始推演:
-
假如处理单个请求的计算量不变(依然很小),但请求量增大,并发量增大,网络IO成为瓶颈,这种模型是不能满足需求的。因此需要使用 IO多路复用 + 单线程模型。
-
假如 请求量、并发量不变,但是处理请求计算量变大,单核CPU成为瓶颈,这种模型也是不能满足需求的。此时需要使用 IO阻塞 + 多线程模型,利用CPU多核提高计算能力。
-
假如请求量、并发量变大,而且处理单个请求的计算量也变大,这种模型更是不能满足需求,但此种情况比较复杂,下面需要详细论述。不过一般情况下也可以使用 IO多路复用 + 多线程模型。
IO同步阻塞 + 多线程
使用这种模型,则是计算量变大,单核CPU往往成为瓶颈,必须使用多核来提高计算能力,但并发度低。数据举例,24核CPU处理每秒处理请求数小于1W,并发度小于24,请求量小于1000/s。
实例,各类 FastCGI 后台服务、php-fpm,用于机器学习模型计算的服务,图像处理服务。
开始推演:
IO同步阻塞 + 多线程,并发度受限于线程数,不适合处理并发,一旦并发量变高,则网络模型应该改用IO多路复用。
IO多路复用 + 单线程
使用这种模型,请求量大,并发量大,但处理每个请求的计算量小。数据举例,qps 5W以上,并发数高,但单核cpu每秒处理也在5W以上。
实例, redis和memcache的网络模型。
IO多路复用 + 多线程
经过上面的推演,IO多路复用 + 多线程模型应该是推演过程的终点。既能处理大量请求,又能提升并发度,提高CPU的利用率解决计算量大的问题。
实例, 大型网络应用。
总结
无论选择什么样的模型,最终的目的就是提高服务器硬件的利用率,并避免资源浪费。
选择合适模型,必须依据其所在的业务场景,根据请求量、并发量、计算量这个3个指标,选择合适的模型。
问题总结
- 为什么不是所有情况都选择IO多路复用 + 多线程模型,IO多路复用 + 多线程解决了高访问量、高并发、计算量大的业务?
主要是因为在一些非高访问量、非高并发、非计算量大的业务场景下,IO多路复用 + 多线程是一种过度设计,容易造成资源浪费。
-
为什么同步IO非阻塞并没有在推演过程中使用?
非阻塞的编码,会让代码逻辑复杂,一般不会使用。