基于动态路由的方案设计

当业务量激增时,增减服务器是很频繁的事,每次手动修改配置文件的 upstream 并不是让人满意的做法,每次增加了服务器 nginx 可以自动刷新就好了,这时候需要使用到 upsync 模块。

基于 upsync 方式,开发了模块 nginx-upsync-module,它的功能是拉取 consul 的后端 server 的列表,并更新 Nginx 的路由信息。此模块不依赖于任何第三方模块。

路由表更新方式
consul 作为 Nginx 的 db,利用 consul 的 KV 服务,每个 Nginx work 进程独立的去拉取各个 upstream 的配置,并更新各自的路由。


Consul集群

环境准备

  • Centos7 3节点
  • 端口
    • 8300 – TCP
    • 8301 – TCP & UDP
    • 8302 – TCP & UDP
    • 8400 – TCP
    • 8500 – TCP
    • 8600 – TCP & UDP
  • 目录规划
    • /data/consul/bin 二进制命令目录
    • /data/consul/config 配置文件目录
    • /data/consul/data 数据目录

主程序包

安装部署

在3个节点上运行

  1. 下载Linux Consul二进制文件
sudo mkdir /data/install

cd /data/install

sudo wget https://releases.hashicorp.com/consul/1.5.0/consul_1.5.0_linux_amd64.zip

sudo unzip consul_1.5.0_linux_amd64.zip
sudo rm -f consul_1.5.0_linux_amd64.zip
  1. 创建用户、创建目录
sudo mkdir /data/consul/{bin,data,config} -p

sudo useradd --system --home /data/consul --shell /bin/false consul

sudo chown consul.consul -R /data/consul
  1. 拷贝命令到执行目录
sudo cp /data/install/consul /data/consul/bin/consul

sudo chown consul.consul /data/consul/bin/consul
  1. 在其中一台服务器上创建consul secret 将密钥复制到文本文件.
/data/consul/bin/consul keygen
  1. 其中一台服务器上创建consul secret 将密钥复制到文本文件.
vim /data/consul/config/server.json

将以下配置复制到该文件

  • encrypt值替换为步骤4中创建的密码
  • advertise_addr替换为服务器IP-
  • start_joinIP替换为集群的IP
  • dc替换为数据中心名称
{
    "bootstrap_expect": 3,
    "client_addr": "0.0.0.0",
    "bind_addr": "0.0.0.0",
    "advertise_addr" : "192.168.103.12",
    "data_dir": "/data/consul/data",
    "domain": "consul",
    "enable_script_checks": true,
    "dns_config": {
        "enable_truncate": true,
        "only_passing": true
    },
    "enable_syslog": true,
    "encrypt": "iOP+NHGTVsrOEzrngTe4XA==",
    "leave_on_terminate": true,
    "log_level": "INFO",
    "rejoin_after_leave": true,
    "server": true,
    "datacenter": "jiajiantest",
    "start_join": [
        "192.168.103.11",
        "192.168.103.12",
        "192.168.103.13"
    ],
    "ui": true
}
  1. 创建systemd文件
vim /etc/systemd/system/consul.service

将以下内容复制到该文件.

[Unit]
Description="HashiCorp Consul - A service mesh solution"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/data/consul/config/consul_server.json

[Service]
User=consul
Group=consul
ExecStart=/data/consul/bin/consul agent -config-dir=/data/consul/config/
ExecReload=/data/consul/bin/consul reload
KillMode=process
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
  1. 引导并启动集群
# 最后调整目录权限
sudo chown consul.consul /data/consul/ -R

# 在三节点分别启动服务
sudo systemctl start consul
  1. 执行命令检查集群状态
/data/consul/bin/consul members

你应该得到如下的输出. 这意味着您的consul集群已启动并正在运行.

[jan@node-1 ~]$ /data/consul/bin/consul members
Node           Address              Status  Type    Build  Protocol  DC          Segment
node-1  192.168.103.11:8301  alive   server  1.4.4  2         us-central  <all>
node-2  192.168.103.12:8301  alive   server  1.4.4  2         us-central  <all>
node-3  192.168.103.13:8301  alive   server  1.4.4  2         us-central  <all>

选项说明

options-doc

ParameterComments
-server指定节点为server,每个数据中心(DC)的server数推荐3-5个
-bootstrap-expect参数表明该服务运行时最低开始进行选举的节点数,当设
-ui启动WEB UI
-node指定节点在集群中的名称,该名称在集群中必须是唯一的
-config-dir指定service的配置文件和检查定义所在的位置。目录必需为
-data-dir指定agent储存状态的数据目录,这是所有agent都必须的,对
-bind指明节点的IP地址,Consul侦听的地址,它必须可以被集群中的所有其他
-client指定可访问这个服务结点的ip
-join将该节点加入集群中
-datacenter指定该 agent 加入到哪一个数据中心,默认为 dc1

OpenResty

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

主程序包

Nginx扩展模块

fix bug: https://github.com/weibocom/nginx-upsync-module/issues/182
这里使用xiaokai-wang修复过的版本

  • ngx_brotli Brotli 压缩算法
    ngx_brotli
    启用 Brotli 压缩算法,对比 Gzip 压缩 CDN 流量再减少 20%
    Google 认为互联网用户的时间是宝贵的,他们的时间不应该消耗在漫长的网页加载中,因此在 2015 年 9 月 Google 推出了无损压缩算法 Brotli。Brotli 通过变种的 LZ77 算法、Huffman 编码以及二阶文本建模等方式进行数据压缩,与其他压缩算法相比,它有着更高的压缩效率。

    • 根据 Google 发布的研究报告,Brotli 压缩算法具有多个特点,最典型的是以下 3 个:
    • 针对常见的 Web 资源内容,Brotli 的性能相比 Gzip 提高了 17-25%;
    • 当 Brotli 压缩级别为 1 时,压缩率比 Gzip 压缩等级为 9(最高)时还要高;
    • 在处理不同 HTML 文档时,Brotli 依然能够提供非常高的压缩率。
  • Jemalloc 内存管理
    jemalloc-5.2.1.tar.bz2
    JeMalloc 是一款内存分配器,与其它内存分配器相比,它最大的优势在于多线程情况下的高性能以及内存碎片的减少。

动态模块Upsync

  • 介绍
    nginx-upsync-module是由王晓开用C开发的nginx模块,用于从consul或其它同步upstream模块配置,动态修改后端服务属性(weight、max_fails等等)。修改这些信息后,不像未使用该模块的nginx一样需要reload下nginx。
    nginx在作为负载均衡角色时,对于单台nginx,增加、删除后端服务,对于进行单台的nginx,修改nginx配置文件后,要想配置文件生效,必须reload下nginx,这是很方便的。但是对于一个十几台或者几十台的nginx集群,要实现这是一个很大的一个工作量。并且reload nginx会增加系统负载也会暂时降低性能。
    nginx-upsync-module可以很容易解决上面所提到的问题,并且也不会影响性能。
    该模块现在仍处于开发,不过已经准备用于生产环境。建议和后端健康检测模块nginx_upstream_check_module配合使用。

  • 兼容性
    master分支兼容1.9版本及以上的nginx。nginx-upsync-1.8.x兼容1.8版本的nginx。

  • 优势
    该模块提供了发现后端的方法。支持通过consul动态添加和删除后端服务和调整后端服务的weight、fail_timeout、max_fails等属性。也会从consul获取新的后端服务并同步到nginx的IP路由表。该模块具有以下优势:

    • 及时性
      会发送给consul带有索引的key,consul会将该索引和consul的索引进行对比,如果索引没有改变,链接会挂起5分钟,在这期间,对该key-value的任何操作,都会立马得到反馈。

    • 几乎无性能损失
      从consul获取后端服务器列表,对于nginx来说就相当于一个请求。更新nginx的IP路由表,需要reload nginx,因此只会对nginx的性能有一点影响。

    • 稳定
      如果这次获取服务器失败,在下一个同步间隔仍会获取服务器列表。这样就保证了后端服务提供服务的稳定性。同时,支持将最近的配置文件备份到本地,即使consul故障宕机了,nginx仍可以随时可以reload配置。

    • 健康检测
      该模块支持对后端服务的健康检测,不过需要nginx_upstream_check_module。因此建议nginx-upsync-module和nginx_upstream_check_module配合使用。

配置参数 官方文档

  • upsync

    • 语法:upsync $consul.api.com:$port/v1/kv/upstreams/pstream_name [upsync_type=consul] [upsync_interval=seconds/nutes] [upsync_timeout=seconds/minutes] [strong_dependency=off/];
    • 默认:upsync_interval=5s upsync_timeout=6m rong_dependency=off
    • 位置:upstream
    • 功能:从consul或etcd获取服务列表
    • 参数解析
      • upsync_interval: 从consul获取服务列表的间隔时间
      • upsync_timeout: 从consul获取服务列表的请求超时时间
      • upsync_type: 指定从什么类型的服务(consul或etcd)获取服务列表。
      • strong_dependency: nginx启动是否强制依赖upsync_type指定的服务关。如果upsync_type指定的是consul,在nginx启动是,consul并未,那么nginx启动会失败。
  • upsync_dump_path

    • 语法: upsync_dump_path $path;
    • 默认:/tem/servers_$host.conf
    • 位置:upstream
    • 功能:备份upstream配置的后端服务器到指定的路径下
  • upsync_lb

    • 语法:upsync_lb round_robin/ip_hash/hash
    • 默认:round_robin
    • 位置:upstream
    • 功能:指定使用的调度方法
  • upstream_show

    • 语法:upstream_show;
    • 默认:None
    • 位置:location
    • 功能:列出指定的upstream配置的所有后端服务器

编译安装Jemalloc

# 进入默认的软件目录
cd /usr/local/src/

# 下载安装包
wget -c https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2
tar xjf jemalloc-5.2.1.tar.bz2
cd jemalloc-5.2.1

# 安装配置
./configure --prefix=/usr/local/jemalloc-5.2.1
make && make install
echo '/usr/local/jemalloc-5.2.1/lib' >> /etc/ld.so.conf.d/local.conf
ldconfig

编译安装OpenResty

  1. nginx源码包打补丁
    nginx源码包不打upstream_check_module补丁,模块加载失效
cd openresty-1.15.8.3/bundle/nginx-1.15.8

patch -p1 < ../../../nginx_upstream_check_module-master/check_1.12.1+.patch

# 得到如下 secceeded 返回则为成功
patching file src/http/modules/ngx_http_upstream_hash_module.c
Hunk #2 succeeded at 241 (offset 3 lines).
Hunk #3 succeeded at 571 (offset 22 lines).
patching file src/http/modules/ngx_http_upstream_ip_hash_module.c
Hunk #2 succeeded at 211 (offset 3 lines).
patching file src/http/modules/ngx_http_upstream_least_conn_module.c
patching file src/http/ngx_http_upstream_round_robin.c
patching file src/http/ngx_http_upstream_round_robin.h
  1. 去除gcc的debug参数(可以减少二进制包的大小)
vim openresty-1.15.8.3/bundle/nginx-1.15.8/auto/cc/gcc
#注释掉这一行
# debug
#CFLAGS="$CFLAGS -g"
    1. 处理报错”./configure: error: Brotli library is missing from the /usr directory.”
      cd ../ngx_brotli && git submodule update --init && cd -
  1. 编译参数
./configure  --prefix=/data/sa/openresty-1.15.8.3-build-`date +%Y%m%d` \
 --without-http_memc_module \
 --without-lua_resty_memcached \
 --without-lua_resty_mysql \
 --with-threads \
 --with-file-aio \
 --with-http_v2_module \
 --with-http_realip_module \
 --with-http_gunzip_module \
 --with-http_gzip_static_module \
 --with-http_auth_request_module \
 --with-http_secure_link_module \
 --with-http_stub_status_module \
 --without-mail_pop3_module \
 --without-mail_imap_module \
 --without-mail_smtp_module \
 --with-http_sub_module \
 --with-stream \
 --with-stream_ssl_module \
 --with-stream_realip_module \
 --with-stream_ssl_preread_module \
 --with-pcre=../pcre-8.44 \
 --with-pcre-jit \
 --http-proxy-temp-path=/data/sadata/openresty/temp/proxy_temp \
 --http-fastcgi-temp-path=/data/sadata/openresty/temp/fastcgi_temp \
 --http-uwsgi-temp-path=/data/sadata/openresty/temp/uwsgi_temp \
 --http-scgi-temp-path=/data/sadata/openresty/temp/scgi_temp \
 --with-zlib=../zlib-1.2.11 \
 --with-openssl=../openssl-1.1.1g \
 --with-openssl-opt='enable-tls1_3 enable-weak-ssl-ciphers' \
 --add-module=../nginx-module-vts-0.1.18 \
 --add-module=../nginx-upsync-module-2.1.2 \
 --add-module=../nginx_upstream_check_module-master \
 --add-module=../ngx_brotli \
 --add-module=../ngx_cache_purge-2.3 \
 --add-module=../ngx_http_substitutions_filter_module-0.6.4 \
 --with-ld-opt="-ljemalloc"
  1. 编译

# 如果编译失败 可以试试 make -j1单进程
make

make install
  1. 查看版本信息
./bin/openresty -V

nginx version: openresty/1.15.8.3
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.1.1g  21 Apr 2020
TLS SNI support enabled
configure arguments: --prefix=/data/sa/openresty-1.15.8.3-build-20200424/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.1rc1 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.15 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.15 --add-module=../rds-csv-nginx-module-0.09 --add-module=../ngx_stream_lua-0.0.7 --with-ld-opt='-Wl,-rpath,/data/sa/openresty-1.15.8.3-build-20200424/luajit/lib -ljemalloc' --with-threads --with-file-aio --with-http_v2_module --with-http_realip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_secure_link_module --with-http_stub_status_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_sub_module --with-stream --with-stream_ssl_module --with-stream_realip_module --with-stream_ssl_preread_module --with-pcre=/usr/local/src/openresty/openresty-1.15.8.3/../pcre-8.44 --with-pcre-jit --http-proxy-temp-path=temp/proxy_temp --http-fastcgi-temp-path=temp/fastcgi_temp --http-uwsgi-temp-path=temp/uwsgi_temp --http-scgi-temp-path=temp/scgi_temp --with-zlib=/usr/local/src/openresty/openresty-1.15.8.3/../zlib-1.2.11 --with-openssl=/usr/local/src/openresty/openresty-1.15.8.3/../openssl-1.1.1g --with-openssl-opt='enable-tls1_3 enable-weak-ssl-ciphers' --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../nginx-module-vts-0.1.18 --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../nginx-upsync-module-2.1.2 --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../nginx_upstream_check_module-master --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../ngx_brotli --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../ngx_cache_purge-2.3 --add-module=/usr/local/src/openresty/openresty-1.15.8.3/../ngx_http_substitutions_filter_module-0.6.4 --with-stream --with-stream_ssl_preread_module --with-http_ssl_module

OpenResty配置Demo

  • 在目标配置jemalloc
cd /usr/local/
# 拷贝编译好的jemalloc-5.2.1到目录
7z x jemalloc-5.2.1.7z
echo '/usr/local/jemalloc-5.2.1/lib' >> /etc/ld.so.conf.d/local.conf
ldconfig
  • 准备运行目录
mkdir -p /data/sadata/openresty/{config,logs}

mkdir -p /data/sadata/openresty/logs/{access,error,pid}

mkdir -p /data/sadata/openresty/config/{auth,blackip,ca,geoip,vhosts,whiteip}
  • 主配置文件 nginx.conf
user  nobody;
worker_processes  auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 100000;

error_log  /data/sadata/openresty/logs/error/error.log error;

pid        /data/sadata/openresty/logs/pid/nginx.pid;
pcre_jit on;

events {
    use epoll;
    worker_connections  65535;
    accept_mutex off;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format main '{"@timestamp":"$time_iso8601",'
             '"clientRealIp":"$clientRealIp",'
             '"remote_addr":"$remote_addr",'
             '"remote_user":"$remote_user",'
             '"time_local":"$remote_user",'
             '"request":"$request",'
             '"status":"$status",'
             '"body_bytes_sent":"$body_bytes_sent",'
             '"http_referer":"$http_referer",'
             '"http_user_agent":"$http_user_agent",'
             '"http_x_forwarded_for":"$http_x_forwarded_for",'
             '"upstream_addr":"$upstream_addr",'
             '"upstream_status":"$upstream_status",'
             '"upstream_response_time":"$upstream_response_time",'
             '"request_time":"$request_time",'
             '"server_name":"$host",'
             '"request_method":"$request_method",'
             '"uri":"$uri"'
        '}';

    log_format main_with_body '{"@timestamp":"$time_iso8601",'
             '"clientRealIp":"$clientRealIp",'
             '"remote_addr":"$remote_addr",'
             '"remote_user":"$remote_user",'
             '"time_local":"$remote_user",'
             '"request":"$request",'
             '"status":"$status",'
             '"body_bytes_sent":"$body_bytes_sent",'
             '"http_referer":"$http_referer",'
             '"http_user_agent":"$http_user_agent",'
             '"http_x_forwarded_for":"$http_x_forwarded_for",'
             '"upstream_addr":"$upstream_addr",'
             '"upstream_status":"$upstream_status",'
             '"upstream_response_time":"$upstream_response_time",'
             '"request_time":"$request_time",'
             '"server_name":"$host",'
             '"request_method":"$request_method",'
             '"content_length":"$content_length",'
             '"content_type":"$content_type",'
             '"request_body":"$request_body",'
             '"uri":"$uri"'
        '}';

    map $http_x_forwarded_for $clientRealIp {
        "" $remote_addr;
        ~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
    }

    #access_log  logs/access.log  main;

    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay    on;

    keepalive_timeout  65;
    send_timeout 15s;
    #more_set_headers "Server: PP_Proxy";
    server_tokens off;


    # server name
    server_names_hash_bucket_size 128;
    server_name_in_redirect off;

    # client
    client_body_timeout 15;
    client_header_buffer_size 16k;
    client_max_body_size 32m;
    client_body_buffer_size  512k;
    large_client_header_buffers 4 32k;

    # proxy
    proxy_connect_timeout    15;
    proxy_read_timeout       15;
    proxy_send_timeout       15;

    proxy_buffer_size        128k;
    proxy_buffers            4 128k;
    proxy_busy_buffers_size 256k;
    proxy_temp_file_write_size 256k;
    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;
    proxy_max_temp_file_size 128m;
    #proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_next_upstream error invalid_header http_502 http_503;
    proxy_temp_path  /dev/shm/proxy_temp;
    proxy_redirect off;
    proxy_ignore_client_abort on;
    proxy_set_header Host $host;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;

    # check
    check_shm_size 50M;

    # check
    check_shm_size 128M;

    # gzip
    gzip  on;
    gzip_min_length 20;
    gzip_buffers 32 128k;
    gzip_http_version 1.1;
    gzip_comp_level 5;
    #gzip_types application/javascript application/rss application/xml application/json application/x-javascript text/xml text/css text/plain image/jpeg image/gif image/png;
    gzip_types *;
    gzip_vary off;
    gzip_disable "msie6";

    # brotli
    brotli on;
    brotli_comp_level 6;
    brotli_buffers 32 128k;
    brotli_min_length 20;
    brotli_types *;
    brotli_static  always;

    ## vts
    #vhost_traffic_status_zone shared:vhost_traffic_status:32m;
    #vhost_traffic_status_filter_by_set_key $uri uri::*;
    ## vhost_traffic_status_filter_by_set_key $geoip_country_code country::*;
    ## vhost_traffic_status_filter_by_set_key $geoip_city city::*;
    #map $http_user_agent $filter_user_agent {
    #    default 'unknown';
    #    ~iPhone ios;
    #    ~Android android;
    #    ~(MSIE|Mozilla) windows;
    #    ~(Axis|Java) java;
    #}
    #vhost_traffic_status_filter_by_set_key $filter_user_agent agent::*;


    server {
         listen 80 default;
         server_name _;
         default_type text/html;
         charset utf-8;
         #return 200 '<center><h1>Hello Proxy</h1></center>';
         access_log off;
         location / {
             content_by_lua_block {
                 ngx.say('<center><h1>域名设置有误! Ngx Proxy找不到域名对应的后端程序, 请与运维团队联系!</h1></center>')
             }
         }
    }

    include /data/sadata/openresty/config/vhosts/*.conf;
}
  • 查看jemalloc是否运行正常
    lsof -n | grep jemalloc
    
    openresty 30734                root  mem       REG              253,0   4397608     604226 /usr/local/jemalloc-5.2.1/lib/libjemalloc.so.2
    openresty 30735              nobody  mem       REG              253,0   4397608     604226 /usr/local/jemalloc-5.2.1/lib/libjemalloc.so.2
    openresty 30736              nobody  mem       REG              253,0   4397608     604226 /usr/local/jemalloc-5.2.1/lib/libjemalloc.so.2
  • 监控配置 slb-status.example.com.conf
server {
    # SLB集群中只需设置一个用来查看的域名即可, 无需所有域名都开

    listen       9913;
    server_name  slb-status.example.com;

    location /ups_status {
        check_status;
    }
    location /ups_list {
        upstream_show;
    }

    location /vts_status {
        vhost_traffic_status_display;
        vhost_traffic_status_display_format json;
        # vhost_traffic_status_display_format prometheus;
        #统计国家流量
        # vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;
        #统计地区流量
        #vhost_traffic_status_filter_by_set_key $geoip_city city::$server_name;
        #统计用户代理流量
        vhost_traffic_status_filter_by_set_key $filter_user_agent agent::$server_name;
        # uri
        vhost_traffic_status_filter_by_set_key $uri uris::$server_name;
        #统计状态页面以外的流量
        vhost_traffic_status_bypass_limit on;
        vhost_traffic_status_bypass_stats on;

    }
    access_log  off;
}
  • 动态Upstream配置
    注意: 要先创建upsync目录, 并且touch一个空的配置文件
sudo mkdir -p /data/sadata/openresty/upsync_dump/

touch /data/sadata/openresty/upsync_dump/test.conf
  • 一键生成upsync路径 以及空配置文件(在每个openresty节点执行)
sudo mkdir -p /data/sadata/openresty/upsync_dump/

curl -Ss localhost:9913/ups_list |grep Upstream |awk -F'[ ;]' '{print "touch /data/sadata/openresty/upsync_dump/"$3".conf"}' > upsync_dir.sh
sudo bash upsync_dir.sh
sudo chown nobody. -R /data/sadata/openresty/upsync_dump/
  • 配置文件test.conf
upstream test {
    # 首次生成upsync_dump数据时用到,后续可以注释掉
    # 生产请用真实的server
    server 127.0.0.1:11111;

    upsync 127.0.0.1:8500/v1/kv/ngx-ups/inside/test upsync_timeout=1m upsync_interval=1s upsync_type=consul strong_dependency=off;
    upsync_dump_path /data/sadata/openresty/upsync_dump/test.conf;

    include /data/sadata/openresty/upsync_dump/test.conf;

    check interval=1000 rise=3 fall=5 timeout=1000 type=http;# default_down=false;
    check_keepalive_requests 100;
    check_http_send "HEAD / HTTP/1.1\r\nConnection: keep-alive\r\nHost: ngx-http-check.info\r\n\r\n";
    check_http_expect_alive http_2xx http_3xx;
}

server {

    listen 80;
    server_name test.example.com;

    location /  {
        proxy_pass http://test;
    }

    access_log  /data/sadata/openresty/logs/access/access_test.log main;


}

Consul操作

选项说明

ConsulAPI github

curl -X ${Mothed} http://$consul_ip:$port/v1/kv/$dir/$upstream_name/$backend_ip:$backend_port

ParameterComments
MothedsAPI方法
dirupstreams路径
  • 加入upstream节点

curl -X PUT ‘http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test/192.168.102.200:80'

curl -X PUT ‘http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test/192.168.102.69:80'

  • 删除upstream节点

curl -X DELETE ‘http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test/192.168.102.200:80'

  • 下架upstream节点

curl -X PUT -d ‘{“weight”:1, “max_fails”:2, “fail_timeout”:10, “down”:1}’ http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test/192.168.102.69:80

  • 激活upstream节点

curl -X PUT -d ‘{“weight”:1, “max_fails”:2, “fail_timeout”:10, “down”:0}’ http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test/192.168.102.69:80

  • 查看指定upstream节点

curl http://192.168.103.12:8500/v1/kv/ngx-ups/inside/test?recurse

  • upstream 首次生成
# 获取upstgream列表 
ngx_ups_list_url="192.168.103.12:9913/ups_list"

curl http://$ngx_ups_list_url|grep -v "^$" |awk -F'[ ;]' '{if ($1=="Upstream") print $3; else print $10}'
# 插入consul
consul_addr="192.168.103.12:8500"
ng_type="inside"
upstream_name="test"

backend="
192.168.21.15:8091
192.168.21.15:82
192.168.21.15:81
192.168.21.15:8092
192.168.21.15:8093
192.168.21.15:8001
"
for i in $backend ; do
    curl -X PUT -d '{"weight":1, "max_fails":3, "fail_timeout":10}' http://$consul_addr/v1/kv/ngx-ups/$ng_type/$upstream_name/$i
done

可以使用下述命令,自动生成生成拼接的shell

# 设定
ngx_ups_list_url="172.16.99.87:9913/ups_list"
consul_addr="172.16.99.56:8500"
ng_type="ngx-proxy"

echo "ngx_ups_list_url=\"${ngx_ups_list_url}\"" > mk_upstream.sh
echo "consul_addr=\"${consul_addr}\"" >> mk_upstream.sh
echo "ng_type=\"${ng_type}\"" >> mk_upstream.sh
curl -Ss http://$ngx_ups_list_url |awk -F'[ ;]' '{if ($1=="Upstream") print "upstream_name=\""$3"\"\nbackend=\""; else if ($10 =="") print "\"\nfor i in $backend ; do curl -X PUT -d \"{\\\"weight\\\":1,\\\"max_fails\\\":0}\" http://$consul_addr/v1/kv/ngx-ups/$ng_type/$upstream_name/$i; done \n"; else print $10}' >> mk_upstream.sh


bash mk_upstream.sh

 目录