构建高性能WEB站点笔记二

时间:2022-05-27 16:52:32

构建高性能WEB站点笔记

因为是跳着看的,后面看到有提到啥epoll模型,那就补充下前面的知识。

第三章 服务器并发处理能力

3.2 CPU并发计算

  • 进程
    • 好处:cpu 时间的轮流使用、对CPU计算和I/O操作进行很好的重叠利用。
    • 进程的调度有内核进行。从内核的观点看,进程的目的就是担任分配系统资源的实体。同时,进程也可以理解为记录程序实例当前运行到什么程度的一组数据。多个程序通过不同的进程描述符与这些数据进行关联。
    • 每个进程都有自己的独立内存空间和生命周期。当子进程被父进程创建后,便将父进程地址空间的所有数据都复制到自己的地址空间。完全继承父进程的所有上下文信息,它们之间可以通信,但是不互相依赖,也无权干涉彼此的地址空间。
    • 进程的创建使用fork()系统调用。
  • 轻量级进程
    • 由于进程之间相对独立,它们之间各自维护庞大的地址空间和上下文信息,无法很好地低成本共享数据,所以采用大量进程的Web服务器(比如Apache的prefork模型)在处理大量并发请求时,内存的大量消耗会成为性能提升的制约因素。但是,进程的优越性有时候恰恰体现在其相互独立所带来的稳定性和健壮性方面。
    • clone()创建轻量级进程,由内核直接管理,像普通的进程一样独立存在,各自拥有进程描述符,但是这些进程已经允许共享一些资源,比如地址空间、打开的文件等。轻量级进程减少了内存开销,并为多进程应用程序的数据共享提供了直接支持,但上下文切换的开销还是在所难免。
  • 线程
    • 多线程的管理完全在用户态。但是某些系统中, 内核线程也被支持,线程管理由内核进行。
  • 系统负载
    • 在进程调度器维护的运行队列中,任何时刻都至少存在一个进程,那就是正在进行的进程。cat /proc/loadavg查看运行队列的情况。
    • 定义:单位时间内运行队列中就绪等待的进程数平均值。
  • IOWait
    • 定义:CPU空闲并且等待I/O操作完成的时间比例。

      3.3 系统调用

      进程有两个运行模式:用户态和内核态,进程通常运行在用户态,这时候可以使用CPU和内存来完成一些任务,而当进程需要对硬件外设进行操作的时候(读磁盘文件、发送网络数据),就必须切换到内核态。

  • 减少不必须要的系统调用,优化Web服务器性能。

    3.5 持久连接

    在Web应用层通信,由于HTTP的无状态特性,使得HTTP通信毫不依赖于TCP长连接,长久以来习惯了“一次性”的HTTP通信,即一次TCP连接处理一个HTTP请求。

HTTP长连接需要浏览器和Web服务器的共同协作。一方面,浏览器需要保持一个TCP连接并重复利用,不断发送多个请求,另一方面,服务器不能过早的主动关闭连接。

Apache中,通过httpd.conf中的如下参数进行配置:
KeepAliveTimeout 30浏览器的设置可以通过修改注册表修改超时时间。

动机:尽量减少连接次数,尽量重用连接通道。

3.6 I/O模型

  • PIO 与 DMA
    • PIO 磁盘和内存之间的数据传输通过CPU控制。数据经过CPU存储转发。
    • DMA 不经过CPU而直接进行磁盘和内存的数据交换。在DMA模式下,CPU只需要向DMA控制器下达命令,让DMA控制器来处理数据的传送即可。DMA控制器通过系统总线来传输数据,传输完毕再通知CPU,这样在很大程度降低了CPU占有率,大大节省了系统资源。
  • 同步阻塞I/O
    • 同步阻塞I/O是指当进程调用某些涉及I/O操作的系统调用或库函数时,比如accept()、send()、recv()等,进程便暂停下来,等待I/O操作完再继续运行。
  • 同步非阻塞I/O
    • 同步阻塞I/O中,进程实际上等待的时候可能包括两部分,一个是等待数据的就绪,另一个是等待数据的复制。对网络I/O来说,前者的时间可能要更长一些。
    • 不同的是,同步非阻塞I/O不会等待数据就绪,如果数据不可写或者不可读,它会立即告诉进程,比如我们使用非阻塞recv()接收网络的时候,如果网卡缓冲区没有可接受的数据,函数就及时返回,告诉进程没有数据刻度。
    • 进程执行多次轮询来看数据是否就绪,这花费大量CPU时间,使得进程处于忙碌等待状态。
    • 非阻塞I/O一般只针对网络I/O有效。我们只要在socket选项设置中使用O_NONBLOCK即可,这样对于该socket的send()或者recv()便采用非阻塞方式。值得注意的是,对于磁盘I/O,非阻塞I/O并不产生效果。
  • 多路I/O就绪通知
    • 提供了对大量文件描述符就绪检查的高性能方案,允许进程通过一种方法来同时监视所有文件描述符,并可以快速获取所有就绪的文件描述符,然后只针对这些文件描述符进行数据访问。
    • I/O就绪通知只是帮助我们快速获得就绪的文件描述符,当得知数据就绪以后,就访问数据本身而言,仍然需要选择阻塞或者费组设的访问方式,一般我们选择非阻塞方式,以防止任何意外的等待阻塞阻塞整个进程。比如有时候就绪通知只是代表一个内核的提示,也许此时未见描述符尚未真正准备好或者已经被客户端关闭连接。

了解以下几种UNIX:

  • select 通过一个select()系统调用来监视包含多个文件描述符的数组,当select()返回以后,该数组中就绪的文件描述符便会被内核修改标志位,使的进程可以获得文件描述符从而进行后续的读写操作。
    • 优:扩平台支持
    • 缺:单个进程能够监视的文件描述符的数量存在最大限制。
    • select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。
  • poll 本质上和select差别不大,但是没有最大文件描述符的限制。
  • epoll 被公认为Linux2.6下性能最好的多路I/O就绪通知方法。同时支持水平触发和边缘触发。
    • 水平触发:select()和poll()将就绪的文件描述符告诉进程后,如果进程对其没有进行I/O操作,那下次调用select()和poll()再次报告这些文件描述符,所以它们一般不会丢失就绪的消息。
    • 边缘触发:SIGIO是告诉我们哪些文件描述符刚刚变成就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知。
  • 内存映射

定义:Linux提供一种访问磁盘文件的特殊方式,它可以将内存中某块地址空间和我们要指定的磁盘文件相关联,从而把我们队这块内存的访问转换为对磁盘文件的访问。
* 大多数情况下,使用内存映射可以提高磁盘I/O的性能,它无须使用read()或者write()等系统调用来访问文件,而是通过mmap()系统调用来建立内存和磁盘文件的关联,然后像访问内存一样*地访问文件。

直接IO

  • 在MySQL中,对应Innodb存储引擎,其自身可以进行数据和索引的缓存管理,所以它对于内核缓冲区的依赖不是那么重要。MySQL提供了一种实现直接I/O的方法,在my.cof配置中,在分配Innodb数据空间文件的时候,使用raw分区跳过内核缓冲区,直接I/O。
    sendfile

  • 大多数时候,我们向web服务器请求静态文件,这个处理请求的过程,磁盘的数据要先经过内核缓冲区,然后到达用户内存空间,因为是不需要任何处理的静态数据,所以它们又被送到网卡对应的内核缓冲区,接着再被送入网卡进行发送。
  • Linux中,sendfile将磁盘文件的特定部门直接传送到客户端的socket描述符,加快了静态文件的请求速度。

异步I/O

  • 阻塞和非阻塞IO是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说相当于函数内部的实现区别,即尚未就绪时是直接返回还是就绪等待;
  • 同步和异步是指数据访问的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞。异步是指主动请求数据后便可以继续处理其他任务,随后等待I/O操作完毕的通知,这可以使进程在数据读写时也不发生阻塞。

    3.7 服务器并发策略

    本质上讲,所有到达服务器的请求都封装在IP包中,位于网卡的接收缓存区中,这时候Web服务器软件要做的是不断地读取这些请求,然后进行处理,并将结果写到发送缓冲区,这其中包含了一些列I/O操作和CPU计算, 而设计一个并发策略的目的,就是让I/O操作和CPU计算尽量重叠进行,一方面要让CPU在I/O等待时不要空闲,另一方面让CPU在I/O调度上尽量花费最少的时间。