range

If there were you, the world would be just right

1. nginx介绍与安装

1.1 nginx介绍

Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,Nginx是一款轻量级的Web 服务器/反向代理服 务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。

反向代理

反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。

负载均衡

负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

单个服务器解决不了,我们增加服务器的数量,然后将请求分发到各个服务器上面,将原先请求到单个服务器上面的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,这就是所说的负载均衡。

动静分离

为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度,降低单个服务器的压力。

1.2 nginx安装

1.2.1 nginx安装

nginx可以使用各平台的默认包来安装,这里介绍使用源码编译安装,包括具体的编译参数信息。

安装前的准备

安装make:

yum install gcc automake autoconf libtool make

安装g++

yum install gcc gcc-c++

安装nginx

下面正式安装nginx:

注意:一般我们都需要先装pcre, zlib,前者为了重写rewrite,后者为了gzip压缩。

  1. 选的源码安装目录

可以是任何目录,这里老师选择的是/home/

cd /home
  1. 安装pcre库

https://ftp.pcre.org/pub/pcre/ 下载最新的 PCRE 源码包,使用下面命令下载编译和安装 PCRE 包:

cd /home
wget https://ftp.pcre.org/pub/pcre/pcre-8.44.tar.gz
tar -zxvf pcre-8.44.tar.gz
cd pcre-8.44
./configure
make
make install
  1. 安装zlib库

http://zlib.net/zlib-1.2.11.tar.gz 下载最新的 zlib 源码包,使用下面命令下载编译和安装 zlib包:

cd /home
wget http://zlib.net/zlib-1.2.11.tar.gz
tar -zxvf zlib-1.2.11.tar.gz
cd zlib-1.2.11
./configure
make
make install
  1. 安装ssl
cd /home
wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz
tar -zxvf openssl-1.1.1g.tar.gz
  1. nginx安装

Nginx 一般有两个版本,分别是稳定版和开发版,您可以根据您的目的来选择这两个版本的其中一个,下面是把 Nginx 安装到 /usr/local/nginx 目录下的详细步骤:

cd /home
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar -zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0

./configure --sbin-path=/usr/local/nginx/nginx --conf-path=/usr/local/nginx/nginx.conf --pid-path=/usr/local/nginx/nginx.pid --with-http_gzip_static_module --with-http_stub_status_module --with-file-aio --with-http_realip_module --with-http_ssl_module --with-pcre=/home/pcre-8.44 --with-zlib=/home/zlib-1.2.11 --with-openssl=/home/openssl-1.1.1g

make -j2
mkae install

--with-pcre=/usr/local/src/pcre-8.44 指的是pcre-8.44 的源码路径。

--with-zlib=/usr/local/src/zlib-1.2.11指的是zlib-1.2.11 的源码路径。

安装成功后 /usr/local/nginx 目录下如下

drwx------. 2 nobody root       6 3月   6 16:59 client_body_temp
drwxr-xr-x. 2 root   root    4096 3月   6 17:19 conf
-rw-r--r--. 1 root   root    1077 3月   6 16:59 fastcgi.conf
-rw-r--r--. 1 root   root    1077 3月   6 16:59 fastcgi.conf.default
-rw-r--r--. 1 root   root    1007 3月   6 16:59 fastcgi_params
-rw-r--r--. 1 root   root    1007 3月   6 16:59 fastcgi_params.default
drwx------. 2 nobody root       6 3月   6 16:59 fastcgi_temp
drwxr-xr-x. 2 root   root      57 3月   6 17:05 html
-rw-r--r--. 1 root   root    2837 3月   6 16:59 koi-utf
-rw-r--r--. 1 root   root    2223 3月   6 16:59 koi-win
drwxr-xr-x. 2 root   root      41 3月   6 16:59 logs
-rw-r--r--. 1 root   root    5231 3月   6 16:59 mime.types
-rw-r--r--. 1 root   root    5231 3月   6 16:59 mime.types.default
-rwxr-xr-x. 1 root   root 7963984 3月   6 16:59 nginx
-rw-r--r--. 1 root   root    2937 3月   6 17:28 nginx.conf
-rw-r--r--. 1 root   root    2656 3月   6 16:59 nginx.conf.default
drwxr-xr-x. 3 root   root      17 3月   6 16:50 nginx--conf-path=
-rw-r--r--. 1 root   root       6 3月   6 19:51 nginx.pid
drwx------. 2 nobody root       6 3月   6 16:59 proxy_temp
-rw-r--r--. 1 root   root     636 3月   6 16:59 scgi_params
-rw-r--r--. 1 root   root     636 3月   6 16:59 scgi_params.default
drwx------. 2 nobody root       6 3月   6 16:59 scgi_temp
-rw-r--r--. 1 root   root     664 3月   6 16:59 uwsgi_params
-rw-r--r--. 1 root   root     664 3月   6 16:59 uwsgi_params.default
drwx------. 2 nobody root       6 3月   6 16:59 uwsgi_temp
-rw-r--r--. 1 root   root    3610 3月   6 16:59 win-utf
  1. 启动

启动nginx:

/usr/local/nginx/nginx

测试:

关闭虚拟机防火墙:systemctl stop firewalld(服务器需要开启80端口)

访问:服务器IP

1.2.2 php-fpm安装

nginx本身不能处理PHP,它只是个web服务器,当接收到请求后,如果是php请求,则发给php解释器处理,并把结果返回给客户端。

nginx一般是把请求发fastcgi管理进程处理,fascgi管理进程选择cgi子进程处理结果并返回被nginx

这里介绍如何使nginx支持PHP

什么是php-fpm

PHP-FPM是一个PHP FastCGI管理器,是只用于PHP的,可以在 http://php-fpm.org/download下载得到.

PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中。必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用。

新版PHP已经集成php-fpm了,不再是第三方的包了,推荐使用。PHP-FPM提供了更好的PHP进程管理方式,可以有效控制内存和进程、可以平滑重载PHP配置,比spawn-fcgi具有更多优点,所以被PHP官方收录了。在./configure的时候带 –enable-fpm参数即可开启PHP-FPM,其它参数都是配置php的

安装前准备

yum -y install gcc automake autoconf libtool make

yum -y install gcc gcc-c++ glibc

以上已经安装了可以不用安装

yum -y install libmcrypt-devel mhash-devel libxslt-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel sqlite-devel sqlite

1. wget https://github.com/kkos/oniguruma/archive/v6.9.4.tar.gz -O oniguruma-6.9.4.tar.gz
2. tar -xvf oniguruma-6.9.4.tar.gz
3. cd oniguruma-6.9.4/
4. ./autogen.sh
5. ./configure --prefix=/usr --libdir=/lib64
6. make && make install

安装php-fpm

php中文镜像地址:http://php.p2hp.com/downloads.php

cd /home
wget https://mirrors.sohu.com/php/php-7.4.16.tar.gz
tar -zxvf php-7.4.16.tar.gz
cd php-7.4.16

./configure --prefix=/usr/local/php  --enable-fpm --with-mcrypt --enable-mbstring --disable-pdo --with-curl --disable-debug  --disable-rpath --enable-inline-optimization --with-bz2  --with-zlib --enable-sockets --enable-sysvsem --enable-sysvshm --enable-pcntl --enable-mbregex --with-mhash --enable-zip --with-pcre-regex --with-mysql --with-mysqli --with-gd --with-jpeg-dir

make all install

安装完成之后,需要生成php-fpm配置文件

cd /usr/local/php
cp etc/php-fpm.conf.default etc/php-fpm.conf

cd /usr/local/php/etc/php-fpm.d
cp www.conf.default www.conf

配置nginx.conf ,使nginx将php动态请求发送到PHP解释器处理

其中server段增加如下配置,否则会出现No input file specified.错误

location ~ \.php$ {
    root html;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

测试:

创建php文件

在/usr/local/nginx/html下创建index.php文件,输入如下内容

<?php
echo phpinfo();
?>

启动php-fpm

/usr/local/php/sbin/php-fpm

浏览器访问:

1.3 nginx指令与server脚本

  1. 启动nginx

nginx安装完成后,切换到nginx安装目录中的sbin目录,通过执行该目录下nginx编译后的二进制文件即可启动程序。具体命令如下

cd /usr/local/nginx/sbin/nginx
./nginx

执行上面的操作后,成功启动nginx,程序是没有任何提示的。我们可以使用ps命令查看nginx的运行状态,具体命令如下:

ps -ef | grep nginx

root      74751      1  0 19:51 ?        00:00:00 nginx: master process /usr/local/nginx/nginx
nobody    74752  74751  0 19:51 ?        00:00:00 nginx: worker process
nobody    74753  74751  0 19:51 ?        00:00:00 nginx: worker process
nobody    74754  74751  0 19:51 ?        00:00:00 nginx: worker process
nobody    74755  74751  0 19:51 ?        00:00:00 nginx: worker process
root      77668  19244  0 20:51 pts/0    00:00:00 grep --color=auto nginx

以上执行了ps -ef 和 grep nginx两个命令。通过这组命令,可以从所有的进程中找到是否存在nginx进程。

上面结果说明:

前面5行分别是nginx主进程(master process)和工作进程(worker process),最后一行是grep nginx命令。当看到这两个nginx进程时,说明nginx已经启动。从第1列可以看出,nginx主进程以root用户运行,而工作进程以nobody用户运行,第二列显示了5个进程的ID(即PID),分别为:74751 74752 74753 74754和74755
  1. 停止nginx

当需要停止nginx服务时,有多种停止方式,可以根据需求才取不同的方式,具体如下:

1). 立即停止服务

nginx程序允许传递选项 -s 表示发送信号到主进程,如果后面跟上stop表示停止服务

./nginx -s stop

2). 从容停止服务

前面的stop是立即停止nginx服务,无论当前工作进程是否正在处理工作。而nginx提供的从容停止方式quit,是在完成当前工作任务后再停止。

./nginx -s quit

3). 通过kill 或 killall 命令杀死进程

linux中提供了kill和killall命令可以杀死进程,从而让指定的进程停止运行

方式一:

kill nginx主进程pid

方式二:

killall nginx

除了启动与停止nginx服务的操作,还有一些其他常用命令:

命令说明
nginx -s reload在nginx已经启动的情况下重新加载配置文件(平滑重启)
nginx -s repopen重新打开日志文件
nginx -c /特定目录/nginx.conf以特定目录下的配置文件启动nginx
nginx -t检查当前配置文件是否正确
nginx -t -c /特定目录/nginx.conf检测特定目录下的nginx配置文件是否正确
nginx -v显示版本信息
nginx -V显示版本信息和编译选项
  1. service服务脚本

Linux服务是可以通过service命令进行控制的,这能使我们在给nginx主进程发送信号以及查看操作nginx服务更加得心应手。在CentOS系统中,Service命令实际是调用/etc/init.d目录下的shell脚本,也就是说,如下两行命令其实等价的、

#直接运行脚本
/etc/init.d/network restart

#通过service命令执行脚本
service network restart

在上面的命令中,network是shell脚本的文件名,restart是传递给脚本的参数。因此将nginx添加到系统服务中,只需要在/etc/init.d中编写一个文件名为nginx的shell脚本即可。

接下来执行touch nginx创建一个脚本文件,使用vim /etc/init.d/nginx命令编写一个shell脚本实现nginx服务管理,提供start stop reload restart status 5个参数,具体的脚本代码如下:

#! /bin/bash

#chkconfig:35 85 15

DAEMON=/usr/local/nginx/nginx
PID=/usr/local/nginx/nginx.pid

case "$1" in
  start)
      echo "Starting nginx daemon..."
      $DAEMON && echo "SUCCESS"  #开启nginx
  ;;
  stop)
      echo "Stopping nginx daemon..."
      $DAEMON -s quit && echo "SUCCESS"  #从容的停止nginx
  ;;
  reload)
      echo "Reloading nginx daemon..."
      $DAEMON -s reload && echo "SUCCESS"  #平滑重启nginx
  ;;
  restart)
      echo "Restarting nginx daemon..."
      $DAEMON -s quit                            #从容的停止nginx
      $DAEMON && echo "SUCCESS"                  #开启nginx
  ;;
  status)
      if [ ! -f "$PID" ]; then                  #因为nginx启动后会生成进程文件nginx.pid,这里通过判断进程文件是否存在,判断nginx是否启动
         echo "Nginx is not running..."
      else
         echo "Nginx is running..."
      fi
  ;;
  *)
      echo "Usage:service nginx (start|stop|restart|reload|status)"
      exit 2
  ;;
esac

代码解释:

#! /bin.bash:通常写在shell脚本的开头,需要使用特殊表示符号#!定义解释此脚本的shell路径。以上代码的意思是这个脚本将使用bash环境执行。
case语句:case语句通常用于多重分支语句匹配的情况,具体语法如下:

case $变量名 in
     模式1)
       命令序列1
     ;;
     模式2)
       命令序列2
     ;;
     *)
       默认执行的命令序列
     ;;
esac

case语句必须以case开始 in结尾,中间的变量表示用户输入的字符,每个模式必须以右括号")"结束,双分号";;"结束命令序列,且匹配模式中可以使用方括号表示一个连续的范围,如[0-9],使用树杠符号“|”表示“或”;最后的“*)”是默认模式,当使用前面的各种模式均无法匹配该变量时,将执行“*)”后的命令序列,最后case语句必须以esac结束。
  1. nginx开机自启

对于一个要经常使用的服务器而言,每次开机后,都需要用户手动开启一些服务较为麻烦。接下来,将通过chkconfig命令完成nginx开机自启动的功能,chkconfig命令的语法格式如下所示:

chlconfig [--add] [--del] [--list] [系统服务]

参数解释:
--add:用于增加指定的系统服务(如nginx),设置该服务为开机自启动
--del:用于删除指定的系统服务,取消该服务的开机自启动
--list:用于列出系统所有的服务启动情况

2. nginx配置与优势

2.1 配置文件基础

默认的nginx服务器配置文件都存放在安装目录conf中,主配置文件名为nginx.conf,下面我们来看看nginx的配置文件内容和一些基本的配置方法。

以下是一个完整的nginx配置文件。

worker_processes 1;                                 #全局生效

events {
  worker_connections 1024;                          #在events部分中生效
}

http {
  include mime.types       ;                               #以下指令在http部分中生效
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 65;
  server {                                          #以下指令在http的server部分中生效
    listen 80;
    server_name localhost;
    location / {                                    #以下指令在http/server的location中生效
      root html;
      index index.html index.htm;
    }
    error_page 500 502 503 504 /50x.html;
    location - /50x.html {
      root html;
    }

    location ~ \.php$ {
        root html;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
  }
}

注意:在nginx配置中,还包括注释内容,注释标志位“#”。

初始的nginx服务器主配置是比较长的,不过结构和内容还是比较清晰的,以下我们分为几个小节进行分析介绍。通过上面的配置文件内容分,我们可以总结出以下nginx.conf的基本结构:

...                            #全局快

events                         #events块
{
  ...
}

http                           #http块
{
  ...                          #http全局块

  server                       #server块
  {
    ...                        #server全局块

    location [PATTERN]         #location块
    {
      ...
    }

    location [PATTERN]         #location块
    {
      ...
    }
  }

  server                       #server块
  {
    ...
  }

  ...                          #http块
}

最外层的花括号将内容整体分为两部分,再加上最开始的内容,即第一行省略号表示的nginx.conf一共由三部分组成,分为全局块,events块和http块。在http块中,又包含http全局块,多个server块。每个server块中,可以包含server全局块和多个location块。在同一块配置中嵌套的配置块,各个之间不存在次序关系。

nginx详细配置信息

以下是一个nginx的完整配置文件,本节我们将以下面的配置文件为主解析nginx各个模块的参数已经配置,在完成解析后测试nginx服务。

####################  全局块 开始 ####################

#配置允许运行nginx服务器的用户和用户组
user root root;

#配置允许nginx进程生成的worker processes数
worker processes 3;

#配置允许nginx服务器运行对错误日志存放路径
error_log logs/error.log;

#配置nginx服务器运行时的pid文件存放路径和名称
pid nginx.pid;

####################  全局块 结束 ####################

####################  server块 开始 ####################

events
{
  #配置事件驱动模型
  use epoll;

  #配置最大连接数
  worker_connections 1024;
}

####################  server块 结束 ####################

####################  http块 开始 ####################
http
{
  # 定义MIME-Type
  include mime.types;
  default_type application/octet-stream;

  #配置允许使用sendfile方式传输
  sendfile on;

  #配置连接超时时间
  keepalive_timeout 65;

  #配置请求处理日志的格式
  log_format access.log;
  '$remote_addr - [$time_local]-"$request"-"$http_user_agent"';

  ####################  server块 开始 ####################
  #配置虚拟主机myServer1
  server {
    #配置监听端口和主机名称(基于名称)
    listen 8081;
    server_name myServer1;

    #配置请求处理日志存放路径
    access_log /myweb/server1/log/access.log;

    #配置错误页面
    error_page 404 /404.html;

    #配置处理/server1/location1请求的location
    location /server/location1 {
      root /myweb;
      index index.svrl-locl.htm;
    }

    #配置处理/server1/location2请求的location
    location /server1/location2 {
      root /myweb;
      index index.svrl-loc2.htm;
    }
  }

  #配置虚拟主机myServer2
  server {
    listen 8082;
    server_name 192.168.1.3;
    access_log /myweb/server1/log/access.log;

    #对错误页面404.html做了定向配置
    error_page 404 /404.html;

    location /server2/location1 {
      root /myweb;
      index index.svr2-locl.htm;W
    }

    location /svr2/loc2 {
      #对location的URL进行更改
      alias /myweb/server2/location2/;
      index index.svr2-loc2.htm;
    }

    #配置错误页面转向
    location = /404.html {
      root /myweb/;
      index 404.html;
    }
  }
  ####################  server块 结束 ####################
}
####################  http块 结束 ####################

3, 网络服务模型

网络IO的本质是socket的读取,socket在linux中被抽象为流,IO操作可以理解为对流的操作。为了操作系统的安全性等考虑,进程是无法直接操作I/O设备的,其必须通过系统调用请求内核来协助完成I/O动作,而内核会为每个I/O设备维护一个buffer。整个请求过程可以概括为:用户进程发起请求,内核接受到请求后,从I/O设备中获取数据到buffer中,再将buffer中的数据copy到用户进程的地址空间,该用户进程获取到数据后再响应客户端。如下图所示:

在整个请求过程中,数据从IO设备输入至kernel buffer需要时间,而从kernel buffer复制到用户进程也需要时间(从IO设备到kernel比从kernel到process需要花更多的时间)。因此根据在这两段时间内等待方式的不同,I/O动作可以分为以下五种模式:

  • 阻塞I/O (Blocking I/O)
  • 非阻塞I/O (Non-Blocking I/O)
  • I/O复用(I/O Multiplexing)
  • 信号驱动的I/O (Signal Driven I/O)
  • 异步I/O (Asynchrnous I/O)

3.1 基本概念了解

3.1.1 进程与线程

进程(Process): 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。

线程(thread):是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

简单的对比:

进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。

线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。

如何理解进程与线程:

比如一个工厂,我们可以看做是一个系统,这个工厂中会有很多的流水线,这些流水线我们可以看做是一个个进程,也就说这个工厂就是我们的应用程序,每个应用程序可以create出很多的进程,每个进程都会有不同的工作。
对于线程来说是流水线中不同阶段的工人,每个工人负责着流水线在不同节点时的工作,而在进程中,线程也可以去处理不同的工作。

3.1.2 异步与同步

异步:就是在发出一个调用时,在没有得到结果之前,这个调用不返回结果,但是一但调用返回,就能得到返回值,也就是在调用者得到返回值前会一直处于等待状态,直到获得返回值。

同步:异步则与同步相反,调用发出之后,这个调用就直接返回了,所以没有返回结果,换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

如何理解同步与异步:

例子:
小五打电话问书店老板有没有《nginx优化》这本书,如果是同步机制,书店老板会说,你稍等,“我查一下”,然后开始查找,一直会等到查到为止(时间可能是几秒也可能是1天),然后在告诉你结果。
如果是异步机制,书店老板会直接告诉你我查找一下,查到了我打电话告诉你,然后通话结束,等到查找好了,主动打电话告诉你,也就是通过回调的方式告诉你结果。

3.1.3 阻塞与非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

3.2 网络服务模型

  1. 同步阻塞IO模型

当用户进程调用了recv()/recvfrom()这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达。比如,还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来)。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞(当然,是进程自己选择的阻塞)。第二个阶段:当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。

所以,同步阻塞(blocking IO)的特点就是在IO执行的两个阶段都被block了。

  1. 同步非阻塞IO模型

非阻塞IO也会进行recvform系统调用,检查数据是否准备好。非阻塞的recvform系统调用调用之后,进程并没有被阻塞,内核马上返回给进程,如果数据还没准备好,此时会返回一个error。进程在返回之后,可以干点别的事情,然后再发起recvform系统调用。重复上面的过程,循环往复的进行recvform系统调用。这个过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。

所以,同步阻塞(nonblocking IO)的特点就是在IO执行的第1个阶段没有被block,第2个阶段被block了。

  1. 异步IO模型

首先用户进程告诉内核态需要什么数据(上图中通过aio_read),然后用户态进程就不管了,做别的事情,内核等待用户态需要的数据准备好,然后将数据复制到用户空间,此时才告诉用户态进程,”数据都已经准备好,请查收“,然后用户态进程直接处理用户空间的数据。

  1. IO多路复用模型

I/O多路复用和阻塞I/O类似,不同的是这里使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。I/O多路复用用户进程阻塞的不是recvfrom,而是select/epoll。但是,用select的优势在于它可以同时处理多个connection。

所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。

  1. 信号驱动

当需要等待数据的时候,首先用户态会向内核发送一个信号,告诉内核我要什么数据,然后用户态就不管了,做别的事情去了,而当内核态中的数据准备好之后,内核立马发给用户态一个信号,说”数据准备好了,快来查收“,用户态进程收到之后,立马调用recvfrom,等待数据从内核空间复制到用户空间,待完成之后recvfrom返回成功指示,用户态进程才处理别的事情。


添加新评论 »

在这里输入你的评论...