iMisty的技术栈

iMisty的技术栈

Nginx进阶之实际应用场景

1368
2020-06-30

前言: 常见Nginx实际使用场景,跨域问题,静态资源防盗链,负载均衡,Nginx控制浏览器缓存,SSL证书配置HTTPS访问,动静分离问题

Nginx中解决跨域问题

CORS跨域资源共享

  • CORS全称Cross-Origin Resource Sharing
  • 允许浏览器向跨Origin的服务器发起js请求获取响应
  • 常见的解决跨域方式 Jsonp,SpringBoot Cors,Nginx

server代码块中加入如下内容支持跨域

#允许跨域请求的域,*代表所有
add_header 'Access-Control-Allow-Origin' *;
#允许带上cookie请求
add_header 'Access-Control-Allow-Credentials' 'true';
#允许请求的方法,比如 GET/POST/PUT/DELETE
add_header 'Access-Control-Allow-Methods' *;
#允许请求的header
add_header 'Access-Control-Allow-Headers' *;

在Nginx中配置静态资源防盗链

通过配置防盗链,只有符合条件的域才能访问静态资源,从而维护站点安全

#对源站点验证
valid_referers *.misty.com; 
#非法引入会进入下方判断,注意这里if 后面需要空格,不然语法错误
if ($invalid_referer) {
    return 404;
} 

Nginx的模块化设计解析

img

Nginx的集群负载均衡解析

单节点: 所有的请求都由一个固定的服务来处理,一旦该服务异常,直接影响功能,扩展能力很差,但是部署迭代方便

集群: 通过多个节点的服务对外提供访问,一个服务异常,并不会影响到用户,可用性高,并发数高,扩容方便,相对于单节点可以充分发挥硬件的资源,但是维护部署迭代成本较高
img

四层、七层与DNS负载均衡

负载均衡: 分为四层负载均衡和七层负载均衡,为企业网络提供更好的服务,提高吞吐量,并发性能,服务器的处理性能,服务器的计算能力,让网络设备更加灵活,当有大量的并发请求来到服务器的时候,将这些请求以一定的规则分配到多台计算机节点上,让更多的节点来处理请求响应,以此来大大缩减用户等待的时间;

四层负载均衡: 基于ip+端口的负载均衡,通过转发请求到后台的服务器,并且记录当前连接是由个哪台服务器处理的,后续的这个连接请求由固定的服务处理,相当于长连接,一旦打开一直处于连接状态,性能很高;处于传输层,基于TCP和UDP;

  • F5硬负载均衡,基于硬件的负载均衡,功能强大性能高,稳定性高,商业级别的负载均衡;
  • LVS四层负载均衡:Linux内核的四层负载,和协议无关,主要用于转发请求,基于C/S端
  • Haproxy四层负载均衡:支持转发功能,灵活性高,除了四层负载均衡也可以支持七层负载均衡
  • Nginx四层负载均衡:1.9以前不支持,新版本可以通过stream模块实现四层协议的协议转发代理(负载均衡),但是主要是用作七层负载均衡针对http做负载均衡;

七层负载均衡: 基于应用层,针对于http协议的负载均衡

  • Nginx七层负载均衡:对http协议或者邮箱协议做负载均衡,性能强劲
  • Haproxy七层负载均衡:支持七层和四层的负载转发功能,灵活性较高
  • Apache 七层负载均衡: 性能远不如Nginx,支持的并发不高,但是当并发达到百万的时候性能越来越差

一般使用LVS做四层负载均衡,七层负载均衡采用Nginx,Haproxy则都可以实现;七层基本都是处理http协议,适用于web服务器(Tomcat ,Apache,Nginx),四层负载均衡主要处理tcp/upd协议用于转发请求,具体的处理交给其他应用,七层用于具体请求处理;

**DNS地域负载均衡:**客户端访问服务器,通过和dns服务器交互获就近的地理位置的服务器公网ip,和就近的机房的物理服务器交互,以此获得更快的响应

使用Nginx搭建三台Tomcat集群

  • 将Tomcat部署到内网互通的三台主机上,然后启动Tomcat服务,注意需要配置防火墙放行配置的端口,或者直接关闭防火墙
    service firewalld stop

  • 在安装有Nginx的主机,将三台Tomcat作为服务节点添加进nginx配置文件,然后重新加载Nginx配置文件

upstream tomcats {
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
}
server {
        listen 80 ;
        server_name www.tomcats.com;

        location / {
                proxy_pass http://tomcats;
        }
}

img

  • 浏览器访问www.tomcats.com 出现Tomcat管理页面,说明配置成功;

注意要修改host配置虚拟域名192.168.43.63 www.tomcats.com,安装有Nginx的主机IP对应虚拟域名,在访问虚拟域名的时候直接请求Nginx

使用JMeter测试单节点与集群的并发异常率

  • 下载Jmeterhttps://jmeter.apache.org/download_jmeter.cgi 然后解压
  • 打开Jmeter(需要Java环境),直接在解压目录的bin目录根据自身系统环境打开即可;
  • 添加线程组,添加取样器,创建测试用例,开启关注的监听器(常用查看结果树,聚合报告,用表格查看结果),然后点击运行即可,可以开始测试,测试完毕可以查看监听器生成报告
    img

注意:因为本机搭建虚拟机集群会因为硬件配置的关系,结果可能会与预设不符合,建议不要用虚拟环境搭建集群,推荐直接在内网互通的主机搭建集群测试更加贴近实际

负载均衡-轮询

集群环境中的每个节点平均分配处理请求,是Nginx默认的负载均衡策略,适合各个节点硬件配置相同的时候使用;

upstream tomcats
{
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
}

负载均衡-加权轮询

可以为每一个集群中的每一个节点配置权重,权重高的分配的处理任务多,默认的权重是1,实际生产环境中根据机器的配置设置权重,配置高的可以适当加大权重

upstream tomcats
{
        server 192.168.43.21:8080 weight=1;
        server 192.168.43.223:8080 weight=3;
        server 192.168.43.248:8080 weight=2;
}

upstream的指令参数

upstream的指令参数之max_conns
限制每台server的连接数,用于保护避免过载,可起到限流作用;
默认值是0代表没有任何限制,老版本不能使用(商业版);当使用多个worker_process进程的时候,使用共享内存,连接的总数会超过max_conns,针对每一个worker_processor限制生效;若是只有一个worker_process,那么最大连接不能超过max_conns设置的数量,当连接数超过的时候不会再处理直接抛出502 Bad Gateway错误,直到当前的连接处理完成才会处理下一批

upstream tomcats
{
    server 192.168.43.21:8080 max_conns=2;
    server 192.168.43.223:8080 max_conns=2;
    server 192.168.43.248:8080 max_connsht=2;
}

upstream的指令参数之slow_start
使服务器慢慢加入集群,而不是让流量一下子进入该节点;适用于服务器不需要很高的流量,但是会有额外的配置的情况;或者运维人员启动监控软件观察流量变化;
设置该参数之后,节点的权重会被覆盖,在设置的时间期间,权重会慢慢提升到设置的正常值,当设置的值为0的时候slow start 是无效的

  • 该参数不能使用在hash和random load balancing中。
  • 如果在 upstream 中只有一台 server,则该参数失效。
  • 只有商业版本才能使用该参数
upstream tomcats
{
server 192.168.43.21:8080 weight=4 slow_start=60s;
        server 192.168.43.223:8080 weight=1;
        server 192.168.43.248:8080 weight=1;
}

upstream的指令参数之down

标识服务器状态不可用,用户无法访问

upstream tomcats
{
        server 192.168.43.21:8080 down;
        server 192.168.43.223:8080 weight=1;
        server 192.168.43.248:8080 weight=1;
}

upstream的指令参数之backup
标识服务器为备用机,正常情况不会被访问,只有在其他服务器都宕机以后,自己才会加入到集群中,被用户访问

upstream tomcats
{
        server 192.168.43.21:8080 backup;
        server 192.168.43.223:8080 weight=1;
        server 192.168.43.248:8080 weight=1;
}

backup参数不能使用在hash和random load balancing中。

upstream的指令参数之max_fails
最大失败次数,当失败次数超过设定值,即认定该服务宕机,Nginx会将该服务节点剔除出集群,新的请求不会访问到该服务
upstream的指令参数之max_timeout
表示失败重试时间;

这个两个参数通常一起使用 max_fails=2 fail_timeout=15s
则代表在15秒内请求某一server失败达到2次后,则认为该server已经挂了或者宕机了,随后再过15秒,这15秒内不会有新的请求到达刚刚挂掉的节点上,而是会请求到正常运作的server,15秒后会再有新请求尝试连接挂掉的server,如果还是失败,重复上一过程,直到恢复。

upstream tomcats
{
        server 192.168.43.21:8080 max_fails=2 fail_timeout=15s ;
        server 192.168.43.223:8080 weight=1;
        server 192.168.43.248:8080 weight=1;
}

使用Keepalived提高吞吐量

  • keepalive: 设置长连接处理的数量
  • proxy_http_version:设置长连接http版本为1.1,1.0版本的http不支持长连接
  • proxy_set_header:清除connection header 信息
upstream tomcats
{
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
        keepalive 32;
}

server
{
        listen 80 ;
        server_name www.tomcats.com;
        location / {
                proxy_pass http://tomcats;
                proxy_http_version 1.1;
                proxy_set_header Connection "";
        }
}

通过Jmeter测试添加keepalive长连接配置,发现吞吐量大增,但是需要清空Jmeter测试缓存,不然极大影响测试结果;
下图为不配置keepalive结果
img
下图为配置keepalive结果
img

负载均衡原理 - ip_hash

通过请求方的ip进行hash计算,确定访问哪一个节点hash(ip)%node_count = index

  • ip_hash 可以保证用户访问可以请求到上游服务中的固定的服务器(一致性),因此服务器的session和缓存有效,前提是用户ip没有发生更改。
  • 使用ip_hash的注意点:不能把后台服务器直接移除,只能标记down,不然hash算法会发送更改,所有的hash算法会重新计算,会话和缓存会失效
    If one of the servers needs to be temporarily removed, it should be marked with the down parameter in order to preserve the current hashing of client IP addresses.
  • 仅仅针对IPv4的前三段进行hash,因此同一内网下的ip访问服务,会访问到同一个节点下
  • hash值会出现偏移,不能保证平均分配到节点,也不能保证和机器的硬件配置相匹配,所以可能会导致部分机器负载过高部分机器相对闲置浪费资源
upstream tomcats
{
        ip_hash;
        server 192.168.43.21:8080;
        server 192.168.43.223:8080 down;
        server 192.168.43.248:8080;
}

参考Nginx官网文档http://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash

hash算法带来的问题
普通的hash算法无论是增加节点或者删除节点都会影响到hash值计算,使请求被重新分配给不同的节点处理

一致性hash算法
用0-2^32 -1 的环形拓扑图模拟IP地址轴,根据hash算法计算服务器节点的ip或者主机名,分配到环上某一个位置,所有的用户请求的iphash计算之后分布到环形IP地址轴上,用户的请求顺时针根据就近原则分配给最近的节点处理;保证用户可以访问到特定的服务器节点
img

服务器减少的情况:某个节点宕机,本来由该节点处理的请求依照顺时针就近原则分配给临近的节点处理,原来的会话和缓存会丢失,其他正常的节点没有变化;

服务器增加的情况:将新增的服务器IP或者主机名hash计算之后分配到环状图中,根据顺时针就近原则将就近的请求重新分配给新增的节点处理,而其他用户的请求不变;

一致性hash算法保证绝大多数的用户请求能够访问到原来的计算机节点,仅仅重新分配一部分的请求,大大减少因为节点增加或者减少带来的风险

负载均衡原理 - url hash 与 least_conn

url hash: 根据每次请求的url地址,hash后访问到固定的服务器节点,hash(url) % node_counts = index

upstream tomcats
{
        # url hash
        hash $request_uri;
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
}

注意:请求的URL地址发生一点变化也会影响到实际访问的节点,www.imisty.cn/user/infowww.imisty.cn/user/info/的url通过hash计算之后对应的节点可能会有区别;

**least_conn:**最少连接数负载均衡,Nginx自动根据当前集群环境中节点的连接数进行分配,连接数最小的优先分配;

upstream tomcats
{
        least_conn;
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
}

nginx的缓存

img

Nginx控制浏览器缓存

浏览器缓存:加速用户访问,提升单个用户(浏览器访问者)体验,缓存在本地;浏览器访问资源服务器,响应码是200代表初次访问每次获取最新的资源(可以在浏览器勾选disable cache实时加载不使用缓存),响应码是304代表加载缓存;

**注意:**浏览器响应数据中Date代表当前的时间,Last-Modified代表最后修改时间,如果文件发生更改则服务器响应最新的数据并且刷新缓存,Cache-Control代表缓存有效时间,Expires表示缓存具体过期的时刻

expire指令:

  • expires [time],设置缓存过期时间;
  • expires @[time],以天为节点进行计算,时间没到就是当天,过了则是第二天
  • expire -[time] ,缓存提前过期,expire -1h表示当前时间提前一个小时过期
  • expire epoch,相当于no-cache 也就是不设置cache
  • expire off :nginx默认的配置,使用浏览器的缓存机制,而不是nginx缓存,Response Header没有Nginx缓存的信息
  • expire max:代表缓存永不过期
location /files {
    alias /home/misty;
    # expires 10s;
    # expires @22h30m;
    # expires -1h;
    # expires epoch;
    # expires off;
    expires max;
}

上游服务器缓存到Nginx

  1. 缓存在nginx端,提升所有访问到nginx这一端的用户
  2. 提升访问上游(upstream)服务器的速度
  3. 用户访问仍然会产生请求流量

Nginx缓存参数

  • proxy_cache_path 设置缓存目录
  • keys_zone 设置共享内存名称以及占用空间大小,单位:100k,10m,1g
  • max_size 设置最大缓存大小
  • inactive 超过此时间则被自动清理,单位:1h ,1m,1s
  • use_temp_path 临时目录,使用后会影响nginx性能,设置为off代表关闭临时目录
upstream tomcats
{
        server 192.168.43.21:8080;
        server 192.168.43.223:8080;
        server 192.168.43.248:8080;
}

proxy_cache_path /usr/local/nginx/upstream_cache keys_zone=mycache:5m max_size=1g inactive=1m use_temp_path=off;

server {
    listen 80 ;
    server_name www.tomcats.com; 
    
    location / {
        proxy_pass  http://tomcats;
        # 开启并且启用缓存,和keys_zone一致
        proxy_cache mycache;
        # 针对200和304状态码缓存时间为8小时
        proxy_cache_valid   200 304 8h;
    }
}

使用Nginx配置SSL证书提供HTTPS访问

前提条件:拥有一个域名且成功备案,成功解析到服务器

1.> 云服务器提供商申请ssl证书,可以使用免费的,一般免费的只能对应一个域名;
2.> 下载申请的ssl证书,需要注意和自己的服务程序对应,这里使用Nginx所以使用Nginx证书
img

3.> 上传证书和秘钥(XXX.crt和XXX.key)到服务器移动到${nginx_home}/conf/cert目录,和主配置文件nginx.conf同级,引入的配置文件在vhost目录
img

4.> 进入nginx解压目录(不是安装配置目录),新增ssl模块(原来的模块依旧保留),重新编译安装一下

./configure  
--prefix=/usr/local/nginx 
--pid-path=/var/run/nginx/nginx.pid  
--lock-path=/var/lock/nginx.lock 
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log  
--with-http_gzip_static_module 
--http-client-body-temp-path=/var/temp/nginx/client 
--http-proxy-temp-path=/var/temp/nginx/proxy    
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi  
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi 
--http-scgi-temp-path=/var/temp/nginx/scgi
--with-http_ssl_module

重新编译安装Nginx

make
make install 

此时进入Nginx解压目录/objs/ngx_modules.c文件就可以看到openssl_module了;
或者直接执行${nginx_home}/sbin/nginx -V配置参数包含with-http_ssl_module说明ssl模块安装成功

5.> 编辑Nginx核心配置文件nginx.conf添加server指令块(当然也可以引用的外部配置文件),参考云服务器文档配置如下

server {
    listen       443;
    server_name  www.imisty.cn;
    # 开启ssl
    ssl     on;
    # 配置ssl证书
    ssl_certificate      cert/xxx.crt;
    # 配置证书秘钥
    ssl_certificate_key  cert/xxx.key;
    # ssl会话cache
    ssl_session_cache    shared:SSL:1m;
    # ssl会话超时时间
    ssl_session_timeout  5m;
    # 配置加密套件,写法遵循 openssl 标准
    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 / {
        proxy_pass http://tomcats/;
        index  index.html index.htm;
    }
 }

腾讯云配置文档https://cloud.tencent.com/document/product/400/35244

6.> 检测配置文件无误之后重载配置

${nginx_home}/sbin/nginx -t 
${nginx_home}/sbin/nginx -s reload

动静分离

动静分离的特点

  • 分布式:动态请求和动态接口和静态数据和资源分开,减少后台服务器压力(不再需要渲染页面),提高静态资源访问的速度;
  • 前后端解耦:开发解耦,部署解耦方便并行开发;
  • 静态归nginx:静态资源由Nginx管理
  • 接口服务化:同时为多个跨平台应用提供服务;

动静分离

  • 静态数据:css/js/html/images/audios/videos...
  • 动态数据:得到的响应可能会和上一次不同

动静分离的方式-CDN
将静态资源部署在云服务器的提供商,从而通过dns服务器访问到最近的物理服务器,从而达到最快的响应速度
img

动静分离的方式-nginx
通过Nginx集群部署多个静态资源站点,然后通过多个Tomcat集群部署多个动态资源站点;用户请求通过访问Nginx网关访问这些动态资源和静态资源

动静分离的问题
跨域问题: SpringBoot的Cros配置,nginx配置跨域参数,jsonp