• C10K问题


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

    可以看这篇文章

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

    另外我之前的文章

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

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

    还有这一篇:

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

    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处理网络堆栈,之后的事情就由你自已来处理。
  • 相关阅读:
    JS定时刷新页面及跳转页面
    javascript 使用btoa和atob来进行Base64转码和解码
    浏览器好玩的的 console.log
    Jmeter(二十三)Jmeter-Question之“批量造数据”
    性能测试---开发世界的狂野一面
    Jmeter(二十二)Jmeter-Question之“不同线程组之间传递变量”
    Jmeter(二十一)Jmeter常见问题及场景应用
    Jmeter(二十)Beanshell or JSR223
    Jmeter(十九)Logic Controllers 之 Module Controller and Include Controller
    Jmeter(十八)Logic Controllers 之 Random Controller and Random order Controller
  • 原文地址:https://www.cnblogs.com/charlesblc/p/6491048.html
Copyright © 2020-2023  润新知