摘要

公司前端用的Nginx反向代理,来访问后端服务器部署的项目。他们通过反向代理,可以直接在localhost访问,感觉还挺好玩,打算学一下。

正文

参考

  1. Nginx快速入门(本文参考的主要文章)
  2. nginx代理的原理和三种模式
  3. Centos8安装Nginx
  4. Nginx官方文档
  5. Nginx中文文档-反向代理
  6. Nginx中文文档-正向代理
  7. 正向代理通过服务器访问公司内网
  8. 负载均衡之加权轮询算法
  9. Nginx配置文件详解

一、背景

最初的项目并发量小,用户使用的少,只需要启动一个项目、一台服务器就足够用了。

随着用户越来越多,并发量越来越大,一台服务器无法满足需求,此时就需要进行横向扩展。

这个时候,几个项目启动在不同的服务器上,用户要访问,就需要增加一个代理服务器,通过代理服务器来帮我们转发和处理请求。

1.png

二、了解

Nginx完全基于C语言开发。

Nginx的作用

  1. 正向代理:代理客户端的,比如vpn
  2. 反向代理:代理服务器端的
  3. 负载均衡

正向代理示意图

2.png

反向代理示意图

3.png

Nginx提供的负载均衡策略

  1. 内置策略:轮询、加权轮询、ip hash
  2. 动静分离策略

2.1 内置策略

轮询就是在服务器间,按顺序分配请求,就类似于扑克牌发牌。

4.png

轮询没有考虑到每台服务器的处理数据的能力,而加权轮询,就是根据服务器的能力来分配权值。

conf
http {  
    upstream cluster {  
        server a weight=1;  
        server b weight=2;  
        server c weight=3;  
    }  
    ...
} 

如上配置文件,加权轮询就是在每6个请求中,1个请求给a,2个给b,3个给c;以此轮流,如果不满足整除,除了权重最多的执行最多,别的就不好说了。如果某一台机器挂掉了,返回500或者404,就会将请求转发下一台服务器(本质上这种都会降低效率,毕竟多了一层判断是否正常连接)。如图

5.png

iphash是对客户端请求的ip进行hash操作,然后将同一个hash的请求分配给同一台服务器进行处理,可以解决session不共享的问题!如下图所示。

6.png

iphash的缺点:如果一台服务器挂了,数据就会丢失,凉凉了。比较好的方法是可以通过缓存与Cookie实现session共享

2.2 动静分离策略

动静分离就是静态资源直接访问本地服务器,不进行代理,并进行缓存;这个比较简单,直接将静态资源放到本地服务器即可。

对动态资源进行转发和处理请求。

7.png

三、配置

Nginx的下载

  1. 官方下载页
  2. centos安装nginx
  3. meethigher/nginx-cluster-demo: 通过nginx实现简易集群的负载均衡
  4. windows无脑安就可以了

管理命令如下

sh
1
2
3
4
5
./nginx #启动
./nginx -s stop #停止
./nginx -s quit #安全退出
./nginx -s reload #重新加载配置文件
ps aux|grep nginx #查看nginx进程

通过nginx配置代理来访问集群,通过访问本地的127.0.0.1:13000,实现代理8080、8081、8082的server集群

3.1 配置轮询转发

在根配置中,配置nginx加载vhost下的所有conf文件

nginx.conf

conf
http { 
	...
	include vhost/*.conf;
}

test.conf

conf
upstream server {
		server 127.0.0.1:8080;
		server 127.0.0.1:8081;
		server 127.0.0.1:8082;  
}
server {
        listen 13000;
        server_name localhost;
        location / {
             proxy_pass http://server;
        }
        
        # 访问127.0.0.1:13000/file/index.html实际会映射到/root/html/file/index.html
        location /file/ {
        	 root /root/html/;
        }
}

实现接口,每个机器调用接口,返回机器的端口地址。

执行12次,最后运行结果

9.png

3.2 配置加权轮询转发

nginx.conf

conf
http { 
	...
	include vhost/*.conf;
}

test.conf

conf
upstream server {
		server 127.0.0.1:8080 weight=1;
		server 127.0.0.1:8081 weight=2;
		server 127.0.0.1:8082 weight=3;
}
server {
        listen 13000 ;
        server_name localhost;
        location / {
            proxy_pass http://server;
        }
}

实现接口,每个机器调用接口,返回机器的端口地址。

执行12次,最后运行结果

8.png

四、详细配置

nginx配置详解

conf
#---- 全局配置区域 ----
 
#定义Nginx运行的用户和用户组
user nginx nginx;
 
#进程文件
pid /var/run/nginx.pid;
 
#worker工作进程的个数,master进程是接收并分配请求给worker处理。这个数值简单一点
#可以设置为cpu的核数grep -c ^processor /proc/cpuinfo,也是 auto 值
worker_processes 4;
 
#在高并发情况下,通过设置cpu粘性来降低由于多CPU核切换造成的寄存器等现场重建带来的性能损耗。
#如worker_cpu_affinity 0001 0010 0100 1000; (四核)
worker_cpu_affinity 0001 0010 0100 1000;
 
#一个nginx进程打开的最多文件描述符数目,理论值应该是最多打开文件数(系统的值ulimit -n)
#与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致.
worker_rlimit_nofile 65535;
 
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx/error.log info;
 
 
#---- events配置区域 ----
events {
    #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
    #epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型
    use epoll;
     
    #单个进程最大连接数(最大连接数=连接数*进程数)
    worker_connections 1024;
     
    #打开同时接受多个新网络连接请求的功能
    multi_accept on;
}
 
 
#---- http配置区域 ----
http {
    #文件扩展名与文件类型映射表
    include mime.types;
     
    #默认文件类型
    default_type application/octet-stream;
     
    #默认编码
    charset utf-8;
     
    #隐藏版本号
    server_tokens off;
     
    #服务器名字的hash表大小
    server_names_hash_bucket_size 128;
     
    #客户端请求头部的缓冲区大小。这个可以根据你的系统分页大小来设置,一般一个请求的头部大小不会超过1k
    client_header_buffer_size 32k;
     
    #客户端请求中较大的消息头的缓存最大数量和大小
    large_client_header_buffers 4 64k;
     
    #客户端请求体数据的Buffer大小
    client_body_buffer_size 128k;
     
    #客户端请求体数据最大值,例如上传文件
    client_max_body_size 8m;
     
    #长连接持续时间,客户端连接超时该值时会断开,为0禁用长链接
    keepalive_timeout 65;
     
    #客户端请求头读取超时时间
    client_header_timeout 10;
     
    #设置客户端请求主体读取超时时间
    client_body_timeout 10;
     
    #响应客户端超时时间
    send_timeout 10;
     
     
    # sendfile指令指定nginx是否调用sendfile函数(zero copy 方式)来输出文件,对于普通应用,必须设为on。
    #如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络IO处理速度,降低系统uptime。
    sendfile on;
     
    # 开启或者关闭nginx在FreeBSD上使用TCP_NOPUSH套接字选项, 在Linux上使用TCP_CORK套接字选项。
    #选项仅在使用sendfile的时候才开启。
    tcp_nopush on;
     
    # 开启或关闭nginx使用TCP_NODELAY选项的功能。 这个选项仅在将连接转变为长连接的时候才被启用。
    tcp_nodelay on;
       
    #---- gzip压缩模块配置 ----
     
    # 开启gzip压缩输出,减少网络传输
    gzip on;
     
    # 设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。默认值是20。
    #建议设置成大于1k的字节数,小于1k可能会越压越大
    gzip_min_length 1k;
     
    # 表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果
    gzip_buffers 4 16k;
     
    # 压缩版本,默认1.1,目前大部分浏览器已经支持gzip解压,前端如果是squid2.5请使用1.0
    gzip_http_version 1.1;
     
    # 压缩等级 1-9 等级越高,压缩效果越好,节约宽带,但CPU消耗大
    gzip_comp_level 2;
     
    # 压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn
    gzip_types text/plain application/x-javascript text/css application/xml;
     
    # 选项可以让前端的缓存服务器缓存经过gzip压缩的页面.例如:用squid缓存经过nginx压缩的数据
    gzip_vary on;
     
     
    # ---- 反向代理配置 ----
      
    #nginx跟后端服务器连接超时时间(代理连接超时)
    proxy_connect_timeout      5;
     
    #代理发送超时
    proxy_send_timeout         5;
     
    #代理接收超时
    proxy_read_timeout         60;
     
    #启动代理缓存功能
    proxy_buffering on;
     
    #设置代理服务器(nginx)保存用户头信息的缓冲区大小
    proxy_buffer_size          16k;
     
    #设置用于读取应答(来自被代理服务器)的缓冲区数目和大小
    proxy_buffers              4 32k;
     
    #高负荷下缓冲大小(proxy_buffers*2)
    proxy_busy_buffers_size    64k;
     
    #设定缓存文件夹大小,大于这个值,将从upstream服务器传
    proxy_temp_file_write_size 64k;
         
    #反向代理缓存目录
    #levels=1:2 设置目录深度,第一层目录是1个字符,第2层是2个字符
    #keys_zone:设置web缓存名称和内存缓存空间大小
    #inactive:自动清除缓存文件时间。
    #max_size:硬盘空间最大可使用值。
    proxy_cache_path /data/proxy/cache levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=1g;
         
    #指定临时缓存文件的存储路径(必须在同一分区)
    proxy_temp_path /data/proxy/temp;
  
    # ---- 负载均衡服务器池配置 ----
     
    upstream server_pool {
     
    #调度算法
    #1.轮循(默认)(weight轮循权值)
    #2.ip_hash:根据每个请求访问IP的hash结果分配。(会话保持)
    #3.fair:根据后端服务器响应时间最短请求。(upstream_fair模块)
    #4.url_hash:根据访问的url的hash结果分配。(需hash软件包)
    #参数:
    #down:表示不参与负载均衡
    #backup:备份服务器
    #max_fails:允许最大请求错误次数
    #fail_timeout:请求失败后暂停服务时间。
     
        server 192.168.1.109:80 weight=1 max_fails=2 fail_timeout=30;
        server 192.168.1.108:80 weight=2 max_fails=2 fail_timeout=30;
    }
 
    #负载均衡调用
    server {
        ...
        location / {
            proxy_pass http://server_pool;
        }
    }
 
  
    #---- 虚拟主机配置反向代理 ----
    server {
     
        #侦听的80端口
        listen       80;
        server_name  localhost;
        location / {
            #反向代理缓存设置命令(proxy_cache zone|off,默认关闭所以要设置)
            proxy_cache cache_one;
             
            #对不同的状态码缓存不同时间
            proxy_cache_valid 200 304 12h;
             
            #设置以什么样参数获取缓存文件名
            proxy_cache_key $host$uri$is_args$args;
             
            #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
             
            #代理设置
            proxy_pass   http://IP;
             
             # 图片缓存时间设置
            location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
            expires 10d;
            }
         
            # JS和CSS缓存时间设置
            location ~ .*\.(js|css)?$ {
            expires 1h;
            }
             
            #文件过期时间控制
            expires    1d;
        }
        #配置手动清楚缓存(实现此功能需第三方模块 ngx_cache_purge)
        #http://www.123.com/2017/0316/17.html访问
        #http://www.123.com/purge/2017/0316/17.html清楚URL缓存
        location ~ /purge(/.*) {
            allow    127.0.0.1;
            deny    all;
            proxy_cache_purge    cache_one    $host$1$is_args$args;
        }
         
        #设置扩展名以.jsp、.php、.jspx结尾的动态应用程序不做缓存
        location ~.*\.(jsp|php|jspx)?$ {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
            proxy_pass http://IP;
        }
    }
     
     
    #虚拟主机的配置
    server
    {
        # 监听端口
        listen 80;
         
        # 域名可以有多个,用空格隔开
        server_name 127.0.0.1;
         
        #编码格式,若网页格式与此不同,将被自动转码
        #charset koi8-r;
         
        #日志相关定义
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        #                  '$status $body_bytes_sent "$http_referer" '
        #                  '"$http_user_agent" "$http_x_forwarded_for"';
        #定义日志的格式。后面定义要输出的内容。
        #1.$remote_addr 与$http_x_forwarded_for 用以记录客户端的ip地址;
        #2.$remote_user :用来记录客户端用户名称;
        #3.$time_local :用来记录访问时间与时区;
        #4.$request  :用来记录请求的url与http协议;
        #5.$status :用来记录请求状态;
        #6.$body_bytes_sent :记录发送给客户端文件主体内容大小;
        #7.$http_referer :用来记录从那个页面链接访问过来的;
        #8.$http_user_agent :记录客户端浏览器的相关信息
         
         
        #虚拟主机访问日志定义
        access_log  logs/host.access.log  main;
                 
        #对URL进行匹配
        location / {
            #访问路径,可相对也可绝对路径
            root   html;
         
            #首页文件。以下按顺序匹配
            index  index.html index.htm;
        }
 
        #错误信息返回页面
        error_page  404  /404.html;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 
        #php脚本请求全部转发给FastCGI处理    
        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;
        }
         
        #限制IP访问
        location / {
            deny 192.168.0.2;
            allow 192.168.0.0/24;
            allow 192.168.1.1;
            deny all;
        }
         
        location /images {
         
            root /var/www/nginx-default/images;
            # 开启目录列表访问,合适下载服务器,默认关闭.
            autoindex off;
     
            # 显示文件大小,默认为on,显示出文件的确切大小,单位是bytes 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
            autoindex_exact_size on;
     
            # 显示文件时间 默认为off,显示的文件时间为GMT时间 改为on后,显示的文件时间为文件的服务器时间
            autoindex_localtime on;
        }
 
        #Nginx运行状态,StubStatus模块获取Nginx自启动的工作状态(编译时要开启对应功能)
        location /NginxStatus {
            #启用StubStatus的工作访问状态   
            stub_status    on;
            #指定StubStaus模块的访问日志文件 可off
            access_log    logs/Nginxstatus.log;
            #Nginx认证机制(需Apache的htpasswd命令生成)
            #auth_basic    "NginxStatus";
            #用来认证的密码文件
            #auth_basic_user_file    ../htpasswd;   
        }
         
                 
        #根据不同的浏览器URL重写
        if($http_user_agent ~ Firefox){
            rewrite ^(.*)$  /firefox/$1 break;
        }
        if($http_user_agent ~ MSIE){
            rewrite ^(.*)$  /msie/$1 break;
        }      
  
        #实现域名跳转
        location / {
            rewrite ^/(.*)$ https://web8.example.com$1 permanent;
        }
         
        #控制跳转https
        rewrite ^(.*) https://$server_name$1 permanent;
    }
     server {
        # 1.1版本后这样写
        listen 443 ssl; 
        #填写绑定证书的域名
        server_name www.domain.com;
        # 指定证书的位置,绝对路径
        ssl_certificate 1_www.domain.com_bundle.crt;
        ssl_certificate_key 2_www.domain.com.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers on;
        location / {
            root   html;
            index  index.html index.htm;
        }
    }
 
}