Nginx使用总结和底层剖析

200 阅读5分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

Nginx

基础

nginx 是高性能的Http和反向代理web服务器, 核心特点是占有内存少, 并发能力强。

  • Http服务器(Web服务器)

    性能非常高, 非常注重效率, 能够经受高负载的考验, 支持50000个并发数。CPU和内存的占用也非常低, 10000个没有活动的连接才占用2.5M的内存。

  • 反向代理服务器

  • 负载均衡服务器

  • 动静分离

特点:

  • 跨平台: 类unix操作系统和windows
  • 配置简单
  • 高并发 性能好 稳定性好

部署

yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
tar -xvf nginx-1.17.8.tar
cd nginx-1.17.8
./configure --prefix=/usr/local/nginx
make
make install
## 此时在/usr/local/下产生nginx
cd /usr/local/nginx/sbin
./nginx

命令

./nginx
./nginx -s stop ## 强制停止
./nginx -s quit ## 优雅退出
./nginx -s reload
./nginx -t
./nginx -s reopen #重启

配置文件

# 全局块
# 用户配置  worker 进程数量  通常设置为CPU数量
#user  nobody;
worker_processes  1;

## 全局错误日志和pid文件位置
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

# events事件块(nginx服务器和用户的网络连接)
events {
    # 单个worker进程最大并发连接数
    worker_connections  1024;
}


# http 块 虚拟主机的配置 监听端口的配置 请求转发 反向代理 负载均衡`2`
http {

    # 引入mime类型定义文件
    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;

    # 一般就开启, 如果IO密集 可以改成off
    sendfile        on;
    #tcp_nopush     on;

    # 连接的超时时间
    #keepalive_timeout  0;
    keepalive_timeout  65;

    # 是否开启GZip压缩
    #gzip  on;

    server {
        # 监听端口
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        # 默认请求
        location / {
            root   html; # 默认的网站根目录
            index  index.html index.htm; # 索引页
        }

        #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;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #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;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

nginx 语法

location [=|~|~*|^~] /uri/ {}
  • 正则匹配 location ~ /abc{}

  • 不区分大小写的正则匹配 location ~*/abc{}

  • 匹配路径的前缀location ^~ /abc{}

  • 精确匹配 location =/abc{}

  • 普通路径前缀匹配 location /abc{}

    优先级: 精确匹配 > 匹配路径前缀 > 不区分大小写正则 > 正则匹配 > 普通路径匹配

反向代理

location / {
    #转发请求
    proxy_pass http://127.0.0.1:8081
    proxy_method: POST
    proxy_set_header HOST $host
    proxy_set_header X-Real-IP $remote_addr
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
}

负载均衡

upstream loadBalanceServer{
    server 127.0.0.1:8080;
    server 127.0.0.1:8002;
}
location / {
	proxy_pass http://loadBalanceServer
} 
策略
  • 默认轮询

  • weight 权重, 默认为1, max_fails默认为1 max_conns默认为0

    fail_timeout 默认10s

    upstream loadBalanceServer{
    	server 127.0.0.1:8080 weight=1 max_fails=3 fail_timeout=15 max_conns=0;
    	server 127.0.0.1:8002 weight=2 backup;
    	server 127.0.0.1:8004 weight=2 down;
    }
    
  • ip_hash

    upstream loadBalanceServer{
        ip_hash;
        server 127.0.0.1:8080;
        server 127.0.0.1:8002;
    }
    
  • least_conn

    选取活跃连接数与权重weight的比值最小者为下一个处理请求的server。当然,上一次已选的server和已达到最大连接数的server照例不在选择的范围。

    upstream loadBalanceServer{    
        least_conn;    
        server 127.0.0.1:8080;    
        server 127.0.0.1:8002;
    }
    

    除此以外还有第三方负载均衡fair等

动静分离

location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
    root   staticData;
}

缓存

proxy_cache_path 缓存文件路径,文件名是cache_key的MD5值

levels 缓存目录下的层级目录结构, 根据哈希后的请求地址创建的。名称从哈希后的字符串结尾处开始截取, 如果地址为12345, levels=1:2, 第一层为5,第二层为34

keys_zone 指定缓存区名称及共享内存大小,存放key和metadata。

inactive 主动清空在指定时间内未被访问的缓存。 10m代表10分钟

max_size 最大cache磁盘空间,不指定会使用掉所有的disk space,达到配额后会使用最少使用的cache文件

proxy_cache_path /data/cache levels=1:2 keys_zone=cache:50m inactive=10m max_size=1g
location / {
	proxy_pass http://loadBalanceServer;
	proxy_cache cache;
	proxy_cache_key $host$uri$is_args$args;
	proxy_cache_valid 200 304 1m;
	add_header X-Proxy-Cache $upstream_cache_status
}

使用ngx_cache_purge 模块 进行缓存清理

location ~ /purge(/.*){
  allow all;
  proxy_cache_purge cache $host$uri$is_args$args;
}

压缩

GZip压缩

配置块作用
gzip on|off;是否开启gzip压缩
gzip_comp_level level;压缩等级。从1到9,默认1
gzip_disable "MSIE[1-6]\.";针对不同客户端发起的请求进行有选择的打开或者关闭gzip命令 后面是浏览器名称 比如禁用IE6的gzip功能
gzip_min_length 1k;最小文件
gizp_http_version 1.0| 1.1;启动压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_buffers number size;使用几个缓存空间, 每个缓存空间的大小。 32 4K | 16 8K
gzip_proxied off|any;off关闭 any压缩所有服务器返回的数据
gzip_types mine-type...;除text/html外, 对指定MIME类型启用响应的压缩
gzip_vary on|off如果启用压缩 是否在响应报文首部插入"Vary:Accept-Encoding", 建议开启参数
gizp on;
gzip_http_version 1.1;
gzip_comp_level 3;
gzip_types text/plain application/json application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png

跨域

location / {
	proxy_pass http://loadBalanceServer;
	add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Headers' 'Content-Type,*';
    add_header 'Access-Control-Allow-Methods' 'GET,POST';
}

底层剖析

Nginx 启动后, 以daemon多进程方式在后台运行,包含一个Master进程和多个worker进程

  • Master进程

    主要管理worker进程

    • 接收外界信号向各worker进程发送信息
    • 监控worker进程的运行状态, 当worker进程异常退出时会自动重新启动新的worker进程等
  • Worker进程

    具体处理网络请求等,多个worker进程之间是对等的, 同等竞争来自客户端的请求, 各进程之间是相互独立的。一个请求只可能在一个worker进程中处理。worker进程的个数一般与机器CPU核数一致

热加载

./nginx -s reload

  • master进程对配置文件进行语法检查
  • 尝试配置
  • 尝试成功使用新的配置, 新建worker进程
  • 新建成功, 给旧的worker进程发送关闭信息
  • 旧的worker进程收到信号后会继续服务,知道把当前进程接收到的请求处理完毕后关闭

请求处理机制

  • master进程创建后, 会建立好需要监听的socket, 然后从master进程中fork出多个worker进程, 所有worker进程的监听符listenfd在新连接到来时都变得可读
  • nginx使用互斥锁保证只有一个worker进程能够处理请求,拿到互斥锁的那个进程注册listenfd读事件, 在读事件里调用accept接受该连接,解析,处理,返回客户端。

多进程好处

  • 每个worker进程独立,不需要加锁,节省开销
  • 每个worker进程独立,互不影响, 一个异常结束,其他的也能提供服务