一、系统 I/O 模型
1、同步/异步:关注的是事件处理的消息通信机制,即在等待⼀件事情的处理结果时,被调⽤者是否提供完成通知
同步:synchronous,调⽤者等待被调⽤者返回消息后才能继续执⾏,如果被调⽤者不提供消息返回则为同步,同步需要调⽤者主动询问事情是否处理完成。即:进程发出请求调⽤后,等内核返回响应以后才继续下⼀个请求,即如果内核⼀直不返回数据,那么进程就⼀直等。
异步:asynchronous,被调⽤者通过状态、通知或回调机制主动通知调⽤者被调⽤者的运⾏状态,即:进程发出请求调⽤后,不等内核返回响应,接着处理下⼀个请求,Nginx是异步的
2、阻塞/⾮阻塞:关注调⽤者在等待结果返回之前所处的状态
阻塞:blocking,指IO操作需要彻底完成后才返回到⽤⼾空间,调⽤结果返回之前,调⽤者被挂起,⼲不了别的事情。
⾮阻塞:nonblocking,指IO操作被调⽤后⽴即返回给⽤⼾⼀个状态值,⽆需等到IO操作彻底完成,最终的调⽤结果返回之前,调⽤者不会被挂起,可以去做别的事情。
二、网络I/O 模型
1. 同步阻塞型 I/O 模型:阻塞IO模型是最简单的IO模型,⽤⼾线程在内核进⾏IO操作时被阻塞 ⽤⼾线程通过系统调⽤read发起IO读操作,由⽤⼾空间转到内核空间。内核等到数据包到达后,然后将接收的数据拷⻉到⽤⼾空间,完成read操作 ⽤⼾需要等待read将数据读取到buffffer后,才继续处理接收的数据。整个IO请求的过程中,⽤⼾线程是被阻塞的,这导致⽤⼾在发起IO请求时,不能做任何事情,对CPU的资源利⽤率不够 优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占⽤ CPU 资源 缺点:每个连接需要独⽴的进程/线程单独处理,当并发请求量⼤时为了维护程序,内存、线程切换开销较⼤,apache 的preforck使⽤的是这种模式。
同步阻塞:程序向内核发送IO请求后⼀直等待内核响应,如果内核处理请求的IO操作不能⽴即返回,则进程将⼀直等待并不再接受新的请求,并由进程轮训查看IO是否完成,完成后进程将IO结果返回给Client,在IO没有返回期间进程不能接受其他客⼾的请求,⽽且是有进程⾃⼰去查看IO是否完成,这种⽅式简单,但是⽐较慢,⽤的⽐较少。
同步阻塞.jpg
2. 同步非阻塞型 I/O 模型:⽤⼾线程发起IO请求时⽴即返回。但并未读取到任何数据,⽤⼾线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执⾏。即 “轮询”机制存在两个问题:如果有⼤量⽂件描述符都要等,那么就得⼀个⼀个的read。这会带来⼤量的Context Switch(read是系统调⽤,每调⽤⼀次就得在⽤⼾态和核⼼态切换⼀次)。轮询的时间不好把握。这⾥是要多久之后数据才能到。等待时间设的太⻓,程序响应延迟就过⼤;设的太短,就会造成过于频繁的重试,⼲耗CPU⽽已,是⽐较浪费CPU的⽅式,⼀般很少直接使⽤这种模型,⽽是在其他IO模型中使⽤⾮阻塞IO这⼀特性。
同步⾮阻塞:程序向内核发送请IO求后⼀直等待内核响应,如果内核处理请求的IO操作不能⽴即返回IO结果,进程将不再等待,⽽且继续处理其他请求,但是仍然需要进程隔⼀段时间就要查看内核IO是否完成。
同步非阻塞.jpg
3. IO多路复用型(IO multiplexing):就是我们说的select,poll,epoll,有些地⽅也称这种IO⽅式为event driven IO。select/poll/epoll的好处就在于单个process就可以同时处理多个⽹络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知⽤⼾进程。 当⽤⼾进程调⽤了select,那么整个进程会被block,⽽同时,kernel会“监视”所有select负责的socket,当任何⼀个socket中的数据准备好了,select就会返回。这个时候⽤⼾进程再调⽤read操作,将数据从kernel拷⻉到⽤⼾进程。
Apache prefork是此模式的主进程+多进程/单线程+select,work是主进程+多进程/多线程+poll模式
IO多路复用.jpg
4. 信号驱动IO:signal-driven I/O ⽤⼾进程可以通过sigaction系统调⽤注册⼀个信号处理程序,然后主程序可以继续向下执⾏,当有IO操作准备就绪时,由内核通知触发⼀个SIGIO信号处理程序执⾏,然后将⽤⼾进程所需要的数据从内核空间拷⻉到⽤⼾空间, 此模型的优势在于等待数据报到达期间进程不被阻塞。⽤⼾主程序可以继续执⾏,只要等待来⾃信号处理函数的通知。 优点:线程并没有在等待数据时被阻塞,内核直接返回调⽤接收信号,不影响进程继续处理其他请求因此可以提⾼资源的利⽤率 缺点:信号 I/O 在⼤量 IO 操作时可能会因为信号队列溢出导致没法通知
异步阻塞:程序进程向内核发送IO调⽤后,不⽤等待内核响应,可以继续接受其他请求,内核收到进程请求后进⾏的IO如果不能⽴即返回,就由内核等待结果,直到IO完成后内核再通知进程,apache event模型就是主进程+多进程/多线程+信号驱动
信号驱动式IO.jpg
** 异步(⾮阻塞) IO(asynchronous IO):**相对于同步IO,异步IO不是顺序执⾏。⽤⼾进程进⾏aio_read系统调⽤之后,⽆论内核数据是否准备好,都会直接返回给⽤⼾进程,然后⽤⼾态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO两个阶段,进程都是⾮阻塞的。 Linux提供了AIO库函数实现异步,但是⽤的很少。⽬前有很多开源的异步IO库,例如libevent、libev、libuv。异步过程如下图所⽰:
异步⾮阻塞:程序进程向内核发送IO调⽤后,不⽤等待内核响应,可以继续接受其他请求,内核调⽤的IO如果不能⽴即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较⼤的同时并实现较⾼的IO复⽤,因此异步⾮阻塞使⽤最多的⼀种通信⽅式,nginx是异步⾮阻塞。
image.png
三、实现基于域名的PC端和移动端
- 创建PC端配置文件
vim /usr/local/nginx/conf/conf.d/pc.conf
server{
listen 80;
listen 443 ssl;
ssl_certificate /usr/local/nginx/certs/www.tuntun.net.crt;
ssl_certificate_key /usr/local/nginx/certs/www.tuntun.net.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
server_name www.tuntun.net;
charset utf-8;
access_log /usr/local/nginx/logs/access_json.log access_json;
error_page 500 502 503 504 404 /error.html;
location = /error.html {
root /data/nginx/html;
}
location / {
root /data/nginx/html;
index index.html index.php;
}
}
- 创建移动端配置文件
vim /usr/local/nginx/conf/conf.d/mobile.conf
server{
listen 80;
server_name www.mobile.tuntun.net;
charset utf-8;
access_log /usr/local/nginx/logs/access_json.log access_json;
error_page 500 502 503 504 404 /error.html;
location = /error.html {
root /data/nginx/mobile;
}
location / {
root /data/nginx/mobile;
index index.html index.php;
}
location =/jd.jpg {
root /data/nginx/images;
index index.html;
}
}
3、分别为PC端和移动端的页面目录并放置不同代码root /data/nginx/html; root /data/nginx/mobile; 并设置不同域名。
server_name www.tuntun.net;

server_name www.mobile.tuntun.net;




