Skip to content

Latest commit

 

History

History
1255 lines (1084 loc) · 49.1 KB

File metadata and controls

1255 lines (1084 loc) · 49.1 KB

Nginx

Nginx can be a web server, load balancer, content cache, and API gateway. - 高并发、高性能 - 扩展性好 : 模块化 - 高可靠性 : - 热部署 :不停止服务的情况下升级服务 - BSD许可证

  • Apache
  • Tomcat
# Install the prerequisties:
$ sudo apt install curl gnupg2 ca-certificates lsb-release

# To set up the apt repository for stable nginx packages, run the following command:
  $ echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
      | sudo tee /etc/apt/sources.list.d/nginx.list

# Next, import an official nginx signing key so apt could verify the packages authenticity
  $ curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -

# Verify the you now have the proper key:
  $ sudo apt-key fingerprint ABF5BD827BD9BF62

# To install nginx, run the following commands:
  $ sudo apt update 
  $ sudo apt install nginx 

# Verifying your installation 
  $ nginx -v 

# Show the Nginx version, build information and configuration arguments 
  $ nginx -V 

# Tests the Nginx configuration 
  $ nginx -t 

# Tests the NGINX configuration and prints the validated configuration to the screen
  $ nginx -T 

# Send a signal to the Nginx master process 
  $ nginx -s signal 
    stop: discontinues the Nginx process immediately 
    quit: stops the nginx process after it finishes processing inflight requests 
    reload: reloads the configuration 
    reopen: instructs nginx to reopen log files

# confirm Nginx 
  $ ps -ef | grep nginx  
  root     1065853       1  0 14:39 ?        00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
  nginx    1065854 1065853  0 14:39 ?        00:00:00 nginx: worker process

# Nginx is return request correctly
  $ curl localhost

# Nginx files and directories:
  /etc/nginx/ -- default configuration root for the Nginx server
    /etc/nginx/nginx.conf -- the default configuration entry point used by the NGINX service
  /etc/nginx/conf.d/ -- contains the default HTTP server configuration file
  /var/log/nginx/ -- the default log location for Nginx 
    access.log file: -- entry for each request Nginx server
    error.log file: -- contain error events and debug information if the debug module is enabled

# Graceful Reload 
  > reload your configuration without dropping packets
  $ sudo nginx -s reload  # send a signal to the master process

# Horizontal scaling : 水平扩展

Many modern web architectures employ state-less application tiers, storing state in shared memory or databases. 
proxies and load balancers must be smart enough to detect failure of upstream servers and stop passing traffic to them.
  Nginx health checks 
    passive health checks monitor the connection or responses of the upstream server as clients make the request or connection.

HTTP Load Balancing:
  upstream backend {
    server 10.10.12.45:80 weight=1;
    server app.example.com:80 weight=2;
    }
  
  The HTTP upstream module controls the load balancing for HTTP. 

TCP Load Balancing:
  Nginx stream module to load balance over TCP serves using the upstream block:
  stream {
    upstream mysql_read {
      server read1.example.com:3306 weight=5; 
      server read2.example.com:3306;
      server 10.10.12.34:3306 backup;
      }

    server {
      listen 3306; 
      proxy_pass mysql_read;
      }
    }

UDP Load Balancing 
  > Use Nginx stream module to load balance over UDP servers using the upstream block defined as udp.
  stream {
    upstream ntp {
      server ntp1.example.com:123 weight=2; 
      server ntp2.example.com:123;
      }

      server {
        listen 123 udp; 
        proxy_pass ntp;
        }
    }
  DNS, NTP, VoIP: UDP services 

Load-Balancing Methods 
  > Round-robin: default load-balancing method
  > least connection : balances load by proxying the current request to the upstream server with the least number of open connectionsa [least_conn]
  > least time : but favors the servers with the lowest averafe response times
  > generic hash : Producing a hash for the current request and placing it against the upstream servers. [hash]
  > random : select a random server from the group
  > IP hash : works only for HTTP. uses the client IP address as the hash, this method ensures that clients are proxied to the same upstream server as long as that server is available, which is extremely helpful when the session state is of concern and not handled by shared 

Passive Health Checks:
  > use Nginx health checks with load balancing to ensure that only healthy upstream servers are utilized:
  upstream backend {
    server backend1.example.com:1234 max_fails=3 fail_timeout=3s; 
    server backend2.exmaple.com:1234 max_fails=3 fail_timeout=3s;
    }
  Monitoring for health is important on all types of load balancing. 

Slow Start:
  > Your application needs to ramp up before taling on full production laod.
  > gradually increase the number of connections over a specified time as a server is reintroduced to the upstream load-balancing pool
  upstream {
    zone backend 64k; 

    server server1.example.com slow_start=20s; 
    server server2.exmaple.com slow_start=15s;
    }

  # Slow start allows the application to warm up by populating caches, initiating database connections without being overwhelmed by connections as soon as it starts.
  

TCP Health Checks:
  stream {
    server {
      listen 3306;
      proxy_pass read_backed; 
      health_check interval=10 passes=2 fails=3;
      }
    } 

Traffic Management:
  > Nginx ability to split client requests based on percentages, utilize geographocal location of the client, and control the flow of traffc in the form of rate, connection, and bandwidth limiting.

A/B Test
  split_clients "${remote_addr}AAA" $variant {
    20.0%   "backendv2";
    # The asterisk denotes the rest of the whole after all percentages are taken
          * "backendv1";
  }

GeoIP Module 
  > GeoIP database and enable its embedded variables within NGINX to log and specify to your application the location of your clients.
  >

Restricting Access Based on Country:
  > restrict access from particular countris for contractual or application requirements
  load_module "/usr/lib64/nginx/modules/ngx_http_geoip_module.so"
  http {
    map $geoip_country_code $country_access {
      }
  }

Finding the Original Client:
  > find the original client IP address because there are proxies in front of the Nginx server.
  
Limiting Connections:
  > limit the number of connections based on a predefined key, such as the clinet's IP address. 
  http {
    limit_conn_zone $binary_remote_addr zone=limitbyaddr:10m; 
    limit_conn_status 429; 

    server {
      limit_conn limitbyaddr 40;
      }
  }

  the service is available, and 500-level response indicate server error wheras 400-level response indicate client error.

Limiting Rate:
  > limit the rate of requests by a predefined key, such as the client's IP address.
  http {
    limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=1r/s; 
    limit_req_status 429; 

    server {
      limit_req zone = limitbyaddr burst=10 nodelay;
      }
    }   
    The rate-limiting module is vary powerful for protecting against abusive rapid request while still providing a quality service to everyone

Limiting Bandwidth:
  > limit download bandwidth per client for your assets
  limit_rate and limit_rate_after
  location /download/ {
    # will be served to the client will be limited after 10 megabytes to a rate of 1 megabyte per second.
    limit_rate_after 10m;
    limit_rate 1m;
  }

Massively Scalable Content Caching
  1. Caching Zones:
    > need to cache content and need to define where the cache is stored
    proxy_cache_path /var/nginx/cache 
                      keys_zone=CACHE:60m 
                      # The levels parameter defines how the file structure is created
                      levels=1:2
                      # The inactive parameter allows for control over the length of time a cache item will be hosted after its last use.
                      inactive=3h 
                      max_size=20g;
    proxy_cache CACHE;

    loads the cache keys into the shared memory zone from the files cached on disk

Caching Hash Keys:
  > how your content is cached and looked up.

Cache Bypass:
  > ability to bypass the caching.
  # bypass the cache if the HTTP request header named cache_bypass is set to any value that is not 0.
  proxy_cache_bypass $http_cache_bypass;

Cache Performance:
  > increase performance by caching on the client side.
  location ~* \.(css|js)$ {
    expires 1y;
    add_header Cache-Control "public";
    }

Purging
  > invalidate an object from the cache

Cache Slicing:
  > increase caching effiency by segmenting the file into fragments
  proxy_cache_path /tmp/mycache keys_zone=mycache:10m; 
  server {
    proxy_cache mycache; 
    slice 1m; 
    proxy_cache_key $host$uri$is_args$args$slice_range;
    proxy_set_header Range $slice_range;
    proxy_http_version 1.1;
    proxy_cache_valid 200 206 1h;

    location / {
      proxy_pass http://origin:80;
    }
  }

Authentication:
  JSON Web Tokens (JWTs)

HTTP Basic Authentication:

初始Nginx

Nginx三个主要应用场景:
    1. 静态资源服务:
        通过本地文件系统提供服务
    2. 反向代理服务:
        Nginx的强大性能
        缓存
        负载均衡
        HTTP request --> Nginx --> Application(Tomcat, Flask) <---> MySQL/Redis 
        Applicatoon service QPS,TPS并发比较低,所以需要将多个App 组成集群提高并发性能,App 集群需要Nginx的反向代理功能,可以将动态请求转发给应用服务,集群需要两种需求:动态扩容、冗灾性,这里需要Nginx的负载均衡功能。Nginx提供静态内容的缓存功能,
    3. API服务
        OpenResty 
        Nginx 直接操作数据库,Redis,利用Nginx强大的并发性能

Nginx出现的历史背景:
    1. 互联网的数据量的快速增长
    2. 摩尔定律,性能提升
    3. 低效Apache 
 
Nginx 组成:
    Nginx 二进制可执行文件:由各个模块源码编译出的一个文件
    Nginx.conf配置文件: 控制Nginx的行为
    access.log访问日志: 记录每一条Http请求信息
    error.log错误日志: 定位问题

Nginx版本发布情况mainline:
    2004年10月4号第一个版本0.1.0
    2005年重构http反向代理
    2009年0.7.5windows系统支持
    2011年: 1.0版本发布,支持上游keep alive http长链接 Nginx plus商业公司成立
    2013年:支持websocket, TFO协议
    2015年: 支持thread pool 提供stream四层反向代理支持reuse port特性 支持httpv2协议
    2016年: 支持动态模块
    2018年: 支持TLSv1.3 

开源版Nginx         http://nginx.org 
商业版Nginx Plus    http://nginx.com 
阿里巴巴Tengine: 是由淘宝网发起的Web服务器项目,他在Nginx的基础上,针对大访问量网站的需求,添加很多高级功能和特征,Tengine的性能和稳定性已经在大型网站淘宝网、天猫商城得到很好的检验,他的最终目标是打造一个高效、稳定、安全、易用的Web平台。从2011年12月开始,Tengine成为一个开源项目,Tengine团队在积极开发和维护。
开源版OpenResty     http://openresty.org  (Lua语言)
    开源Web平台主要由章亦春agentzh因为大部分Nginx模块都是由本软件包的维护者开发,所以可以确保所有这些模块及其他组件可以很好的一起工作.打包的各种软件组件版权属于各自版权所有.
商业版OpenResty     http://openresty.com 

# 编译Nginx
1. 下载(http://nginx.org/en/download.html)
    Mainline version 
    Stable version -- http://nginx.org/download/nginx-1.16.1.tar.gz 
    Legacy version 
    $ wget http://nginx.org/download/nginx-1.16.1.tar.gz 
    $ extract nginx-1.16.1.tar.gz 
    $ cd nginx-1.16.1 
    $ tree -L 1 .
        auto    -- 
        conf    -- 
        configure 
        contrib -- 
        html -- 
        man -- 
        src -- 源代码
        objs -- ./configure 中间生成文件
            ngx_modules.c -- 指定编译时那些模块

2. 编译 
    $ ./configure --help 
    $ ./configure --prefix=/usr/local/openresty --with-http_ssl_module --add-module=../tengine-2.3.2/modules/ngx_slab_stat/
    $ make -j4 
    $ sudo make install 
    $ nginx   # 启动nginx 
    # If you get following error, when you try to start nginx... 
    nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
    nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
    # Then it means nginx or some other process is already using port 80. 
    # you can kill it using:
    $ sudo fuser -k 80/tcp 

3. NGINX systemd service file 
# Save this file as /lib/systemd/system/nginx.service 
$ sudo vim /etc/systemd/system/nginx.service 

Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

4. Nginx配置语法
    配置文件由指令与指令快构成
    每条指令以;分号结尾,指令与参数间以空格符号分隔
    指令快以{}大括号将多条指令组织在一起
    include语句允许组合多个配置文件以提升可维护性
    使用#符号添加注释、提高可读性
    使用$符号使用变量
    部分指令的参数支持正则表达式
配置参数: 时间单位
    ms : milliseconds 
    s : seconds 
    m : minutes
    h : hours
    d : days
    w : weeks 
    M : months, 30 days 
    y : years, 365 days 
配置参数: 空间单位
        : bytes
    k/K : kilobytes 
    m/M : megabytes 
    g/G : gigabytes 
Http配置的指令快
    http 
    server  -- 域名
    upstream  -- 上游服务
    location -- URL表达式

Nginx命令行
$ nginx -s reload 
    -? -h 帮助
    -c 指定配置文件
    -g 指定配置指令
    -p 指定运行目录
    -s 发送信号 
        stop  立刻停止服务
        quit 优雅停止服务
        reload 重载配置文件
        reopen 重新开始记录日志文件
    -t -T  测试配置文件是否有语法错误
    -v -V 打印nginx的配置信息、编译信息

# -- Nginx 热部署 
# 查看nginx运行状态
$ ps -ef | grep nginx 
root     13635  0.0  0.2   4600  2192 ?        Ss   22:54   0:00 nginx: master process ./sbin/nginx                              
nobody   13675  0.0  0.2   5324  2728 ?        S    22:56   0:00 nginx: worker process
pi       13697  0.0  0.0   4376   676 pts/0    S+   22:57   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclud$-dir=.git --exclude-dir=.hg --exclude-dir=.svn nginx   
# Nginx 热更新,仅仅是替换nginx二进制文件
$ kill -USR2 13635  # nginx master进程
$ ps -aux | grep nginx
root     13635  0.0  0.2   4600  2192 ?        Ss   22:54   0:00 nginx: master process ./sbin/nginx
nobody   13675  0.0  0.2   5324  2728 ?        S    22:56   0:00 nginx: worker process
root     13784  0.0  0.2   4464  2716 ?        S    23:01   0:00 nginx: master process ./sbin/nginx   -- 新启动的Master
nobody   13785  0.0  0.2   5212  2612 ?        S    23:01   0:00 nginx: worker process
pi       13787  0.0  0.0   4376   676 pts/0    S+   23:01   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn nginx
$ kill -WINCH 13635 # 关闭old nginx  worker进程
$ ps -aux | grep nginx 
root     13635  0.0  0.2   4600  2192 ?        Ss   22:54   0:00 nginx: master process ./sbin/nginx  # nginx old master 进程不会主动退出,保留以防用户做版本回退
root     13784  0.0  0.2   4464  2716 ?        S    23:01   0:00 nginx: master process ./sbin/nginx
nobody   13785  0.0  0.2   5212  2612 ?        S    23:01   0:00 nginx: worker process
pi       13866  0.0  0.0   4376   724 pts/0    S+   23:05   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn nginx

# -- Nginx 切割日志文件
$ mv logs/access.log /logs/access.log.bak 
╭─    ~/chyidl.com/nginx/logs ─────────────────────────────────────────────────────────────────────────────── ✔  pi@RPi3B 
╰─ ll
total 16K
-rw-r--r-- 1 pi   pi   434 Aug 30 22:55 access.log.bak
-rw-r--r-- 1 pi   pi   828 Aug 30 23:01 error.log
-rw-r--r-- 1 root root   6 Aug 30 23:01 nginx.pid
-rw-r--r-- 1 root root   6 Aug 30 22:54 nginx.pid.oldbin
╭─    ~/chyidl.com/nginx/logs ───────────────────────────────────────────────────────────────────────────── 1 ↵  pi@RPi3B 
╰─ sudo ../sbin/nginx -s reopen
[sudo] password for pi: 
╭─    ~/chyidl.com/nginx/logs ─────────────────────────────────────────────────────────────────────────────── ✔  pi@RPi3B 
╰─ ll
total 16K
-rw-r--r-- 1 nobody root    0 Aug 30 23:40 access.log
-rw-r--r-- 1 pi     pi    434 Aug 30 22:55 access.log.bak
-rw-r--r-- 1 nobody pi   1.1K Aug 30 23:40 error.log
-rw-r--r-- 1 root   root    6 Aug 30 23:01 nginx.pid
-rw-r--r-- 1 root   root    6 Aug 30 22:54 nginx.pid.oldbin
日常每周、每天、每月做日志切割
$ crontab -l   # 添加到定时任务中
0 0 1 * * root /home/pi/chyidl.com/nginx/logs/rotate.sh 
$ vim rotate.sh 
#!/binbash                                                                                                                 
#Rotate the Nginx logs to prevent a single logfile from consuming too much disk space.
LOGS_PATH=/home/pi/chyidl.com/nginx/logs/history
CUR_LOGS_PATH=/home/pi/chyidl.com/nginx/logs
YESTERDAY=$(date -d "yesterday" + %Y-%m%d)
mv ${CUR_LOGS_PATH}/access.log ${LOGS_PATH}/access_$(YESTERDAY).log
mv ${CUR_LOGS_PATH}/error.log ${LOGS_PATH}/error_$(YESTERDAY).log
# 向Nginx主进程发送USR1信号, USR1信号是重新打开日志文件
kill -USR1 ${cat /home/pi/chyidl.com/nginx/logs/nginx.pid}

# Nginx 搭建静态资源Web服务器
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    gzip on;
    gzip_min_length 10;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml text/javascript applicatio/x-httpd-php image/jpeg image/gif image/png; 

    alias chyidlTutorial/;
    autoindex on; # Enables or disables the directory listing output.
    set $limit_rate 10k; -- limits the rate of response transmission to a client. 

# Nginx 搭建具备缓存功能的反向代理服务
    反向代理 + 多个上游服务

    upstream local {
        server 127.0.0.1:8080; 
        ...
    }
    
    proxy_cache_path /tmp/nginxcache levels=1:2 keys_zone=my_cache:10m max_size=1g 
        inactive=60m use_temp_path=off;

    location / {
        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_cache my_cache;
        proxy_cache_key $host$uri$is_args$args;
        proxy_cache_valid 200 304 302 1d;

        proxy_pass http://local;
    }

# GoAccess 实施分析Access log文件
https://goaccess.io 
GoAccess is an open source real time Web log analyzer and interactive viewer that runs in a terminal in linux systems or through your browser.
$ sudo apt-get install goaccess 
Websocket: 协议
    
    location /report.html {
        alias /home/chyi/chyidl.com/ReverseProxy/nginx/html/report.html;
    }

$ sudo goaccess logs/access.log -o  html/report.html --real-time-html  --time-format='%H:%M:%S' --date-format='%d/%b/%Y' --log-format=COMBINED 
WebSocket server ready to accept new client connections


# TLS/SSL 安全协议 
SSL: Secure Sockets Layer
TLS: Transport Layer Security 
1995 SSL3.0 -> 1999 TLS1.0 -> 2006 TLS1.1 -> 2008 TLS1.2 -> 2018 TLS1.3 
ISO/OSI七层模型: 物理层-> 数据链路层 -> 网络层 -> 传输层 -> 会话层 -> 表示层 -> 应用层 
四层模型: 链路层 -> 网络层 -> 传输层 -> 应用层 
HTTP协议所属于应用层
SSL/TLS 所属于表示层
    握手
    交换密钥
    告警
    对称加密应用数据
SSL/TLS安全密码套件: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 
    ECDHE: 密钥交换 -- 密钥交换算法
    RSA:身份验证 -- 身份验证算法
    AES_128_GCM: 密码, AES算法、128强度、GCM模式 -- 对称加密算法、强度、分组模式
    SHA256: MAC 或 PRF -- 签名hash算法

# 对称加密算法和非对称加密算法
对称加密:
    RC4序列算法: 密钥序列1010、明文0110、密钥 异或 明文 = 密文1100
    异或运算有对称特性
非对称加密算法:
    公钥加密后的明文转变为密文,密文只能使用私钥才能解密
    私钥加密后的明文转变为密文,密文只能使用公钥才能解密

# PKI公钥基础设施
    CA机构负责颁发证书
    证书类型:
        域名验证 domain validated DV证书 
        组织验证 organization validated OV证书 
        扩展验证 extended validation EV证书 
    证书链:
        根证书-二级证书-子证书

# TLS/SSL 通讯过程
    验证身份   
    打成安全套件共识
    传递密钥
    加密通讯
    1. Client Hello         --->   
                    - Support Ciphers 
                    - Random number 
                    - Seconds ID(if any) 
                            <---      2. Server Hello 
                    - choose ciphers 
                    - random number 
                    - Session ID 
                    - (Re-use, or new) 
                            <---      3. Server Certification 
    Check Certificate validity
                            <---      4. Server Hello Done 
    5. Create Key           --->      
Exchange Message    - Encrypted       6. Key generation 
                    premanter secret
    6. Key generation
    CipherSpec Exchange     --->    
    7. Finished
                            <---      7. CipherSpec Exchange 
                                        Finished.

# Encrypt with Nginx Server
Certificate Authority(CA) that provides an easy way to obtain and install free TLS/SSL certificates, thereby enabliing encrypted 
    Installing Certbot 
    $ sudo add-apt-repository ppa:certbot/certbot   # First, add the repository 
    $ sudo apt-get update  # Then, update the package list to pick up the new repository package information 
    $ sudo apt-get install python-certbot-nginx  # Finally, install Cerbot's Nginx package with apt-get.
    Config HTTPS 
    $ certbot --nginx --nginx-server-root=/home/chyi/chyidl.com/ReverseProxy/nginx/conf/ -d chyidl.com

# OpenResty & Lua Language
OpenResty is a dynamic web platform based on NGINX and LuaJIT.
    # Download Source Code 
    $ wget https://openresty.org/download/openresty-1.15.8.1.tar.gz 
    $ tar -xvf openresty-1.15.8.1.tar.gz 
    $ cd openresty-1.15.8.1 
    $ tree -L 1
    .
    ├── bundle   -- Nginx 源代码存储位置
    ├── configure
    ├── COPYRIGHT
    ├── patches
    ├── README.markdown
    ├── README-windows.txt
    └── util
    3 directories, 4 files
    $ ./configure --prefix=/home/chyi/chyidl.com/openresty 
    $ make -j2
    $ make install 
    
    location /lua {
        default_type text/html;
        content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])';
    }
    

PKI 公钥基础设施

Nginx架构基础

Master - Worker 架构模型,Worker数量与CPU核心数相匹配、多个Worker之间共享数据
#Nginx请求处理流程 
    Nginx 内部有三大状态机:
        传输层状态机    -- 传输层
        HTTP状态机      -- 应用层
        Mail状态机      -- 
    Nginx核心属于:非阻塞的事件驱动处理引擎(epoll),通常使用异步需要使用状态机识别和处理.使用线程池处理磁盘阻塞调用。大多数Nginx作为负载均衡和反向代理使用
    Nginx可以通过协议将请求传输给HTTP,Mail,Stream(TCP)代理,或者利用应用层相关协议FastCGI, uWSGI, SCGI,代理应用服务器
    Web/Email/TCP流量 --> 

# Nginx进程结构
    1. 单进程结构 -- 适合开发调试使用
    2. 多进程结构 --  Nginx要提高高可用性,由于线程使用共享内存,所以个别线程错误会引发连锁反应导致Nginx不可用.
        Master Process -- 父进程 : 主要用作Worker进程的监控管理
        Worker Process -- 子进程 : 处理请求,需要和CPU核心数一致并且绑定,可以提高使用CPU缓存的命中率
        Cache Manager  -- 子进程 : 缓存的管理
        Cache loader   -- 子进程 :缓存的加载
        Worker, Cache manager, Cache loader之间的进程间通信通过使用共享内存。

$ ps -ef | grep nginx  # 查看当前进程ID,父进程ID
pi       10280     1  0 Sep02 ?        00:00:00 nginx: master process ./sbin/nginx
pi       11958 10280  0 11:22 ?        00:00:00 nginx: worker process
pi       11959 10280  0 11:22 ?        00:00:00 nginx: worker process
$ sudo ./sbin/nginx -s reload  # 退出旧Worker进程,重新创建Worker进程
$ ps -ef | grep nginx
pi       10280     1  0 Sep02 ?        00:00:00 nginx: master process ./sbin/nginx
pi       11985 10280  0 11:26 ?        00:00:00 nginx: worker process
pi       11986 10280  0 11:26 ?        00:00:00 nginx: worker process
$ kill -SIGHUP 10280 
$ ps -ef | grep nginx
pi       10280     1  0 Sep02 ?        00:00:00 nginx: master process ./sbin/nginx
pi       11999 10280  0 11:29 ?        00:00:00 nginx: worker process
pi       12000 10280  0 11:29 ?        00:00:00 nginx: worker process
$ kill -SIGTERM 11999  # 退出Worker进程
$ ps -ef | grep nginx
pi       10280     1  0 Sep02 ?        00:00:00 nginx: master process ./sbin/nginx
pi       12000 10280  0 11:29 ?        00:00:00 nginx: worker process
pi       12011 10280  0 11:31 ?        00:00:00 nginx: worker process

Nginx许多命令本质上是向Nginx Master进程发送信号

# Nginx 进程管理: 信号
    Nginx多进程间通信使用共享内存、信号量,进程间管理通常使用信号
    Master进程:
        监控Worker进程
            CHLD: --当子进程终止会向父进程发送CHLD信号 
        管理Worker进程-接收信号
            TERM, INT -- 立刻停止Nginx进程 
            QUIT -- 优雅停止Nginx进程
            HUP -- 重新加载Nginx配置文件
            USR1 -- 重新打开日志文件,对日志文件进行切割
            USR2 -- kill -USR2 Nginx Master pid 
            WINCH -- kill -WINCH Nginx Master pid 
    Worker 进程-接收信号
            TERM, INT 
            QUIT 
            USR1
            WINCH 
    Nginx命令 
        reload: HUP  
        reopen: USR1
        stop: TERM 
        quit: QUIT 

# Nginx reload nginx.conf 原理
$ sudo ./sbin/nginx -s reload 
    1. 向Nginx Master进程发送HUP信号 (reload命令)
    2. Nginx Master 进程检验conf/nginx.conf配置语法是否正确
    3. Nginx master进程打开新的监听端口[子进程会继承所有父进程打开的端口和文件]
    4. Nginx Master 进程使用新配置文件启动新的Worker子进程
    5. Nginx Master 进程会向老的Worker子进程发送QUIT信号(优雅关闭)
    6. 老的Worker进程关闭监听句柄,处理完当前连接后结束进程

# Nginx 热升级原理
    1. 将旧的Nginx可执行文件替换成新的Nginx可执行文件(注意备份旧的Binary文件)
    2. 向旧的Nginx Master 进程发送USR2信号
    3. 旧的Nginx Master进程修改pid文件名,加上后缀.oldbin 
    4. 旧的Nginx Master进程使用新的Nginx binary文件启动新的Nginx Master进程 [目前新的Nginx Master 进程是就Nginx Master进程的子进程]
    5. 向旧的Nginx Master进程发送WINCH信号,关闭旧的Nginx Worker 进程 
    6. 回滚,向旧的Nginx Master 发送HUP,向新的Nginx Master发送QUIT.

# 关闭worker进程 
    QUIT Nginx Worker进程 HTTP 请求
        1. 设置定时器 Worker_Shutdown_Timeout 
        2. 关闭监听句柄 
        3. 关闭空闲的连接
        4. 再循环中等待全部连接关闭
        5. 退出进程

# Nginx事件
    Nginx属于事件(网络事件)驱动框架,每一个网络连接对应两个事件(读事件、写事件)

    应用层->传输层->网络层->链路层->[以太网]
                                        |--> 链路层->网络层
                                        |<-- 链路层 <--|
                                    [广域网]    
                                        |--> 链路层->网络层
                                        |<-- 链路层 <--|
    应用层<-传输层<-网络层<-链路层<-[以太网]

TCP Stream 报文: 
    TCP/IP 协议层级
        应用层:                                       DATA [HTTP, SMTP, POP3, IMAP, SSH, DNS]
        传输层:               Source Port/Dest Port + DATA [TCP, UDP]
        网络层:         Source IP/Dest IP + Source Port/Dest Port + DATA [IP, ICMP, DHCP, ARP]
    数据链路层:         Source Mac addr/Dest Mac addr + Source IP/Dest IP + Source Port/Dest Port + DATA + Footer(Ethernet) 

    HTTP协议拆分成小的报文,网络层报文MTU = 1500 byte,报文大小称为MSS

TCP协议与非阻塞接口:
    读事件:
        Accept 建立连接
        Read读消息
    写事件:
        Write写消息
        TCP协议         :非阻塞接口
    请求建立TCP连接事件 : 读事件中Accep建立连接事件
    TCP连接可读事件     : 读事件中Read读消息
    TCP连接关闭事件     : 读事件中Read 
    TCP连接可写事件     : 写事件中Write
    异步读写磁盘事件    : 
    定时器事件          : 

    事件收集分发器: 事件属于生产者

# Wireshark 
    Capture using this filter: host 176.122.152.20 and port 443
    TCP三次握手 192.168.1.188   176.122.152.20.16clouds.com TCP 78  54927 → https(443) [SYN] Seq=0 Win=65535 Len=0 MSS=1460 WS=64 TSval=998541513 TSecr=0 SACK_PERM=1
        Transmission Control Protocol, Src Port: 54927 (54927), Dst Port: https (443), Seq: 0, Len: 0  [进程端口与进程端口通信]
        Internet Protocol Version 4, Src: 192.168.1.188 (192.168.1.188), Dst: 176.122.152.20.16clouds.com (176.122.152.20)
    TCP 三次握手:
        Src -> Dst  [SYN] 0x002
        Src <- Dst  [PSH, ACK] 0x018
        Src -> Dst  [ACK] 0x010
        Src <- Dst  [SYN, ACK] 0x012 

# Nginx 事件驱动模型
    Nginx事件循环 Nginx Event Loop 
        1. Wait For Event On Connections(epoll Wait) --> 2, 3 
        2. Linux Kernel 将事件存放在事件队列中 -- > 4 
        3. Get New Events 
        4. 事件存放队列 
        5. Process The Events 
    Nginx Events Queue Processing Cycle:
        
# epoll 原理
    Nginx如何快速从Linux Kernel中获取等待处理的事件
    epoll, Kqueue, Poll, Select : 网络事件收集分发器, epoll和Kqueue性能要远远好于poll, Select 
    epoll要求高并发连接中,每次处理活跃连接数量占比要很小
    epoll实现原理:
        红黑树: 
        链表: 
        
        eventpoll: 
            +lock
            +mtx
            +wq
            +poll_wait 
            +rdllist: 红黑树中每个结点都是基于epitem结构中的rdllink成员 
            +rbr: 红黑树中每个结点都是基于epitem结构中的rbn成员
            +ovflist 
            +user 
        
        epitem:
            +rbn 
            +rdllink 
            +next 
            +ffd 
            +nwait 
            +pwqlist 
            +ep 
            +fllink 
    epoll使用:
        创建 
        操作: 添加/修改/删除
        获取句柄
        关闭

# Nginx 请求切换
    Traditional Server: Apache, Tomcat : 线程仅处理一个连接,并且依赖OS进程调度实现并发
    Nginx Server: 线程同时处理多连接,用户态代码完成连接切换,尽量减少操作系统进程切换.
    操作系统分配的事件片的长度一般是5ms - 800ms,Nginx Worker将进程优先级配置-19,这样操作系统往往会分配比较大的时间片.
    
# 同步&异步 阻塞&非阻塞
    阻塞&非阻塞主要是操作系统底层C库提供的方法或者系统调用,方法可能会导致进程进入Sleep状态(当前条件不满足的情况下,操作系统主动切换进程)。非阻塞方法是操作系统不会在进程的事件片没有使用完之前提前切换进程.
    阻塞调用: 进程间主动切换
    非阻塞调用: 代码控制是否切换新任务
        非阻塞调用下的同步:
            Openresty同步调用代码
                local client = redis:new()
                client:set_timeout(30000)
                local ok, err = client:connect(ip, port) // 同步调用,内部实现是非阻塞方法
                if not ok then 
                    ngx.say('failed:', err)
                    return 
                end 

        标准的异步调用
            rc = ngx_http_read_request_body(r, ngx_http_upstream_init);
            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                return rc;
            }

# Nginx 模块
    使用Nginx第三方模块需要
        首先编译进Nginx binary 
        熟悉第三方模块提供哪些配置项
        熟悉第三方模块何时被开启
        熟悉第三方模块的变量
    $ ./configure 
    $ cd objs/
    $ vim ngx_modules.c 
        find ngx_module_t *ngx_modules[] 
    $ cd src/http/modules/
    $ vim ngx_http_gzip_filter_module.c 
        find ngx_command_t -- 表示支持的指令名

    Nginx模块:高内聚,抽象 

    Nginx 模块分类
        NGX_CORE_MODULE:
            events:
            core  
            errlog 
            thread_pool
            openssl 
            http
            mail
            stream
        NGX_CONF_MODULE: 负责解析nginx.conf文件
            ngx_conf_module 
        NGX_EVENT_MODULE:
            epoll
            event_core : 所有子模块共有通用模块 
        NGX_HTTP_MODULE:
            ngx_http_core_module 
            请求处理模块
            响应过滤模块
            upstream相关模块
        NGX_MAIL_MODULE:
            ngx_mail_core_module 
        NGX_STREAM_MODULE:
            ngx_stream_core_module 
         
# Nginx 连接池
    ngx_cycle_t 数据结构
        connections : 连接池数组 worker_connections default 512;
        read_events : default 与connections 数量大小一致
        write_events :  
        connections 指向的连接池中每个连接所需要的读写事件都以相同的数组序号对应着read_events, write_events读写事件数组,所以相同序号下三个数组的元素是配合使用的.

    ngx_connection_s : 每个连接使用结构体
        void            *data;
        ngx_event_t     *read;      读事件
        ngx_event_t     *write;     写事件
        ngx_socket_t    fd;
        ngx_recv_pt     recv;
        ngx_send_pt     send;   抽象解耦OS底层方法
        off_t           sent;   bytes_send变量
        ngx_log_t       *log;
        ngx_pool_t      *pool;  初始connection_pool_size配置
        int             type;
        struct socketaddr *sockaddr;
        socklen_t       socklen;
        ngx_str_t       addr_text;
        ngx_str_l       proxy_protocol_addr;
        in_port_t       proxy_protocol_port;
        ngx_buf_t       *buffer;
        ngx_queue_t     queue;
    ngx_event_s : 

    内存池:减少内存碎片的产生、
        连接内存池:connection_pool_size 256|512; bytes
        请求内存池:request_pool_size 4k; 

# Nginx Worker 进程间通讯
    Nginx进程间的通讯方式
        信号、共享内存(锁、Slab内存管理器)
    共享内存:跨worker进程通讯
        ngx_http_lua_api:  
        rbtree: 红黑树
            Ngx_stream_limit_conn_module  流控
            Ngx_http_limit_conn_module
            Ngx_stream_limit_req_module 
            Ngx_http_file_cache 
            Ngx_http_proxy_module 
            Ngx_http_scgi_module 
            Ngx_http_uwsgi_module 
            Ngx_http_fastcgi_module 
            Ngx_http_ssl_module 
            Ngx_mail_ssl_module 
            Ngx_stream_ssl_module 
        单链表: 
            Ngx_http_upstream_zone_module 
            Ngx_stream_upstream_zone_module 
    Slab内存分配管理:
        Bestfit: 最多两倍内存消耗
            合适小对象、避免碎片、避免重复初始化
        ngx_slab_stat: 统计Slab使用状态 
(Tengine) http://tengine.taobao.org/document/ngx_slab_stat.html
    $ wget http://tengine.taobao.org/download/tengine-2.3.2.tar.gz
    $ extract tengine-2.3.2.tar.gz 
    $ cd tengine-2.3.2/modules/ngx_slab_stat 
    $ cd openresty-1.15.8.1
    $ ./configure --prefix=/home/chyi/chyidl.com/openresty --add-module=../tengine-2.3.2/modules/ngx_slab_stat/

    location = /slab_stat {
        slab_stat;
    }

    $curl https://chyidl.com/set                
    STORED
    $ curl https://chyidl.com/get 
    8 
    $ curl https://chyidl.com/slab_stat        
    * shared memory: dogs
    total:       10240(KB) free:       10168(KB) size:           4(KB)
    pages:       10168(KB) start:00007FE18625E000 end:00007FE186C4E000
    slot:           8(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:          16(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:          32(Bytes) total:         127 used:           1 reqs:           1 fails:           0
    slot:          64(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:         128(Bytes) total:          32 used:           2 reqs:           2 fails:           0
    slot:         256(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:         512(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:        1024(Bytes) total:           0 used:           0 reqs:           0 fails:           0
    slot:        2048(Bytes) total:           0 used:           0 reqs:           0 fails:           0

# Nginx容器
    数组:
    链表:
    队列:
    哈希表:
        ngx_hash_t 
        ngx_hash_elt_t: 结构体
        Nginx hash表主要应用于静态不变的内容
            Max size
            Bucket size 需要考虑CPU Cache Size对齐问题 
            (http/stream) - variables: 
                variables_hash_bucket_size 
                variables_hash_max_size 
            (http/stream) - map:
                map_hash_bucket_size 
                map_hash_max_size 
            http proxy:
                proxy_headers_hash_bucket_size 
                proxy_headers_hash_max_size 
            ngx_http_uwsgi_module:
            ngx_http_scgi_module:
            ngx_http_fastcgi_module 
            http module:
                ngx_http_referer_module:
                    referer_hash_bucket_size 
                    referer_hash_max_size 
                ngx_http_ssi_module:
                    ngx_cacheline_size 
                    1024 
                ngx_http_scrache_filter_module:
                    ngx_cacheline_size 
                server name:
                    server_names_hash_bucket_size 
                    server_names_hash_max_size 
                MIME types:
                    types_hash_bucket_size 
        hash表遍历复杂度为O(n)
    红黑树:
        ngx_rbtree_t: 描述红黑树的结构体
            root
            sentinel 
            insert 
            ngx_rbtree_init() 
            ngx_rbtree_insert()
            ngx_rbtree_delete() 
        红黑树:根结点,左子节点、右子节点、NIL哨兵节点;二叉查找树
        红黑树做定时器,查找最小和最大值 
        自平衡二叉查找树:
            高度不会超过2倍的logn(n)
            增删改查算法复杂度O(log(n))
            遍历复杂度O(n)
        Nginx中使用红黑树的模块:
            ngx_conf_module: 
            ngx_event_timer_rbtree 
            Ngx_http_file_cache  
            Ngx_http_geo_module 
            Ngx_http_limit_conn_module 
            Ngx_http_limit_req_module 
            Ngx_http_lua_shdict:ngx.shared.DICT  LRU链表性质
            resolver 
            Ngx_stream_geo_module 
            Ngx_stream_limit_conn_module 
    基数数:

# Nginx 动态模块
    Nginx使用静态模块的过程:
        Nginx Source + Module Souce --> Nginx Build System --> Nginx Executable 
    动态模块-减少编译环节
        Nginx Source + Module Source --> Nginx Build System --> Nginx Executable + Module Shared Object 

    静态库:会将源代码直接编译到可执行二进制文件中
    动态库:会在二进制文件中保留动态库的位置,执行时直接调用动态库

    1. Configure 加入动态模块
    2. 编译进binary 
    3. 启动时初始化模块数组
    4. 读取load_module配置 指明动态模块的路径
    5. 打开动态库并加入模块数组
    6. 基于模块数组开始初始化
    
    --with-http_xslt_module=dynamic
    $ ./configure --prefix=/home/chyi/chyidl.com/nginx --with-http_image_filter_module=dynamic
    $ cd modules && ls 
    ngx_http_image_filter_module.so 

Nginx 网络事件抓包

详解HTTP模块


反向代理与负载均衡

Nginx 和 OpenResty

Setup Password Authentication with Nginx

Web applications often provide their own authentication and authorization methods, but the web server itself can be used to restrict access if there are inadequate or unavailable.

# Create the Password File 
To start out, we need to create the file that will hold our username and password combinations. 
    Create the Password File Using the OpenSSL Utilities 
        # create a hidden file called .htpasswd in the /etc/nginx configuration directory to store our username and password combinations 
        $ sudo sh -c "echo -n 'chyi:' >> /etc/nginx/.htpasswd" 
        # add an encrypted password entry for the username by typing 
        $ sudo sh -c "openssl passwd -apr1 >> /etc/nginx/.htpasswd"
        # check the username and encrypted passwords are stored within the file 
        $ cat /etc/nginx/.htpasswd 

# Configure Nginx Password Authentication 
    Now that we have a file with our users and passwords in a format that Nginx can read. we need to configure Nginx to check this file before serving our protected content. 
    $ sudo vim /usr/local/nginx/conf/nginx.conf 
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


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  0;
    keepalive_timeout  65;

    #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;
            auth_basic "Restricted Content";
            auth_basic_user_file /usr/local/nginx/.htpasswd;
        }

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

}
$ sudo systemctl restart nginx 

nginx.conf 配置文件

https://juejin.im/post/5c1616186fb9a049a42ef21d
Nginx配置文件分为四部分:
    1. main(全局设置): 影响其他所有部分的设置
    2. server(主机设置): 指定虚拟主机域名
    3. upstream(上游服务设置: 主要为了反向代理、负载均衡相关配置): 
    4. location(URL配置特定位置后的设置): 

Nginx 查看配置文件

Nginx 的配置存放在nginx.conf 文件中,可以使用locate查看nginx.conf 文件

➜ sudo find / -name "nginx.conf"
/etc/nginx/nginx.conf

查看nginx 实际调用的配置文件
1.查看nginx 路径 
$ ps aux | grep nginx 
root        3254  0.0  0.0   7992   804 ?        Ss   12:12   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data    3255  0.0  0.0   9340  3592 ?        S    12:12   0:00 nginx: worker process
www-data    3256  0.0  0.0   9340  3592 ?        S    12:12   0:00 nginx: worker process
www-data    3257  0.0  0.0   9340  3604 ?        S    12:12   0:00 nginx: worker process
www-data    3258  0.0  0.0   9340  3592 ?        S    12:12   0:00 nginx: worker process
ubuntu      4700  0.0  0.0   5956   680 pts/0    S+   13:09   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox nginx

2. 查看nginx配置文件路径
使用nginx 的-t 参数进行配置检查 查看实际调用的配置文件路径是否调用有效
➜ sudo /usr/sbin/nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Optimize Nginx Configuration

  1. Worker Processes and Worker Connections Worker Processes: grep processor /proc/cpuinfo | wc -l Worker_connections:
    the default value is 768; however considerr that every browser usually opens up at least 2 connections/server, this number can half. This is why we need to adjust our worker connections to its full potential. $ ulimit -n worker_connections 1024;

  2. Buffers

If the buffer size are too low, then Nginx will have to write to a temprary file causing the disk to read and write constantly. client_body_buffer_size: This handles the client buffer size. client_header_buffer_size: For all intents and purposes, 1K is usually a decent size for this directive. client_max_body_size: The maximum allowed size for a client request. If the maximum size is exceeded, then Nginx will split out a 413 error or Request Entity Too Large. large_client_header_buffers: The maximum number and size of buffers for large client headers.

  1. Timeouts

client_body_timeout, client_header_timeout are responsible for the time a server will wait for a client body or client header to be sent after request. client_body_timeout 12; client_header_timeout 12; keepalive_timeout 15; send_timeout 10;

  1. Gzip Compression

Gzip can help reduce the amount of network transfer Nginx deals with. However, be careful increasing the gzip_comp_level too high as the server will begin wasting cpu cycles. gzip on; gzip_comp_level 2; gzip_min_length 1000; gzip_proxied expired no-cache no-store private auth; gzip_types text/plain application/x-javascript text/xml text/css application/xml;

  1. Static File Caching

It's possible to set expire headers for files that don't change and are served regularly. This directive can be added to the actual Nginx server block. location ~* .(jpg|jepg|png|gif|ico|css|js)$ { expires 365d; }

  1. Logging

Nginx logs every request that hits the VPS to a log file. access_log off;