NGINX 正向与反向代理

NGINX 正向与反向代理

最后发布时间
Oct 19, 2021 07:35 PM
Tags
nginx
cloud
 
NGINX [engine x], 是一个 HTTP 和反向代理服务器, 通用 TCP/UDP 代理服务器。

C10K 问题

服务器基于进程,线程模型,新接收到一个TCP连接, 就需要分配一个进程或是线程。如果客户端请求超过10K就要创建10K个进程或是线程,造成进程资源效率低下,单机情况下操作系统无法承受,此类普遍的网络现象和技术局限被称为C10K问题。
notion image
 
其本质上创建进程,线程过多, 数据在用户态和内核态拷贝频繁; 进程和线程上下文切换消耗,导致IO 阻塞。
有限的资源内,高效的利用CPU 资源,减少上下文切换?
基于事件循环驱动,只创建少量的进程或是线程来处理若干连接,在操作系统层面, 应运而生 select ,kqueue,poll, epoll 网络模型,
在Node.js ( libuv),Python (selector),Redis 等单线程程序网络处理比较突出。
 
notion image
 

NGINX 多进程模型

nginx分为单进程模式和多进程模式。单进程模式常常在开发环境调试时候使用。在对外服务时nginx多以多进程方式工作。
多进程工作方式中为方便进程的统一管理,系统中分为一个master进程和多个work进程,master进程主要负责信号处理以及work进程的管理,包括接收外界信号、向worker进程发送信号,监控worker进程的运行状态等,不直接对外提供web服务;
 
worker进程则主要对外提供web服务,各个work进程之间相互隔离且相互平等,从而避免进程之间的资源竞争导致的性能损耗,worker进程数目可以设置,一般为了降低进程之间上下文切换带来的损耗, 机器cpu核数和worker 设置相同。
 
NGINX 主子进程
notion image
notion image
 

NGINX 源码编译

环境

Ubuntu20.04.3 LTS
 
GCC 安装
apt-get update
apt-get upgrade
apt-get install build-essential
OpenSSL 下载
wget -c https://www.openssl.org/source/openssl-1.1.1l.tar.gz && tar zxvf openssl-1.1.1l.tar.gz
Zib 下载
wget http://zlib.net/zlib-1.2.11.tar.gz && tar zxvf wget zlib-1.2.11.tar.gz
Pcre 下载
wget -c https://ftp.pcre.org/pub/pcre/pcre-8.45.tar.gz && tar zxvf pcre-8.45.tar.gz
 
## 下载源码
git clone 
 
Nginx 编译
## 下载 Nginx 源码
wget -c http://nginx.org/download/nginx-1.18.0.tar.gz && tar zxvf nginx-1.18.0.tar.gz
## 进入nginx 目录
cd nginx-1.18.0
## 加载ngx_http_proxy_connect 补丁
patch -p1 < /root/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_1018.patch
## 配置检查
./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-HdenXw/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --add-module=/root/ngx_http_proxy_connect_module --with-pcre=../pcre-8.45 --with-openssl=../openssl-1.1.1l --with-zlib=../zlib-1.2.11
## 编译
make
## 安装
sudo make install
sudo mkdir -p /var/lib/nginx
## 检查
sudo ./objs/nginx -t

NGINX 代理

正向代理

正向代理是一个位于客户端和目标服务器之间充当代理服务器。
客户端向代理服务器发送一个请求,并且指定目标服务器,之后代理向目标服务器转交并且将获得的内容返回给客户端。客户端感知其请求的目标服务资源。
notion image
  • http 代理配置 (ngx_http_proxy_connect_module )
server {
     listen                         7777;

     # dns resolver used by forward proxying
     resolver                       114.114.114.114;

     # forward proxy for CONNECT request
     proxy_connect;
     proxy_connect_allow            443 563;
     proxy_connect_connect_timeout  10s;
     proxy_connect_read_timeout     10s;
     proxy_connect_send_timeout     10s;

     # forward proxy for non-CONNECT request
     location / {
         proxy_pass http://$host;
         proxy_set_header Host $host;
     }
 }
 
  • TCP 正向代理
## 编译追加stream模块和stream_ssl模块
--with-stream --with-stream_ssl_module

反向代理

反向代理正好相反。对于客户端来说,反向代理就好像目标服务器。并且客户端不会感知目标服务。客户端向反向代理发送请求,反向代理判断请求指向具体服务,并将响应转交给客户端,一次客户端并不会感知到反向代理后面的服务。
通常情况下,我们常用到反向代理做负载均衡。
  • RR(round robin :轮询 默认)
    • 每个请求按时间顺序逐一分配到不同的后端服务器,也就是说第一次请求分配到第一台服务器上,第二次请求分配到第二台服务器上,如果只有两台服务器,第三次请求继续分配到第一台上,这样循环轮询下去,也就是服务器接收请求的比例是 1:1, 如果后端服务器down掉,能自动剔除。轮询是默认配置,不需要太多的配置
      同一个项目分别使用8081和8082端口启动项目
      upstream web_servers {  
         server localhost:8081;  
         server localhost:8082;  
      }
      
      server {
          listen       80;
          server_name  localhost;
          #access_log  logs/host.access.log  main;
      
      
          location / {
              proxy_pass http://web_servers;
              # 必须指定Header Host
              proxy_set_header Host $host:$server_port;
          }
       }
  • 权重
    • 指定轮询几率,weight和访问比率成正比, 也就是服务器接收请求的比例就是各自配置的weight的比例,用于后端服务器性能不均的情况,比如服务器性能差点就少接收点请求,服务器性能好点就多处理点请求。
      upstream test {
          server localhost:8081 weight=1;
          server localhost:8082 weight=3;
          server localhost:8083 weight=4 backup;
      }
 
  • ip_hash
    • 上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
      upstream test {
          ip_hash;
          server localhost:8080;
          server localhost:8081;
      }
 
  • fair(第三方)
    • 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
      upstream backend {
          fair;
          server localhost:8080;
          server localhost:8081;
      }
 
  • url_hash(第三方)
    • 按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
      upstream backend {
          hash $request_uri;
          hash_method crc32;
          server localhost:8080;
          server localhost:8081;
      }
网站镜像
upstream google_upstream {
        server 142.250.80.46:443 weight=1;
        server 142.250.80.47:443 weight=1;
        server 142.250.80.49:443 weight=1;
        server 142.250.80.50:443 weight=1;

        # add more servers here
    }
    server{
        set $simplebox "simplebox";
        listen 443  ssl http2  fastopen=5;
            server_name     zeit.fun *.zeit.fun;
            resolver        8.8.8.8;
            ssl_certificate                         /etc/letsencrypt/live/zeit.fun/fullchain.pem;
            ssl_certificate_key                     /etc/letsencrypt/live/zeit.fun/privkey.pem;
            ssl_trusted_certificate         /etc/letsencrypt/live/zeit.fun/fullchain.pem;

        # 首页
        location / {
            proxy_set_header Host "www.google.com";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_pass https://google_upstream;
            # gzip, subs_filer 需要设置为空
            proxy_set_header  Accept-Encoding   "";
            proxy_set_header  Referer           "$simplebox , $http_referer";
            proxy_set_header  X-Real-IP         $remote_addr;
            proxy_set_header  User-Agent        $http_user_agent;
            proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
            proxy_set_header Accept-Language    "en-US,en;q=0.5";
            proxy_set_header  Cookie "PREF=ID=047808f19f6de346:U=0f62f33dd8549d11:FF=2:LD=en-US:NW=1:TM=1325338577:LM=1332142444:GM=1:SG=2:S=rE0SyJh2W1IQ-Maw";

           
            #设置cookie 
            proxy_set_header X-Forwarded-Proto  https; # 其他应用#
            proxy_redirect off; #关闭重定向
            add_header zeit "hi from zeit.fun";
        }
    
notion image
 

其他

openresty
apisix
envoy

参考