系统设计 - 异步I/O模型及异步编程 Ⅱ - 从C10K问题到C10M问题
推动互联网发展的技术挑战
C10k问题
互联网在20年前还并不像现在这样有大规模的应用,在当时还没有现在的分布式、微服务这样的系统设计;
大家的注意力还都放在如何提升单台服务器性能,如何榨干硬件的最后价值上,当然这背后的推动力其实也是成本的考量;
在1999年 Dan Kegel 提出了 C10k问题:
简单来说就是在当时1200美元能够购买的单机硬件成本配置下(具体配置见下表)如何使得单机能够同时处理10k个连接请求。
计算资源 | 配置 |
---|---|
CPU | 1 core - 1000MHZ |
RAM | 2G |
Ethernet | 1Gb/s |
Disk | HDD |
当然 Dan Kegel 在1999年的时候已经在 ftp 服务站点 cdrom.com 上实现了这个目标。并在它的C10k问题的主页上给出了一些实现 C10k目标的建议。
影响C10k性能的限制
文件描述符(File descriptor)打开数量限制
在 Unix-like 的操作系统中这个最大文件打开数的配置由ulimit
或setrlimit
设置。
CentOS这个值的默认值为:
1 | # cat /proc/sys/fs/file-max |
这个值的含义是每个登录的用户会话可以打开的FD数;
当然这个数会与Linux发行版有关,这个值在Ubuntu下为 176772
在Linux上修改FD最大打开数
下次机器重启前修改有效
$ sudo sysctl -w fs.file-max=500000
检查修改是否生效:$ cat /proc/sys/fs/file-max
修改永久有效
$ sudo vi /etc/sysctl.conf
然后添加下面配置fs.file-max=500000
如果希望不再重新登录后生效:$ sudo sysctl -p
更详细的配置参看这个 Post How to Increase Number of Open Files Limit in Linux
线程限制
// TODO
解决C10k问题的建议
kenel 层面
zero_copy
使用基于epoll()/IOCompletionPort的IO模型
尽可能的使用带有缓存的IO方法
从C10k问题的角度看Nginx
使用上述方式解决C10K问题的典型WebServer代表就是Nginx,使用了以事件驱动(event-driven)、异步非阻塞的多路复用的I/O模型 epoll/kqueue。
更多Nginx架构信息请查看NGINX architecture, by Andrew Alexeev
如果你对Nginx还不太熟悉可以参考下这篇官方文章 Inside NGINX: How We Designed for Performance & Scale
官方的这篇文章也从C10K的角度提出了Nginx性能调优的建议 Tuning NGINX for Performance
经过调优后的 Nginx 可以达到 10K并发连接 / 工作进程 的性能,我们都知道 Nginx 是根据宿主机器的CPU核心数进行工作进程的分配,所以这样的性能也就等同于 10k并发连接/核心 。
C10M问题
恰恰是C10k问题提出的10后Robert David Graham在Shmoocon提出了C10M的问题:
10年的硬件发展水平使得硬件的计算能力有了10k倍数的提升,那么在1200美元购置的标准硬件下如何使得单机能够处理10M的连接请求。
计算资源 | 配置 |
---|---|
CPU | 8 core - 1000MHZ |
RAM | 64G |
Ethernet | 10Gb/s |
Drive | SSD |
事实上在硬件的发展速度上来看,系统的scalability的限制已经不在硬件设备上,而是在软件,特别是操作系统上。
其实 C10k提出10年后的2010年,大家已经将注意力从单体性能转移到如何通过分布式和微服务的方式提升整体服务的性能,那为什么还会有人在意单体的性能呢?
原因就是虽然通过scale out 的方式可以提升connection per second 的性能,但是很不幸,这个提升并不是线性的关系,而是低于线性增长的关系($O(log^n)$ ?) 详情参见YouTube -Shmoocon 2013 - C10M Defending The Internet At Scale
所以大家又同时开始关注单机层面的性能提升,继续薅“单机”羊毛,不过这一次与C10k的那次不同,不再从I/O模型的层面思考如何改善kernel部分的性能,而是考虑将数据层的工作全部交给应用程序,将控制层的工作交给内核;这一就是 The Secret To 10 Million Concurrent Connections -The Kernel Is The Problem, Not The Solution 这篇著名博文核心主张
The kernel isn’t the solution. The kernel is the problem.
Which means:
Don’t let the kernel do all the heavy lifting.
C10M并发连接挑战意味着什么
- 1千万的并发连接数
- 1百万个连接/秒——每个连接以这个速率持续约10秒
- 10GB/秒的连接——快速连接到互联网
- 1千万个数据包/秒——据估计目前的服务器每秒处理50K的数据包,以后会更多。过去服务器每秒可以处理100K的中断,并且每一个数据包都产生中断
- 10微秒的延迟——可扩展服务器也许可以处理这个规模,但延迟可能会飙升
- 10微秒的抖动——限制最大延迟
- 并发10核技术——软件应支持更多核的服务器。通常情况下,软件能轻松扩展到四核。服务器可以扩展到更多核,因此需要重写软件,以支持更多核的服务器。
实现C10M的思路
网络包 Scalability - 绕过Unix TCP网络栈的限制,实现自己的网络驱动
当然这个思路并不是从零开始,目前支持你编写自己的网络驱动,直接将数据包发送到你的应用程序的开发工具或开发平台主要有下面3个:CPU多核 Scalability
内存 Scalability
总结
//TODO