zoukankan      html  css  js  c++  java
  • 高性能网络编程(二)

    C10K问题的解决方案探讨
    要解决这一问题,从纯网络编程技术角度看,主要思路有两个:

      一个是对于每个连接处理分配一个独立的进程/线程;另一个思路是用同一进程/线程来同时处理若干连接。

    8.1 思路一:每个进程/线程处理一个连接
      这一思路最为直接。但是由于申请进程/线程会占用相当可观的系统资源,

      同时对于多进程/线程的管理会对系统造成压力,因此这种方案不具备良好的可扩展性。

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

      即便资源足够富裕,效率也不够高。总之,此思路技术实现会使得资源占用过多,可扩展性差。


    8.2 思路二:每个进程/线程同时处理多个连接(IO多路复用)
    IO多路复用从技术实现上又分很多种,我们逐一来看看下述各种实现方式的优劣。

    ● 实现方式1:传统思路最简单的方法是循环挨个处理各个连接,每个连接对应一个 socket,当所有 socket 都有数据的时候,这种方法是可行的。

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

    实现小结:直接循环处理多个连接。
    问题归纳:任一文件句柄的不成功会阻塞住整个应用。

    ● 实现方式2select要解决上面阻塞的问题,思路很简单,如果我在读取文件句柄之前,先查下它的状态,ready 了就进行处理,不 ready 就不进行处理,这不就解决了这个问题了嘛?于是有了 select 方案。用一个 fd_set 结构体来告诉内核同时监控多个文件句柄,当其中有文件句柄的状态发生指定变化(例如某句柄由不可用变为可用)或超时,则调用返回。之后应用可以使用 FD_ISSET 来逐个查看是哪个文件句柄的状态发生了变化。这样做,小规模的连接问题不大,但当连接数很多(文件句柄个数很多)的时候,逐个检查状态就很慢了。因此,select 往往存在管理的句柄上限(FD_SETSIZE)。同时,在使用上,因为只有一个字段记录关注和发生事件,每次调用之前要重新初始化 fd_set 结构体。

    [align=right !important][color=initial !important]1 intselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);


    实现小结:有连接请求抵达了再检查处理。
    问题归纳:句柄上限 + 重复初始化 + 逐个排查所有文件句柄状态效率不高。

    ● 实现方式3:poll 主要解决 select 的前两个问题:通过一个 pollfd 数组向内核传递需要关注的事件消除文件句柄上限,

                                 同时使用不同字段分别标注关注事件和发生事件,来避免重复初始化。

    实现小结:设计新的数据结构提供使用效率。
    问题归纳:逐个排查所有文件句柄状态效率不高。

    ● 实现方式4poll既然逐个排查所有文件句柄状态效率不高,很自然的如果调用返回的时候只给应用提供发生了状态变化(很可能是数据 ready)的文件句柄,进行排查的效率不就高多了么。epoll 采用了这种设计,适用于大规模的应用场景。实验表明,当文件句柄数目超过 10 之后,epoll 性能将优于 select 和 poll;当文件句柄数目达到 10K 的时候,epoll 已经超过 select 和 poll 两个数量级。

    实现小结:只返回状态变化的文件句柄。
    问题归纳:依赖特定平台(Linux)。

    因为Linux是互联网企业中使用率最高的操作系统,Epoll就成为C10K killer、高并发、高性能、异步非阻塞这些技术的代名词了。FreeBSD推出了kqueue,Linux推出了epoll,Windows推出了IOCP,Solaris推出了/dev/poll。这些操作系统提供的功能就是为了解决C10K问题。epoll技术的编程模型就是异步非阻塞回调,也可以叫做Reactor,事件驱动,事件轮循(EventLoop)。Nginx,libevent,Node.js这些就是Epoll时代的产物。

    ● 实现方式5由于epoll, kqueue, IOCP每个接口都有自己的特点,程序移植非常困难,于是需要对这些接口进行封装,以让它们易于使用和移植,其中libevent库就是其中之一。跨平台,封装底层平台的调用,提供统一的 API,但底层在不同平台上自动选择合适的调用。按照libevent的官方网站,libevent库提供了以下功能:当一个文件描述符的特定事件(如可读,可写或出错)发生了,或一个定时事件发生了,libevent就会自动执行用户指定的回调函数,来处理事件。目前,libevent已支持以下接口/dev/poll, kqueue, event ports, select, poll 和 epoll。Libevent的内部事件机制完全是基于所使用的接口的。因此libevent非常容易移植,也使它的扩展性非常容易。目前,libevent已在以下操作系统中编译通过:Linux,BSD,Mac OS X,Solaris和Windows。使用libevent库进行开发非常简单,也很容易在各种unix平台上移植。一个简单的使用libevent库的程序如下:

  • 相关阅读:
    ant design vue模态框中下拉滚动样式分离解决方法
    vue+element处理前端分页
    vue中引入图片报Error: Can't resolve '../../assets/xx.png' in 'xxxx' 无法解析错误记录
    同页面多个echarts饼图组件封装
    后台报错"Optional int parameter 'page' is present but cannot be translated into a null value due to being declared as a primitive type"
    ant design vue中table动态合并列
    vuex数据持久化
    ant design vue中使用TreeSelect懒加载
    vue报错You are using the runtime-only build of Vue where the template compiler
    ant design vue中表格自带分页
  • 原文地址:https://www.cnblogs.com/zhangkele/p/8973529.html
Copyright © 2011-2022 走看看