一. Nginx动静分离
1. 准备
1个web程序:部署在7061端口,启动 【dotnet NginxWeb.dll --urls="http://*:7061" --ip="127.0.0.1" --port=7061】
Nginx程序:监听7000端口
2. 目的
比如单独启动部署在7061端口下的web程序,进行访问,我们会发现,除了请求的加载,还有很多静态 css、js、图片等资源的加载,这些资源的加载也是占服务器带宽的,假设带宽为1m,几个大图片直接就占满了。
所以这里引入动静分离,将静态资源单独隔离出来,不占据主服务器的带宽,同时也有利于静态资源做缓存处理。
3. 实操
方案1:在Nginx同一个Server实现动静分离
剖析:
将wwwroot文件夹从发布包中单独处理出来,然后通过location配置绝对地址,实现静态资源的分离。
缺点:动静资源在一个虚拟主机中,那么静态资源和动态资源共享同一个资源,如果静态或者动态资源访问量比较大,把资源消耗殆尽,动态和静态资源互相会进行影响,导致系统整体上性能下降。
代码分享:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 7000; #监听端口
server_name test1; #随意配置一个地址即可,优先走代理
#动态资源
location / {
proxy_pass http://localhost:7061; #代理地址
}
#静态资源
location ~ \.(ico|js|css|png|jpg|mp4)$ {
root C:/Users/Administrator/Desktop/publish/wwwroot;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
方案2:在Nginx多个Server下实现动静分离
剖析:
使用主机7000端口监听动态资源,使用主机7001端口监听静态资源,在7000的主机下通过代理的形式链接 静态资源: proxy_pass http://localhost:7001; #代理地址
缺点:虽然是两个Sever,但这都是虚拟,还是在一台服务器上,一台服务器的承受能力毕竟是有限的。
代码分享:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#1.动态资源Server
server {
listen 7000; #监听端口
server_name test1; #随意配置一个地址即可,优先走代理
#动态资源
location / {
proxy_pass http://localhost:7061; #代理地址
}
#静态资源--指向静态代理Server
location ~ \.(ico|js|css|png|jpg|mp4)$ {
proxy_pass http://localhost:7001; #代理地址
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#2.静态资源Server
server {
listen 7001; #监听端口
server_name test2; #随意配置一个地址即可,优先走代理
#静态资源
location ~ \.(ico|js|css|png|jpg|mp4)$ {
root C:/Users/Administrator/Desktop/publish/wwwroot;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
方案3:在多个Nginx下实现动静分离
代码分享:
即两个Nginx程序,部署在不同服务器,一个处理动态资源,一个处理静态资源,在动态资源的nginx中通过 proxy_pass http://xxxxx:xxxx; 代理到静态资源的服务器上即可。
nginx_dynamic
nginx_static
剖析:
多个nginx部署在多个服务器上,减轻压力,避免同一台服务器上进行资源竞争。
更多C++后台开发技术点知识内容包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux内核,TCP/IP,协程,DPDK多个高级知识点。
C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址
【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取
二. Nginx缓存配置
1. 背景
分析一个电商网站的详情页面,如下图,设计到很多微服务:商品详情页HTML页面渲染、价格服务、促销服务、库存状态/配送至服务、广告词服务、预售/秒杀服务、评价服务、试用服务、推荐服务、商品介绍服务、各品类相关的一些特殊服务。
常见的解决方案:
前端通过ajax动态加载,服务端则把这些文案以html的形式缓存到Redis中,如下图:
剖析:
一个详情页html 主体达平均150 kb, 那么在500QPS 已接近千M局域网宽带极限,所以必须减少内网通信。
2. Nginx缓存
相关模块【ngx_http_proxy_module】 http://nginx.org/en/docs/http/ngx_http_proxy_module.html
针对上面占满内网带宽的情况,可以在Ngxin这一层做静态文件缓存,然后后台维护商品的时候删除缓存(修改商品→删除缓存),架构图如下:
3. 配置说明
其它补充:
proxy_set_header Host $host; #用于后端的real server区分不同的虚拟主机;
proxy_set_header X-Real-IP $remote_addr; #记录客户端真实ip地址,而不是代理服务器地址,需要后端web服务器开启日志相应功能接收;
proxy_cache_methods GET HEAD; #表示对客户端请求的GET 和 HEAD方法进行缓存;
proxy_cache_revalidate on; #本地缓存过期会检查后端服务器该缓存是否存在,避免后端重传占据带宽;
proxy_cache_valid 200 302 10m; proxy_cache_valid 404 1m; proxy_cache_valid any 1m; #针对于不同的响应码进行缓存不同的时间设定;
proxy_cache_min_uses 1; #某一个请求被响应多少次才会被缓存,默认是1,可以将该值设置为大一些;
proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504; #指明哪种场景可以使用过期缓存,提升用户体验;
4. 实操
这里对一个web页面进行缓存,不进行redis的存储。
剖析:
(1). 首先在nginx的根目录下创建文件夹 ypfCache/nginx , 用来存放缓存。
(2). 启动7061端口的web程序,启动nginx程序,访问nginx,发现缓存目录下多了个文件。
(3). 关闭7061端口的web程序,重新访问nginx,继续可以访问,说明缓存成功了。
代码分享:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#缓存声明
proxy_cache_path ypfcache/nginx/ levels=1:2 keys_zone=mycache:64m;
server {
listen 7000; #监听端口
server_name test1; #随意配置一个地址即可,优先走代理
location / {
proxy_pass http://localhost:7061; #代理地址
#缓存相关配置
proxy_cache mycache;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_methods GET HEAD;
proxy_cache_revalidate on;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
proxy_cache_min_uses 1;
proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_503 http_504;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
三. Nginx性能调优
1. worker_processes number
每个worker进程都是单线程的进程,它们会调用各个模块以实现多种多样的功能。如果这些模块确认不会出现阻塞式的调用,那么,有多少CPU内核就应该配置多少个进程;反之,如果有可能出现阻塞式调用,那么需要配置稍多一些的worker进程。例如,如果业务方面会致使用户请求大量读取本地磁盘上的静态资源文件,而且服务器上的内存较小,以至于大部分的请求访问静态资源文件时都必须读取磁盘(磁头的寻址是缓慢的),而不是内存中的磁盘缓存,那么磁盘I/O调用可能会阻塞住worker进程少量时间,进而导致服务整体性能下降。
2. 每个worker 进程的最大连接数
语法:worker_connections number; 默认:worker_connections 1024
3. worker_cpu_affinity cpumask[cpumask……]绑定Nginx worker进程到指定的CPU内核
为什么要绑定worker进程到指定的CPU内核呢?假定每一个worker进程都是非常繁忙的,如果多个worker进程都在抢同一个CPU,那么这就会出现同步问题。反之,如果每一个worker进程都独享一个CPU,就在内核的调度策略上实现了完全的并发。 例如,如果有4颗CPU内核,就可以进行如下配置: worker_processes 4; worker_cpu_affinity 1000 0100 0010 0001; 注意 worker_cpu_affinity配置仅对Linux操作系统有效。
4. Nginx worker 进程优先级设置
语法:worker_priority nice; 默认:worker_priority 0; 优先级由静态优先级和内核根据进程执行情况所做的动态调整(目前只有±5的调整)共同决定。nice值是进程的静态优先级,它的取值范围是–20~+19,–20是最高优先级,+19是最低优先级。因此,如果用户希望Nginx占有更多的系统资源,那么可以把nice值配置得更小一些,但不建议比内核进程的nice值(通常为–5)还要小
5. Nginx worker进程可以打开的最大句柄描述符个数
语法: worker_rlimit_nofile limit; 默认:空 更改worker进程的最大打开文件数限制。如果没设置的话,这个值为操作系统的限制。设置后你的操作系统和Nginx可以处理比“ulimit -a”更多的文件,所以把这个值设高,这样nginx就不会有“too many open files”问题了。
6. 是否打开accept锁
语法:accept_mutex[on|off] 默认:accept_mutext on; accept_mutex是Nginx的负载均衡锁,当某一个worker进程建立的连接数量达到worker_connections配置的最大连接数的7/8时,会大大地减小该worker进程试图建立新TCP连接的机会,accept锁默认是打开的,如果关闭它,那么建立TCP连接的耗时会更短,但worker进程之间的负载会非常不均衡,因此不建议关闭它。
7. 使用accept锁后到真正建立连接之间的延迟时间
语法:accept_mutex_delay Nms; 默认:accept_mutex_delay 500ms; 在使用accept锁后,同一时间只有一个worker进程能够取到accept锁。这个accept锁不是堵塞锁,如果取不到会立刻返回。如果只有一个worker进程试图取锁而没有取到,他至少要等待accept_mutex_delay定义的时间才能再次试图取锁。
四. Nginx集群
1. 准备两台服务器
【192.168.140.1】
【192.168.140.2】
2. Nginx的安装
两台服务器上均进行nginx的安装,步骤详见 https://www.cnblogs.com/yaopengfei/p/13766324.html
3. Keepalive的安装
(1). 两个服务器均进行安装keepalive
【yum install keepalived】
(2). 修改配置文件
【cd /etc/keepalived/keepalived.conf】
查看代码
global_defs {
notification_email { # keepalived服务宕机异常出现的时候,发送通知邮件 可以是多个 acassen@firewall.loc # 收件人邮箱1
failover@firewall.loc # 收件人邮箱2
sysadmin@firewall.loc # 收件人邮箱3
}
notification_email_from Alexandre.Cassen@firewall.loc #邮件发件人
smtp_server 192.168.200.1 # 邮件服务器地址
smtp_connect_timeout 30 # 超时时间
router_id LVS_DEVEL # 机器标识 局域网内唯一即可
vrrp_skip_check_adv_addr # 默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)。
#vrrp_strict # 严格遵守VRRP协议。下列情况将会阻止启动Keepalived:1. 没有VIP地址。2. 单播邻居。3. 在VRRP版本2中有IPv6地址。
vrrp_garp_interval 0 # 小数类型,单位秒,在一个网卡上每组gratuitous arp消息之间的延迟时间,默认为0,一个发送的消息=n组 arp报文
vrrp_gna_interval 0 # 小数类型,单位秒, 在一个网卡上每组na消息之间的延迟时间,默认为0
}
vrrp_instance VI_1 {
state MASTER # 服务器状态 MASTER是主服务器 BACKUP是备份服务器 主服务器的priority要比备份服务器大
interface ens33 # 通信端口 通过ip addr可以看到 根据自己的机器配置
virtual_router_id 51 # vrrp实例id keepalived集群,实例id必须一致
priority 100 # 权重比 主服务器的priority要比备份服务器大
advert_int 1 # 心跳间隔 单位秒 keepalived多机器集群 通过心跳检测,如果发送心跳没反应 就立刻接管;
authentication { # 服务器之间通信密码
auth_type PASS
auth_pass 1111
}
virtual_ipaddress { # 自定义虚拟IP
192.168.91.199
}
}
(3). 进行启动
【systemctl start keepalived.service】 启动 【systemctl stop keepalived.service】 关闭 【systemctl restart keepalived.service】重启
(4). 日志查看 【tail -f /usr/local/nginx/logs/access.log】 【tail -f /var/log/messages】 (5). 进程查看 【ps -ef|grep keep】
4. 配置Nginx重启脚本
(1). 创建脚本,nginx_restart.sh
#!/bin/bash
echo 'xxxxxx'
count_nginx=`ps -ef|grep -w nginx|grep -v grep|wc -l`
echo $count_nginx
if [ $count_nginx -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -ef|grep -w nginx|grep -v grep|wc -l` -eq 0 ];then
systemctl stop keepalived.service
fi
fi
(2). keepalived配置中添加如下内容
vrrp_script chk_http_port {
script "/root/nginx_restart.sh" #脚本地址
interval 2 #检测脚本执行的间隔
weight 2 #比重
}
原文链接:第三节:Nginx动静分离、缓存配置、性能调优、集群配置 - Yaopengfei - 博客园