我就是认真:nginx总结

关于web的基础概念

http服务是一个标准的C/S架构服务,客户端请求,服务端响应。

一个完整的http架构包括:

  • Client:User Agent、Browser、AB命令等压力测试工具(http request)

  • Server:Web Server(http response)

  • Web Object:web resource(URL)

    • css javascript images html

  • ASCII:html(http)纯文本

  • MIME(Multipurpose Internet Mail Extensions):非文本信息重新编码成文本并传输给客户端,客户端再还原成原有的格式并调用相应的应用程序给予展示,其实就是对每一个web内容类型的标识。

    • 内容类型标识:客户端代理去识别内容标识格式,客户端每一种标识对应的MIME类型都有一个与之相关的插件或者外部应用程序,拿到这个标识以后,就调用插件进行解码,先把换用成对应的格式,在用插件来解码或者外部程序。

httpd使用的方法:

GET 获取资源,返回内容body

HEAD 只返回响应首部,不返回响应body

POST 提交表单是用的方法

PUT 上传文件

DELETE 删除远程服务器上的文件

OPTIONS 服务器上对某个资源的请求支持那种方法

TRACE 追踪代理服务器

CONNCET 制定获取资源的方式

http使用TCP/IP来保证可靠传输

一个网页多有个对象,每个对象需要单独请求,为了加速这个过程浏览器支持多线程,比如一次可以发出3个请求,虽然只有一个IP访问,服务可能会用3个进程去响应,可见客户跟请求不是一一对应的。

线程

关于线程的基础概念:

线程分为服务器线程和进程的线程

  • 服务器线程:有些操作系统(Windwos)原生就支持线程,每个线程就是独立的执行单位。

  • 进程的线程:Linux不支持源生态线程机制,所以进程不在负责处理请求,变为仲裁者,派生线程处理请求。

问题:linux支持多少种类型的线程库,如何切换线程库。

WEB服务响应多个用户请求使用的多路响应模型

  1. 单进程:一个进程响应多个用户请求,但同一时间只能处理一个,需要排队。

  2. 多进程/单线程:一个进程中只包含一个线程,每一个进程处理一个请求(服务器进程)

  3. 单进程/多线程:一个进程处理多个请求(进程的线程),线程的开销比进程小很多,线程可以共享进程的资源,响应速度会快些。

  4. 多进程/多线程:多个进程处理N个请求,是对3的扩张,因为一个进程中的线程如果过多,会导致资源争用,解决争用需用仲裁机制,如果仲裁机制面临需要仲裁的时间过多,会导致效率下降,为了避免这种问题,就多启动几个进程。

IO模型

同步 阻塞 (信号完成与否) 闲等状态

同步 非阻塞 (需要时间,阻塞信号和进程) 忙等状态 效率更差

异步 阻塞 (已接受,阻塞信号,进程走) select epoll

异步 非阻塞 (又称作AIO,内核执行回调函数,后续所有工作内核进程完成,回调内容)

select机制

每隔一段时间,扫描所有处理状态,向用户空间通知“完成与否”,一次可以管理的1024个,能力有限,效率也有限。

epoll机制

基于事件通知,每一个用户请求被置成一种状态,当处理完成时,状态会变为完成,epoll机制只将那些已完成的状态通知到用户空间,所打开的文件描述符受操作系统限制。

epoll触发类型 :

  • epoll的边缘触发:只通知一次。

  • epoll的水平触发:通知多次,直到用户空间响应。

五种IO模型

IO发生时涉及的对象和步骤。对于一个网络请求,会涉及到两个系统对象,一个是调用这个请求的进程或线程,另一个就是系统内核。一个有磁盘IO的请求在服务器上等待是两段式的,即:

  • 等待数据准备

  • 将数据从内核拷贝到进程中

通俗的说,就是进程将请求交给cpu,等待cpu返回数据,而进程本身可以是异步、同步、阻塞、非阻塞状态;而内核对磁盘IO的调用,包括从内核内存空间复制到用户内存空间,这些操作都占据了大量的时间。

进程无法直接操作IO设备,必须通过系统调用请求内核来协助IO操作;内核在IO操作时,会为每一个IO设备维护一个buffer,等待数据输入到buffer、从buffer复制到进程内存空间,都需要时间。

根据等待的模式不同,IO动作可以分为五种

Apache模型

apache有三种模型进程处理模块:

  1. Prefork:多进程,每个请求用一个进程响应。

  2. Worker:多进程(每个进程可以生成多个线程),每个请求用一个线程响应,没有优势,因为linux中线程和进程管理机制差不多,而worker实现机制复杂。

  3. Event:多进程,每个进程响应多个用户请求,每个请求用事件来实现。

prefork

Apache在启动之初,就预派生 fork一些子进程,然后等待请求进来,子进程进行处理请求,并且总是保持一些备用的子进程。在Unix系统中,父进程通常以root身份运行以便邦定80端口,而 Apache产生的子进程通常以一个低特权的用户运行。User和Group指令用于配置子进程的低特权用户。运行子进程的用户必须要对他所服务的内容有读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。

  • 优点:

    成熟,兼容所有新老模块。进程之间完全独立,使得它非常稳定。同时,不需要担心线程安全的问题。

  • 缺点:

    一个进程相对占用更多的系统资源,消耗更多的内存(重量级)。而且,它并不擅长处理高并发请求,在这种场景下,它会将请求放进队列中,一直等到有可用进程,请求才会被处理。

worker

Worker模式使用多进程+多线程的模式,预先fork了几个子进程(数量比较少),每个子进程能够生成一些服务线程和一个监听线程,该监听线程监听接入请求并将其传递给服务线程处理和应答。Apache总是试图维持一个备用(spare)或是空闲的服务线程池。这样,客户端无须等待新线程或新进程的建立即可得到处理。

  • 优点:占据更少的内存,高并发下表现更优秀。

  • 缺点:线程安全的问题,因为多个子线程是共享父进程的内存地址的。如果使用keep-alive的长连接方式,也许中间几乎没有请求,这时就会发生阻塞,线程被挂起,需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用。也就是说线程抢占资源问题。

event

Event MPM解决了 keep-alive 场景下 ,长期被占用的线程的资源浪费问题。event MPM中,会有一个专门的线程来管理这些 keep-alive 类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样,一个线程就能处理几个请求了,实现了异步非阻塞。

event MPM需要Linux系统(Linux 2.6+)对Epoll的支持,才能启用。

what

高并发的网络复用

基于线程(worker)

不管是线程还是进程模式,在并发访问下,磁盘IO完成,线程响应用户就必须在cpu上执行,把用户报文通过网络给用户, 线程过多切换本身就会有很大开销,如果每个用户都等待时间很短,那么切换频率势必高,就会带来线程抖动,过快不好,过慢也不好,不快不慢的时候切换本身也是有开销的。

基于事件(event)

一个进程只能干一件事,多个用户请求进来应该如何相应?其实仔细分析过程,会发现进程其实并不忙,进程接收到一个用户请求以后,发现用户是请求资源的,而资源在磁盘上,取得资源需要通过系统调用,系统调用需用磁盘IO,磁盘IO需要时间,磁盘IO完全之前进程处于空闲状态,如果一个进程可以相应多个用户请求,则需要run-lookup机制。

run-lookup机制

进程内部不停循环,一个进程处于LISTENING状态就意味着被动打开,而后第三次握手之后变 为ESTABLISHED状态,此时无法接受其他用户请起,直到状态转变为LISTENING,而这段时间需要等待系统调用(磁盘IO),而run-lookup机制则不等待系统调用完成,交于后续机制epoll完成相应处理,直接将ESTABLISHED状态重新转换成LISTENING状态,所以此进程一直是LISTENING,就可以同时接收多个用户的请求,实现网络复用。

高并发的磁盘复用

单硬盘

单硬盘下任何IO模型没有意义:磁臂只有一个,不可能同时取出2个文件,成型同步阻塞,即使网络使用的是异步阻塞,接受多个用户,服务器性能未必好,服务器性能取决于短板。

多硬盘

多硬盘下应该选择的IO模型:磁盘IO选择epoll效果并不好,因为需要通知,而进程最终目的是获取磁盘数据,所以文件IO上异步非阻塞(文件AIO机制)是最好的,当磁盘IO完成以后直接把数据回调到进程,省去通知过程。

内存映射机制

进程获取数据,需要发起系统调用,在完成系统调用之前,数据是从磁盘上先读到内核空间的内核文件缓冲池buffer中,接着使用copy机制将数据从内核空间复制到用户空间的进程,然后复制则需要开销和时间,为了节约开销和算短时间,引入内存映射机制mmap。

内存映射机制mmap:将buffer物理地址发送给进程,而不是数据。

Nginx模型

nginx官网,是一个俄罗斯人在2002年开始开发的,第一版在2004年问世。

nginx不像传统的web服务器,一个线程响应一个请求,使用事件驱动(异步IO)架构,所以接受的连接数特别大。从而解决了c10k问题(支持三五万并发)。

nginx定义:

  1. 开源的,高性能、轻量级的web服务器

  2. 反向代理服务器:http协议、mail协议

作为web服务器,nginx的特点:

  1. 高性能

  2. 稳定性

  3. 丰富特性

  4. 简单的配置

  5. 低资源消耗

nginx是一个基于事件驱动(event driven),支持边缘触发,mmap,AIO的一种轻量级web服务器。同时nginx还支持Web反向代理,mail(smtp,pop3,imap)反向代理

web服务器

Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均应以非特权用户身份运行。

主进程主要完成如下工作:

  1. 读取并验正配置信息;

  2. 创建、绑定及关闭套接字;

  3. 启动、终止及维护worker进程的个数;

  4. 无须中止服务而重新配置工作特性;

  5. 控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本;

  6. 重新打开日志文件,实现日志滚动;

  7. 编译嵌入式perl脚本;

worker进程主要完成的任务包括:

  1. 接收、传入并处理来自客户端的连接;

  2. 提供反向代理及过滤功能;

  3. nginx任何能完成的其它任务;

cache loader进程主要完成的任务包括:

  1. 检查缓存存储中的缓存对象;

  2. 使用缓存元数据建立内存数据库;

cache manager进程的主要任务:

  1. 缓存的失效及过期检验;

nginx配置

Nginx的配置有着几个不同的上下文:main、http、server、upstream和location(还有实现邮件服务反向代理的mail)。配置语法的格式和定义方式遵循所谓的C风格,因此支持嵌套,还有着逻辑清晰并易于创建、阅读和维护等优势。

Nginx的代码是由一个核心和一系列的模块组成, 核心主要用于提供Web Server的基本功能,以及Web和Mail反向代理的功能;还用于启用网络协议,创建必要的运行时环境以及确保不同的模块之间平滑地进行交互。不过,大多跟协议相关的功能和某应用特有的功能都是由nginx的模块实现的。这些功能模块大致可以分为事件模块、阶段性处理器、输出过滤器、变量处理器、协议、upstream和负载均衡几个类别,这些共同组成了nginx的http功能。事件模块主要用于提供OS独立的(不同操作系统的事件机制有所不同)事件通知机制如kqueue或epoll等。协议模块则负责实现nginx通过http、tls/ssl、smtp、pop3以及imap与对应的客户端建立会话。

在nginx内部,进程间的通信是通过模块的pipeline或chain实现的;换句话说,每一个功能或操作都由一个模块来实现。例如,压缩、通过FastCGI或uwsgi协议与upstream服务器通信,以及与memcached建立会话等。

配置文件

配置文件路径:

 
[root@nginx_rs nginx]# pwd
/etc/nginx
[root@nginx_rs nginx]# ls
fastcgi.conf          fastcgi_params.default  mime.types          nginx.conf.default   uwsgi_params
fastcgi.conf.default  koi-utf                 mime.types.default  scgi_params          uwsgi_params.default
fastcgi_params        koi-win                 nginx.conf          scgi_params.default  win-utf

以default后缀结束的是nginx默认提供的配置文件

其他的是根据编译选项生成的不同的配置文件:

nginx.conf:nginx的主配置文件

mime.types:提供各种非文本文件格式

fastcgi.conf、fastcgi_params:实现fastcgi功能

nginx.conf

nginx.conf是nginx服务的主配置文件

 
user  nginx;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    keepalive_timeout  65;
    #gzip  on;
    server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;
    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}

Nginx的配置文件有着几个不同的上下文:main、http、server、upstream和location(还有实现邮件服务反向代理的mail)。

main段:

 
user  nginx;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;

user:运行nginx服务的用户

worker_processes:如果负载以CPU密集型应用为主(计算多),如SSL或压缩应用,则worker数应与CPU数相同;如果负载以IO密集型为主(读取数据多),如响应大量内容给客户端,则worker数应该为CPU个数的1.5或2倍。

events:

 
events {
    worker_connections  1024;
}

worker_connections:每个cpu的连接数,具体最优的取值应该在测试后得到。

修改worker_connections值的方法

http段:

 
http {
    include       mime.types;   //包含的文件
    default_type  application/octet-stream;     //默认支持的类型
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
//日志格式
    #access_log  logs/access.log  main;
//访问日志
    sendfile        on; //sendfile功能
    #tcp_nopush     on; //不做推送
    #keepalive_timeout  0;  //使用长连接,并指定超时时长
    keepalive_timeout  65;
    #gzip  on;  //对于给用户响应的内容,是否先压缩再发送
  //server段,每一个server段定义一个虚拟主机
    server {
        listen       80;    //监听的端口
        server_name  localhost; //基于名称的虚拟主机,主机名
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {    //定义本地资源位置、格式。基于uri路径,根目录为nginx安装根目录
            root   html;    //相对uri,网页位置路径
            index  index.html index.htm;    //主页面
        }
        #error_page  404                 /404.html; //错误代码
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;
    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}

http段里面也是模块化的形式。

location

location在实现URI匹配时支持五种方式:

  1. location URI {} :表示大括号中所定义的属性的对URI所有文件都生效(包括子路径资源)

  2. location = URI {} :只对当前文件生效,精确匹配路径,不包括子路径

  3. location ~ URI {} :实现模式匹配,可使用正则表达式,但区分大小写

  4. location ~* URI {} :实现模式匹配,不区分大小写

  5. location ^~ URI {} :实现禁用正则表达式匹配,做逐字符匹配

这五种方式有优先级:由高到底:2、5、3、4、1

 
        location / {    //相对root定义的路径,类似于URI
            root   /web;//相对文件系统的路径,类似于URL
            index  index.html index.htm;    //当访问主页时,如IP:index.html,会找到服务器的/web/index.html
        }
        location /bbs/ {
            root   /web/;
            index  index.html index.htm;    //访问ip:/bbs/时,会找到服务器的/web/bbs/index.html
        }
        error_page  404              /404.html;     //设置404错误页面
        location = /404.html {
                root /web/error/;   //当访问到一个不存在的页面时,会被定义到/web/error/404.html
        }
        error_page   500 502 503 504  /error.html;
        location = /error.html {
            root   /web/error/;
        }

location下的一些定义法则:

ip禁止和允许

deny IP 指定拒绝访问的IP地址,类似黑名单

allow IP 指定允许访问的IP地址,类似白名单

如:

 
        location /bbs/ {
            root   /web/;
            allow 172.25.254.11;
            deny 172.25.254.18;
            index  index.html index.htm;
        }

记得重启nginx服务器

IP为172.25.254.11的主机访问:

[root@bogon ~]# curl 172.25.254.18:/bbs/index.html<h1> nginx for BBS </h1>

IP为172.25.254.18的主机访问:

[root@nginx_rs error]# curl 172.25.254.18:/bbs/index.html<html><head><title>403 Forbidden</title></head><body bgcolor="white"><center><h1>403 Forbidden</h1></center><hr><center>nginx/fsx-1.0</center></body></html>

auth_basic模块

auth_basic "restricted";

auth_basic_user_file htpasswd;

创建认证文件,存储用户和用户名

 
[root@nginx_rs error]# htpasswd -c -m /etc/nginx/.user fsx
New password: 
Re-type new password: 
Adding password for user fsx
//第一次添加使用-c,之后就不需要使用-c,-m使用md5加密
[root@nginx_rs nginx]# cat .user 
fsx:$apr1$of9jUy26$KvEEld92It/4rE2ULxYEu0

编译nginx.conf文件:

 
        location /bbs/ {
            root   /web/;
            #allow 172.25.254.11;
            #deny 172.25.254.18;
            auth_basic  "Restricted Area";
            auth_basic_user_file  /etc/nginx/.user;
            index  index.html index.htm;
        }

在浏览器上访问时,会让使用用户名和密码登陆。记得重启服务器。

autoindex自动索引模块

autoindex on|off

autoindex_exact_size :显示精确值

autoindex_localtime :当前操作系统得时间

如果没有index文件,将所有资源罗列出来。

stub_status显示状态信息模块

使用到的模块:--with-http_stub_status_module

定义一个location:

 
        location /status {
                stub_status on;
                access_log  off;
                allow 172.25.254.11;
                deny all;
        }
//只允许172.25.254.11IP地址访问状态信息
//reload服务器

IP为172.25.254.11的主机可以访问状态信息

 
[root@bogon ~]# curl 172.25.254.18:/status
Active connections: 1   //当前处于活动状态的连接个数
server accepts handled requests //服务器段已经处理的请求个数。
//accept接受的连接数、handled处理的连接数、requests处理的请求数
 2 2 2 
Reading: 0 Writing: 1 Waiting: 0 
//reading:正在读请求首部的个数、writing:读的请求主体,进程请求,或正在响应客户端、waiting:处于长连接状态,处于活动状态
ssl模块

创建ssl证书:(实验环境服务器既是ca认证端,也是ca申请端)

服务端:

  1. 生成私钥

     
    [root@nginx_rs CA]# (umask 077;openssl genrsa 2048 > private/cakey.pem)
    Generating RSA private key, 2048 bit long modulus
    ............+++
    ............+++
    e is 65537 (0x10001)
  2. 生成自签证书

     
    [root@nginx_rs CA]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:CN
    State or Province Name (full name) []:SX
    Locality Name (eg, city) [Default City]:XA
    Organization Name (eg, company) [Default Company Ltd]:westos
    Organizational Unit Name (eg, section) []:xupt
    Common Name (eg, your name or your server's hostname) []:ca.fsx.com
    Email Address []:[email protected]
  3. 创建几个文件

     
    [root@nginx_rs CA]# touch serial
    [root@nginx_rs CA]# touch "01" > serial 
    [root@nginx_rs CA]# touch index.txt

客户端:

  1. 创建目录存放证书

     
    [root@nginx_rs nginx]# mkdir /etc/nginx/ssl
    [root@nginx_rs nginx]# cd /etc/nginx/ssl/
  2. 创建私钥

     
    [root@nginx_rs ssl]# (umask 077;openssl genrsa 1024) > nginx.key
    Generating RSA private key, 1024 bit long modulus
    ....++++++
    .................................................++++++
    e is 65537 (0x10001)
  3. 创建自签证书

     
    [root@nginx_rs ssl]# openssl req -new -key nginx.key -out nginx.csr
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:CN
    State or Province Name (full name) []:SX
    Locality Name (eg, city) [Default City]:XA
    Organization Name (eg, company) [Default Company Ltd]:westos
    Organizational Unit Name (eg, section) []:xupt
    Common Name (eg, your name or your server's hostname) []:www.fsx.com
    Email Address []:
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
  4. 创建ca认证证书

     
    [root@nginx_rs ssl]# openssl ca -in nginx.csr -out nginx.crt -days 3650
    Using configuration from /etc/pki/tls/openssl.cnf
    Check that the request matches the signature
    Signature ok
    Certificate Details:
            Serial Number: 1 (0x1)
            Validity
                Not Before: Jun 15 07:19:18 2018 GMT
                Not After : Jun 12 07:19:18 2028 GMT
            Subject:
                countryName               = CN
                stateOrProvinceName       = SX
                organizationName          = westos
                organizationalUnitName    = xupt
                commonName                = www.fsx.com
            X509v3 extensions:
                X509v3 Basic Constraints: 
                    CA:FALSE
                Netscape Comment: 
                    OpenSSL Generated Certificate
                X509v3 Subject Key Identifier: 
                    0C:A0:E2:41:95:2E:90:AE:EB:70:5E:F5:08:E2:BE:71:19:8E:AD:DE
                X509v3 Authority Key Identifier: 
                    keyid:E1:6A:FB:97:7C:7A:77:32:B8:B1:9C:EE:F6:A7:6A:5D:A2:A0:34:09
    Certificate is to be certified until Jun 12 07:19:18 2028 GMT (3650 days)
    Sign the certificate? [y/n]:y

    1 out of 1 certificate requests certified, commit? [y/n]yWrite out database with 1 new entriesData Base Updated

 
修改nginx配置文件:
~~~nginx
    server {
        listen       443 ssl;
        server_name  nginx_rs;
        ssl_certificate      nginx.crt;
        ssl_certificate_key  nginx.key;
        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;
        location / {
            root   /web/https/;
            index  index.html index.htm;
        }
    }

reload服务

查看nginx启动443端口:

 
[root@nginx_rs nginx]# netstat -antple |grep 443
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      0          44385      4594/nginx: master  

使用浏览器访问:https:172.25.254.18即可成功访问https

基于主机名的nginx虚拟主机

在server模块外,重新定义一个server模块,即可实现虚拟主机。

添加新的server模块:

 
        server {
                listen 80;
                server_name fsx.a.com;
                location / {
                        root /web/virtul2/; //改目录需要创建
                        index index.html;   //改文件需要新建
                }

reload服务

添加域名解析:(这里仅仅实验,在客户端/etc/hosts内添加域名解析)

访问:

 
[root@bogon ~]# curl fsx.a.com
<h1> nginx for virtul service </h1>
[root@bogon ~]# curl 172.25.254.18
<h1> welcome to nginx </h1>

web反向代理

Web代理是工作在应用层的,会重新封装tcp/ip和http首部,服务器响应给代理服务器,而后代理服务器再相应给客户端,客户端意识不到后台服务器的存在,大部分请求分装都是由代理完成的。

nginx反响代理基于异步阻塞,web代理可以暂存客户端数据,待处理完成一起同步到后端服务器,客户端不用在意后端服务器是否在线。

什么是反向代理?什么是正向代理?

反向代理:工作在服务器前端,如nginx

正向代理:工作在客户端前端,如vpn

nginx反向代理

nginx可以作为七层协议上的负载均衡主机,即在应用层上的负载均衡主机,七层负载是面向服务的,报文已经被转发至用户空间,这是不同于四层负载的地方(四层负载在内核(TCP协议栈)就被转发给后台RS)。

proxy模块

Nginx通过proxy模块实现反向代理功能。在作为web反向代理服务器时,nginx负责接收客户请求,并能够根据URI、客户端参数或其它的处理逻辑将用户请求调度至上游服务器上(upstream server)。nginx在实现反向代理功能时的最重要指令为proxy_pass,它能够将location定义的某URI代理至指定的上游服务器(组)上。如下面的示例中,location的/uri将被替换为上游服务器上的/newuri。

 
location /uri {
        proxy_pass http://www.fsx.com:/newuri;
    }

不过,这种处理机制中有两个例外。

  • 一个是如果location的URI是通过模式匹配定义的,其URI将直接被传递至上游服务器,而不能为其指定转换的另一个URI。例如下面示例中的/forum将被代理为:http://www.fsx.com/forum

 
    location ~ ^/bbs {
        proxy_pass http://www.fsx.com;
    }
  • 如果在loation中使用的URL重定向,那么nginx将使用重定向后的URI处理请求,而不再考虑上游服务器上定义的URI。如下面所示的例子中,传送给上游服务器的URI为/index.php?page=<match>,而不是/index。

 
    location / {
        rewrite /(.*)$ /index.php?page=$1 break;
        proxy_pass http://localhost:8080/index;
    }
proxy模块的指令

proxy模块的可用配置指令非常多,它们分别用于定义proxy模块工作时的诸多属性,如连接超时时长、代理时使用http协议版本等。下面对常用的指令做一个简单说明。

proxy_connect_timeout:nginx将一个请求发送至upstream server之前等待的最大时长;proxy_cookie_domain:将upstream server通过Set-Cookie首部设定的domain属性修改为指定的值,其值可以为一个字符串、正则表达式的模式或一个引用的变量;proxy_cookie_path: 将upstream server通过Set-Cookie首部设定的path属性修改为指定的值,其值可以为一个字符串、正则表达式的模式或一个引用的变量;proxy_hide_header:设定发送给客户端的报文中需要隐藏的首部;proxy_pass:指定将请求代理至upstream server的URL路径;proxy_set_header:将发送至upsream server的报文的某首部进行重写;proxy_redirect:重写location并刷新从upstream server收到的报文的首部;proxy_send_timeout:在连接断开之前两次发送至upstream server的写操作的最大间隔时长;proxy_read_timeout:在连接断开之前两次从接收upstream server接收读操作的最大间隔时长;

设置示例:

 
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout 30;
    proxy_send_timeout 15;
    proxy_read_timeout 15;
proxy_pass指令

在server模块内部,设置反向代理:

 
        location ^~  /proxy/ {
                proxy_pass http://172.25.254.18:80;
        }//这就是特殊情况一,不能为其指定转换的另一个URI
        location   /forum {
                proxy_pass http://172.25.254.18:80/bbs;
        }//这是将访问本地ip/forum转发给172.25.254.18,并访问改服务器发布目录下的/bbs目录
upstream模块

与proxy模块结合使用的模块中,最常用的就是upstream模块。upstream模块可定义一个新的上下文,它包含了一组upstream服务器,这些服务器可能被赋予了不同的权重、不同的类型甚至可以基于维护等原因被标记为down。

upstream模块的指令

upstream模块常用的指令有:

ip_hash:基于客户端IP地址完成请求的分发,它可以保证来自于同一个客户端的请求始终被转发至同一个upstream服务器;keepalive:每个worker进程为发送到upstream服务器的连接所缓存的个数;least_conn:最少连接调度算法;server:定义一个upstream服务器的地址,还可包括一系列可选参数,如:

 
weight:权重;
max_fails:最大失败连接次数,失败连接的超时时长由fail_timeout指定;
fail_timeout:等待请求的目标服务器发送响应的时长;
backup:用于fallback的目的,所有服务均故障时才启动此服务器;
down:手动标记其不再处理任何请求;

如:

 
upstream backend {
  server www.fsx.com weight=5;
  server www2.fsx.com:8080       max_fails=3  fail_timeout=30s;
}

upstream模块的负载均衡算法主要有三种,轮调(round-robin)、ip哈希(ip_hash)和最少连接(least_conn)三种。

upstream定义一个后端服务器组,定义在server模块之外。

 
upstream backend {
  server IP:PORT weight=n;
  server IP:PORT weight=n'
  ...
  server unix:/tmp/backend3;
  
}
server {
  location / {
    proxy_pass http:backend;
  }
  
}

实例配置:

172.25.254.11和172.25.254.18均提供web服务,172.25.254.17为nginx反向代理服务器IP地址

编辑172.25.254.17nginx反向代理服务器主配置文件,nginx.conf

在server外部设置upstream模块:

 
    upstream fsx {
        server 172.25.254.11:80 weight=3 max_fails=2 fail_timeout=2;
        server 172.25.254.18:80 weight=1;
        server 127.0.0.1 backup;
        }

在server内部设置发向代理,并指向upstream模块:

 
        location /fsx {
                proxy_pass http://fsx/;
                index index.html;
        }

访问代理服务器:

 
[root@nginx nginx]# for i in {1..10};do curl 172.25.254.17/fsx;done
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.18 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.18 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.11 </h1>
<h1> RS 172.25.254.11 </h1>
nginx缓存

nginx做为反向代理时,能够将来自upstream的响应缓存至本地,并在后续的客户端请求同样内容时直接从本地构造响应报文。

nginx缓存大致上由两部分组成:

  • cache:共享内存(存储键和缓存对象元数据),查找在内存上

  • data:数据在磁盘空间

proxy_cache_path:定义缓存空间(不能定义在server段中,在http段中),属于proxy模块

proxy_cache_path:定义一个用记保存缓存响应报文的目录,及一个保存缓存对象的键及响应元数据的共享内存区域(keys_zone=name:size),其可选参数有:

levels:每级子目录名称的长度,有效值为1或2,每级之间使用冒号分隔,最多为3级;1:2表示两个级别目录,一级子目录由一个字符组成,二级子目录由二个字符组成
keys_zone:给共享内存命名,存储键的区域,可以定义多个区域,每个区域要有个名称引用。
inactive:非活动缓存项从缓存中剔除之前的最大缓存时长;
max_size:缓存空间大小的上限,当需要缓存的对象超出此空间限定时,缓存管理器将基于LRU算法对其进行清理;
loader_files:缓存加载器(cache_loader)的每次工作过程最多为多少个文件加载元数据;
loader_sleep:缓存加载器的每次迭代工作之后的睡眠时长;
loader_threashold:缓存加载器的最大睡眠时长;
例如:  proxy_cache_path  /data/nginx/cache/one    levels=1      keys_zone=one:10m;
		proxy_cache_path  /data/nginx/cache/two    levels=2:2    keys_zone=two:100m;
		proxy_cache_path  /data/nginx/cache/three  levels=1:1:2  keys_zone=three:1000m;

在proxy反向代理服务器上实现cache:

  1. 编辑nginx.conf文件,添加cache模块

     
        proxy_cache_path /nginx/cache/first levels=1:2 keys_zone=first:20m max_size=1g;
        upstream fsx {
            #ip_hash;
            server 172.25.254.11:80 weight=3 max_fails=2 fail_timeout=2;
            server 172.25.254.18:80 weight=1;
            server 127.0.0.1 backup;
            }

    在指定的location模块中启用chache

     
            location /fsx {
                    proxy_pass http://fsx/;
                    proxy_cache first;
                    proxy_cache_valid 200 10m;
            }
            add_header X-Via $server_addr;
            add_header X_cache_hit $upstream_cache_status;

  2. 创建指定的目录

    [root@nginx nginx]# mkdir -p /nginx/cache/first/
    
  3. 重启服务(reload即可)

     
    [root@nginx nginx]# nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    [root@nginx nginx]# nginx -s reload
  4. 在浏览器访问服务器URL:IP/fsx,因为使用了缓存,所以不会负载均衡

  5. 查看缓存文件

     
    [root@nginx 3e]# pwd
    /nginx/cache/first/4/3e
    [root@nginx 3e]# ls
    b902746d2bc6b97f03809b8f36d263e4
    [root@nginx 3e]# file b902746d2bc6b97f03809b8f36d263e4 
    b902746d2bc6b97f03809b8f36d263e4: Hitachi SH big-endian COFF object, not stripped
  6. 浏览器上按F12可以查看到response header信息

     
    Accept-Ranges: bytes
    Connection: keep-alive
    Content-Length: 201
    Content-Type: text/html; charset=UTF-8
    Date: Sat, 16 Jun 2018 16:04:47 GMT
    Etag: "c9-56de7d12abff8"
    Last-Modified: Tue, 05 Jun 2018 16:48:17 GMT
    Server: nginx/fsx-1.0 server
    X-Via: 172.25.254.17    //服务器地址
    X_cache_hit: HIT        //命中

也可以这样编辑:

		add_header X-Via $server_addr;
        add_header X_cache_hit $upstream_cache_status;
更改为:
		add_header X_cache "$upstream_cache_status from $server_addr";
效果相同

proxy_cache其他的一些指令:

proxy_cache zone|off:定义一个用于缓存的共享内存区域,其可被多个地方调用;缓存将遵从up stream服务器的响应报文首部中关于缓存的设定,如 "Expires"、"Cache-Control: no-cache"、 "Cache-Control: max-age=XXX"、"private"和"no-store" 等,但nginx在缓存时不会考虑响应报文的"Vary"首部。为了确保私有信息不被缓存,所有关于用户的私有信息可以upstream上通过"no-cache" or "max-age=0"来实现,也可在nginx设定proxy_cache_key必须包含用户特有数据如$cookie_xxx的方式实现,但最后这种方式在公共缓存上使用可能会有风险。因此,在响应报文中含有以下首部或指定标志的报文将不会被缓存。

Set-Cookie
Cache-Control containing "no-cache", "no-store", "private", or a "max-age" with a non-numeric or 0 value
Expires with a time in the past
X-Accel-Expires: 0

proxy_cache_key:设定在存储及检索缓存时用于“键”的字符串,可以使用变量为其值,但使用不当时有可能会为同一个内容缓存多次;另外,将用户私有信息用于键可以避免将用户的私有信息返回给其它用户; proxy_cache_lock:启用此项,可在缓存未命令中阻止多个相同的请求同时发往upstream,其生效范围为worker级别;proxy_cache_lock_timeout:proxy_cache_lock功能的锁定时长;proxy_cache_min_uses:某响应报文被缓存之前至少应该被请求的次数;

proxy_cache_use_stale:在无法联系到upstream服务器时的哪种情形下(如error、timeout或http_500等)让nginx使用本地缓存的过期的缓存对象直接响应客户端请求;其格式为:

proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off 

proxy_cache_valid [ code ...] time:用于为不同的响应设定不同时长的有效缓存时长,例如:proxy_cache_valid 200 302 10m;proxy_cache_methods [GET HEAD POST]:为哪些请求方法启用缓存功能;proxy_cache_bypass string:设定在哪种情形下,nginx将不从缓存中取数据;例如:

 proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;

proxy_cache_bypass http_authorization;

使用示例:

 
http {
    proxy_cache_path  /data/nginx/cache  levels=1:2    keys_zone=STATIC:10m
                                         inactive=24h  max_size=1g;
    server {
        location / {
            proxy_pass             http://www.magedu.com;
            proxy_set_header       Host $host;
            proxy_cache            STATIC;
            proxy_cache_valid      200  1d;
            proxy_cache_valid      301 302 10m;
            proxy_cache_vaild      any 1m;
            proxy_cache_use_stale  error timeout invalid_header updating
                                   http_500 http_502 http_503 http_504;
        }
    }
}

另外常用的三种缓存:

  • open_log_cache:日志缓存

  • open_file_cache:将打开的文件直接缓存到nginx内存空间

  • fastcgi_cache:将php处理的结果缓存到nginx内存空间

nginx的limit限制也基于共享内存实现。

nginx压缩功能

nginx将响应报文发送至客户端之前可以启用压缩功能,这能够有效地节约带宽,并提高响应至客户端的速度。通常编译nginx默认会附带gzip压缩的功能,因此,可以直接启用。

gzip_proxied指令可以定义对客户端请求哪类对象启用压缩功能,如“expired”表示对由于使用了expire首部定义而无法缓存的对象启用压缩功能,其它可接受的值还有“no-cache”、“no-store”、“private”、“no_last_modified”、“no_etag”和“auth”等,而“off”则表示关闭压缩功能。

如:

 
http {
    gzip on;
    gzip_http_version 1.0;
    gzip_comp_level 2;
    gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript application/json;
    gzip_disable msie6;
}
nginxURL重定向

rewrite是实现URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。

Nginx的rewrite功能在企业里应用非常广泛:

  • 可以调整用户浏览的URL,看起来更规范,合乎开发及产品人员的需求。

  • 为了让搜索引擎搜录网站内容及用户体验更好,企业会将动态URL地址伪装成静态地址提供服务。

  • 网址换新域名后,让旧的访问跳转到新的域名上。例如,访问京东的360buy.com会跳转到jd.com

  • 根据特殊变量、目录、客户端的信息进行URL调整等

rewrite语法格式及参数:

rewrite <regex> <replacement> [flag];
rewrite:关键字,不能改变,可以在http段定义、也可以在location模块定义
<regex>:正则
<replacement>:代替内容,将正则内容替换成<replacement>的内容
[flag]:标记,可以不定义

关于flag可以选取四个参数:

  • last #本条规则匹配完成后,继续向下匹配新的location URI规则

  • break #本条规则匹配完成即终止,不再匹配后面的任何规则

  • redirect #返回302临时重定向,浏览器地址会显示跳转后的URL地址

  • permanent #返回301永久重定向,浏览器地址栏会显示跳转后的URL地址

例如:

 
rewrite ^/poem/(.*)$ http://172.25.254.18/libai/$1 redirect;
^/poem/(.*)$,是一个正则表达式,匹配URL下poem目录里的所有内容
http://172.25.254.18/libai/$1,将正则匹配的内容重写到某一个主机下libai目录内
redirect:302临时重定向
常用正则表达式说明
字符 描述
\ 将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如“\n”匹配一个换行符,而“$”则匹配“$”
^ 匹配输入字符串的起始位置
$ 匹配输入字符串的结束位置
* 匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”
+ 匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“oll”,但不能匹配“o”
? 匹配前面的字符零次或一次,例如“do(es)?”能匹配“do”或者“does”,"?"等效于"{0,1}"
. 匹配除“\n”之外的任何单个字符,若要匹配包括“\n”在内的任意字符,请使用诸如“[.\n]”之类的模式。
(pattern) 匹配括号内pattern并可以在后面获取对应的匹配,常用9属性获取小括号中的匹配内容,要匹配圆括号字符需要(Content)

具体配置:

  1. 编辑172.25.254.17服务器nginx配置文件,在server段添加:

     
            location / {
                root   html;
                index  index.html index.htm;
                rewrite ^/poem/(.*)$ http://172.25.254.18/libai/$1 redirect;
            }

    将当前服务器的URL/poem/临时重定向到172.25.254.18RS服务器的URL/libai/目录下

  2. 172.25.254.18nginx服务器开启,并在发布目录下有libai目录

     
    [root@nginx_rs libai]# pwd
    /web/libai
    [root@nginx_rs libai]# cat index.html 
    <h1> rewrite for nginx </h1>
  3. 在浏览器上访问172.25.254.17/poem会被重定向到172.25.254.18/libai/

  4. 在终端使用curl命令会有如下效果:

     
    [root@nginx nginx]# curl 172.25.254.17/poem/
    <html>
    <head><title>302 Found</title></head>
    <body bgcolor="white">
    <center><h1>302 Found</h1></center>
    <hr><center>nginx/fsx-1.0 server</center>
    </body>
    </html>

    表示已经被临时重定向了

nginx读写分离

在location模块内,使用if:

 
        location   /forum {
                proxy_pass http://172.25.254.11:80/;
                if ($request_method = "PUT") {
                        proxy_pass http://172.25.254.18:80;
                }
        }

当访问nginx服务器URL/forum时,读操作11服务器完成。如果时PUT操作,只能18完成

读操作:

 
[root@nginx nginx]# curl 172.25.254.17:/forum
<h1>范顺心</h1>
<a href="/fsx.html" download="fsx">
<img border="0" src="/fsx.html" alt="点击下载">
</a>
<a href="/html" download="博客">
<img border="0" src="/html" alt="进入博客">
</a>
[root@nginx nginx]# curl 172.25.254.11
<h1>范顺心</h1>
<a href="/fsx.html" download="fsx">
<img border="0" src="/fsx.html" alt="点击下载">
</a>
<a href="/html" download="博客">
<img border="0" src="/html" alt="进入博客">
</a>
[root@nginx nginx]# curl 172.25.254.18
<h1> welcome to nginx </h1>

反复刷新,读操作也只负载到172.25.254.11服务器上

写操作:

 
[root@nginx nginx]# curl -T nginx.conf 172.25.254.17:/forum
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0<html>
<head><title>405 Not Allowed</title></head>
<body bgcolor="white">
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/fsx-1.0</center>
</body>
</html>
100  3705  100   174  100  3531   148k  3008k --:--:-- --:--:-- --:--:-- 3448k

此时上传的nginx.conf文件被上传到172.25.254.18服务器上

猜你喜欢

转载自blog.csdn.net/fsx2550553488/article/details/80721983