C10K 问题引发的技术变革

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

C10K 问题

服务器应用领域很古老很出名的一个问题,大意是说单台服务器要同时支持并发 10K 量级的连接,这些连接可能是保持存活状态的。

解决这一问题,主要思路有两个:一个是对于每个连接处理分配一个独立的进程/线程;另一个思路是用同一进程/线程来同时处理若干连接。

每个进程/线程处理一个连接

这一思路最为直接。但是由于申请进程/线程会占用相当可观的系统资源,同时对于多进程/线程的管理会对系统造成压力,因此这种方案不具备良好的可扩展性。

因此,这一思路在服务器资源还没有富裕到足够程度的时候,是不可行的;即便资源足够富裕,效率也不够高。

问题:资源占用过多,可扩展性差。

每个进程/线程同时处理多个连接

传统思路

最简单的方法是循环挨个处理各个连接,每个连接对应一个 socket,当所有 socket 都有数据的时候,这种方法是可行的。

但是当应用读取某个 socket 的文件数据不 ready 的时候,整个应用会阻塞在这里等待该文件句柄,即使别的文件句柄 ready,也无法往下处理。

  • 思路:直接循环处理多个连接。
  • 问题:任一文件句柄的不成功会阻塞住整个应用。

select

要解决上面阻塞的问题,思路很简单,如果我在读取文件句柄之前,先查下它的状态,ready 了就进行处理,不 ready 就不进行处理,这不就解决了这个问题了嘛?

于是有了 select 方案。用一个 fd_set 结构体来告诉内核同时监控多个文件句柄,当其中有文件句柄的状态发生指定变化(例如某句柄由不可用变为可用)或超时,则调用返回。之后应用可以使用 FD_ISSET 来逐个查看是哪个文件句柄的状态发生了变化。

这样做,小规模的连接问题不大,但当连接数很多(文件句柄个数很多)的时候,逐个检查状态就很慢了。因此,select 往往存在管理的句柄上限(FD_SETSIZE)。同时,在使用上,因为只有一个字段记录关注和发生事件,每次调用之前要重新初始化 fd_set 结构体。

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
思路:有连接请求抵达了再检查处理。
问题:句柄上限+重复初始化+逐个排查所有文件句柄状态效率不高。

  

poll

poll 主要解决 select 的前两个问题:通过一个 pollfd 数组向内核传递需要关注的事件消除文件句柄上限,同时使用不同字段分别标注关注事件和发生事件,来避免重复初始化。

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
思路:设计新的数据结构提供使用效率。
问题:逐个排查所有文件句柄状态效率不高。

  

epoll

既然逐个排查所有文件句柄状态效率不高,很自然的,如果调用返回的时候只给应用提供发生了状态变化(很可能是数据 ready)的文件句柄,进行排查的效率不就高多了么。

epoll 采用了这种设计,适用于大规模的应用场景。

实验表明,当文件句柄数目超过 10 之后,epoll 性能将优于 select 和 poll;当文件句柄数目达到 10K 的时候,epoll 已经超过 select 和 poll 两个数量级。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
思路:只返回状态变化的文件句柄。
问题:依赖特定平台(Linux)。

libevent

跨平台,封装底层平台的调用,提供统一的 API,但底层在不同平台上自动选择合适的调用。

C10K 到 C10M

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

那么,新的瓶颈在哪里呢?

从前面的演化过程中,我们可以看到,根本的思路是要高效的去阻塞,让 CPU 可以干核心的任务。

当连接很多时,首先需要大量的进程/线程来做事。同时系统中的应用进程/线程们可能大量的都处于 ready 状态,需要系统去不断的进行快速切换,而我们知道系统上下文的切换是有代价的。虽然现在 Linux 系统的调度算法已经设计的很高效了,但对于 10M 这样大规模的场景仍然力有不足。

所以我们面临的瓶颈有两个,一个是进程/线程作为处理单元还是太厚重了;另一个是系统调度的代价太高了。

很自然地,我们会想到,如果有一种更轻量级的进程/线程作为处理单元,而且它们的调度可以做到很快(最好不需要锁),那就完美了。

这样的技术现在在某些语言中已经有了一些实现,它们就是 coroutine(协程),或协作式例程。具体的,Python、Lua 语言中的 coroutine(协程)模型,Go 语言中的 goroutine(Go 程)模型,都是类似的一个概念。实际上,多种语言(甚至 C 语言)都可以实现类似的模型。

它们在实现上都是试图用一组少量的线程来实现多个任务,一旦某个任务阻塞,则可能用同一线程继续运行其他任务,避免大量上下文的切换。每个协程所独占的系统资源往往只有栈部分。而且,各个协程之间的切换,往往是用户通过代码来显式指定的(跟各种 callback 类似),不需要内核参与,可以很方便的实现异步。

[svc]C10K 问题引发的技术变革的更多相关文章

  1. C10K 问题引发的技术变革

    C10K 问题引发的技术变革 http://rango.swoole.com/archives/381

  2. 引领技术变革,腾讯云、腾讯WeTest和英特尔,合作布局云游戏

    WeTest 导读 ChinaJoy作为中国泛娱乐产业年度风向标,受到全球业界的高度关注.在本届ChinaJoy上,腾讯云.腾讯WeTest和英特尔,合作为游戏玩家.游戏开发者等业界人士联合展出了云游 ...

  3. 一次修改mysql字段类型引发的技术探究

    说来,mysql数据库是我们项目中用的比较多的库,ORM工具喜欢采用细粒度的MyBatis.这里面就这么引出了两者之间的故事! 首先,说改字段吧,将一个表中的varchar字段改为enum字段.如下: ...

  4. 一个远程启动windows c++程序引发的技术决策现象

    还是因为那个8点半前要启动近百套报盘程序的问题,差不多两周前表示自己会抽空给解决掉,一次性启动,直到昨天才差不多能够抽点时间出来开始想怎么解决的问题. 这个问题的复杂点在于除了启动exe外,还需要鼠标 ...

  5. Token:共识的下一个100年,区块链技术是无可阻挡的文明进程

    Token:共识的下一个100年,区块链技术是无可阻挡的文明进程.很少有人意识到,区块链的应用——Token可能是近100年来最伟大的制度创新,超越股份制,并将是『债券』之后最重要最主流的交易品种,没 ...

  6. 吓哭原生App的HTML5离线存储技术,却出乎意料的容易!【低调转载】

    吓哭原生App的HTML5离线存储技术,却出乎意料的容易![WeX5低调转载] 2015-11-16 lakb248 起步软件 近几天,WeX5小编编跟部分移动应用从业人士聊了聊,很多已经准备好全面拥 ...

  7. 深入分析Java Web技术内幕(修订版)

    阿里巴巴集团技术丛书 深入分析Java Web技术内幕(修订版)(阿里巴巴集团技术丛书.技术大牛范禹.玉伯.毕玄联合力荐!大型互联网公司开发应用实践!) 许令波 著   ISBN 978-7-121- ...

  8. 【原创】高性能网络编程(二):上一个10年,著名的C10K并发连接问题

    1.前言 对于高性能即时通讯技术(或者说互联网编程)比较关注的开发者,对C10K问题(即单机1万个并发连接问题)应该都有所了解."C10K"概念最早由Dan Kegel发布于其个人 ...

  9. 杀死你网站SEO的5个技术

    胡亮亮先生(网迈SEO总监)在其微信公众帐号里发布了文章<杀死你网站SEO的5个技术>,发出来给大家分享一下: 应百度站长平台邀请,抽空把这篇文章做一些细节上的补充 ,欢迎大家关注并讨论. ...

随机推荐

  1. python笔记21-列表生成式

    前言 python里面[]表示一个列表,快速生成一个列表可以用range()函数来生成. 对列表里面的数据进行运算和操作,生成新的列表最高效快速的办法,那就是列表生成式了. range() 1.一个连 ...

  2. MsChart<3> 饼状图

    MsChart,饼状图 1 <asp:Chart ID="Chart1" runat="server" BorderlineDashStyle=" ...

  3. 跨平台app开发(引擎)工具的选择

    1.html5执行速度慢,用户体验不好 2.原生应用开发,即ios和安卓分别开发,需要两种技术人员,后期代码维护困难,很难达到统一. 3.xamarin是一款c#的解决方案,收费.xamarin.fo ...

  4. CSS_LESS 语法/函数详解

    嵌套规则 01 #header { color: black; }#header .navigation {  font-size: 12px; 02 }#header .logo {  03   w ...

  5. 9个实用的Javascript代码高亮脚本

    代码高亮很有用,特别是在需要在网站或者blog中显示自己编写的代码的时候,或者给其他人查看或调试语法错误的时候.我们可以将代码高亮,以便阅读者可以十分方便的读取代码块,增加用户阅读代码的良好体验. 目 ...

  6. Node.js:Buffer(缓冲区)介绍及常用方法

    JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门 ...

  7. 字符串转成整型(int)

    1 题目 Implement atoito convert a string to an integer. Hint: Carefullyconsider all possible input cas ...

  8. Android -- ListView与Adapter

    ListView在Android中有着很重要的作用.Android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示. 背景              ...

  9. ES6 中的 Set

    收录待用,修改转载已取得腾讯云授权 作者:kurtshen ES6 新增了几种集合类型,本文主要介绍Set以及其使用. 其基本描述为 Set对象是值的集合,你可以按照插入的顺序迭代它的元素. Set中 ...

  10. 解决Asp输出乱码问题

    在一个Asp页面中页面正常的中文字符都没有问题,但如果用Asp程序输出的话就显示为乱码 终于在百度经验上找到解决方案: 1.将文件编码更改为Utf-8 2.在页头添加"<%@LANGU ...