nginx

发布时间 2023-06-14 00:37:55作者: 转角90

·1. nginx 应用场景

  • 静态资源服务
  • 反向代理服务
  • API 接口服务

2. nginx 的优势

  • 高并发高性能
  • 可扩展性好
  • 高可靠性
  • 热部署
  • 开源许可证

3. 学习环境

3.1 常用版本四大阵营

3.2 操作系统

  • VMware: 新建虚拟机
  • CentOS7:镜像

2023-06-13_183049

2023-06-13_184155

2023-06-13_184511

2023-06-13_184719

2023-06-13_215804

2023-06-13_220034

3.3 环境确认

  • 启动网卡

    vi /etc/sysconfig/network-scripts/ifcfg-ens33
    ONBOOT=yes  # 是否随网路服务启动,ens33生效
    
    systemctl restart network # 重启网络
    
  • 配置静态 ip 地址:

    # vi /etc/sysconfig/network-scripts/ifcfg-ens33
    
    TYPE="Ethernet"
    PROXY_METHOD="none"
    BROWSER_ONLY="no"
    - BOOTPROTO="dhcp"
    + BOOTPROTO="static"
    DEFROUTE="yes"
    IPV4_FAILURE_FATAL="no"
    IPV6INIT="yes"
    IPV6_AUTOCONF="yes"
    IPV6_DEFROUTE="yes"
    IPV6_FAILURE_FATAL="no"
    IPV6_ADDR_GEN_MODE="stable-privacy"
    NAME="ens33"
    UUID="5439782d-91b9-43c5-8709-063de676279f"
    DEVICE="ens33"
    ONBOOT="yes"
    + IPADDR="192.168.75.137" # 静态ip地址
    + NETMASK="255.255.255.0" # 子网掩码
    + GATEWAY="192.168.75.1" # 网关
    + DNS1="8.8.8.8" # DNS服务器
    
    # 重启网络 systemctl restart network
    
    • 一些公网 DNS 服务器

      • 阿里

        223.5.5.5
        223.6.6.6
        
      • 腾讯

        119.29.29.29
        182.254.118.118
        
      • 百度

        180.76.76.76
        
      • 114DNS

        114.114.114.114
        114.114.115.115
        
      • 谷歌

        8.8.8.8
        8.8.4.4
        
  • 虚拟机不能上网排除:VMware->编辑->虚拟网络编辑器

    2023-06-13_224527

    2023-06-13_225416

    2023-06-13_225443

    2023-06-13_225605

    /etc/sysconfig/network-scripts/ifcfg-ens33 中网关改为"192.168.75.2"

  • 关闭防火墙

    • systemctl stop firewalld.service:关闭防火墙
    • systemctl disable firewalld.service : 禁止开机启动
  • 重启防火墙

    firewall-cmd --reload
    
  • 确认停用 selinux

    • 安全增强型 Linux(Security-Enhanced Linux) 简称 SElinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统

    • SELinux 主要作用就是最大限度地减少系统中服务进程可访问的资源(最小权限原则)

      vi /etc/selinux/config
      SELINUX=disabled
      
      • 强制模式SELINUX=enforcing:表示所有违反安全策略的行为都将被禁止。
      • 宽容模式SELINUX=permissive:表示所有违反安全策略的行为不被禁止,但是会在日志中作记录

      修改config文件后,需要重启实例,但直接重启实例将会出现系统无法启动的错误。因此在重启之前需要在根目录下新建autorelabel文件。

      touch /.autorelabel
      

      重启

      shutdown -r now
      
  • 放行端口

    firewall-cmd --zone=public --add-port=80/tcp --permanent
    
  • 安装依赖模块

    yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
    yum -y install wget httpd-tools vim
    

4. nginx 的架构

4.1 轻量

  • 源代码只包含核心模块
  • 其他非核心功能都是通过模块实现,可以自由选择

4.2 架构

  • Nginx 采用的是多进程(单线程)和多路 IO 复用模型

4.2.1 工作流程

  1. Nginx 在启动后,会有一个 master 进程和多个互相独立的 worker 进程
  2. 接收来自外界的信号,向各 worker 进程发送信号,每个进程都有可能处理这个连接
  3. master 进程能监控 worker 进程的运行状态,当 worker 进程退出(异常情况下),会自动启动新的 worker 进程

  • worker 进程数,一般会设置成机器 cpu 核数,因为更多 worker 数,只会导致进程相互竞争 cpu,从而带来不必要的上下文切换
  • 使用多进程模式,不仅能提高并发率,而且进程之间相互独立,一个 worker 进程挂了不影响其他 worker 进程

4.2.2 IO 多路复用

  • 多个文件描述符的 IO 操作都能在一个线程里并发交替顺序完成,复用线程。多对一,一对多。如:多个客户,对应一个服务员下单,服务员对多个厨师派发任务

4.2.3 CPU 亲和

  • 把 CPU 内核和 nginx 的工作进程绑定在一起,让每一个 worker 进程固定在一个 CPU 上执行,从而减少 CPU 的切换并提高缓存命中率,提高性能。

4.2.4 sendfile

  • sendfile 零拷贝传输模式

5. nginx 安装及启动

5.1 版本分类

  • Mainline version 开发版
  • Stable version 稳定版
  • Legacy versions 历史版

5.2 下载及安装

  • nginx

    • 下载

    • 上传

    • 解压:

      tar zxvf nginx-1.24.0.tar.gz  # z:gzip属性,x:解压,v:显示所有过程,f:使用文档名
      
    • 安装

      cd  nginx-1.24.0
      ls
      # auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  man  README  src
      
      # 安装命令
      ./configure --prefix=/usr/local/nginx
      
      • 错误提示及解决

        checking for OS
        + Linux 3.10.0-693.el7.x86_64 x86_64
        checking for C compiler ... not found
        ./configure: error: C compiler cc is not found
        
        # 解决
        yum install -y gcc
        
        ./configure: error: the HTTP rewrite module requires the PCRE library.
        You can either disable the module by using --without-http_rewrite_module
        option, or install the PCRE library into the system, or build the PCRE library
        statically from the source with nginx by using --with-pcre=<path> option.
        
        # 解决
        yum install -y pcre pcre-devel
        
        ./configure: error: the HTTP gzip module requires the zlib library.
        You can either disable the module by using --without-http_gzip_module
        option, or install the zlib library into the system, or build the zlib library
        statically from the source with nginx by using --with-zlib=<path> option.
        
        # 解决
        yum install -y zlib zlib-devel
        
    • 执行

      make
      make install
      
  • linux_packages

    # 创建文件
    vi /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
    
    
    # yum 安装
    yum install nginx -y
    nginx -v
    nginx -V
    

5.3 启动

进入安装好的目录/usr/local/nginx/sbin

./nginx # 启动
./nginx -s stop # 快速停止
./nginx -s quit # 优雅关闭,在退出前完成已经接收的连接请求
./nginx -s reload # 重新加载配置

5.4 安装成系统服务

创建服务脚本

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

脚本内容

[Unit]
Description=nginx - web server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecQuit=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target

重新加载系统服务

systemctl daemon-reload

启动服务

# 启动服务前需要,先关闭nginx服务,否则有冲突,
systemctl start nginx.service

开机启动

systemctl enable nginx.service

6. 目录

6.1 安装目录

查看 nginx 安装的配置文件和目录

rpm -ql nginx

6.2 日志的切割

vi /etc/logrotate.d/nginx

# 文件内容
/var/log/nginx/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

# 查询日志文件
ls /var/log/nginx/*.log
/var/log/nginx/access.log  /var/log/nginx/error.log

6.3 主配置文件

路径 用途
/etc/nginx/nginx.conf 核心配置文件
/etc/nginx/conf.d/default.conf 默认 http 服务器配置文件

6.4 cgi 配置

  • CGI 是 common gateway interface(通用网关接口)
  • Web server 通过 CGI 协议可以把动态的请求传递给如 php/jsp/python/perl 等应用程序
  • FastCGI 实际上是增加了一些扩展功能的 CGI,是 CGI 的改进,描述了客户端和 Web 服务器程序之间传输数据的一种标准
  • SCGI 协议是一个 CGI 协议的替代品,它是一个应用于 http 服务器的接口标准,类似于 fastCGI,但它设计的更为容易实现
  • uwsgi 是一个 web 服务器,它实现了 wsgi 协议、uwsgi、http 等协议

2023-06-10_003050

6.5 编码转换映射转化文件

  • 这三个文件都是与编码转换映射文件,用于在输出内容到客户端时,将一种编码转换到另一种编码
  • koi8-r 是斯拉夫文字 8 位元编码,供俄语及保加利亚语使用,在 Unicode 未流行之前,koi8-r 是最为广泛使用的俄语编码,使用率甚至比 ISO/IEC 8859-5 还高。
路径 用途
/etc/nginx/koi-utf koi8-r<---> utf-8
/etc/nginx/koi-win koi8-r<---> windows-1251
/etc/nginx/win-utf windows-1251<---> utf-8

6.6 扩展名文件

路径 用途
/etc/nginx/mime.types 设置 http 协议的 Content-Type 与扩展名对应关系

6.7 nginx 模块目录

路径 用途
/etc/nginx/modules 最基本的共享库和内核模块

存放用于启动系统和执行 root 文件系统的命令如/bin/sbin的二进制文件的共享库

6.8 文档

路径 用途
/usr/share/doc/nginx-1.24.0 帮助文档
/usr/share/doc/nginx-1.24.0/COPYRIGHT 版权声明
/usr/share/man/man8/nginx.8.gz 手册

6.9 缓存目录

路径 用途
/var/cache/nginx nginx 的缓存目录

6.10 日志目录

路径 用途
/var/log/nginx nginx 的日志目录

6.11 可执行命令

路径 用途
/var/sbin/nginx 可执行命令
/var/sbin/nginx-debug 调试执行可执行命令

7. 编译参数

7.1 安装目录和路径

7.2 临时性文件

执行对应模块时 nginx 所保留的临时性文件

7.3 指定用户

用户和用户组权限越少越好

7.4 设置额外参数

  • 设置额外的参数将被添加到CFLAGS变量
  • CFLAGS变量用来存放 C 语言编译时的优化参数
--with-cc-opt='-02 -g -pipe -Wall -Wp, -D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong'

7.5 设置链接文件参数

  • 定义要传递到 C 链接器命令行的其他选项
  • PCRE 库,需要指定-with-ld-opt="-L /usr/local/lib"
--with-lld-opt="-Wl,-z,relro -Wl,-z,now -pie"

8. 配置文件

路径 用途
/etc/nginx/nginx.conf 主配置文件
/etc/nginx/conf.d/*.conf conf.d 目录下的所有配置文件
/etc/nginx/conf.d/default.conf 默认配置文件

8.1 nginx 配置语法

# 使用#可以添加注释,使用$符号可以使用变量
# 配置文件由指令与指令块组成,指令块以{}将多条指令组织在一起
user  nginx;  # 设置运行此nginx用户名 (权限可能受限)
worker_processes  auto; # 工作进程数

error_log  /var/log/nginx/error.log notice;  # 指定错误日志的路径 格式为notice
pid        /var/run/nginx.pid;  # 这是一个文件,放的是当前nginx的进程号


events {
    worker_connections  1024; # 工作进程的最大连接数
}


http {
    # include语句可以将多个文件包含进来
    include       /etc/nginx/mime.types; # 包含内容和文件名后缀的对应关系
    # 每行指令以;分号结尾,指令与参数之间以空格分隔
    default_type  application/octet-stream; # 默认的文件类型Content-Type 字节流的方式

	# 日志格式,日志格式名称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  /var/log/nginx/access.log  main;

    sendfile        on;  # 零拷贝模式
    #tcp_nopush     on;  # TCP不推,有一定的缓存,攒够一定数量后再返回给客户端

    keepalive_timeout  65; # 活动链接的超时时间s

    #gzip  on; # 是否启用压缩

    include /etc/nginx/conf.d/*.conf;  # 包含其他配置文件
}

server { # 每个server对应一个网站
    listen       80;  # 监听端口号
    server_name  localhost; # 监听的域名 可以是多个

	#charset koi8-r # 指定字符集
    #access_log  /var/log/nginx/host.access.log  main;  # 指定访问日志位置和格式

    location / {  # 匹配所有路径
        root   /usr/share/nginx/html;  # 静态文件根目录
        index  index.html index.htm;  # 索引文件
    }

    #error_page  404              /404.html;  # 错误页面,返回的状态码为404时,重定向到/404.html

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html; # 错误,重定向到/50x.html
    location = /50x.html {  # 精确匹配,当路径为/50x.html时,根目录是/usr/share/nginx/html
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {  # 如果访问的文件名是.php结尾的话,会把此请求转发给http://127.0.0.1
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ { # 如果访问的文件名是.php结尾的话,会把此请求转发给127.0.0.1:9000
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    # 如果路径是/.ht的话, 禁止所有人访问
    #location ~ /\.ht {
    #    deny  all;
    #}
}

正则匹配

  • 正则语法
    • = 进行普通字符精确匹配
    • ~ 波浪线表示执行一个正则匹配,区分大小写
    • ~* 表示执行一个正则匹配,不区分大小写
    • ^~ ^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
    • @ 定义命名 location 区段,这些区段客户端不能访问,只可以由内部产生的请求来访问,内部跳转,如 try_files 或 error_page 等
    • !~ 区分大小写不匹配
    • !~* 不区分大小写不匹配
    • ^ 以什么开头的匹配
    • $ 以什么结尾的匹配
    • \ 转义字符。可以转. * ?等
    • * 代表任意字符
  • 查找顺序和优先级
    • 1:带有“=“的精确匹配优先
    • 2:没有修饰符的精确匹配
    • 3:正则表达式按照他们在配置文件中定义的顺序
    • 4:带有“^~”修饰符的,开头匹配
    • 5:带有“~” 或“~*” 修饰符的,如果正则表达式与 URI 匹配
    • 6:没有修饰符的,如果指定字符串与 URI 开头匹配

日志

日志类型

  • 访问日志:/var/log/nginx/access.log
  • 错误日志:/var/log/nginx/error.log

日志格式

log_format name [escape=default[json] string]

nginx -V: 验证格式是否正确

变量名称(内置) 用途
$remote_addr 客户端地址
$remote_user 客户端用户名
$time_local 访问时间和时区
$request 请求行
$body_bytes_sent 发送给客户端文件内容大小
$status HTTP 请求状态
变量名称(http 请求) 用途 例子
arg_PARAMETER 请求参数 $arg_name
http_HEADER 请求头 $http_referer $http_host $http_user_agent $http_x_forwarded_for(代理过程)
sent_http_HEADER 响应头 sent_htttp_cookie

9. 核心模块

9.1 监控 nginx 客户端的状态

模块名

--with-http_stub_status_module:监控 nginx 客户端的状态

语法

Syntax: stub_status on/off
Default: -
Content: server->location

实战

vi /etc/nginx/conf.d/status.conf

+ location = /status {
+     stub_status on;
+ }

systemctl reload nginx.service

# 浏览器访问http://192.168.75.136/status

# 返回结果:
Active connections: 2
server accepts handled requests
 2 2 3
Reading: 0 Writing: 1 Waiting: 1

9.2 随机主页

模块名

--with-http_random_index_module:在根目录里随机选择一个主页显示

语法

Syntax: random_index on/off
Default: off
Content: location

实战

vi /etc/nginx/conf.d/default.conf
+ location / {
+     root /data/html;
+     random_index on;
+ }

9.3 内容替换

模块名

--with-http_sub_module:内容替换

语法

Syntax: sub_filter string repalcement;
Default: --
Content: http, service, location

实战

vi /etc/nginx/conf.d/default.conf
location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
+   sub_filter 'word' 'hyf';   # 将word替换成 hyf
+   sub_filter_once off; # 默认替换一次,关闭 全部替换
}


9.4 请求限制

模块名

  • --with-limit_conn_module: 连接频率限制
  • --with-limit_req_module:请求频率限制
  • 一次 TCP 请求至少产生一个 http 请求
  • SYN > SYN, ACK > ACK > request > response > FIN > ACK > FIN > ACK

ab

  • Apache 的 ab 命令模拟多线程并发请求,测试服务器负载压力,也可以测试 nginx、lighthttp、IIS 等其他 web 服务器的压力

    • -n 总共的请求数
    • -c 并发的请求数
    ab -n 40 -c 20 http://127.0.0.1/
    
  • 报错:Benchmarking htpp: (be patient)...apr_sockaddr_info_get() for htpp:: Name or service not known (670002)

  • 解决:安装yum install -y httpd

    yum install -y httpd
    ab -c 1000 -n 10000 http://192.168.2.38/
    
    # -c指定1000并发,-n指定总10000次,相当于1000个人访问10次。
    # -k 是否开启长连接
    
    Server Software:        nginx/1.24.0 #服务器信息和版本
    Server Hostname:        localhost #服务器的域名
    Server Port:            80 #端口
    
    Document Path:          / #访问的路径
    Document Length:        16 bytes #文档的大小为 16 bytes(此为http响应的正文长度)
    
    Concurrency Level:      20 #并发请求数
    Time taken for tests:   0.026 seconds #整个测试持续的时间,默认秒
    Complete requests:      40 #完成的请求数
    Failed requests:        0 #失败的请求书
    Write errors:           0 #网络连接写入错误数
    Total transferred:      5520 bytes #传输的总数据量
    HTML transferred:       640 bytes #传输的HTML内容传输量
    Requests per second:    1512.00 [#/sec] (mean) #平均每秒请求数
    Time per request:       13.228 [ms] (mean)
    Time per request:       0.661 [ms] (mean, across all concurrent requests) #单个用户请求一次的时间
    Transfer rate:          203.77 [Kbytes/sec] received #传输速率
    
    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        0    2   1.6      3       6
    Processing:     0    4   3.3      3       9
    Waiting:        0    4   3.1      2       8
    Total:          2    7   3.6      8      11
    #所有服务请求的百分比占用时间,这里50%的请求用时8ms,一般看90%的部分
    Percentage of the requests served within a certain time (ms)
      50%      8
      66%      9
      75%     11
      80%     11
      90%     11
      95%     11
      98%     11
      99%     11
     100%     11 (longest request)
    

请求限制

语法

# 可以以IP为key zone为空间的名称 size为空间的大小 rate 每秒中发送一次
Syntax: limit_req_zone key zone=name1:size rate=1r/s;
Default: --
Content: http(定义在server以外)
# zone= 上述定义的name1
Syntax: limit_req zone=name1 [burst] [nodelay];
# burst突发的,burst=3 如果有4个请求,1个将被处理,3个将被放到队列中等待处理
# nodelay
Default: --
Content: http,server,location

实例

vi
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
server {
 location / {
     root   /usr/share/nginx/html;
     index  index.html index.htm;
+     limit_req zone=req_zone;
 }

}
  • $binary_remote_addr: 远程的 IP 地址
  • zone=req_zone:10 表示 一个内存大小为 10M,并设定名称为 req_zone
  • rate=1r/s: 速率是每秒钟请求 1 次
  • zone=req_zone: 对应 limit_req_zone 中定义的 zone 名称
  • burst=3: 请求队列的长度,如果有 4 个请求,1 个将被处理,3 个将被放到队列中等待处理
  • nodelay: 表示不延时

连接限制

语法

# 可以以IP为key zone为空间的名称 size为空间的大小
Syntax: limit_conn_zone key zone=name1:size;
Default: --
Content: http(定义在server以外)
# zone= 上述定义的name1  number限制的数量
Syntax: limit_conn zone number;
Default: --
Content: http,server,location

实例

vi /etc/nginx/conf.d/status.conf
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
+ limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
server {
 location / {
     root   /usr/share/nginx/html;
     index  index.html index.htm;
     limit_req zone=req_zone;
+    limit_conn conn_zone 1;
 }

}

9.5 访问限制

  • 基于 IP 的访问限制 -http_access_module
  • 基于用户的信任登录 -http_auth_basic_module

http_access_module

Syntax: allow address|all;
Default: --
Content: http,server,locaion,limit_except
Syntax: deny address|CIDR|all;
Default: --
Content: http,server,locaion,limit_except
server {
+ location ~ ^/admin.html {
+     deny 192.168.66.1
+     allow all
+	}
}
server {
+ location ~ ^/admin.html {
+     if ($http_x_forwarded_for !~* '^8\.8\.8\.8'){
+           return 403
+    	}
+    }
}
符号 含义
= 严格匹配,如果这个查询匹配,那么将停止搜索并立即处理此请求
~ 区分大小写匹配
!~ 区分大小写不匹配
~* 不区分大小写匹配
!~* 不区分大小写不匹配
^~ 如果把这个前缀用于一个常规字符串,那么就是告诉 nginx 如果路径匹配,那么不测试正则表达式

http_auth_basic_module

Syntax: auth_basic string|off;
Default: auth_basic off;
Content: http,server,locaion,limit_except
Syntax: auth_basic_user_file file;
Default: --
Content: http,server,locaion,limit_except
server {
+ auth_basic '请登录';
+ auth_basic_user_file /data/users/users.conf;
}
htpasswd -c /data/users/users.conf hyf

10. 静态资源 web 服务

10.1 静态和动态资源

  • 静态资源: 一般客户端发送请求到 web 服务器,web 服务器从内存取到响应的文件,返给客户端,客户端解析并渲染显示出来
  • 动态资源:客户端请求动态资源,先交于 web 服务器,然后连接数据库获取数据,返回客户端

10.2 CDN

  • CDN:内容分发网络,Content Delivery Network
  • CDN 系统能够实时根据网络流量和各节点的链接,负载状况以及到用户的距离和响应时间综合信息将用户的请求重新导向离用户最近的服务节点上。目的是使得用户就近获取所需内容,解决 Internet 网络拥堵的状况,提高用户访问网络的响应速度

10.3 配置语法

10.3.1 sendfile

不经过用户内核发送文件

Syntax: sendfile on|off;
Default: off;
Content: http,server,locaion,if in location

10.3.2 tcp_nopush

在 sendfile 开启的情况下,合并多个数据包,提高网络包的传输效率

Syntax: tcp_nopush on|off;
Default: off;
Content: http,server,locaion

10.3.3 tcp_nodelay

在 keeplive 连接下,提高网络包的传输实时性

Syntax: tcp_nodelay on|off;
Default: on;
Content: http,server,locaion

10.3.4 gzip

压缩文件可以节约带宽和提高网络传输效率

Syntax: gzip on|off;
Default: off;
Content: http,server,locaion

10.3.5 gzip_comp_level

压缩比率越高,文件被压缩的体积越小 1-9

Syntax: gzip_comp_level level;
Default: 1;
Content: http,server,locaion

10.3.6 gzip_http_version

压缩版本

Syntax: gzip_http_version 1.0/1.1;
Default: 1.1;
Content: http,server,locaion

10.3.7 http_gzip_static_module

先找磁盘上同名的.gz文件,节约 CPU 的压缩时间和性能损耗

Syntax: gzip_static on/off;
Default: off;
Content: http,server,locaion

10.3.8 gzip_min_length

启动压缩的限制条件,如gzip_min_length 1k表示大于 1k 才压缩

10.3.9 gzip_types

压缩的类型 application/javascript text/css text/xml (无论是否指定)"text/html"类型总是会被压缩的

11. 浏览器缓存

11.1 缓存策略

强缓存

不会向服务器发送请求,直接从缓存中读取资源

  • expire: expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
  • cache-control比 expire优先级更高
  • cache-control 的值:
    • no-cache: 表示需要和服务器一致,也就是协商缓存
    • no-store: 表示不缓存
    • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
    • private:所有内容只有客户端可以缓存
    • max-age=xxx (xxx is numeric):缓存内容将在 xxx 秒后失效

协商缓存

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

  • last-modified: 服务器会返回这个字段,浏览器会缓存下这个时间
    • 保存的时间是以秒为单位的,1 秒内多次修改是无法捕捉到
    • 各机器读取到的时间不一致,就有出现误差的可能性
  • if-modified-since: 浏览器缓存的 last-modified 值
  • Etag: 一种缓存验证机制,生成 etag 常用的方法包括对资源内容使用抗碰撞散列函数,使用最近修改的时间戳的哈希值,甚至只是一个版本号,浏览器会先发送一个请求得到etag的值,
  • if-none-match: 保存的 Etag 的值,请求时携带,与服务器端的 Etag 对比

二者对比

  • 精确度上:Etag要优于Last-Modified。 -
  • 优先级上:服务器校验优先考虑Etag。 -
  • 性能上:Etag要逊于Last-Modified,etag 每次服务端生成都需要进行读写操作,而 last-modified 只需要读取操作

12. 跨域

一个域名下的脚步或文档去请求另一个域名下的资源

Syntax: add_header name value;
Default: --;
Content: http,server,locaion
location ~ .*\.json$ {
add_header Access-Control-Allow-Origin http://localhost:8888;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
root /data/json;
}

13. 防盗链

  • 防止资源被盗用
  • 保证信息安全
  • 防止流量过量
  • 使用http_refer实现
Syntax: valid_referers none | blocked | server_names | string ;
Default: --;
Content: server,locaion
location ~ .*\.(jpg|png|gif)$ {
	valid_referers none blocked xx.xx.xx.xx;  # 没有referer头,或非正式HTTP请求,或特定的IP地址都是可以访问的
	if($invalid_referer) { #允许访问为0,不允许访问为1
		return 403
	}
	root /data/json;
}

14. 代理服务

Syntax: proxy_pass URL;
Default: --;
Content: server,locaion

14.1 正向代理

代理的是客户端,服务端看不到真正的客户端。如:通过公司代理服务器上网

14.2 反向代理

代理的是服务端,客户端看不到正在的服务端。

resolver 8.8.8.8; # 谷歌的域名解析地址,配置域名进行访问的时候,需要配置此项目,否则会报502错误
server {
	location ~ .*\.json$ {
		# $http_host 要访问的主机名, $request_uri 请求路径
        proxy_pass http://$http_host$request_uri;
    }
}

15. 负载均衡

  • 使用集群是解决高并发、海量数据问题的常用手段
  • 增加服务器,分担原有服务器的访问和存储压力,通过负载均衡调度服务器,将访问请求分发到集群中的任何一台服务器上进行处理

15.1 upstream

nginx 将请求转发到后台的一组upstream服务池

Syntax: upstream name {};
Default: --;
Content: http
upstream hostName1 {
	server 127.0.0.1:3000;
	server 127.0.0.1:4000;
	server 127.0.0.1:5000;
}
server {
	location ~ .*\.json$ {
		# $http_host 要访问的主机名, $request_uri 请求路径
        proxy_pass http://hostName1;
    }
}

分配方式

  • 轮询:默认轮询

    upstream hostName1 {
    
    server 192.168.1.11 down;
    
    server 192.168.1.22 backup;
    
    server 192.168.1.33 max_fails=1 fail_tiemout=10s;
    
    }
    
    • down,表示当前 server 已停用;
    • backup,表示当前 server 是备用服务器,只有其它非 backup 后端服务器都挂掉了或很忙才会分配请求给它;
    • weight,表示当前 server 负载权重,权重越大几率愈高;
    • max_fails 和 fail_timeout 一般会关联使用,如果某台 server 在 fail_timeout 时间内出现了 max_fails 次连接失败,那么 Nginx 会认为其已经挂掉,从而在 fail_timeout 时间内不再去请求它,fail_timeout 默认是 10s,max_fails 默认是 1,即默认情况只要是发生错误就认为服务器挂了,如果将 max_fails 设置为 0,则表示取消这项检查。\
    • max_conns: 限制每个 server 最大的接收的连接数,性能高的服务器可以连接数多一些
  • weight:

    轮询的加强版,既可以指定轮询比率,weight 和访问几率成正比,主要应用于后端服务器异质的场景下。

    upstream hostName1 {
    
    server 192.168.1.11 weight=1;
    
    server 192.168.1.22 weight=2;
    
    server 192.168.1.33 weight=3;
    
    }
    
  • least_conn:

    哪个机器上的连接数少就分发给谁

    upstream hostName1 {
    
    least_conn;
    
    server 192.168.1.11:7777;
    
    server 192.168.1.22:8888;
    
    server 192.168.1.33:9999;
    
    }
    
  • ip_hash:

    每个请求按照访问 Ip(即 Nginx 的前置服务器或客户端 IP)的 hash 结果分配,这样每个访客会固定访问一个后端服务器,可以解决 session 一致问题。

    upstream hostName1 {
    
    ip_hash;
    
    server 192.168.1.11:7777;
    
    server 192.168.1.22:8888;
    
    server 192.168.1.33:9999;
    
    }
    
  • fair(第三方)

    公平地按照后端服务器的响应时间(rt)来分配请求,响应时间(rt)小的后端服务器优先分配请求。

    upstream hostName1 {
    
    fair;
    
    server 192.168.1.11:7777;
    
    server 192.168.1.22:8888;
    
    server 192.168.1.33:9999;
    
    }
    
  • url_hash(第三方)

    安访问的 URL 地址来分配请求,每个 URL 都定向到同一个后端服务器上

    upstream hostName1 {
    
    url_hash;
    
    server 192.168.1.11:7777;
    
    server 192.168.1.22:8888;
    
    server 192.168.1.33:9999;
    
    }
    
  • 自定义 hash

    自定义哈希 key

    upstream hostName1 {
    
    hash $request_url;
    
    server 192.168.1.11:7777;
    
    server 192.168.1.22:8888;
    
    server 192.168.1.33:9999;
    
    }
    

16. 多级缓存

20. 附录

20.1 用户空间和内核空间

我们知道操作系统采用的是虚拟地址空间,以 32 位操作系统举例,它的寻址空间为 4G(2 的 32 次方),这里解释二个概念:

  1. 寻址: 是指操作系统能找到的地址范围,32 位指的是地址总线的位数,你就想象 32 位的二进制数,每一位可以是 0,可以是 1,是不是有 2 的 32 次方种可能,2^32 次方就是可以访问到的最大内存空间,也就是 4G。
  2. 虚拟地址空间:为什么叫虚拟,因为我们内存一共就 4G,但操作系统为每一个进程都分配了 4G 的内存空间,这个内存空间实际是虚拟的,虚拟内存到真实内存有个映射关系。例如 X86 cpu 采用的段页式地址映射模型。

操作系统将这 4G 可访问的内存空间分为二部分,一部分是内核空间,一部分是用户空间

内核空间是操作系统内核访问的区域,独立于普通的应用程序,是受保护的内存空间。

用户空间是普通应用程序可访问的内存区域

以 linux 操作系统为例,将最高的 1G 字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF),供内核使用,称为内核空间,而将较低的 3G 字节(从虚拟地址 0x00000000 到 0xBFFFFFFF),供各个进程使用,称为用户空间

20.2 进程上下文切换

  • 保存上下文信息
  • 还原上下文信息

20.3 进程的阻塞

  • 正在执行的进程,由于期待的某些事件未发生,将自己的运行状态变为阻塞状态
  • 进程的阻塞是进程自身的一种主动行为,也因为只有处于运行态的进程(获取 CPU),才能将其转为阻塞状态,当进程进入阻塞是不占用 CPU 资源的

20.4 文件描述符

  • 一个用于表述指向文件引入的抽象概念
  • 当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符

20.5 I/O 模式

  • 对于一次 IO 访问,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的缓存区,最后交给进程。当一个 read 发生时,会经历两个阶段
    • 等待数据准备
    • 将数据从内核拷贝到进程中

20.6 分类

  • 同步阻塞 IO
  • 同步非阻塞 IO
  • 异步阻塞 IO(IO 多路复用)
  • 异步非阻塞 IO

20.7 事件模型

  • 目前支持 IO 多路复用的系统调用有 select,poll 和 epoll
  • I/O 多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(读就绪,写就绪)。能够通知程序进行相应的读写操作
  • 但 select/poll/epoll 本质上都是同步 IO,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的

20.8 进程间通信

  • 管道(也称作共享文件)

    • 管道中的数据只能单向流动

    • 匿名管道只能用于父子进程之间的通信。

    • 管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区的操作

    • 管道这种进程通信方式虽然使用简单,但是效率比较低,不适合进程间频繁地交换数据,并且管道只能传输无格式的字节流。

  • 消息队列(也称作消息传递)

    • 消息队列的本质就是存放在内存中的消息的链表,而消息本质上是用户自定义的数据结构

    需要注意的是,消息队列对于交换较少数量的数据很有用,因为无需避免冲突。但是,由于用户进程写入数据到内存中的消息队列时,会发生从用户态拷贝数据到内核态的过程;同样的,另一个用户进程读取内存中的消息数据时,会发生从内核态拷贝数据到用户态的过程。因此,如果数据量较大,使用消息队列就会造成频繁的系统调用,也就是需要消耗更多的时间以便内核介入

  • 共享内存(也称作共享存储)

    两个不同进程的逻辑地址通过页表映射到物理空间的同一区域,它们所共同指向的这块区域就是共享内存。不同于消息队列频繁的系统调用,对于共享内存机制来说,仅在建立共享内存区域时需要系统调用,一旦建立共享内存,所有的访问都可作为常规内存访问,无需借助内核。这样,数据就不需要在进程之间来回拷贝,所以这是最快的一种进程通信方式

  • 信号量和 PV 操作

    为了保证共享内存在任何时刻只有一个进程在访问(互斥),并且使得进程们能够按照某个特定顺序访问共享内存(同步),我们就可以使用进程的同步与互斥机制,常见的比如信号量与 PV 操作。

    信号量其实就是一个变量 ,我们可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为 1 的信号量。

    用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现进程互斥或同步。这一对原语就是 PV 操作:

    1)P 操作:将信号量值减 1,表示申请占用一个资源。如果结果小于 0,表示已经没有可用资源,则执行 P 操作的进程被阻塞。如果结果大于等于 0,表示现有的资源足够你使用,则执行 P 操作的进程继续执行。

    可以这么理解,当信号量的值为 2 的时候,表示有 2 个资源可以使用,当信号量的值为 -2 的时候,表示有两个进程正在等待使用这个资源。不看这句话真的无法理解 V 操作,看完顿时如梦初醒。

    2)V 操作:将信号量值加 1,表示释放一个资源,即使用完资源后归还资源。若加完后信号量的值小于等于 0,表示有某些进程正在等待该资源,由于我们已经释放出一个资源了,因此需要唤醒一个等待使用该资源(就绪态)的进程,使之运行下去。

  • 信号

    信号是进程通信机制中唯一的异步通信机制,它可以在任何时候发送信号给某个进程。通过发送指定信号来通知进程某个异步事件的发送,以迫使进程执行信号处理程序。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成和发送信号。

    比如常见的组合键 Ctrl+C 产生 SIGINT 信号,比如 kill -9 1111 ,表示给 PID 为 1111 的进程发送 SIGKILL 信号,让其立即结束。

  • 套接字(Socket)

    • 跨网络与不同主机上的进程进行通信
    • Socket 套接字是网络通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。