C10K问题

开宗明义,epoll以及BSD的kqueue就是推出来解决 C10K的。Linux2.6 2003年左右。html

 

能够看这篇文章node

http://www.oschina.net/translate/the-secret-to-10-million-concurrent-connections-the-kernel程序员

另外我以前的文章算法

http://www.cnblogs.com/charlesblc/p/6242479.htmlapache

也讲到了百万级别链接的要点 epoll的一些内部实现编程

 

还有这一篇:服务器

http://rango.swoole.com/archives/381swoole

Epoll就是为了解决C10K问题而生。网络

Nginx,libevent,node.js这些就是Epoll时代的产物。并发

 

当程序员还沉浸在解决C10K问题带来的成就感时,一个新的问题被抛出了。异步嵌套回调太TM难写了。

因而一个新的技术被提出来了,那就是协程(coroutine)。这个技术本质上也是异步非阻塞技术,它是将事件回调进行了包装,让程序员看不到里面的事件循环。

程序员就像写阻塞代码同样简单。好比调用 client->recv() 等待接收数据时,就像阻塞代码同样写。其实是底层库在执行recv时悄悄保存了一个状态,好比代码行数,局部变量的值。而后就跳回到EventLoop中了。何时真的数据到来时,它再把刚才保存的代码行数,局部变量值取出来,又开始继续执行。

 

这就是协程的本质。协程是异步非阻塞的另一种展示形式。Golang,Erlang,Lua协程都是这个模型。

注:我理解,就是把异步交给语言去处理;暴露的接口是同步形式的。

 

实际上同步阻塞程序的性能并不差,它的效率很高,不会浪费资源。当进程发生阻塞后,操做系统会将它挂起,不会分配CPU。直到数据到达才会分配CPU。多进程只是开多了以后反作用太大,由于进程多了互相切换有开销。因此若是一个服务器程序只有1000左右的并发链接,同步阻塞模式是最好的。

 

异步回调是没有切换开销的,它等同于顺序执行代码。因此异步回调程序的性能是要优于协程模型的。

这里是指Nginx这种多进程异步非阻塞程序。Node.js/Redis此类程序若是不开多个进程,因为没法利用多核计算优点,因此性能并很差。


再看第三篇

C10K的问题——过去十年 

十年前,工程师在处理C10K可扩展性问题时,都尽量的避免服务器处理超过10,000个的并发链接。经过修正操做系统内核以及用事件驱动型服务器(如Nginx和Node)替代线程式的服务器(如Apache)这个问题已经解决。从Apache转移到可扩展的服务器上,人们用了十年的时间。在过去的几年中,(咱们看到)可扩展服务器的采用率在大幅增加。

Apache的问题

  • Apache的问题是,(并发)链接数越多它的性能会越低下。
  • 关键问题:(服务器的)性能和可扩展性并非一码事。它们指的不是同一件事情。当人们谈论规模的时候每每也会谈起性能的事情,可是规模和性能是不可同日而语的。好比Apache。
  • 在仅持续几秒的短时链接时,好比快速事务处理,若是每秒要处理1,000个事务,那么大约有1,000个并发链接到服务器。
  • 若是事务增长到10秒,要保持每秒处理1,000个事务就必需要开启10K(10,000个)的并发链接。这时Apache的性能就会陡降,即便抛开DDos攻击。仅仅是大量的下载就会使Apache宕掉。
  • 若是每秒须要处理的并发请求从5,000增长到10,000,你会怎么作?假使你把升级硬件把处理器速度提高为原来的两倍。会是什么状况?你获得了两倍的性能,可是却没有获得两倍的处理规模。处理事务的规模或许仅仅提升到了每秒6,000个(即每秒6,000个并发请求)。继续提升处理器速度,仍是无济于事。甚至当性能提高到16倍时,并发链接数还不能达到10,000个。由此,性能和规模并非一回事。
  • 问题在于Apache老是建立了一个进程而后又把它关闭了,这并非可扩展的。
  • 为何?由于内核采用的O(n^2) 算法致使服务器不能处理10,000个并发链接。
    • 内核中的两个基本问题:
      • 链接数 = 线程数/进程数。当一个包(数据包)来临时,它(内核)会遍历全部的10,000个进程以决定由哪一个进程处理这个包。
      • 链接数= 选择数/轮询次数(单线程状况下)。一样的扩展性问题。每一个包不得不遍历一遍列表中的socket。
    • 解决方法:修正内核在规定的时间内进行查找
      • 无论有多少线程,线程切换的时间都是恒定的
      • 使用一个新的可扩展的epoll()/IOCompletionPort在规定的时间内作socket查询
  • 因为线程调度依然没有被扩展,所以服务器对sockt大规模的采用epoll,致使须要使用异步编程模式,然而这正是Node和Nginx所采用的方式。这种软件迁移会获得(和原来)不同的表现(指从apache迁移到ngix等)。即便在一台很慢(配置较低)的服务器上增长链接数性能也不会陡降。介于此,在开启10K并发链接时,一台笔记本电脑(运行ngix)的速度甚至超越了一台16核的服务器(运行Apache)。

 

  • 一个颇具影响的例子,就是在考虑到Apache的线程每一个链接模型(is to consider Apache’s thread per connection model)。 这就意味着线程调度器根据到来的数据(on which data arrives)决定调用哪个(不一样的)read()函数(方法)。把线程调度系统当作(数据)包调度系统来使用(我很是喜欢这一点,以前历来没据说过相似的观点)。
  • Nginx宣称,它并不把线程调度看成(数据)包调度来用使用,它自已作(进行)包调度。使用select来查找socket,咱们知道数据来了,因而就能够当即读取并处理它,数据也不会堵塞。
  • 经验:让Unix处理网络堆栈,以后的事情就由你自已来处理。
相关文章
相关标签/搜索