一.nginx基础

1.nginx安装

nginx的官网安装文档

http://nginx.org/en/linux_packages.html#RHEL-CentOS

0.yum安装

yum install -y epel-release             //安装扩展源
yum install -y nginx

查看nginx安装过程执行了哪些操作。
rpm -q --scripts nginx-filesystem  

查看nginx生成了哪些文件
 rpm -ql nginx

除了上面之外,还可以自定义源,这样的话安装nginx的版本比上面更新

1.搭建yum仓库安装

安装相关yum工具

sudo yum install -y yum-utils

配置yum源

vim /etc/yum.repos.d/nginx.repo

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

//如果有epel源则先要禁用,否则冲突

如果这个变量识别不了的话是缺少软件包,
$releasever
下载就可以了
yum install centos-release

清除yum缓存和重新加载

yum clean all

yum makecache fast

默认情况下,使用稳定的nginx软件包的存储库。如果要使用主线nginx软件包,请运行以下命令:

sudo yum-config-manager --enable nginx-mainline

开始安装

sudo yum install nginx

2.源码安装

编译安装nginx来定制自己的模块,首先安装缺少的依赖包:

yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel

下载源码包

cd /usr/local/src/
wget http://nginx.org/download/nginx-1.18.0.tar.gz
解压
tar zxf nginx-1.18.0.tar.gz 

为了后续准备我们另外下载2个插件模块:nginx_upstream_check_module-0.3.0.tar.gz —— 检查后端服务器的状态,nginx-goodies-nginx-sticky-module-ng-bd312d586752.tar.gz(建议在/usr/local/src下解压后将目录重命名为nginx-sticky-module-ng-1.2.6) —— 后端做负载均衡解决session sticky问题(与upstream_check模块结合使用需要另外打补丁)。

请注意插件与nginx的版本兼容问题,一般插件越新越好,nginx不用追新,稳定第一。nginx-1.4.7,nginx-sticky-module-1.1,nginx_upstream_check_module-0.2.0,这个搭配也没问题。sticky-1.1与nginx-1.6版本由于更新没跟上编译出错。(可以直接使用Tengine,默认就包括了这些模块)

下载nginx-upstream_check_module模块
wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz
tar xzf v0.3.0.tar.gz

下载nginx-goodies-nginx-sticky模块
wget https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/get/1.2.6.tar.gz

tar zxf 1.2.6.tar.gz
mv nginx-goodies-nginx-sticky-module-ng-c78b7dd79d0d nginx-sticky-module-ng-1.2.6

image-20200624231027770.png

开始初始化

cd nginx-1.18.0/

./configure --prefix=/usr/local/nginx       //如果有报错,yum安装pcre-devel和zlib-devel
上面这种是最简单的编译安装

其他的
创建运行用户、组
useradd -M -s /sbin/nologin nginx

./configure --prefix=/usr/local/nginx-1.8 --user=nginx --group=nginx --with-pcre --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-http_realip_module --add-module=../nginx_upstream_check_module-0.3.0

初始化完成会出现下面的结果
image-20200624231158168.png

开始安装

 make && make install

安装成功/usr/local/就会有nginx目录

2.2 常用编译选项说明

nginx大部分常用模块,编译时./configure --help--without开头的都默认安装。

  • --prefix=PATH : 指定nginx的安装目录。默认 /usr/local/nginx
  • --conf-path=PATH : 设置nginx.conf配置文件的路径。nginx允许使用不同的配置文件启动,通过命令行中的-c选项。默认为prefix/conf/nginx.conf
  • --user=name: 设置nginx工作进程的用户。安装完成后,可以随时在nginx.conf配置文件更改user指令。默认的用户名是nobody。--group=name类似
  • --with-pcre : 设置PCRE库的源码路径,如果已通过yum方式安装,使用--with-pcre自动找到库文件。使用--with-pcre=PATH时,需要从PCRE网站下载pcre库的源码(版本4.4 – 8.30)并解压,剩下的就交给Nginx的./configuremake来完成。perl正则表达式使用在location指令和 ngx_http_rewrite_module模块中。
  • --with-zlib=PATH : 指定 zlib(版本1.1.3 – 1.2.5)的源码解压目录。在默认就启用的网络传输压缩模块ngx_http_gzip_module时需要使用zlib 。
  • --with-http_ssl_module : 使用https协议模块。默认情况下,该模块没有被构建。前提是openssl与openssl-devel已安装
  • --with-http_stub_status_module : 用来监控 Nginx 的当前状态
  • --with-http_realip_module : 通过这个模块允许我们改变客户端请求头中客户端IP地址值(例如X-Real-IP 或 X-Forwarded-For),意义在于能够使得后台服务器记录原始客户端的IP地址
  • --add-module=PATH : 添加第三方外部模块,如nginx-sticky-module-ng或缓存模块。每次添加新的模块都要重新编译(Tengine可以在新加入module时无需重新编译)

为主程序设置环境变量

vim /etc/profile
在末尾添加
export PATH=$PATH:/usr/local/nginx-1.8/sbin/
保存退出

source /etc/profile

或者直接添加软连接也可以
ln -s /usr/local/nginx-1.8/sbin/nginx /usr/local/sbin/nginx

nginx启动相关命令

nginx -h 查看所有命令帮助

检测配置文件是否正确
nginx -t 

查看编译的选项或版本
nginx -V 

启动关闭或重新加载
nginx 

nginx -s stop 
nginx -s reload

-s signal —向 主进程发送信号。参数信号可以是以下之一:
stop —快速关闭
quit —正常关闭
reload —重新加载配置,使用新配置启动新工作进程,并正常关闭旧工作进程。
reopen —重新打开日志文件

把这个日子文件重新分隔 /usr/local/nginx/logs/access.log
mv access.log access.log.bak
再新建access.log 
touch access.log 
这时候需要执行下reopen命令
nginx -s reopen

查看nginx是否启动

ps -aux |grep nginx

image-20200624234704052.png

通过信号量控制nginx

官方文档
http://nginx.org/en/docs/control.html

nginx可以通过信号进行控制。/usr/local/nginx/logs/nginx.pid默认情况下,主进程的进程ID被写入文件 。可以在配置时或nginx.conf使用 pid 伪指令更改此名称 。主进程支持以下信号:

TERM, INT    快速关机
QUIT        正常关关机,优雅的关闭进程,等待请求结束后再关闭
HUP            更改配置,使用新配置启动新工作进程,正常关闭旧工作进程,和reload一样
USR1         重新打开日志文件,在日志按月/日分隔时有用
USR2        升级可执行文件 平滑的升级
WINCH        优雅关闭旧工作进程(配合USR2来进行升级)

示例:
kill -INT 19569   快速关闭nginx主进程
kill -QUIT 25914  优雅的关闭
kill -HUP 26172   重新加载配置文件,同nginx -s reload一样

可以不用每次都查看进程号,
kill -HUP $(cat /usr/local/nginx-1.8/logs/nginx.pid)

源码安装配置system服务

编写启动脚本

vim  /usr/lib/systemd/system/nginx.service

[Unit]
Description=nginx

After=network.target remote-fs.target nss-lookup.target

[Service]

Type=forking

PIDFile=/usr/local/nginx-1.8/logs/nginx.pid

ExecStartPost=/bin/sleep 0.1

ExecStartPre=/usr/local/nginx-1.8/sbin/nginx -t -c /usr/local/nginx-1.8/conf/nginx.conf

ExecStart=/usr/local/nginx-1.8/sbin/nginx -c /usr/local/nginx-1.8/conf/nginx.conf

ExecReload=/bin/kill -s HUP $MAINPID

ExecStop=/bin/kill -s QUIT $MAINPID

PrivateTmp=true

[Install]

WantedBy=multi-user.target

加载下系统

systemctl daemon-reload

这时候就可以通过下面几种方式启动了

启动停止,重启
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
重新加载
systemctl reload nginx

开机自启动和diable
systemctl enable nginx
systemctl disable nginx

这里需要注意的是配置了system服务后。通过systemctl start nginx启动的服务。然后通过nginx -s stop也是可以关闭nginx的,但是通过直接通过nginx 启动的,就不能通过systemctl stop nginx 来关闭,

同时再通过systemctl start nginx来启动nginx也会报错。因为nginx已经在启动了

2.nginx配置

官方文档地址

http://nginx.org/en/docs/

1.nginx.conf配置文件

Nginx配置文件主要分成四部分:main(全局设置)、server(主机设置)、upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)和 location(URL匹配特定位置后的设置),每部分包含若干个指令。

main部分设置的指令将影响其它所有部分的设置;

server部分的指令主要用于指定虚拟主机域名、IP和端口;

upstream的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;

location部分用于匹配网页位置(比如,根目录“/”,“/images”,等等)。

他们之间的关系式:server继承main,location继承server;upstream既不会继承指令也不会被继承。它有自己的特殊指令,不需要在其他地方的应用。

当前nginx支持的几个指令上下文

通用模板

下面的nginx.conf简单的实现nginx在前端做反向代理服务器的例子,处理js、png等静态文件,jsp等动态请求转发到其它服务器tomcat:

user nginx nginx;
worker_processes 2;  #这里可以指定auto; 自动
  
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
  
pid logs/nginx.pid;
  
  
events {
use epoll;
worker_connections 2048;
}
  
  
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 65;
  
# gzip压缩功能设置
gzip on;
gzip_min_length 1k;
gzip_buffers 32 4k;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_types  text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
  
# http_proxy 设置
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 75;
proxy_send_timeout 75;
proxy_read_timeout 75;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
  
# 设定负载均衡后台服务器列表
upstream backend {
#ip_hash;
server 192.168.224.11:8080 max_fails=2 fail_timeout=30s ;
server 192.168.224.12:8080 max_fails=2 fail_timeout=30s ;
}
  
# 很重要的虚拟主机配置
server {
listen 80;
server_name itoatest.example.com;
root /apps/oaapp;
  
charset utf-8;
access_log logs/host.access.log main;
  
#对 / 所有做负载均衡+反向代理
location / {
root /apps/oaapp;
index index.jsp index.html index.htm;
  
proxy_pass http://backend;
proxy_redirect off;
# 后端的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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
  
}
  
#静态文件,nginx自己处理,不去backend请求tomcat
location ~* /download/ {
root /apps/oa/fs;
  
}
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
root /apps/oaapp;
expires 7d;
}
location /nginx_status {
stub_status on;
access_log off;
allow 192.168.224.0/24;
deny all;
}
  
location ~ ^/(WEB-INF)/ {
deny all;
}
#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;
}
}
include /software/站点配置文件/*.conf;
  
## 其它虚拟主机,server 指令开始
}

2.配置nginx的正常访问

主要修改server段

正常80端口

server {
        listen       80;
        server_name  server1.com;

        location / {
            root   /software/server1;
            index    index.html index.htm;
        }
}

本机的域名绑定可以通过windos下修改hosts文件。

win+ R键 输入下面的命令,去etc找hosts文件去修改内容。
C:\Windows\System32\drivers\etc\

如果权限不足,可以鼠标右击点击属性,点击安全,进行权限编辑。

3.nginx日志管理

1.日志格式,是指记录哪些选项

默认的日志格式: main

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;


ip地址 - 远程用户 - 用户时间 请求方式(如GET/POST)  status状态 请求体body长度(如果状态是304的话,长度一般是0 )  referer来源信息,也就是当前网页的url地址。 
http_user_agent 用户代理/蜘蛛, 被转发的请求的原始ip.
http_x_forwarded_for: 在经过代理时,代理把你的本来ip加在此头信息中。传输你的原始ip

蜘蛛

这里可以看到各种蜘蛛名,有百度、谷歌、搜狗等等。
www.baidu.com/robots.txt

User-agent: Googlebot
Disallow: /baidu
Disallow: /s?
Disallow: /shifen/
Disallow: /homepage/
Disallow: /cpro
Disallow: /ulink?
Disallow: /link?
Disallow: /home/news/data/
Disallow: /bh

上面表示google蜘蛛爬虫 不能爬的目录有哪些。,有些是竞价用的。

自定义格式1

log_format  main  '[\$time_local] \$http_host "\$request" \$remote_addr \$remote_user '
                      '\$status \$body_bytes_sent "\$http_referer" "\$http_user_agent" '
                      '"\$http_x_forwarded_for" \$request_time \$upstream_response_time '
                      '"\$upstream_addr" \$upstream_status';

request_time: 请求的用的时间  
upstream_reponse_time  响应时间
$upstream_addr 后端服务的地址
upstream_statu后端响应的状态

nginx允许针对不同的server做不同的Log(有的web服务器不支持)

修改下配置文件

server {
        listen       80;
        server_name  yichen1.com;


        location / {
            root   /software/yichen1;
            index    index.html index.htm;
        }
        access_log /usr/local/nginx-1.8/logs/yichen1.com.access.log main;

}

然后重新加载

systemctl reload nginx

这时候就会发现对应的目录下生成的yichen1的日志。也是main格式的。

2.nginx定时任务完成日志切割

用shell脚本实现

vim runlog.sh

#!/bin/bash
LOGPATH=/usr/local/nginx-1.8/logs/access.log
BASEPATH=/usr/local/nginx-1.8/logs

bak=$BASEPATH/$(date -d yesterday +%Y%m%d).assess.log #昨天的时间
#bak=$BASEPATH/$(date -d yesterday +%Y%m%d%H%M).access.log
echo $bak
mv $LOGPATH $bak

#压缩日志
tar -czf ${bak}.gz $bak 2&> /dev/null
     
touch $LOGPATH

kill -USR1  $(cat /usr/local/nginx-1.8/logs/nginx.pid)

rm -rf $bak   #删除原有日志没有压缩的
touch $LOGPATH

kill -USR1  $(cat /usr/local/nginx-1.8/logs/nginx.pid)

然后做定时任务

cronte -e 
00 0 * * *  sh  /software/runlog.sh   #每天执行

#每个月的1号,11号,21号,31号执行
0 0 */10 * *  sh  /software/runlog.sh

#每个月执行
0 0 1 * *   sh  /software/runlog.sh

3.其他方式日志轮转

参考网址

https://ethendev.github.io/2019/01/10/roate-nginx-log/
    # 日志轮转
    cat <<EOF >/etc/logrotate.d/nginx
/etc/nginx/logs/*log {
    daily
    rotate 10
    missingok
    notifempty
    compress
    sharedscripts
    dateext
    postrotate
        [ ! -f /usr/local/openresty/nginx/logs/nginx.pid ] || /bin/kill -USR1 `cat /usr/local/openresty/nginx/logs/nginx.pid 2>/dev/null` 2>/dev/null || true
    endscript
}
EOF

调试脚本,测试脚本是否正确

sudo /usr/sbin/logrotate -d -f /etc/logrotate.d/nginx

手动运行运行脚本分割日志

sudo /usr/sbin/logrotate -f /etc/logrotate.d/nginx 

添加定时任务

通过下面的命令添加定时任务(注意需要指定运行 nginx 的用户,不然可能没有权限无法正确执行)

sudo crontab -u root -e 

# rotate nginx log erery day
0 0 * * * /usr/sbin/logrotate -f /etc/logrotate.d/nginx   #每天执行

如果要删除上面的定时任务,运行如下命令

crontab -r 

如果任务没有正确执行,可以通过如下命令查看任务日志

vim /var/log/cron

4.location的正则匹配

location: 用来设定不同的uri的文件系统的路径映射,一个server中可以设置多个location,nginx会根据用户请求的uri地址来逐个判断location,找出最佳匹配规则,然后应用该location中定义的配置。locationnginx使用频率非常非常高的指令,匹配规则以及匹配优先级是location指令比较复杂的地方,

网址的解释

http://yichen1.com/index.html?channelCode=22&&b=2
url 表示整个网址
uri 表示域名后面的字符串 /index.html?channelCode=22&&b=2
host 表示域名 yichen1.com

而location是匹配uri的。
配置文件里面可以通过变量提取
https://$host$request_uri;
$host表示yichen1.com $request_uri表示 /index.html?channelCode=22&&b=2

基本语法

语法:    location [ = | ~ | ~* | ^~ ] uri {...}
location @name {...}
默认:     —
可以使用的块:    server, location

其中:

=:对uri做精确匹配,优先级最高,如果匹配成功,则停止向下搜索,并立即处理此请求。比如:

location = / {
... ...
}

当请求https://www.baidu.com/时匹配,但当访问https://www.baidu.com/index.html则不匹配;

^~: 对uri起始字符做字符串匹配(注意: 不是正则匹配), 区分大小写,会检索所有匹配,以匹配长度为优先,一旦匹配上,不再进行正则匹配;

~: 对uri(可以不是起始字符)做正则表达式匹配,区分大小写;

~*: 对uri(可以不是起始字符)做正则表达式匹配,不区分大小写;

不带符号: 匹配起始于此字符串的所有uri,区分大小写。

注意: 字符串匹配(无论是 ^~ 还是 无符号 匹配),后面都必须以/ 开头,否则将永远匹配不上。正则匹配可以。

它们匹配度优先级为: = > ^> > ~ = ~* > 不带符号

下面可以测试

server {

        listen 80 ;
        listen 443 ssl;
        server_name  yichen2.com;
        root /usr/share/nginx/html;
              index test.html ;
        ssl_certificate  /root/ssl/yichen2.crt;
        ssl_certificate_key /root/ssl/yichen2.key;
   location  = / {
        return 701;
}

   location ^~ /img {

      return  702;
}
   location ~ /img {

      return 703;
}
   location ~* /img {
      return 704;
}
   location   /imgs {

      return 705;
}

  location /  {

      return 666;
}
}

通过curl 来方式测试下优先级

curl -k -I yichen2.com         返回701 
curl -k -I yichen2.com/img     返回702
curl -k -I yichen2.com/imgs    返回703  #因为正则比无符号优先级高
curl -k -I yichen2.com/ssdjdj  返回666  

正则匹配和普通匹配

server {
        listen       80;
        server_name  yichen1.com;

        location / {
            root   /software/yichen1;
            index    index.html index.htm;
        }
        #access_log /usr/local/nginx-1.8/logs/yichen1.com.access.log main;

        location ~ image {
          root /software/;
        index index.html;
}
}

index 的内容

<img src="./image/6dong.gif" />

创建一个放image的目录。让放入图片

mkdir /software/image 

此时访问yichen1.com 会出现图片。但是路径是访问的/software/image/6dong.gif的图片。而不是默认的/software/yichen1/image/的图片。

总结: location的命中过程是这样的。

1.先判断精准命中,如果命中。立刻返回结果并结束解析过程

2.判断普通命中,如果有多个命中,记录下来最长的命中结果。(注意: 记录但不结束,最长的为准)

3.继续判断正则表达式解析的结果,按配置里的正则表达式顺序为准,由上到下开始匹配,一旦匹配成功1个,立即返回结果,并结束解析过程。

延时分析:a. 普通命中 顺序无所谓,是因为按命中的长短来确定的。

​ b. 正则命中,顺序有所谓,因为是从前往后命中的。

5.rewrite语法详解

官方文档

http://nginx.org/en/docs/http/ngx_http_rewrite_module.html

重写中常用的指令

break #跳出 rewrite

if (条件) {} 设定条件再进行重写

return #返回状态码,也可以在返回新的url地址

rewrite #重写

set #设置变量

指令1: break

Syntax:    break;
Default:    —
Context:    server, location, if

语法: break;
默认:  -
可以使用的块: server, location, if, 

如果在location中指定了伪指令,则 在此位置继续进行请求的进一步处理。

if ($slow) {
    limit_rate 10k;
    break;
}

指令2: if

语法:    if (condition) { ... }
默认:     —
可以使用的块:    server, location

指定的condition(条件表达式)被评估。如果为true,则执行大括号内指定的此模块指令,并在指令内为请求分配配置 ifif指令中的配置是从先前的配置级别继承的。

条件可以是以下任意一种:

  • 变量名;如果变量的值为空字符串或“ 0 ”,则为false;否则为false 。

    在1.0.1版之前,任何以“ 0” 开头的字符串都被视为错误值。
  • 使用“ =”和“ !=”运算符将变量与字符串进行比较;
  • 使用“ ~”(用于区分大小写的匹配)和“ ~*”(用于不区分大小写的匹配)运算符将变量与正则表达式进行匹配。正则表达式可以包含捕获,这些捕获可用于以后在$1.. $9变量中重用。负运算符“ !~”和“ !~*”也可用。如果正则表达式包含“ }”或“ ;”字符,则整个表达式应用单引号或双引号引起来。
  • 使用“ -f”和“ !-f”运算符检查文件是否存在;
  • 使用“ -d”和“ !-d”运算符检查目录是否存在;
  • 使用“ -e”和“ !-e”运算符检查文件,目录或符号链接是否存在;
  • 使用“ -x”和“ !-x”运算符检查可执行文件。

例子:

可以引用的变量

 cat conf/fastcgi.conf
可以去这里看。
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}  #如果客户端浏览器是IE浏览器 则重写到/msie/$1  目录下的内容。break 退出

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}

if ($request_method = POST) {
    return 405;
} #如果请求模式是post 就返回405

if ($slow) {
    limit_rate 10k;
}

if ($invalid_referer) {
    return 403;
}

下面的是:如果访问ip是224.1的就返回403,不让访问下面的家目录。
location / {
           if ($remote_addr = 192.168.224.1) {
        return 403;
}
            root   /software/yichen1;
            index    index.html index.htm;
        }

如果是ie浏览器访问的键跳转其他页面。
 location / {
           if ($http_user_agent ~ Trident) {

        rewrite ^(.*)$  /ie.html break;
}
            root   /software/yichen1/;
            index    index.html index.htm;
        }

判断路径文件不存在就返回404.html页面。
 location / {
           if ( !-e $document_root$fastcgi_script_name) {

        rewrite ^(.*)$  /404.html break;
}
            root   /software/yichen1/;
            index    index.html index.htm;
        }

指令3: return

语法:    return code [text];

      return code URL;
      return URL;
默认:    -
可以使用的块:    server,location,if

另外,URL可以将带有代码302 的用于临时重定向的a 指定为唯一参数。这样的参数应以“ http://”,“ https://”或“ $scheme”字符串开头。一个URL可以包含变量。

指令4: rewrite

语法:    rewrite 正则表达式 replacement [flag];
默认:    -
可以使用的块:    server,location,if

replacement: 替换的新内容

如果指定的正则表达式与请求URI匹配,则URI将按照replacement字符串中的指定进行更改。该rewrite指令在其在配置文件中出现的顺序执行。可以使用标志终止指令的进一步处理。如果替换字符串以“ http://”,“ https://”或“ $scheme” 开头,则处理将停止并将重定向返回给客户端。

可选*flag*参数可以是以下之一:

  • last

    停止处理当前ngx_http_rewrite_module指令集, 并开始搜索与更改后的URI相匹配的新位置;

  • break

    ngx_http_rewrite_modulebreak指令一样, 停止处理当前的指令集 ;

  • redirect

    返回带有302代码的临时重定向;如果替换字符串不是以“ http://”,“ https://”或“ $scheme” 开头,则使用

  • permanent

    返回带有301代码的永久重定向。

    完整的重定向URL是根据请求方案($scheme)以及 server_name_in_redirectport_in_redirect指令形成的。

break 和permanent的区别

 location ~ {

        rewrite goods-(\d+).html  /test.html break;
}
#访问http://yichen.com/goods-122.html 会显示/test.html的内容,但是网页上还是显示当前的url  http://yichen.com/goods-122.html;

 location ~ {

        rewrite goods-(\d+).html  /test.html permanent;
}

#访问http://yichen.com/goods-122.html 会直接永久重写到/test.html的内容,且url会跳转到http://yichen.com/test.html

例:

server {
    ...
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;
    return  403;
    ...
}

但是,如果将这些指令放在“ /download/”位置,last则应将标志替换为 break,否则nginx将执行10个循环并返回500错误:

location /download/ {
    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break;
    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  break;
    return  403;
}

如果*replacement*字符串包含新的请求参数,则先前的请求参数将附加在它们之后。如果不希望这样,请在替换字符串的末尾添加问号,避免附加它们,例如:

rewrite ^/users/(.*)$ /show?user=$1? last;

指令5: set

语法:set $variable value;
默认:-
可以同的块:serverlocationif

value为指定的 设置variable。该value可以包含文本,变量,他们的组合

set是设置变量用的,可以用来达到多个条件判断时做标记用,如下

判断是IE浏览器并重写,其不用break退出。也能防止死循环。

    if ($http_user_agent ~* trident) {
        set $isie 1;
}  #如果是IE isie变量的值为1
    if ($fastcgi_script_name = ie.html){
   set $isie 0;  #如果跳转到路径名是ie.html isie变量的值为0
}
      if ($isie = 1) {

  rewrite ^(.*)$  /ie.html;

}

1.url重写实战

访问指定的html就重写到真实的地址

location /ecshop {

        rewrite 'goods-(\d{1,7})\.html' /ecshop/goods.php?id=1;
}

#只要匹配的goods-3454.html,就重写到/ecshop/goods.php?id=1;的内容。

location /ecshop {

        rewrite 'goods-(\d{1,7})\.html' /ecshop/goods.php?id=$1;
}
#只要匹配的goods-3454.html,就重写到/ecshop/goods.php?id=3454的内容。
目的在于不让客户端知道/etcshop/goods.php?id=3454的这个参数。

6. gzip压缩提升网站速度

官网文档

http://nginx.org/en/docs/http/ngx_http_gzip_module.html

常用参数

gzip            on|off; 是否开启gzip
gzip_buffers   32 4k | 16 8k 缓冲(压缩在内存中缓冲几块?每块多大?)
gzip_comp_level [1-9] 推荐6 压缩级别(级别越高,压的越小。也浪费cpu资源)
gzip_disable  #正则匹配UA 什么样的url不进行gzip
gzip_http_version 1.0 | 1.1  开始压缩的http协议版本。(可以不用设置)
gzip_min_length 1000;   设置将被压缩的响应的最小长度。(再小就不用压缩了,意义不大)
gzip_proxied    ;响应为代理请求启用或禁用响应的压缩
gzip_types      text/plain application/xml; #对哪些类型的文件用压缩。
gzip_vary on|off #是否传输gzip压缩标志,是否告诉客户端是否有压缩。

注意:

图片和视频 这样的二进制文件,不必压缩 因为压缩比比较小,比如100->80 字节。而且压缩也是耗费cpu资源的。

7.expires缓存提升网站负载

官网文档

http://nginx.org/en/docs/http/ngx_http_core_module.html

设置过期时间。

在location 或if段里来写

格式 expires 30s

expires 30m; 30分过期

expires 2h; 2小时

expires 30d; 30天。

location /images/ {
    try_files $uri /images/default.gif;
}

location = /images/default.gif {
    expires 30s;
}   表示/images/default.gif这个里面的图片在客户浏览器中30秒后过期。。

location ~* \.(jpg|jpeg|gif|png) {
 expires 1d;
}
#只要是图片都1天后才过期。

注意:服务器的日期要准确。

另: 304也是一种很好的缓存手段

8.HTTP跳转HTTPS协议几种方式性能对比

我这里已http://yichen2.com 为例,要求所有访问该页面的请求全部跳转至https://yichen2.com,

并请求的uri 和参数$query_string 要保留下来。

常见的几种方法:

1.使用if进行协议判断 --最差

这种情况下,多为把httphttps写在同一个server中,配置如下:

   server {

        listen 80 default_server;
        listen 443 ssl;
        server_name  yichen2.com;
        root /usr/share/nginx/html;
        index  test.html ;
        ssl_certificate  /root/ssl/yichen2.crt;
        ssl_certificate_key /root/ssl/yichen2.key;
        charset  utf-8;
        if ( $scheme = http ) {
        rewrite ^/(.*)$ https://yichen2.com/$1 permanent ;
}
        location / {

}

}

这种配置看起来简洁很多,但是性能是最差的,首先每次连接进来都需要nginx 进行协议判断,其次判断http 协议时进行地址匹配、重写、返回、再次判断,最后还有正则表达式的处理... .... 所以,生产上我们极不建议 这种写法。另外,能少用if 的尽量不用,如果一定要使用,也最好在location 段,并且结合ruturn 或者rewrite ... last 来使用。

2.rewrite 方法1 --差

一般80端口 443 ssl端口不要写在同一个server 中,这样虽然代码简洁了一些,但是性能并不是很好。

   server {

        listen 80 default_server;
        listen 443 ssl;
        server_name  yichen2.com;
        root /usr/share/nginx/html;
        index  test.html ;
        ssl_certificate  /root/ssl/yichen2.crt;
        ssl_certificate_key /root/ssl/yichen2.key;
        charset  utf-8;
        rewrite ^/(.*)$ https://yichen2.com/$1 permanent;
        location / {

}

}

测试

curl -k -I yichen2.com/a.html?a=3

HTTP/1.1 301 Moved Permanently
Server: nginx/1.16.1
Date: Mon, 29 Jun 2020 22:10:12 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://yichen2.com/a.html?a=3

可以看到实现了httphttps的跳转。并且保留了参数

3.rewrite 方法2 --好

不使用正则表达式。而使用变量来提升性能:

server {
        listen       80;
        server_name  yichen2.com;
        rewrite      ^ https://yichen2.com$request_uri? permanent;

}
server {

        listen       443 ssl;
        server_name  yichen2.com;
        root /usr/share/nginx/html;
        index  test.html ;
        ssl_certificate  /root/ssl/yichen2.crt;
        ssl_certificate_key /root/ssl/yichen2.key;
        charset  utf-8;
        location / {

}
}

注意: $request_uri 已经包含了查询参数,所以要在其重写规则后面加上? 以禁止再次传递参数,这种方法避免了nginx 内部处理正则的性能损坏,相比较上面的方式好了很多。

4.return 301实现最优解 -- 最好

虽然上面我们使用参数代替了正则,但是rewrite 规则会先对url 进行匹配,匹配上了再执行相应的规则,而 return 没有匹配url 层面的性能消耗,直接返回用户新的连接,所以是最优的解决方案。

server {
        listen       80;
        server_name  yichen2.com;
        return       301 https://$host$request_uri ;
}
server {

        listen       443 ssl;
        server_name  yichen2.com;
        root /usr/share/nginx/html;
        index  test.html ;
        ssl_certificate  /root/ssl/yichen2.crt;
        ssl_certificate_key /root/ssl/yichen2.key;
        charset  utf-8;
        location / {

}
}

注意: 在return 中, $request_uri 后面不用加? (加? 用来避免携带参数是rewrite 中的特性)。

如果希望实现永久重定向,则使用return 301 https://$host$request_uri , 不过想要两个域名都会使用,所以更多情况下使用302 临时重定向。

301重定向和302重定向的区别

  302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,因为服务器返回302,所以,搜索搜索引擎认为新的网址是暂时的。

  而301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向之后的网址。

  

3.nginx负载均衡

参考文档

http://nginx.org/en/docs/http/ngx_http_upstream_module.html

1.基础负载均衡

客户端 ----> nginx .html ----> proxy_pass ----> apache 或 php

这种动静分离。动静分离不是一个严谨的说法。叫反向代理比较规范。

反向代理后端如果有多台服务器,自然可形成负载均衡。

但 prox_pass 如何指向多台服务器呢?

location / {
        proxy_pass http://192.168.224.11/;
        proxy_pass http://192.168.224.12/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;    
        }

这样是会出现错误。

解决办法。

把多个台服务器用 upstream 指定绑定在一起并起个组名。

然后 proxy_pass 指向该组。

 upstream backendweb {
        server yichen2.com:81  weight=1 max_fails=2 fail_timeout=1s;
        server server2.com:82  weight=1 max_fails=2 fail_timeout=1s;
}

这样就可以了。
location / {
                proxy_pass http://backendweb;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;
        }

模块用于定义可以由proxy_passfastcgi_passuwsgi_passscgi_passmemcached_passgrpc_pass指令引用的服务器组

参数说明:

weight 表示权重。默认为1 。

max_fails = 2 表示持续时间内与服务器通信失败2次,则认为该服务器不可用。

fail_timeout=1s 代表健康检查(检查后台web是否ok,访问超时1秒,并两次超时,则认为不健康

负载均衡(lb load banlance)一般要注意四个方面:

1,算法 round-robin

2,健康检查

3,会话保持

4,数据一致 rsync drbd    共享存储   分布式存储

2.使用ip_hash.实现同一ip客户端一旦调到一台,就一直调那一台

 upstream backendweb {
      ip_hash;   #在上个例子的基础上只加这一句;
        server yichen2.com:81  weight=1 max_fails=2 fail_timeout=1s;
        server server2.com:82  weight=1 max_fails=2 fail_timeout=1s;
}

nginx的ip_hash的意思是,如果一个客户端的访问被调度到其中一台后台服务器,那么同一个源IP来的

访问都只会被调到这个后台服务器;这里测试时,如果都用同一个网段的内网IP来做客户端测试,可能会

都只转到一个后台(因为nginx的hash算法是按网段来算的,如果是公网不同网段的客户端IP就不一样了)

对于nginx的upstrem算法总结:

1,round-robin 轮循(平均分配)

2,weight 权重(人为地分配权重,用于后台服务器性能不均的情况)

3,fair 响应时间(按后台的响应时间来分配,需要第三方模块,但如果后台服务器都在内网,就没太大必要使用这种算法了)

4,url_hash 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为多台缓存时比较有效,提高缓存命中率(后面例子会讲)

5,ip_hash 在负载均衡的基础上加上会话保持(优点是配置方便,缺点是不能完全的负载均衡)

4.nginx常用搭建方式

1.网站的数据切分

什么是网站数据切分?

其实也是七层调度

比如我要把新浪新闻,新浪体育给分开

方法1:

用DNS的二级域名(直接dns解析成不同的ip)

新浪新闻 news.sina.com 新浪国内新闻 news.sina.com/china/ --说明没有用二级域名

​ 新浪国际新闻 news.sina.com/world/

​ 新浪国内新闻 china.news.sina.com #用了四级域名

​ 新浪国际新闻 world.news.sina.com

新浪体育  sports.sina.com 新浪体育nba sports.sina.com/nba/

​ 新浪体育nba nba.sports.sina.com

方法2:

前端使用代理(squid,varnish,apache,nginx,haproxy)

通过代理软件七层调度来分离

location 网站数据切分

​ client(宿主机) 192.168.2.x

​ 192.168.2.19

​ nginx(虚拟机1)

​ 192.168.224.10

​ web1(虚拟机2) web2(虚拟机3)

​ 192.168.224.11 192.168.224.12

nginx配置如下

location /nba/ {
    proxy_pass http://192.168.224.11/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;        
}    
location /cba/ {
    proxy_pass http://192.168.224.12/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;        
}    

然后重启

接着在11和12服务器上操作

在11和12操作
yum install -y httpd
echo web2 > /var/www/html/index.html
systemctl restart httpd
curl 192.168.224.12

客户端验证

http://192.168.2.19/nba/
web1
http://192.168.2.19/cba/
web2

2.网站动静分离

把location段修改为如下

location ~* \.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
        proxy_pass http://192.168.224.11;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;            
    }  #静态文件走这台服务器
    
    location ~  \.(php|cgi|txt)$ {
        proxy_pass http://192.168.224.12;  #使用正则表达式IP后面不用加/号,会报错
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
    }  #动态文件php|cgi等,走这台服务器。

5.nginx集群搭建

​ client 192.168.2.x

​ |

​ | 192.168.2.19(模拟网站公网ip,整个架构的域名假设为server1.com )

​ nginx 反向代理 192.168.224.10

​ |

​ -----------

​ | | 命中 hit 直接返回

动态程序文件.php | |

​ | squid(web加速,缓存静态文件或图片)

直接找web | | 192.168.224.12

​ ---- | 没命中 miss 找后端web去取

​ | |

​ lnmp <---- |

​ 192.168.224.11

实验前准备:

1,所有机器配置主机名并在/etc/hosts里互相绑定主机

2,几台服务器都能互相连接ping通

创建4台centos

创建网络
docker network create -d bridge mynginx

创建centos容器。
centos容器
docker run -it --restart=always --privileged=true --name centos -p 88:80 -h centos --network mynginx  -v /etc/localtime:/etc/localtime -d centos:7 /usr/sbin/init

centos1容器
docker run -it --restart=always  --privileged=true --name centos1 -p 8080:80 -h centos1 --network mynginx  -v /etc/localtime:/etc/localtime -d centos:7 /usr/sbin/init

centos2容器
docker run -it --restart=always  --privileged=true --name centos2  -h centos2 --network mynginx  -v /etc/localtime:/etc/localtime -d centos:7 /usr/sbin/init

centos3容器
docker run -it --restart=always --privileged=true --name centos3  -h centos3 --network mynginx  -v /etc/localtime:/etc/localtime -d centos:7 /usr/sbin/init

分别进去容器测试是否正常ping通

docker exec -it centos /bin/bash

docker exec -it centos1 /bin/bash

docker exec -it centos2 /bin/bash

docker exec -it centos3 /bin/bash

安装相关命令
yum provides ip

yum install -y iproute net-tools vim

ping centos1
ping centos2
ping centos3

vim /etc/hosts
增加

172.30.0.2      centos  centos.com
172.30.0.3      centos1 centos1.com
172.30.0.4      centos2 centos2.com
172.30.0.5      centos3 centos3.com

开始部署

第一大步:配置discuz论坛

1.在上图中的lnmp服务器上安装并配置discuz论坛

centos1上操作

yum install epel-release -y
    yum install mariadb mariadb-server php php-mysql php-gd libjpeg\* php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-bcmath php-mhash php-fpm  php-pecl-zendopcache nginx -y

rpm -qa|grep php

systemctl restart mariadb.service
systemctl enable mariadb.service
systemctl status mariadb.service
设置新密码
mysqladmin password '123.yichen'

2.优化php-fpm

优化php-fpm,并启动(php-fpm为php的fastcgi模式,简单来说就是php的服务模式)

 vim /etc/php-fpm.d/www.conf   #打开php-fpm主配置文件并进行优化(以下优化在生产环境视具体情况而定)
 
12  listen = /var/run/php-fpm/fastcgi.socket    #原来是监听127.0.0.1:9000也是可以的,我这里换成socket来做(本机连接可以使用socket或tcp/ip协议方式,远程连接只能使用tcp/ip协议方式)

31 listen.owner = nginx
32 listen.group = nginx        #socket文件的权限设置。用户与组和跑nginx服务的用户一致,避免权限问题(如果前面使用的是tcp/ip的方式,这里就注释就好)
33 listen.mode = 0666

39 user = nginx            #用户与组和跑nginx服务的用户一致,避免权限问题    
41 group = nginx

60 pm = dynamic           #对于专用服务器,pm可以设置为static。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则可以动态调整下面几个参数
70 pm.max_children = 64     #子进程最大数,我这里只是参考值(看系统资源决定,视实际环境测试后调整,下几个参数也一样)
75 pm.start_servers = 20     #启动时默认启动的进程数
80 pm.min_spare_servers = 5    #保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
85 pm.max_spare_servers = 35    #保证空闲进程数最大值,如果空闲进程大于此值,此进行清理

160 rlimit_files = 65535     #打开的文件描述符数量,不能大于系统的限制(系统可以使用ulimit命令查看和设置,后面有例子)
218 php_flag[display_errors] = on    #打开php错误显示功能

修改php-fpm的权限

chown nginx.nginx /var/run/php-fpm/ -R

设置系统打开的文件描述符数量,与上面的配置对应

ulimit -n

ulimit -SHn 65535

echo "ulimit -SHn 65535" >> /etc/rc.local (设置永久生效)

启动php-fpm服务

systemctl start php-fpm.service
systemctl status php-fpm.service 
systemctl enable php-fpm.service

3.配置nginx

nginx的配置server段修改如下

  server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  centos1.com;
        root         /usr/share/nginx/html;
         index index.php index.html;
        include /etc/nginx/default.d/*.conf;

        location / {
        }
        
    location ~\.php$ {
        fastcgi_pass    127.0.0.1:9000; #表示转发到本地的9000端口php处理此类文件
            fastcgi_index  index.php;    
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        include /etc/nginx/fastcgi.conf;

}  

启动

systemctl start nginx.service        #80端口不要被其它服务(如httpd)占用了
systemctl enable nginx.service
systemctl status nginx.service
 curl -I 127.0.0.1   #(访问本机80端口,验证Nginx服务)

4.测试nginx工作是否支持PHP

在nginx家目录里加上php测试页

 vim /usr/share/nginx/html/test.php
 
 <?php
        phpinfo();
?>

在浏览器输入地址

http://server1.com:8080/test.php

curl -i  centos1.com/test.php

如果有出现php的版本信息,说明架构搭建好了。

1,解压discuz到nginx家目录

yum install -y unzip
mkdir /usr/share/nginx/html/discuz/
通过主机把包往容器里面复制。
docker cp Discuz_X3.3_SC_UTF8.zip centos1:/usr/share/nginx/html/discuz/

unzip Discuz_X3.3_SC_UTF8.zip -d /usr/share/nginx/html/discuz/

cd /usr/share/nginx/html/discuz/

mv upload/* ./
 rm upload/ -rf

环境检查这一步,有些目录和文件权限需要修改(下面直接使用简单方式全改成nginx的owner和group)

 chown nginx.nginx /usr/share/nginx/html/discuz -R

2.mariadb数据库授权

mysql -p
MariaDB [(none)]> create database discuz;  #创建一个库,用于存放将要安装的discuz论坛的表

MariaDB [(none)]> grant all on discuz.* to 'discuz'@'localhost' identified by '123';   #授权一个用户,用于discuz论坛程序连接mysql

MariaDB [(none)]> flush privileges;

3.开始访问

http://192.168.224.11:8080/discuz/
填上对应的数据库地址,库,用户,密码。开始安装
    On web page wizard:
        选择:全新安装 Discuz! X (含 UCenter Server)
        数据库名:discuz
        数据库用户名:discuz
        数据库密码:123
        管理员密码:123
        重复密码:123

如果发现权限不可写,把权限改下就可以了。
chmod o+w /usr/share/nginx/html/discuz/* -R

4.测试论坛

http://192.168.224.11:8080/discuz/forum.php 测试论坛

第二大步:在上图中的nginx服务器上安装并配置nginx

centos上操作 这部可以在宿主机操作

 yum install nginx -y

配置文件如下 http段的内容

upstream squid {
    server centos2.com;
}
upstream web {
    server centos1.com;
}


 server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  192.168.224.11;  #替换为实际的名字
        root         /usr/share/nginx/html;

        include /etc/nginx/default.d/*.conf;


       location ~ .*\.php$ {
            proxy_pass   http://web;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location ~ .*\.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
            proxy_pass   http://squid;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location / {
            proxy_pass   http://squid;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

重启nginx

 systemctl restart nginx

第三大步:安装并配置squid

1.在上图中的squid服务器上安装并配置squid

yum install squid -y

2.配置squid主配置文件

 vim /etc/squid/squid.conf 
 
 http_access allow all        #把这一行前面的全删除,再把这行修改成允许所有。注意!有多个重复的http_access,都要删除
 
 http_port 80 accel vhost vport  #修改成支持反向代理模式,端口也为80与nginx的配置对应(这里如果用3128也可以,nginx和这里对应的端口也要改成3128,并且后面清缓存的http://192.168.2.19/static/image/common/logo.png要改成http://192.168.2.19:3128/static/image/common/logo.png)

cache_dir ufs /var/spool/squid 256 16 256    #打开缓存目录的定义这一句


cache_peer 172.30.0.3 parent 80 0 no-query originserver name=web    172.30.0.3是 lnmp server
cache_peer_domain web 192.168.224.11    
#加上这两句,表示代理后台的lnmp的80端口;server1.com为网站的域名,192.168.2.19为我这个架构最前端的nginx的IP

image-20200628021817261.png

3,启动squid

 yum install openssl -y #需要安装OpenSSL,否则无法启动squid

在/etc/hosts中配置nginx的外部网卡IP和域名的绑定

systemctl restart squid

查询目前所有缓存的资料

/usr/bin/squidclient -p 80 mgr:objects | grep png 

第四大步:验证

在客户端机器192.168.2.x上首先绑定静态DNS

用于模拟DNS,如果不绑定,也可以直接使用公网IP192.168.2.19来访问,因为在squid里配置了(cache_peer_domain web server1.com 和 cache_peer_domain web 192.168.2.19 两句)

cat /etc/hosts

192.168.2.19 server1.com #IP要为前端nginx的IP,名字为这个网站的域名要和squid里的cache_peer_domain web server1.com 要对应

1,在客户端用firefox访问http://server1.com/discuzhttp://192.168.2.19/discuz是可以正常看到我的lnmp安装的discuz论坛

2,在客户端使用下面的命令验证discuz论坛的一个logo,可以看到在squid上命中的信息

curl -I http://192.168.224.11:/discuz/static/image/common/logo.png

image-20200628034709160.png
3,关闭squid,在客户端用firefox访问,会发现整个网站都没有图片(静态的元素)

curl -I http://server1.com/discuz/static/image/common/logo.png来验证也会报错

curl -I http://server1.com/discuz/static/image/common/logo.png
报502错误

因为我的架构里只有一台squid,再次启动squid后,一切又恢复正常

4,关于squid手动清缓存

vim /etc/squid/squid.conf

acl purge_admin src 127.0.0.1  #设定管理员为purge_admin 从本地可以清除缓存
acl purge method PURGE         
http_access allow purge_admin purge  #允许purge_admin执行purge
http_access deny all purge           #默认禁止所有用户操作清除缓存


 systemctl restart squid

最基本的清除一条缓存的操作,必须要在squid本机执行

squidclient -m PURGE -h 127.0.0.1 -p 80 http://192.168.224.11/discuz/static/image/common/logo.png
# -h参数后只能接127.0.0.1;-p 80是squid的监听端口;最后的路径就是客户端访问的路径
清除缓存后再到客户端访问,就变成miss了

如果要批量清除squid,可以使用下面的脚本(你需要修改成自己对应的路径)

 vim /tmp/purge_squid.sh
 
 #!/bin/bash
squidcache_path="/var/spool/squid/"
squidclient_path="/usr/bin/squidclient"
grep -a -r $1 $squidcache_path/* | strings | grep ^"http" | while read url
do
$squidclient_path -h 127.0.0.1 -m PURGE -p 80 $url > /dev/null 2>&1
echo "$url被清除"
done

注意:脚本的squidcache_path修改成你对应的缓存目录,squidclient_path修改成squidclient命令的路径;-h 127.0.0.1是因为我做了acl限制的,所以只能在squid本机上清除

批量清除的方法:
sh /tmp/purge_squid.sh .txt   #表示清除所有的.txt结尾的缓存
sh /tmp/purge_squid.sh .      #表示清除所有缓存
sh /tmp/purge_squid.sh /aaa/  #表示url里有/aaa/路径就清掉缓存

在上面的架构基础上多加一台squid2(我这里IP为172.30.0.5),

client 192.168.2.x

​ |

​ | 192.168.2.19

​ nginx

​ | 192.168.224.11

​ |

​ |------------|---------------

​ | | |

​ | squid1 squid2 centos3.com

​ | centos2.com

​ |------------|

​ |

​ |

​ lnmp

​ centos1.com

以下练习在Squid2进行:

yum install openssl -y
yum install squid -y

在squid2中安装squid软件,配置文件与squid服务器中的配置保持一致/etc/squid/squid.conf

vim /etc/squid/squid.conf

http_access allow all

acl purge_admin src 127.0.0.1
acl purge method PURGE
http_access allow purge_admin purge
http_access deny all purge


# Squid normally listens to port 3128
http_port 80 accel vhost vport

# Uncomment and adjust the following to add a disk cache directory.
cache_dir ufs /var/spool/squid 256 16 256
cache_peer 172.30.0.3 parent 80 0 no-query originserver name=web
cache_peer_domain web server.example.com
cache_peer_domain web 192.168.224.11

# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid

#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp:           1440    20%     10080
refresh_pattern ^gopher:        1440    0%      1440
refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
refresh_pattern .               0       20%     4320

重启2台squid服务器上的squid服务

systemctl restart squid

做法,在nginx配置要修改为下面一段

upstream squid {
    server 172.30.0.4 weight=1 max_fails=2 fail_timeout=3s;
    server 172.30.0.5 weight=1 max_fails=2 fail_timeout=3s;
}


systemctl restart nginx

在客户端用curl -I去测试多个不同的文件请求,看缓存情况,如:

curl -I http://server1.com/discuz/static/image/common/logo.png
curl -I http://server1.com/discuz/static/image/feed/task_b.png
curl -I http://server1.com/discuz/static/image/feed/album_b.png
curl -I http://server1.com/discuz/static/image/feed/portal_b.png
curl -I http://server1.com/discuz/static/image/feed/wall_b.png

测试结果为:第一次squid1(conts2),第二次squid2(centos3),第三次squid1...以此类推(round-robin)

但这个做法的缺点为:比如同一个url的请求,连续访问,它也会RR轮循给squid1和squid2,这样会造成两个squid重复缓存。

改进的做法为:使用nginx的url_hash的算法,把同一个url的请求只给同一个后台squid,以提高缓存命中率。如果要做这个改进的话,只需要把nginx的配置再修改成如下:

upstream squid {
    hash $request_uri;
    server 172.30.0.4 weight=1 max_fails=2 fail_timeout=3s;
    server 172.30.0.5 weight=1 max_fails=2 fail_timeout=3s;
}

再次测试:

结果为:新的请求仍然会RR轮循调给squid1和squid2,但已经请求过的地址再次被请求,会调给第一次调的squid,提高缓存命中率。

查询缓存

/usr/bin/squidclient -p 80 mgr:objects | grep png

nginx又做反向代理又做缓存

在上面的架构中,把squid去掉,由nginx又做反向代理,又做缓存

nginx做缓存需要一个另外一个软件(ngx_cache_purge)

下载网址为

wget  http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz

这时候nginx需要重新源码安装,

下面的源码包都可以,一个是旧版本,一个是新版本。
wget  http://nginx.org/download/nginx-1.8.1.tar.gz
wget http://nginx.org/download/nginx-1.12.2.tar.gz

架构图,在上面做的基础上把squid去掉。

client 192.168.2.x

​ |

​ | 192.168.2.19

​ nginx 反向代理加缓存

​ | 192.168.224.11

​ |

​ lnmp

​ cetos1.com

192.168.224.11虚拟机在上一个实验的基础上继续做。但是需要停掉nginx(恢复快照也可以,但是要

自己创建nginx用户,useradd -s /usr/sbin/nologin nginx

ystemctl stop nginx
systemctl disable nginx

第一步:

先把squid停掉

使用源码版本编译

yum install pcre-devel zlib-devel gcc  openssl-devel -y

复制压缩包到本地

tar xf nginx-1.8.1.tar.gz -C /usr/src/

tar xf ngx_cache_purge-2.3.tar.gz -C /usr/src/
cd /usr/src/nginx-1.8.1/

./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_gzip_static_module  --with-http_stub_status_module  --add-module=../ngx_cache_purge-2.3/

使用--add-module=../ngx_cache_purge-2.3/参数加上缓存模块的功能,两个目录是同级目录(从编译的路径可以看出来)

如果上一步执行报错需要安装gcc: yum -y install gcc

make && make install

第二步:

修改nginx主配置文件

vim /usr/local/nginx/conf/nginx.conf
user  nginx;
worker_processes  auto;
error_log  logs/error.log  info;
pid        logs/nginx.pid;

events {
    worker_connections  65535;
    use epoll;
}

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" "$upstream_cache_status"';
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip on;

    proxy_temp_path   /usr/local/nginx/proxy_temp_dir 1 2;
    proxy_cache_path  /usr/local/nginx/proxy_cache_dir/cache  levels=1:2 keys_zone=cache:100m inactive=1d max_size=10g;    

upstream web {
    server 172.30.0.3 weight=1 max_fails=2 fail_timeout=30s;
}


    server {
        listen       80;
        server_name  server1.com;
    access_log  logs/host.access.log  main;

        location / {
        proxy_pass   http://web;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_cache cache;
        proxy_cache_key $host$uri$is_args$args;
        proxy_cache_valid 200 304 10m;    
        add_header X-Cache '$upstream_cache_status from $host';
        expires 1d;
        }
        location ~ .*\.(php|cgi)$ {
        proxy_pass   http://web;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        }

    }
}

上面的配置参数说明

1、http段设置。

proxy_temp_path /usr/local/nginx/proxy_temp_dir; #设置临时目录

proxy_cache_path /usr/local/nginx/proxy_cache_dir/cache levels=1:2 keys_zone=cache:100m inactive=1d max_size=10g;

keys_zone=cache:100m #表示这个zone名称为cache,分配的内存大小为100MB

/usr/local/nginx/proxy_cache_dir/cache #表示cache这个zone的文件要存放的目录

levels=1:2 #表示缓存目录的第一级目录是1个字符,第二级目录是2个字符,即/usr/local/nginx/proxy_cache_dir/cache/a/1b这种形式

inactive=1d #表示这个zone中的缓存文件如果在1天内都没有被访问,那么文件会被cache manager进程删除掉

max_size=10g 表示这个zone的硬盘容量为10GB

2、server段设置

proxy_cache cache; #设置缓存共享内存区块,也就是keys_zone名称

proxy_cache_key $host$uri$is_args$args; #设置缓存key

proxy_cache_valid 200 304 10m; #设置http状态码为200,304缓存时间为10分钟

add_header X-Cache '$upstream_cache_status from $host'; # $upstream_cache_status表示资源缓存的状态,有HIT MISS EXPIRED三种状态

expires 1d; #设置失期时间,为1天

保存主配置文件后,建立对应的缓存目录

mkdir /usr/local/nginx/proxy_cache_dir/cache -p

ls /usr/local/nginx/proxy_cache_dir/cache

启动nginx

/usr/local/nginx/sbin/nginx

/usr/local/nginx/sbin/nginx -t
clip_image002.jpg

如果遇到句柄限制就执行 ulimit -n 65535
clip_image004.jpg

参考:停止服务 /usr/local/nginx/sbin/nginx -s stop

警告信息没有了
clip_image006.jpg

创建软连接,可以方便启动

ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/nginx 

nginx -s quit 停止nginx

第三大步:

客户端测试

1,使用下面的命令访问
 curl -I http://192.168.224.11/discuz/static/image/common/logo.png
curl -I http://192.168.224.11/discuz/static/image/common/logo.png

第一次为MISS 
第二次为HIT

2,在客户端用户firefox访问http://192.168.224.11/discuz,可以访问整个discuz论坛

在nginx上查看缓存目录,会看到很多子目录(缓存都在这些目录里)

ls /usr/local/nginx/proxy_cache_dir/cache

3,nginx的缓存清除

在nginx服务器写一个脚本,如下

vim /tmp/purge_nginx_cache.sh

#!/bin/bash
cachedir=/usr/local/nginx/proxy_cache_dir/cache

grep -ra  $1 $cachedir |grep $1 | awk -F':' '{print $1,$3}'|while read cacheurl url
do
    rm  -rf  $cacheurl
        echo "$url 被清除"
done
echo "缓存清除成功"

清除方法为

bash /tmp/purge_nginx_cache.sh .png$   #清除所有的.png结尾的缓存

手动搜索缓存文件,txt后面要有$符号

grep -ra .png$ /usr/local/nginx/proxy_cache_dir/cache/

6,nginx优化

1.ab压力测试及nginx性能统计模块

windos下载地址
https://www.apachehaus.com/cgi-bin/download.plx

yum install -y httpd   #安装httpd 就有ab 这个工具了。
yum -y install httpd-tools  #或者只下载工具

测试场景:模拟1000个用户,对首页发起总共5万次请求。
ab -c 1000 -n 50000  http://192.168.224.12/index.html

ab常用参数的介绍:

-n :总共的请求执行数,缺省是1;

-c: 并发数,缺省是1;

-t:测试所进行的总时间,秒为单位,缺省50000s

-p:POST时的数据文件

-k 启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认时,不启用KeepAlive功能

-w: 以HTML表的格式输出结果

继续测试

ab -c 2000 -n 80000  http://192.168.224.12/index.html
并发达到2000后服务器响应速度就变慢了,

image-20200628065949478.png

开始优化

ulimit -n   发现最大打开文件描述符是1024, 这时候要优化了,把改为最大65535

ulimit -SHn 65535
echo "ulimit -SHn 65535" >> /etc/rc.local (设置永久生效)

配置nginx性能统计模块

server {
        listen       80 ;
        server_name  server2.com;  #工作中一般选择localhost

        location = /status {
            access_log off;
            stub_status on;
            allow 127.0.0.1 ;
         allow 192.168.224.12 ;
        allow 192.168.224.1;
            deny all; #限制所有
        }
}

访问就能出现结果了;
http://server2.com/status 

Active connections: 2  #活跃连接数,并发
server accepts handled requests
 750427 750427 747109 
Reading: 0 Writing: 1 Waiting: 1 

1.优化socket层面

优化nginx

worker_rlimit_nofile 10000; 
worker_processes auto;


events {
    worker_connections 65535; #设置子进程能打开多少个sock连接。设置最大。
}

系统层面

cat /proc/sys/net/core/somaxconn #这里面都是系统运行状态的值。发现是128 把改大
128
echo 50000 > /proc/sys/net/core/somaxconn

加快tcp连接的回收回收recycle
cat /proc/sys/net/ipv4/tcp_tw_recycle
0 #表示不回收,
echo 1 >  /proc/sys/net/ipv4/tcp_tw_recycle

空的tcp是否允许回收利用reuse
cat /proc/sys/net/ipv4/tcp_tw_reuse
0
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

关闭洪峰防御
cat /proc/sys/net/ipv4/tcp_syncookies
1

echo 0 > /proc/sys/net/ipv4/tcp_syncookies

直接写个脚本

vim tcpopt.sh

#!/bin/bash

echo 50000 > /proc/sys/net/core/somaxconn
echo 1 >  /proc/sys/net/ipv4/tcp_tw_recycle
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
echo 0 > /proc/sys/net/ipv4/tcp_syncookies

这时候再去访问,会发现可以支持2000并发了

ab -c 2000 -n 100000   http://192.168.224.12/index.html

5千的并发,客户端撑不住了。

ab -c 5000 -n 200000   http://192.168.224.12/index.html

客户端也优化下

ulimit -SHn 65535
echo 50000 > /proc/sys/net/core/somaxconn

用两台客户端测试分别5000并发

这时服务端还是可以支持共1万的并发

下面在测试其他参数加个-k参数

ab -c 5000 -n 200000 -k  http://192.168.224.12/index.html

这时候会发现很多是Waiting状态。等待状态。

需要修改nginx的keeplive_timeout的时间

keepalive_timeout   65; #65秒太多了。对于高并发的网站,这个需要修改最小。

keepalive_timeout   0;  #修改为0秒。

系统层面的优化还有其他参数需要修改。可以向上面的动态修改关机重启就恢复默认了,也可以写入/etc/sysctl.conf文件中

如下参考:

vim /etc/sysctl.conf

fs.file-max = 1000000
fs.inotify.max_user_instances = 8192
net.ipv4.tcp_syncookies = 1    #1是打开洪峰防御
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1      # 对应上面的/proc/sys/net/ipv4/tcp_tw_reuse 文件
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1     #默认为6次尝试连接。大概就是63秒 ,所以改为1。
net.ipv4.tcp_synack_retries = 1
net.core.somaxconn = 50000     #对应上面的/proc/sys/net/core/somaxconn 文件。
net.core.netdev_max_backlog = 32768
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_max_orphans = 32768
# forward ipv4
net.ipv4.ip_forward = 1

sync洪峰攻击测试

yum install -y hping3

hping3 -c 1000 -d 120 -S -w 64 -p 80 --flood --rand-source  192.168.224.12

使用 netstart -nat 会发现很多tcp的连接状态是属于SYN_RECV状态
image-20200629041643791.png

Last modification:July 20th, 2020 at 05:42 pm
如果觉得我的文章对你有用,请随意赞赏