俄文网站建设 俄文网站设计,外贸平台是什么,wordpress 主页调整,娱乐平台网站开发免费文章目录 C10KC10K的由来C10K问题在技术层面的典型体现C10K问题的本质C10K解决思路思路一#xff1a;每个进程/线程处理一个连接思路二#xff1a;每个进程/线程同时处理多个连接#xff08;IO多路复用#xff09;● 实现方式1#xff1a;直接循环处理多个连接● 实现方式… 文章目录 C10KC10K的由来C10K问题在技术层面的典型体现C10K问题的本质C10K解决思路思路一每个进程/线程处理一个连接思路二每个进程/线程同时处理多个连接IO多路复用● 实现方式1直接循环处理多个连接● 实现方式2: select● 实现方式3: poll● 实现方式4: epoll● 实现方式5: libevent C10K 英文地址 http://www.kegel.com/c10k.html
中文地址 https://www.oschina.net/translate/c10k C10K是指单机1万网络并发连接和数据处理能力。 C10M是指单机1000万网络并发连接和数据处理能力 C10K的由来
众所周知互联网的基础是网络通信早期的互联网规模有限只涉及小规模用户群体。在这个阶段互联网的用户数量相对较少一台服务器同时在线100个用户已经算是大规模应用了因此并没有面临所谓的C10K难题。
互联网的爆发期可以追溯到出现www网站、浏览器和雅虎等平台之后。早期互联网被称为Web1.0时代主要用于下载HTML页面用户通过浏览器查看网页上的信息而不需要进行复杂的实时交互。在这个时期并不需要解决C10K问题。
然而随着Web2.0时代的到来情况发生了变化。一方面互联网的普及率大幅提高用户数量呈几何级增长。另一方面互联网不再局限于简单的网页浏览而是逐渐变为互动的平台应用程序的逻辑也变得更加复杂从简单的表单提交发展到了实时通信和在线实时互动。正是在这个背景下C10K问题开始显现出来。因为每个用户都需要与服务器保持TCP连接以进行实时数据交互。 早期的腾讯QQ也遇到了C10K问题不过他们采用了UDP这种原始的包交换协议绕过了这一难题尽管过程相当具有挑战性。如果当时已经有epoll技术他们很可能会选择使用TCP。众所周知后来的手机QQ和微信都采用了TCP协议。 实际上当时也有一些异步模型例如select和poll模型但它们都存在一些限制。比如select模型的最大连接数不能超过1024而poll没有这个限制但每次需要遍历每个连接以检查哪个连接有数据请求。
这时候出现了一个关键问题最初的服务器基于进程/线程模型每当有新的TCP连接时就需要分配一个新的进程或线程。然而进程是操作系统中最昂贵的资源之一因此一台机器无法同时创建大量进程。如果要应对C10K问题可能需要创建上万个进程这对单台机器来说是难以承受的效率低下甚至可能导致系统崩溃。如果采用分布式系统要维护上亿用户的在线连接可能需要上万台服务器成本巨大 。
鉴于上述情况如何突破单机性能的限制成为高性能网络编程不得不面对的问题。这些限制和问题最早由Dan Kegel总结和归纳他首次系统地分析并提出了解决方案。后来这些普遍存在的网络现象和技术限制都被广泛称为C10K问题。 C10K问题在技术层面的典型体现
C10K问题的主要特点在于当程序设计不够精良时其性能与连接数量和机器性能之间的关系通常表现为非线性。 举例来说如果没有考虑C10K问题一个经典基于select的程序在旧服务器上可以良好地处理1000个并发连接但在性能翻倍的新服务器上却常常无法处理2000个并发连接。这是因为在策略不当的情况下大量操作的开销与当前连接数n成线性相关导致单个任务的资源消耗与当前连接数之间呈线性关系即O(n)。对于服务程序来说需要同时处理数以万计的套接字I/O操作累积下来的资源开销相当可观这显然会导致系统吞吐量无法与机器性能相匹配。 这便是C10K问题在技术层面的典型体现。这也解释了为什么大多数开发人员可以相对容易地从功能上实现相同的功能但一旦应用到高并发场景中初级开发人员和高级开发人员的技术实现会产生截然不同的实际应用效果。
因此一些缺乏大规模并发实践经验的技术从业者例如那些开发即时通讯应用等网络应用的人往往在没有经受检验和考验的情况下声称其应用能够在单台服务器上支持上万、上十万甚至上百万的用户这种说法常常难以经受实际验证。 C10K问题的本质
C10K问题本质上与操作系统的设计和性能密切相关。在Web1.0和Web2.0时代传统的同步阻塞I/O模型在操作系统中普遍存在处理方式都以requests per second为标准而区分处理10K并发和100并发的关键在于CPU性能。
当创建大量进程和线程时会导致数据频繁拷贝包括缓存I/O、内核将数据从内核空间拷贝到用户进程空间等并且进程/线程上下文切换的成本较高。这导致操作系统面临巨大的挑战可能因此崩溃这正是C10K问题的本质所在。
因此解决C10K问题的关键在于尽可能减少对CPU等核心计算资源的消耗从而充分发挥单台服务器的性能以突破C10K问题所描述的性能瓶颈。这可以通过采用异步I/O模型、事件驱动编程、使用高效的多路复用技术如epoll等以及优化操作系统内核等方式来实现。通过这些方法可以显著提高服务器的吞吐量减少资源消耗从而解决C10K问题。 C10K解决思路
要解决这一问题从纯网络编程技术角度看主要思路有两个
对于每个连接处理分配一个独立的进程/线程用同一进程/线程来同时处理若干连接
思路一每个进程/线程处理一个连接
这一思路最为直接。但是由于申请进程/线程会占用相当可观的系统资源同时对于多进程/线程的管理会对系统造成压力因此这种方案不具备良好的可扩展性。
因此这一思路在服务器资源还没有富裕到足够程度的时候是不可行的。即便资源足够富裕效率也不够高。
总之此思路技术实现会使得资源占用过多可扩展性差。 思路二每个进程/线程同时处理多个连接IO多路复用
IO多路复用从技术实现上又分很多种我们逐一来看看下述各种实现方式的优劣。
● 实现方式1直接循环处理多个连接
传统思路最简单的方法是循环挨个处理各个连接每个连接对应一个 socket当所有 socket 都有数据的时候这种方法是可行的。但是当应用读取某个 socket 的文件数据不 ready 的时候整个应用会阻塞在这里等待该文件句柄即使别的文件句柄 ready也无法往下处理。
实现小结直接循环处理多个连接。 问题归纳任一文件句柄的不成功会阻塞住整个应用。 ● 实现方式2: select
select要解决上面阻塞的问题思路很简单如果我在读取文件句柄之前先查下它的状态ready 了就进行处理不 ready 就不进行处理这不就解决了这个问题了嘛
于是有了 select 方案。用一个 fd_set 结构体来告诉内核同时监控多个文件句柄当其中有文件句柄的状态发生指定变化例如某句柄由不可用变为可用或超时则调用返回。之后应用可以使用 FD_ISSET 来逐个查看是哪个文件句柄的状态发生了变化。这样做小规模的连接问题不大但当连接数很多文件句柄个数很多的时候逐个检查状态就很慢了。
因此select 往往存在管理的句柄上限FD_SETSIZE。同时在使用上因为只有一个字段记录关注和发生事件每次调用之前要重新初始化 fd_set 结构体。
intselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);实现小结有连接请求抵达了再检查处理。 问题归纳句柄上限重复初始化逐个排查所有文件句柄状态效率不高。 ● 实现方式3: poll
poll 主要解决 select 的前两个问题通过一个 pollfd 数组向内核传递需要关注的事件消除文件句柄上限同时使用不同字段分别标注关注事件和发生事件来避免重复初始化。
实现小结设计新的数据结构提供使用效率。 问题归纳逐个排查所有文件句柄状态效率不高。 ● 实现方式4: epoll
poll既然逐个排查所有文件句柄状态效率不高很自然的如果调用返回的时候只给应用提供发生了状态变化很可能是数据 ready的文件句柄进行排查的效率不就高多了么。
epoll 采用了这种设计适用于大规模的应用场景。实验表明当文件句柄数目超过 10 之后epoll 性能将优于 select 和 poll当文件句柄数目达到 10K 的时候epoll 已经超过 select 和 poll 两个数量级。
实现小结只返回状态变化的文件句柄。 问题归纳依赖特定平台Linux。
因为Linux是互联网企业中使用率最高的操作系统Epoll就成为C10K killer、高并发、高性能、异步非阻塞这些技术的代名词了。FreeBSD推出了kqueueLinux推出了epollWindows推出了IOCPSolaris推出了/dev/poll。这些操作系统提供的功能就是为了解决C10K问题。epoll技术的编程模型就是异步非阻塞回调也可以叫做Reactor事件驱动事件轮循EventLoop。Nginxlibeventnode.js这些就是Epoll时代的产物。 ● 实现方式5: libevent
由于epoll, kqueue, IOCP每个接口都有自己的特点程序移植非常困难于是需要对这些接口进行封装以让它们易于使用和移植其中libevent库就是其中之一。
跨平台封装底层平台的调用提供统一的 API但底层在不同平台上自动选择合适的调用。
按照libevent的官方网站libevent库提供了以下功能当一个文件描述符的特定事件如可读可写或出错发生了或一个定时事件发生了libevent就会自动执行用户指定的回调函数来处理事件。
目前libevent已支持以下接口/dev/poll, kqueue, event ports, select, poll 和 epoll。Libevent的内部事件机制完全是基于所使用的接口的。
因此libevent非常容易移植也使它的扩展性非常容易。目前libevent已在以下操作系统中编译通过LinuxBSDMac OS XSolaris和Windows。使用libevent库进行开发非常简单也很容易在各种unix平台上移植。
一个简单的使用libevent库的程序如下