文章目录
  1. 1. C10k problem的解决方法
    1. 1.1. Serve one client with each thread/process, and use blocking I/O
    2. 1.2. Serve many clients with single thread, and use nonblocking I/O and readiness notification
    3. 1.3. Serve many clients with each thread, and use nonblocking I/O and readiness notification
    4. 1.4. Serve many clients with each thread, and use asynchronous I/O
  2. 2. C1000k problem
    1. 2.1. 协程
  3. 3. 参考

所谓的C10k problem指的是单台服务器要同时支持并发10K量级的连接,这些连接可能是保持存活状态的。

C10k problem的解决方法

C10k problem的最大问题是:设计不够良好的程序,其性能和连接数和机器性能的关系是非线性的。
一个没有考虑过C10k problem的基于select()函数的程序能在一台旧服务器上很好处理1000并发的吞吐量,但是它在2倍性能的服务器上处理不了2000并发的吞吐量。
因为在策略不当时候,大量操作的消耗和当前连接数n成线性关系。比如说select()函数的策略我的程序阻塞在select()上,然后select()函数会自己去轮询socket连接,发现socket连接有事件发生的时候,才通知我的程序,然后我的程序要加上if条件判断来判断一下是哪个socket触发了事件。这种策略就决定了当socket连接很多的时候,select()就要做更多的轮询,同时我的程序也就需要做更多的判断。也就是说当有一个socket描述符被触发的时候,2000并发的服务器所消耗的资源比1000并发的服务器要多,所以大量操作的消耗和当前连接数n才不是线性关系。

我在《socket连接池SocketPool分析(八): 并发服务器》上列举了很多的并发服务器的编程方法。

下面是常用的经典策略:

Serve one client with each thread/process, and use blocking I/O

启动多个线程,每个线程连接一个客户端,采用阻塞I/O。这种策略很难满足高性能程序的需求,好处是实现极其简单,容易嵌入复杂的交互逻辑。如果是C10K就要创建1万个线程,那么操作系统是无法承受的。如果是采用分布式系统,维持1亿用户在线需要10万台服务器,成本巨大,也只有Facebook,Google,雅虎才有财力购买如此多的服务器。

Serve many clients with single thread, and use nonblocking I/O and readiness notification

单线程服务多个客户端,使用非阻塞I/O,并且是事件就绪通知。这就是reactor模式。
Epoll就是为了解决C10K问题而生。使用Epoll技术,使得小公司也可以玩高并发。不需要购买很多服务器,有几台服务器就可以服务大量用户。Nginx,libevent,node.js这些就是Epoll时代的产物。

Serve many clients with each thread, and use nonblocking I/O and readiness notification

启动多线程,每个线程服务多个客户端,使用非阻塞I/O,并且是事件就绪通知。这是one loop per thread模式。

Serve many clients with each thread, and use asynchronous I/O

启动多线程,每个线程服务多个客户端,使用异步I/O
异步I/O需要使用操作系统的异步I/O接口。linux kernel 2.6(CentOS 6.5)仅仅提供了对AIO的有限支持—仅仅支持文件系统。Windows对AIO很友好,有 IOCP 队列和 IPCP 回调两种方式。所以在linux作为操作系统的时候,还是选择one loop per thread模式。

C1000k problem

随着技术的演进,epoll 已经可以较好的处理 C10K 问题,但是如果要进一步的扩展,例如支持 1000k 规模的并发连接,原有的技术就无能为力了。

什么因素限制了 C1000K 问题的解决. 主要是这几点:

  • 操作系统能否支持百万连接?
  • 操作系统维持百万连接需要多少内存?
  • 应用程序维持百万连接需要多少内存?
  • 百万连接的吞吐量是否超过了网络限制?

协程

coroutine(协程),或协作式例程。
线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任何时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停。

协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

由于协程的作用,没有线程的内存开销,就能够减轻上面提到的C1000k problem当中的“操作系统维持百万连接需要很大内存”的问题。

参考

文章目录
  1. 1. C10k problem的解决方法
    1. 1.1. Serve one client with each thread/process, and use blocking I/O
    2. 1.2. Serve many clients with single thread, and use nonblocking I/O and readiness notification
    3. 1.3. Serve many clients with each thread, and use nonblocking I/O and readiness notification
    4. 1.4. Serve many clients with each thread, and use asynchronous I/O
  2. 2. C1000k problem
    1. 2.1. 协程
  3. 3. 参考