nginx简介

Nginx是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。

nginx 多线程下载_nginx

反向代理服务器?

经常听人说到一些术语,如反向代理,那么什么是反向代理,什么又是正向代理呢?                                                                       

nginx 多线程下载_配置文件_02

 

nginx 多线程下载_Nginx_03

反向代理示意图

由于防火墙的原因,我们并不能直接访问谷歌,那么我们可以借助VPN来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,而且客户端是知道目标的,而目标是不知道客户端是通过VPN访问的。

当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。

Nginx的Master-Worker模式

nginx 多线程下载_Nginx_04

nginx进程

启动Nginx后,其实就是在80端口启动了Socket服务进行监听,如图所示,Nginx涉及Master进程和Worker进程。

nginx 多线程下载_Nginx_05

Master-Worker模式

nginx 多线程下载_配置文件_06

nginx.conf

Master进程的作用是?

读取并验证配置文件nginx.conf;管理worker进程;

Worker进程的作用是?

每一个Worker进程都维护一个线程(避免线程切换),处理连接和请求;注意Worker进程的个数由配置文件决定,一般和CPU个数相关(有利于进程切换),配置几个就有几个Worker进程。

思考:Nginx如何做到热部署?

所谓热部署,就是配置文件nginx.conf修改后,不需要stop Nginx,不需要中断请求,就能让配置文件生效!(nginx -s reload 重新加载/nginx -t检查配置/nginx -s stop)

通过上文我们已经知道worker进程负责处理具体的请求,那么如果想达到热部署的效果,可以想象:

方案一:

修改配置文件nginx.conf后,主进程master负责推送给woker进程更新配置信息,woker进程收到信息后,更新进程内部的线程信息。(有点valatile的味道)

方案二:

修改配置文件nginx.conf后,重新生成新的worker进程,当然会以新的配置进行处理请求,而且新的请求必须都交给新的worker进程,至于老的worker进程,等把那些以前的请求处理完毕后,kill掉即可。

Nginx采用的就是方案二来达到热部署的!

思考:Nginx如何做到高并发下的高效处理?

上文已经提及Nginx的worker进程个数与CPU绑定、worker进程内部包含一个线程高效回环处理请求,这的确有助于效率,但这是不够的。

作为专业的程序员,我们可以开一下脑洞:BIO/NIO/AIO、异步/同步、阻塞/非阻塞...

要同时处理那么多的请求,要知道,有的请求需要发生IO,可能需要很长时间,如果等着它,就会拖慢worker的处理速度。

Nginx采用了Linux的epoll模型,epoll模型基于事件驱动机制,它可以监控多个事件是否准备完毕,如果OK,那么放入epoll队列中,这个过程是异步的。worker只需要从epoll队列循环处理即可。

思考:Nginx挂了怎么办?

Nginx既然作为入口网关,很重要,如果出现单点问题,显然是不可接受的。

答案是:Keepalived+Nginx实现高可用

Keepalived是一个高可用解决方案,主要是用来防止服务器单点发生故障,可以通过和Nginx配合来实现Web服务的高可用。(其实,Keepalived不仅仅可以和Nginx配合,还可以和很多其他服务配合)

Keepalived+Nginx实现高可用的思路:

第一:请求不要直接打到Nginx上,应该先通过Keepalived(这就是所谓虚拟IP,VIP)

第二:Keepalived应该能监控Nginx的生命状态(提供一个用户自定义的脚本,定期检查Nginx进程状态,进行权重变化,,从而实现Nginx故障切换)

nginx 多线程下载_Nginx_07

Keepalived+Nginx

我们的主战场:nginx.conf

很多时候,在开发、测试环境下,我们都得自己去配置Nginx,就是去配置nginx.conf。

nginx.conf是典型的分段配置文件,下面我们来分析下。

虚拟主机

nginx 多线程下载_nginx 多线程下载_08

http的server段

nginx 多线程下载_nginx 多线程下载_09

访问结果

其实这是把Nginx作为web server来处理静态资源。

第一:location可以进行正则匹配,应该注意正则的几种形式以及优先级。(这里不展开)

第二:Nginx能够提高速度的其中一个特性就是:动静分离,就是把静态资源放到Nginx上,由Nginx管理,动态请求转发给后端。

第三:我们可以在Nginx下把静态资源、日志文件归属到不同域名下(也即是目录),这样方便管理维护。

第四:Nginx可以进行IP访问控制,有些电商平台,就可以在Nginx这一层,做一下处理,内置一个黑名单模块,那么就不必等请求通过Nginx达到后端在进行拦截,而是直接在Nginx这一层就处理掉。

反向代理【proxy_pass】

所谓反向代理,很简单,其实就是在location这一段配置中的root替换成proxy_pass即可。root说明是静态资源,可以由Nginx进行返回;而proxy_pass说明是动态请求,需要进行转发,比如代理到Tomcat上。

反向代理,上面已经说了,过程是透明的,比如说request -> Nginx -> Tomcat,那么对于Tomcat而言,请求的IP地址就是Nginx的地址,而非真实的request地址,这一点需要注意。不过好在Nginx不仅仅可以反向代理请求,还可以由用户自定义设置HTTP HEADER

负载均衡【upstream】

上面的反向代理中,我们通过proxy_pass来指定Tomcat的地址,很显然我们只能指定一台Tomcat地址,那么我们如果想指定多台来达到负载均衡呢?

第一,通过upstream来定义一组Tomcat,并指定负载策略(IPHASH、加权论调、最少连接),健康检查策略(Nginx可以监控这一组Tomcat的状态)等。

第二,将proxy_pass替换成upstream指定的值即可。

负载均衡可能带来的问题?

负载均衡所带来的明显的问题是,一个请求,可以到A server,也可以到B server,这完全不受我们的控制,当然这也不是什么问题,只是我们得注意的是:用户状态的保存问题,如Session会话信息,不能在保存到服务器上。

缓存

缓存,是Nginx提供的,可以加快访问速度的机制,说白了,在配置上就是一个开启,同时指定目录,让缓存可以存储到磁盘上。具体配置,大家可以参考Nginx官方文档,这里就不在展开了。

常用命令:

nginx -s stop       快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。
nginx -s quit       平稳关闭Nginx,保存相关信息,有安排的结束web服务。
nginx -s reload     因改变了Nginx相关配置,需要重新加载配置而重载。
nginx -s reopen     重新打开日志文件。
nginx -c filename   为 Nginx 指定一个配置文件,来代替缺省的。
nginx -t            不运行,而仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件。
nginx -v            显示 nginx 的版本。
nginx -V            显示 nginx 的版本,编译器版本和配置参数。

通过nginx访问静态文件配置 

进入 /usr/local/nginx/conf 或者/etc/nginx/conf.d/

sudo cd /etc/nginx/conf.d/
sudo vi test.conf
修改 test.conf 文件

server{
	listen 9090;
	server_name localhost;
	location / {
		root html;
		index  index.html  index.htm;
	}
	location /file/ {
		alias /message_api_svr/upload/;
		autoindex on;
	}
}

sudo systemctl restart nginx 重启nginx服务

就可以通过:http://localhost:9090/file/xxx.txt 访问相应的文件,其他开通访问该服务器的9090端口访问权限的也可以通过这种路径访问下面文件http://10.2.XX.XX:9090/file/xxx.txt

nginx 80端口重定向到443端口

nginx 80端口重定向到443端口,也就是http访问自动跳转到https,按照如下格式修改nginx.conf 配置文件,80端口会自动转给443端口,这样就强制使用SSL证书加密了。访问http的时候会自动跳转到https上面。

server {
    listen 80;
    server_name www.test.com;
    rewrite ^(.*)$ https://${server_name}$1 permanent; 
}

server {
    listen 443;
    server_name www.test.com;
    ssl on;
    ssl_certificate   /etc/pki/CA/certs/214321311540956.pem;
    ssl_certificate_key  /etc/pki/CA/certs/214321311540956.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;   
    index index.php index.htm index.html;
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location ~ \.php {
    root /alidata/www/html;
    fastcgi_pass unix:/tmp/php-cgi.sock;
    fastcgi_index index.php;
    include   fastcgi.conf;

    set $path_info "";
    set $fastcgi_script_name_new $fastcgi_script_name;

        if ($fastcgi_script_name ~*   "^(.+\.php)(/.+)$"  ) {
            set $fastcgi_script_name_new $1;
        set $path_info $2;
    }

    fastcgi_param   SCRIPT_FILENAME   $document_root$fastcgi_script_name_new;
    fastcgi_param   SCRIPT_NAME   $fastcgi_script_name_new;                    
    fastcgi_param   PATH_INFO $path_info;
    }

    location / {
    root /alidata/www/html;
    index index.php index.html index.htm;
    if (!-e  $request_filename){
        rewrite ^(.*)$ /index.php$1 last;
    }
  }
}

 把http重定向到https使用了nginx的重定向命令。那么应该如何写重定向?之前老版本的nginx可能使用了以下类似的格式。

rewrite ^/(.*)$ http://domain.com/$1 permanent;

或者

rewrite ^ http://domain.com$request_uri? permanent;

现在nginx新版本已经换了种写法,上面这些已经不再推荐。

下面是nginx http页面重定向到https页面最新支持的写法:

server {

    listen 80;

    server_name my.domain.com;

    return 301 https://$server_name$request_uri;

}


server {
    
    listen 443 ssl;

    server_name my.domain.com;


    [....]

}

Nginx 设置域名转发到指定端口

监听80,转发到8080端口 

server {
	# 监听 80 端口
    listen 80;
    autoindex on;
    server_name www.sport.com;
    access_log /usr/local/nginx/logs/access.log combined;
    index index.html index.htm index.jsp index.php;
    if ( $query_string ~* ".*[\;'\<\>].*" ){
        return 404;
    }
    location / {
        # 反向代理到 8080 端口
        proxy_pass http://127.0.0.1:8080;
        add_header Access-Control-Allow-Origin *;
    }
}

下面例子将https://api.tiger.com:5050代理到 https://10.2.1X.**:5050

server {
  listen 5050 ssl ;
  server_name  api.tiger.com;

  ssl on;
  ssl_certificate       /home/tiger/check_api_svr/conf/api.tiger.com.crt;
  ssl_certificate_key   /home/tiger/check_api_svr/conf/api.tiger.com.key;


  access_log off;


  gzip on;
  gzip_vary on;
  gzip_disable "msie6";
  gzip_comp_level 5;
  gzip_types text/css application/javascript image/svg+xml image/png image/jpeg image/gif;

  location / {
	 proxy_pass  https://10.2.1X.**:5050/;
  }


  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   /usr/share/nginx/html;
  }
}

nginx 80 443 并存

 如果一站点既要80 http访问,又要443https访问。

要让https和http并存,不能在配置文件中使用ssl on,配置listen 443 ssl;

实例

server
{

    listen 80;
    listen 443 ssl;
    server_name www.iamle.com;
    index index.html index.htm index.php;
    root /home/wwwroot/www.iamle.com/;
    #ssl on; 这里要注释掉
    ssl_certificate /usr/local/nginx/conf/ssl/www_iamle_com.crt;
    ssl_certificate_key /usr/local/nginx/conf/ssl/www_iamle_com.key;

    #以下配置省略

}