├── .travis.yml ├── ngx_http_upstream_check_module.h ├── ngx_stream_upstream_check_module.h ├── config ├── nginx.conf.example ├── common.h.in ├── ngx_healthcheck_common.c ├── nginx_healthcheck_for_tengine_2.3+.patch ├── README-zh_CN.md ├── README.md ├── nginx_healthcheck_for_nginx_1.19+.patch ├── nginx_healthcheck_for_nginx_1.16+.patch ├── nginx_healthcheck_for_nginx_1.14+.patch ├── nginx_healthcheck_for_nginx_1.12+.patch └── ngx_healthcheck_status.c /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | 5 | os: 6 | - linux 7 | 8 | dist: 9 | - zesty 10 | 11 | sudo: true 12 | 13 | addons: 14 | apt: 15 | packages: 16 | - libpcre3-dev 17 | - zlib1g-dev 18 | - openssl 19 | 20 | before_install: echo before install addons. 21 | 22 | before_script: echo before script. 23 | 24 | script: bash ./build.sh 25 | 26 | after_success: echo ok! 27 | -------------------------------------------------------------------------------- /ngx_http_upstream_check_module.h: -------------------------------------------------------------------------------- 1 | #ifndef _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 2 | #define _NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | ngx_uint_t ngx_http_upstream_check_add_peer(ngx_conf_t *cf, 10 | ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer); 11 | 12 | ngx_uint_t ngx_http_upstream_check_peer_down(ngx_uint_t index); 13 | 14 | void ngx_http_upstream_check_get_peer(ngx_uint_t index); 15 | void ngx_http_upstream_check_free_peer(ngx_uint_t index); 16 | 17 | 18 | #endif //_NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 19 | 20 | -------------------------------------------------------------------------------- /ngx_stream_upstream_check_module.h: -------------------------------------------------------------------------------- 1 | #ifndef _NGX_STREAM_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 2 | #define _NGX_STREAM_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | //add a backend server to health checker system. 10 | ngx_uint_t ngx_stream_upstream_check_add_peer(ngx_conf_t *cf, 11 | ngx_stream_upstream_srv_conf_t *us, ngx_addr_t *peer); 12 | 13 | //get status of one backend . 14 | ngx_uint_t ngx_stream_upstream_check_peer_down(ngx_uint_t index); 15 | 16 | //inc peer's busyness cnt 17 | void ngx_stream_upstream_check_get_peer(ngx_uint_t index); 18 | 19 | //dec peer's busyness cnt 20 | void ngx_stream_upstream_check_free_peer(ngx_uint_t index); 21 | 22 | 23 | #endif //_NGX_STREAM_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 24 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | #module config script 2 | 3 | ngx_addon_name=ngx_healthcheck_module 4 | ngx_feature_path="$ngx_addon_dir" 5 | ngx_feature_deps="$ngx_addon_dir/ngx_http_upstream_check_module.h \ 6 | $ngx_addon_dir/ngx_stream_upstream_check_module.h " 7 | ngx_feature_src="$ngx_addon_dir/ngx_http_upstream_check_module.c \ 8 | $ngx_addon_dir/ngx_stream_upstream_check_module.c \ 9 | $ngx_addon_dir/ngx_healthcheck_common.c \ 10 | $ngx_addon_dir/ngx_healthcheck_status.c " 11 | 12 | 13 | have=NGX_STREAM_UPSTREAM_CHECK . auto/have 14 | have=NGX_HTTP_UPSTREAM_CHECK . auto/have 15 | 16 | if [ "$ngx_module_link" = DYNAMIC ]; then 17 | echo "[ERROR] ngx_healthcheck_module do not support dynamic loading yet.";exit 1 18 | #first module name as main module name. 19 | ngx_module_name="ngx_upstream_check_status_module \ 20 | ngx_stream_upstream_check_module \ 21 | ngx_http_upstream_check_module " 22 | ngx_module_incs="$ngx_feature_path" 23 | ngx_module_srcs="$ngx_feature_src" 24 | ngx_module_deps="$ngx_feature_deps" 25 | ngx_module_libs= 26 | 27 | . auto/module 28 | else 29 | STREAM_MODULES="$STREAM_MODULES ngx_stream_upstream_check_module" 30 | HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_check_module" 31 | HTTP_MODULES="$HTTP_MODULES ngx_upstream_check_status_module" 32 | CORE_INCS="$CORE_INCS $ngx_feature_path" 33 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_feature_deps" 34 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_feature_src" 35 | fi 36 | 37 | #end 38 | -------------------------------------------------------------------------------- /nginx.conf.example: -------------------------------------------------------------------------------- 1 | #user root; 2 | worker_processes 1; 3 | error_log logs/error.log info; 4 | #error_log logs/debug_stream.log debug_stream; 5 | error_log logs/debug_http.log debug_http; 6 | #pid logs/nginx.pid; 7 | 8 | events { 9 | worker_connections 256; 10 | } 11 | http { 12 | log_format main '$remote_addr:$remote_port -> $server_addr:$server_port [$time_local] "$request" ' 13 | '$status $body_bytes_sent "$http_referer" ' 14 | '"$http_user_agent" "$http_x_forwarded_for"'; 15 | access_log logs/access.log main; 16 | server { 17 | listen 8081; 18 | # status interface 19 | location /status { 20 | healthcheck_status json; 21 | } 22 | # http front 23 | location / { 24 | proxy_pass http://http-cluster; 25 | } 26 | } 27 | # as a backend server1. 28 | server { 29 | listen 127.0.0.1:8082; 30 | location / { 31 | default_type application/json ; 32 | return 201 '{"name":"server1","status": "UP"}'; 33 | } 34 | } 35 | # as a backend server2. 36 | server { 37 | listen 127.0.0.2:8082; 38 | location / { 39 | default_type application/json ; 40 | return 202 '{"name":"server2","status": "DOWN"}'; 41 | } 42 | } 43 | 44 | upstream http-cluster { 45 | # simple round-robin 46 | server 127.0.0.1:8082; 47 | server 127.0.0.2:8082; 48 | 49 | check interval=3000 rise=2 fall=5 timeout=5000 type=http; 50 | check_http_send "GET /heartbeat HTTP/1.0\r\n\r\n"; 51 | check_http_expect_alive http_2xx http_3xx; 52 | # I just wanna enable servers whose response content contain ('server1' or 'server3') and 'UP' 53 | check_http_expect_body ~ "server[13].+UP"; 54 | } 55 | } 56 | 57 | stream { 58 | upstream tcp-cluster { 59 | # simple round-robin 60 | server 127.0.0.1:22; # nomarl 61 | server 192.168.0.2:22; 62 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=tcp; 63 | #check_http_send "UDP_TEST"; 64 | } 65 | upstream udp-cluster { 66 | # simple round-robin 67 | server 127.0.0.1:5432; # port unreachable 68 | server 8.8.8.8:5432; # no error icmp msg 69 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=udp; 70 | check_http_send "UDP_TEST"; 71 | } 72 | 73 | upstream http-cluster2 { 74 | # simple round-robin 75 | server 127.0.0.1:8082; 76 | server 127.0.0.2:8082; 77 | 78 | check interval=3000 rise=1 fall=1 timeout=5000 type=http; 79 | #check_http_send "GET /heartbeat2 HTTP/1.1\r\nHost: localhost\r\n\r\n"; 80 | check_http_send "GET /heartbeat2 HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n"; 81 | # when use keepalive, you must use HTTP/1.1 with Host like above, or use HTTP/1.0 with header 'Connection: Keep-Alive' 82 | check_keepalive_requests 10; 83 | check_http_expect_alive http_2xx http_3xx; 84 | # I just wanna enable servers whose response content contain ('server1' or 'server3') and 'UP' 85 | check_http_expect_body ~ "server[13].+UP"; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /common.h.in: -------------------------------------------------------------------------------- 1 | 2 | /* module internal common header */ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct ngx_upstream_check_peer_s ngx_upstream_check_peer_t; 10 | typedef struct ngx_upstream_check_srv_conf_s ngx_upstream_check_srv_conf_t; 11 | 12 | typedef ngx_int_t (*ngx_upstream_check_packet_init_pt) 13 | (ngx_upstream_check_peer_t *peer); 14 | typedef ngx_int_t (*ngx_upstream_check_packet_parse_pt) 15 | (ngx_upstream_check_peer_t *peer); 16 | typedef void (*ngx_upstream_check_packet_clean_pt) 17 | (ngx_upstream_check_peer_t *peer); 18 | 19 | 20 | typedef struct { 21 | ngx_uint_t type; 22 | 23 | ngx_str_t name; 24 | 25 | ngx_str_t default_send; 26 | 27 | /* HTTP */ 28 | ngx_uint_t default_status_alive; 29 | 30 | ngx_event_handler_pt send_handler; 31 | ngx_event_handler_pt recv_handler; 32 | 33 | ngx_upstream_check_packet_init_pt init; 34 | ngx_upstream_check_packet_parse_pt parse; 35 | ngx_upstream_check_packet_clean_pt reinit; 36 | 37 | unsigned need_pool; 38 | unsigned need_keepalive; 39 | } ngx_check_conf_t; 40 | 41 | struct ngx_upstream_check_srv_conf_s { 42 | ngx_uint_t port; 43 | ngx_uint_t fall_count; 44 | ngx_uint_t rise_count; 45 | ngx_msec_t check_interval; 46 | ngx_msec_t check_timeout; 47 | ngx_uint_t check_keepalive_requests; 48 | 49 | ngx_check_conf_t *check_type_conf; 50 | ngx_str_t send; 51 | 52 | union { 53 | ngx_uint_t return_code; 54 | ngx_uint_t status_alive; 55 | } code; 56 | ngx_regex_t *expect_body_regex; 57 | ngx_array_t *fastcgi_params; //only for http module. 58 | ngx_uint_t default_down; 59 | }; 60 | 61 | typedef struct { 62 | ngx_shmtx_t mutex; 63 | #if (nginx_version >= 1002000) 64 | ngx_shmtx_sh_t lock; 65 | #else 66 | ngx_atomic_t lock; 67 | #endif 68 | 69 | ngx_pid_t owner; 70 | 71 | ngx_msec_t access_time; 72 | 73 | ngx_uint_t fall_count; 74 | ngx_uint_t rise_count; 75 | 76 | ngx_uint_t busyness; 77 | ngx_uint_t access_count; 78 | 79 | struct sockaddr *sockaddr; 80 | socklen_t socklen; 81 | 82 | ngx_atomic_t down; //current status. 83 | ngx_str_t *upstream_name; 84 | u_char padding[64]; 85 | } ngx_upstream_check_peer_shm_t; 86 | 87 | typedef struct { 88 | ngx_uint_t generation;// current process generation(==reload_num +1) 89 | ngx_uint_t checksum;// we can know if peer config file changed by calculate it. 90 | ngx_uint_t number; 91 | 92 | /* ngx_upstream_check_status_peer_t */ 93 | ngx_upstream_check_peer_shm_t peers[1]; //hack: peer[0] 94 | } ngx_upstream_check_peers_shm_t; 95 | /* followed with (peers_num-1)*ngx_upstream_check_peer_shm_t dynamicly,*/ 96 | /* so we can ref by peers_shm->peers[0],[1],... */ 97 | 98 | 99 | 100 | struct ngx_upstream_check_peer_s { 101 | ngx_flag_t state; 102 | ngx_pool_t *pool; 103 | ngx_uint_t index; 104 | ngx_uint_t max_busy; 105 | ngx_str_t *upstream_name; 106 | ngx_addr_t *check_peer_addr; 107 | ngx_addr_t *peer_addr; 108 | ngx_event_t check_ev; 109 | ngx_event_t check_timeout_ev; 110 | ngx_peer_connection_t pc; 111 | 112 | void *check_data; 113 | ngx_event_handler_pt send_handler; 114 | ngx_event_handler_pt recv_handler; 115 | 116 | ngx_upstream_check_packet_init_pt init; //zhoucx: function ptr 117 | ngx_upstream_check_packet_parse_pt parse; 118 | ngx_upstream_check_packet_clean_pt reinit; 119 | 120 | ngx_upstream_check_peer_shm_t *shm; 121 | ngx_upstream_check_srv_conf_t *conf; 122 | }; 123 | 124 | typedef struct { 125 | ngx_str_t check_shm_name; 126 | ngx_uint_t checksum; 127 | /* peers include ngx_upstream_check_peer_t item*/ 128 | ngx_array_t peers; 129 | ngx_upstream_check_peers_shm_t *peers_shm; 130 | } ngx_upstream_check_peers_t; 131 | 132 | 133 | -------------------------------------------------------------------------------- /ngx_healthcheck_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017- Changxun Zhou(changxunzhou@qq.com) 3 | * desc: nginx upstream server health check. 4 | * date: 2020-06-21 23:40 5 | */ 6 | #include "common.h.in" 7 | 8 | ngx_int_t 9 | ngx_upstream_check_http_body_regex(ngx_conf_t *cf, ngx_upstream_check_srv_conf_t *ucscf, 10 | ngx_str_t *regex, ngx_uint_t caseless) 11 | { 12 | #if (NGX_PCRE) 13 | ngx_regex_compile_t rc; 14 | u_char errstr[NGX_MAX_CONF_ERRSTR]; 15 | 16 | ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); 17 | 18 | rc.pattern = *regex; 19 | 20 | rc.err.len = NGX_MAX_CONF_ERRSTR; 21 | rc.err.data = errstr; 22 | rc.pool = cf->pool; 23 | 24 | #if (NGX_HAVE_CASELESS_FILESYSTEM) 25 | rc.options = NGX_REGEX_CASELESS; 26 | #else 27 | rc.options = caseless ? NGX_REGEX_CASELESS : 0; 28 | #endif 29 | 30 | if (ngx_regex_compile(&rc) != NGX_OK) { 31 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 32 | "ngx_regex_compile: %V", 33 | &rc.err); 34 | return NGX_ERROR; 35 | } 36 | 37 | ucscf->expect_body_regex = rc.regex; 38 | return NGX_OK; 39 | 40 | #else 41 | 42 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 43 | "using regex \"%V\" requires PCRE library", 44 | regex); 45 | return NGX_ERROR; 46 | 47 | #endif 48 | } 49 | 50 | ngx_int_t 51 | ngx_upstream_check_http_parse_status_line( 52 | ngx_buf_t *b, ngx_uint_t *pstate, ngx_http_status_t *status) 53 | { 54 | u_char ch, *p; 55 | enum { 56 | sw_start = 0, 57 | sw_H, 58 | sw_HT, 59 | sw_HTT, 60 | sw_HTTP, 61 | sw_first_major_digit, 62 | sw_major_digit, 63 | sw_first_minor_digit, 64 | sw_minor_digit, 65 | sw_status, 66 | sw_space_after_status, 67 | sw_status_text, 68 | sw_lf, 69 | sw_cr, 70 | sw_almost_done, 71 | receive_body 72 | } state; 73 | 74 | state = *pstate; 75 | 76 | if (state == receive_body) { 77 | return NGX_OK; 78 | } 79 | 80 | for (p = b->pos; p < b->last; p++) { 81 | ch = *p; 82 | 83 | switch (state) { 84 | 85 | /* "HTTP/" */ 86 | case sw_start: 87 | if (ch != 'H') { 88 | return NGX_ERROR; 89 | } 90 | 91 | state = sw_H; 92 | break; 93 | 94 | case sw_H: 95 | if (ch != 'T') { 96 | return NGX_ERROR; 97 | } 98 | 99 | state = sw_HT; 100 | break; 101 | 102 | case sw_HT: 103 | if (ch != 'T') { 104 | return NGX_ERROR; 105 | } 106 | 107 | state = sw_HTT; 108 | break; 109 | 110 | case sw_HTT: 111 | if (ch != 'P') { 112 | return NGX_ERROR; 113 | } 114 | 115 | state = sw_HTTP; 116 | break; 117 | 118 | case sw_HTTP: 119 | if (ch != '/') { 120 | return NGX_ERROR; 121 | } 122 | 123 | state = sw_first_major_digit; 124 | break; 125 | 126 | /* the first digit of major HTTP version */ 127 | case sw_first_major_digit: 128 | if (ch < '1' || ch > '9') { 129 | return NGX_ERROR; 130 | } 131 | 132 | state = sw_major_digit; 133 | break; 134 | 135 | /* the major HTTP version or dot */ 136 | case sw_major_digit: 137 | if (ch == '.') { 138 | state = sw_first_minor_digit; 139 | break; 140 | } 141 | 142 | if (ch < '0' || ch > '9') { 143 | return NGX_ERROR; 144 | } 145 | 146 | break; 147 | 148 | /* the first digit of minor HTTP version */ 149 | case sw_first_minor_digit: 150 | if (ch < '0' || ch > '9') { 151 | return NGX_ERROR; 152 | } 153 | 154 | state = sw_minor_digit; 155 | break; 156 | 157 | /* the minor HTTP version or the end of the request line */ 158 | case sw_minor_digit: 159 | if (ch == ' ') { 160 | state = sw_status; 161 | break; 162 | } 163 | 164 | if (ch < '0' || ch > '9') { 165 | return NGX_ERROR; 166 | } 167 | 168 | break; 169 | 170 | /* HTTP status code */ 171 | case sw_status: 172 | if (ch == ' ') { 173 | break; 174 | } 175 | 176 | if (ch < '0' || ch > '9') { 177 | return NGX_ERROR; 178 | } 179 | 180 | status->code = status->code * 10 + ch - '0'; 181 | 182 | if (++status->count == 3) { 183 | state = sw_space_after_status; 184 | status->start = p - 2; 185 | } 186 | 187 | break; 188 | 189 | /* space or end of line */ 190 | case sw_space_after_status: 191 | switch (ch) { 192 | case ' ': 193 | state = sw_status_text; 194 | break; 195 | case '.': /* IIS may send 403.1, 403.2, etc */ 196 | state = sw_status_text; 197 | break; 198 | case CR: 199 | state = sw_almost_done; 200 | break; 201 | case LF: 202 | goto done; 203 | default: 204 | return NGX_ERROR; 205 | } 206 | break; 207 | 208 | /* any text until end of line */ 209 | case sw_status_text: 210 | switch (ch) { 211 | case CR: 212 | state = sw_lf; 213 | break; 214 | case LF: 215 | goto done; 216 | } 217 | break; 218 | /* LF */ 219 | case sw_lf: 220 | switch (ch) { 221 | case LF: 222 | state = sw_cr; 223 | break; 224 | default: 225 | return NGX_ERROR; 226 | } 227 | break; 228 | 229 | /* CR */ 230 | case sw_cr: 231 | switch (ch) { 232 | case CR: /* second CR */ 233 | state = sw_almost_done; 234 | break; 235 | default: /* response header */ 236 | state = sw_status_text; 237 | break; 238 | } 239 | break; 240 | 241 | /* LF */ 242 | case sw_almost_done: 243 | switch (ch) { 244 | case LF: 245 | /* all header_end */ 246 | status->end = p - 1; 247 | goto done; 248 | default: 249 | return NGX_ERROR; 250 | } 251 | case receive_body: 252 | return NGX_OK; 253 | } 254 | } 255 | 256 | // save parsed state. 257 | b->pos = p; 258 | *pstate = state; 259 | return NGX_AGAIN; 260 | 261 | done: 262 | // set pos to start of body. 263 | b->pos = p + 1; 264 | 265 | if (status->end == NULL) { 266 | status->end = p; 267 | } 268 | *pstate = receive_body; 269 | 270 | return NGX_OK; 271 | } 272 | 273 | -------------------------------------------------------------------------------- /nginx_healthcheck_for_tengine_2.3+.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c 2 | index f3e2b9d3..6e05100b 100644 3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c 4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c 5 | @@ -568,6 +568,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 6 | continue; 7 | } 8 | 9 | +#if (NGX_HTTP_UPSTREAM_CHECK) 10 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 11 | + "get consistent_hash peer, check_index: %ui", 12 | + peer->check_index); 13 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 14 | + continue; 15 | + } 16 | +#endif 17 | + 18 | if (peer->max_conns && peer->conns >= peer->max_conns) { 19 | continue; 20 | } 21 | diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c 22 | index 4fa9a2dc..103b4de1 100644 23 | --- a/src/stream/ngx_stream_upstream_hash_module.c 24 | +++ b/src/stream/ngx_stream_upstream_hash_module.c 25 | @@ -9,6 +9,9 @@ 26 | #include 27 | #include 28 | 29 | +#if (NGX_STREAM_UPSTREAM_CHECK) 30 | +#include "ngx_stream_upstream_check_module.h" 31 | +#endif 32 | 33 | typedef struct { 34 | uint32_t hash; 35 | @@ -237,6 +240,16 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 36 | goto next; 37 | } 38 | 39 | +#if (NGX_STREAM_UPSTREAM_CHECK) 40 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 41 | + "(stream_module)get least_conn peer, check_index: %ui", 42 | + peer->check_index); 43 | + 44 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 45 | + goto next; 46 | + } 47 | +#endif 48 | + 49 | if (peer->max_fails 50 | && peer->fails >= peer->max_fails 51 | && now - peer->checked <= peer->fail_timeout) 52 | @@ -550,6 +563,17 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 53 | continue; 54 | } 55 | 56 | +#if (NGX_STREAM_UPSTREAM_CHECK) 57 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 58 | + "(stream_module)get_chash_peer, check_index: %ui", 59 | + peer->check_index); 60 | + 61 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 62 | + continue; 63 | + } 64 | +#endif 65 | + 66 | + 67 | if (peer->max_fails 68 | && peer->fails >= peer->max_fails 69 | && now - peer->checked <= peer->fail_timeout) 70 | diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c 71 | index 739b20a9..48e72671 100644 72 | --- a/src/stream/ngx_stream_upstream_least_conn_module.c 73 | +++ b/src/stream/ngx_stream_upstream_least_conn_module.c 74 | @@ -9,6 +9,9 @@ 75 | #include 76 | #include 77 | 78 | +#if (NGX_STREAM_UPSTREAM_CHECK) 79 | +#include "ngx_stream_upstream_check_module.h" 80 | +#endif 81 | 82 | static ngx_int_t ngx_stream_upstream_init_least_conn_peer( 83 | ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); 84 | @@ -143,6 +146,16 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 85 | continue; 86 | } 87 | 88 | +#if (NGX_STREAM_UPSTREAM_CHECK) 89 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 90 | + "(stream_module)get least_conn peer, check_index: %ui", 91 | + peer->check_index); 92 | + 93 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 94 | + continue; 95 | + } 96 | +#endif 97 | + 98 | if (peer->max_fails 99 | && peer->fails >= peer->max_fails 100 | && now - peer->checked <= peer->fail_timeout) 101 | @@ -198,6 +211,16 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 102 | continue; 103 | } 104 | 105 | +#if (NGX_STREAM_UPSTREAM_CHECK) 106 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 107 | + "(stream_module)get least_conn peer, check_index: %ui", 108 | + peer->check_index); 109 | + 110 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 111 | + continue; 112 | + } 113 | +#endif 114 | + 115 | if (peer->conns * best->weight != best->conns * peer->weight) { 116 | continue; 117 | } 118 | diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c 119 | index 36e2ec5c..60985f73 100644 120 | --- a/src/stream/ngx_stream_upstream_round_robin.c 121 | +++ b/src/stream/ngx_stream_upstream_round_robin.c 122 | @@ -9,6 +9,10 @@ 123 | #include 124 | #include 125 | 126 | +#if (NGX_STREAM_UPSTREAM_CHECK) 127 | +#include "ngx_stream_upstream_check_module.h" 128 | +#endif 129 | + 130 | 131 | #define ngx_stream_upstream_tries(p) ((p)->number \ 132 | + ((p)->next ? (p)->next->number : 0)) 133 | @@ -104,6 +108,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 134 | peer[n].down = server[i].down; 135 | peer[n].server = server[i].name; 136 | 137 | +#if (NGX_STREAM_UPSTREAM_CHECK) 138 | + if (!server[i].down) { 139 | + peer[n].check_index = 140 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 141 | + } 142 | + else { 143 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 144 | + } 145 | +#endif 146 | + 147 | *peerp = &peer[n]; 148 | peerp = &peer[n].next; 149 | n++; 150 | @@ -168,6 +182,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 151 | peer[n].down = server[i].down; 152 | peer[n].server = server[i].name; 153 | 154 | +#if (NGX_STREAM_UPSTREAM_CHECK) 155 | + if (!server[i].down) { 156 | + peer[n].check_index = 157 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 158 | + } 159 | + else { 160 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 161 | + } 162 | +#endif 163 | + 164 | *peerp = &peer[n]; 165 | peerp = &peer[n].next; 166 | n++; 167 | @@ -234,6 +258,11 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 168 | peer[i].max_conns = 0; 169 | peer[i].max_fails = 1; 170 | peer[i].fail_timeout = 10; 171 | + 172 | +#if (NGX_STREAM_UPSTREAM_CHECK) 173 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 174 | +#endif 175 | + 176 | *peerp = &peer[i]; 177 | peerp = &peer[i].next; 178 | } 179 | @@ -354,6 +383,11 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 180 | peer[0].max_conns = 0; 181 | peer[0].max_fails = 1; 182 | peer[0].fail_timeout = 10; 183 | + 184 | +#if (NGX_STREAM_UPSTREAM_CHECK) 185 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 186 | +#endif 187 | + 188 | peers->peer = peer; 189 | 190 | } else { 191 | @@ -388,6 +422,11 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 192 | peer[i].max_conns = 0; 193 | peer[i].max_fails = 1; 194 | peer[i].fail_timeout = 10; 195 | + 196 | +#if (NGX_STREAM_UPSTREAM_CHECK) 197 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 198 | +#endif 199 | + 200 | *peerp = &peer[i]; 201 | peerp = &peer[i].next; 202 | } 203 | @@ -452,6 +491,12 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 204 | goto failed; 205 | } 206 | 207 | +#if (NGX_STREAM_UPSTREAM_CHECK) 208 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 209 | + goto failed; 210 | + } 211 | +#endif 212 | + 213 | rrp->current = peer; 214 | 215 | } else { 216 | @@ -557,6 +602,12 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) 217 | continue; 218 | } 219 | 220 | +#if (NGX_STREAM_UPSTREAM_CHECK) 221 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 222 | + continue; 223 | + } 224 | +#endif 225 | + 226 | peer->current_weight += peer->effective_weight; 227 | total += peer->effective_weight; 228 | 229 | diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h 230 | index 35d9fce6..ff6398ee 100644 231 | --- a/src/stream/ngx_stream_upstream_round_robin.h 232 | +++ b/src/stream/ngx_stream_upstream_round_robin.h 233 | @@ -49,6 +49,10 @@ struct ngx_stream_upstream_rr_peer_s { 234 | 235 | ngx_stream_upstream_rr_peer_t *next; 236 | 237 | +#if (NGX_STREAM_UPSTREAM_CHECK) 238 | + ngx_uint_t check_index; 239 | +#endif 240 | + 241 | NGX_COMPAT_BEGIN(25) 242 | NGX_COMPAT_END 243 | }; 244 | -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 | # ngx-healthcheck-module 2 | 3 | ![loading](https://travis-ci.org/zhouchangxun/ngx_healthcheck_module.svg?branch=master) 4 | Travis CI 构建状态 : [点击查看](https://travis-ci.org/zhouchangxun/ngx_healthcheck_module) 5 | 6 | (English language see [here](https://github.com/zhouchangxun/ngx_healthcheck_module)) 7 | 8 | > 该模块可以为Nginx提供主动式后端服务器健康检查的功能(同时支持四层和七层后端服务器的健康检测)。 9 | 10 | ![html status ouput](http://zhouchangxun.github.io/disk/img/check-html.png) 11 | 12 | Table of Contents 13 | ================= 14 | 15 | * [项目状态](#项目状态) 16 | * [描述](#描述) 17 | * [如何安装](#如何安装) 18 | * [基本用法](#基本用法) 19 | * [扩充的nginx指令用法](#扩充的nginx指令用法) 20 | * [healthcheck](#healthcheck) 21 | * [check](#check) 22 | * [错误和补丁](#错误和补丁) 23 | * [关于作者](#关于作者) 24 | * [版权和许可](#版权和许可) 25 | * [相关链接](#相关链接) 26 | 27 | 项目状态 28 | ====== 29 | 30 | 这个项目还在开发中完善中,欢迎贡献代码,或报告bug。一起使它变得更好。 31 | 有意愿一起开发完善的同学或者有疑问的可以联系我: 32 | - `QQ`:373882405 33 | - `mail`: changxunzhou@qq.com 34 | 35 | 描述 36 | =========== 37 | 38 | 当你使用nginx作为负载均衡器时,nginx原生只提供了基本的重试方式来保证访问到正常的后端服务器。 39 | 40 | 相比之下,这个nginx第三方模块可以对后端服务器提供主动式的健康状态检测。 41 | 它维护了一个后端服务器列表,保证新的请求直接发送到一个健康的后端服务器。 42 | 43 | 主要特性: 44 | - 同时支持四层和七层后端服务器的健康检测 45 | - 四层支持的检测类型:tcp / udp / http 46 | - 七层支持的检测类型:http / fastcgi 47 | - 提供一个统一的http状态查询接口,输出格式:html / json / csv 48 | 49 | 如何安装 50 | ============ 51 | 52 | ``` 53 | git clone https://github.com/nginx/nginx.git 54 | git clone https://github.com/zhouchangxun/ngx_healthcheck_module.git 55 | 56 | cd nginx/; 57 | git checkout branches/stable-1.12 58 | git apply ../ngx_healthcheck_module/nginx_healthcheck_for_nginx_1.12+.patch 59 | 60 | ./auto/configure --with-stream --add-module=../ngx_healthcheck_module/ 61 | make && make install 62 | ``` 63 | 64 | [Back to TOC](#table-of-contents) 65 | 66 | 基本用法 67 | ===== 68 | 69 | **nginx.conf 样例** 70 | ```nginx 71 | user root; 72 | worker_processes 1; 73 | error_log logs/error.log info; 74 | #pid logs/nginx.pid; 75 | 76 | events { 77 | worker_connections 1024; 78 | } 79 | 80 | http { 81 | server { 82 | listen 80; 83 | # status interface 84 | location /status { 85 | healthcheck_status json; 86 | } 87 | # http front 88 | location / { 89 | proxy_pass http://http-cluster; 90 | } 91 | } 92 | # as a backend server. 93 | server { 94 | listen 8080; 95 | location / { 96 | root html; 97 | } 98 | } 99 | 100 | upstream http-cluster { 101 | # simple round-robin 102 | server 127.0.0.1:8080; 103 | server 127.0.0.2:81; 104 | 105 | check interval=3000 rise=2 fall=5 timeout=5000 type=http; 106 | check_http_send "GET / HTTP/1.0\r\n\r\n"; 107 | check_http_expect_alive http_2xx http_3xx; 108 | } 109 | } 110 | 111 | stream { 112 | upstream tcp-cluster { 113 | # simple round-robin 114 | server 127.0.0.1:22; 115 | server 192.168.0.2:22; 116 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=tcp; 117 | } 118 | server { 119 | listen 522; 120 | proxy_pass tcp-cluster; 121 | } 122 | 123 | upstream udp-cluster { 124 | # simple round-robin 125 | server 127.0.0.1:53; 126 | server 8.8.8.8:53; 127 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=udp; 128 | } 129 | server { 130 | listen 53 udp; 131 | proxy_pass udp-cluster; 132 | } 133 | 134 | } 135 | ``` 136 | 137 | **健康状态查询接口** 138 | 139 | json格式输出样例: 140 | ``` python 141 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# curl localhost/status 142 | {"servers": { 143 | "total": 6, 144 | "generation": 3, 145 | "http": [ 146 | {"index": 0, "upstream": "http-cluster", "name": "127.0.0.1:8080", "status": "up", "rise": 119, "fall": 0, "type": "http", "port": 0}, 147 | {"index": 1, "upstream": "http-cluster", "name": "127.0.0.2:81", "status": "down", "rise": 0, "fall": 120, "type": "http", "port": 0} 148 | ], 149 | "stream": [ 150 | {"index": 0, "upstream": "tcp-cluster", "name": "127.0.0.1:22", "status": "up", "rise": 22, "fall": 0, "type": "tcp", "port": 0}, 151 | {"index": 1, "upstream": "tcp-cluster", "name": "192.168.0.2:22", "status": "down", "rise": 0, "fall": 7, "type": "tcp", "port": 0}, 152 | {"index": 2, "upstream": "udp-cluster", "name": "127.0.0.1:53", "status": "down", "rise": 0, "fall": 120, "type": "udp", "port": 0}, 153 | {"index": 3, "upstream": "udp-cluster", "name": "8.8.8.8:53", "status": "up", "rise": 3, "fall": 0, "type": "udp", "port": 0} 154 | ] 155 | }} 156 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# 157 | ``` 158 | 159 | [Back to TOC](#table-of-contents) 160 | 161 | 扩充的nginx指令用法 162 | ======== 163 | 164 | check 165 | ----- 166 | 167 | `语法` 168 | > check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true|false] [type=tcp|udp|http] [port=check_port] 169 | 170 | `默认值`: interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp 171 | 172 | `上下文`: http/upstream || stream/upstream 173 | 174 | 通过在http或stream下的upstream配置块中添加`check`指令来开启对该upstream中的后端服务器的健康检查。 175 | 176 | `详细参数` 177 | 178 | - interval:向后端发送的健康检查包的间隔。 179 | - fall(fall_count): 如果连续失败次数达到fall_count,服务器就被认为是down。 180 | - rise(rise_count): 如果连续成功次数达到rise_count,服务器就被认为是up。 181 | - timeout: 后端健康请求的超时时间。 182 | - default_down: 设定初始时服务器的状态,如果是true,就说明默认是down的,如果是false,就是up的。 183 | 默认值是true,也就是一开始服务器认为是不可用,要等健康检查包达到一定成功次数以后才会被认为是健康的。 184 | - type:健康检查包的类型,现在支持以下多种类型 185 | - tcp:简单的tcp连接,如果连接成功,就说明后端正常。 186 | - udp:简单的发送udp报文,如果收到icmp error(主机或端口不可达),就说明后端异常。(只有stream配置块中支持udp类型检查) 187 | - http:发送HTTP请求,通过后端的回复包的状态来判断后端是否存活。 188 | - port: 指定后端服务器的检查端口。你可以指定不同于真实服务的后端服务器的端口, 189 | 比如后端提供的是443端口的应用,你可以去检查80端口的状态来判断后端健康状况。默认是0,表示跟后端server提供真实服务的端口一样。 190 | 191 | 该指令用法样例: 192 | ```nginx 193 | stream { 194 | upstream tcp-cluster { 195 | # simple round-robin 196 | server 127.0.0.1:22; 197 | server 192.168.0.2:22; 198 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=tcp; 199 | } 200 | server { 201 | listen 522; 202 | proxy_pass tcp-cluster; 203 | } 204 | ... 205 | } 206 | ``` 207 | 208 | healthcheck 209 | ----------- 210 | 211 | `语法`: healthcheck_status [html|csv|json] 212 | 213 | `默认值`: healthcheck_status html 214 | 215 | `上下文`: http/server/location 216 | 217 | `详细参数` 218 | 219 | - [html|csv|json]:表示默认输出格式。 220 | 221 | 该指令用法样例: 222 | ```nginx 223 | http { 224 | server { 225 | listen 80; 226 | 227 | # status interface 228 | location /status { 229 | healthcheck_status; 230 | } 231 | ... 232 | } 233 | ``` 234 | 235 | 通过配置该指令,你可以查看当前已开启健康检查的upstream的检查状态。 236 | 237 | 【关于输出格式】你可以通过URL请求参数`format`指定查询接口的输出格式: 238 | 239 | /status?format=html 240 | 241 | /status?format=csv 242 | 243 | /status?format=json 244 | 245 | 【关于数据过滤】 你可以通过URL请求参数`status`来过滤显示down和up的后端服务器: 246 | 247 | /status?format=json&status=down 248 | 249 | /status?format=html&status=down 250 | 251 | /status?format=csv&status=up 252 | 253 | 254 | [Back to TOC](#table-of-contents) 255 | 256 | 257 | 未完成的工作 258 | ========= 259 | 260 | - 添加测试用例。 261 | - 整理代码/规范日志输出等。 262 | - 特性增强。 263 | 264 | [Back to TOC](#table-of-contents) 265 | 266 | 错误和补丁 267 | ================ 268 | 269 | 报告错误 270 | 271 | - 点击提交[GitHub Issue](http://github.com/zhouchangxun/ngx_healthcheck_module/issues), 272 | 273 | 提交你的修复补丁 274 | 275 | - 点击提交[Pull request](https://github.com/zhouchangxun/ngx_healthcheck_module/pull/new/master) 276 | 277 | [Back to TOC](#table-of-contents) 278 | 279 | 关于作者 280 | ====== 281 | 282 | Chance Chou (周长勋) . 283 | 284 | [Back to TOC](#table-of-contents) 285 | 286 | 版权和许可 287 | ===================== 288 | 289 | 部分代码参考Yaoweibin的nginx_upstream_check_module模块: 290 | (); 291 | 292 | This module is licensed under the BSD license. 293 | 294 | Copyright (C) 2017-, by Changxun Zhou 295 | 296 | Copyright (C) 2014 by Weibin Yao 297 | 298 | All rights reserved. 299 | 300 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 301 | 302 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 303 | 304 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 305 | 306 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 307 | 308 | [Back to TOC](#table-of-contents) 309 | 310 | 相关链接 311 | ======== 312 | 313 | * nginx: http://nginx.org 314 | 315 | [Back to TOC](#table-of-contents) 316 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngx-healthcheck-module 2 | 3 | ![loading](https://travis-ci.org/zhouchangxun/ngx_healthcheck_module.svg?branch=master) 4 | Travis CI build details : [Click to see](https://travis-ci.org/zhouchangxun/ngx_healthcheck_module) 5 | 6 | (中文版本请参看[这里](https://github.com/zhouchangxun/ngx_healthcheck_module/blob/master/README-zh_CN.md)) 7 | 8 | > Health-checker for Nginx upstream servers (support http upstream && stream upstream) 9 | > This module can provide NGINX with the capability of active back-end server health check (supports health check of both four and seven back-end servers). 10 | 11 | ![html status ouput](http://zhouchangxun.github.io/disk/img/check-html.png) 12 | 13 | Table of Contents 14 | ================= 15 | 16 | * [Status](#status) 17 | * [Description](#description) 18 | * [Installation](#installation) 19 | * [Usage](#usage) 20 | * [Synopsis && Directive](#synopsis) 21 | * [healthcheck](#healthcheck) 22 | * [check](#check) 23 | * [Bugs and Patches](#bugs-and-patches) 24 | * [Author](#author) 25 | * [Copyright and License](#copyright-and-license) 26 | * [See Also](#see-also) 27 | 28 | Status 29 | ====== 30 | 31 | This nginx module is still under development, you can help improve and it. 32 | 33 | The project is also well developed in development, and you are welcome to contribute code, or report bugs. Together to make it better. 34 | 35 | If you have any questions, please contact me: 36 | - `QQ`:373882405 37 | - `mail`: changxunzhou@qq.com 38 | 39 | Description 40 | =========== 41 | 42 | When you use nginx as a load balancer, nginx natively provides only basic retries to ensure access to a normal backend server. 43 | 44 | In contrast, this nginx third-party module provides proactive health State Detection for back-end servers. 45 | It maintains a list of back-end servers that guarantee that new requests are sent directly to a healthy back-end server. 46 | 47 | Key features: 48 | - Supports health detection for both four-tier and seven-tier back-end servers 49 | - Four-layer supported detection type: `tcp` / `udp` / `http` 50 | - Seven-layer supported detection Type: `http` / `fastcgi` 51 | - Provide a unified http status query interface, output format: `html` / `json` / `csv` / `prometheus` 52 | - Provide a unified http status query interface, output format: `html` / `json` / `csv` / `prometheus` 53 | - Support judge status according to http response code or body like `check_http_expect_body ~ ".+OK.+";` 54 | 55 | Installation 56 | ============ 57 | 58 | ``` 59 | git clone https://github.com/nginx/nginx.git 60 | git clone https://github.com/zhouchangxun/ngx_healthcheck_module.git 61 | 62 | cd nginx/; 63 | git checkout branches/stable-1.12 64 | git apply ../ngx_healthcheck_module/nginx_healthcheck_for_nginx_1.12+.patch 65 | 66 | ./auto/configure --with-stream --add-module=../ngx_healthcheck_module/ 67 | make && make install 68 | ``` 69 | 70 | [Back to TOC](#table-of-contents) 71 | 72 | Usage 73 | ===== 74 | 75 | **nginx.conf example** 76 | ```nginx 77 | user root; 78 | worker_processes 1; 79 | error_log logs/error.log info; 80 | #pid logs/nginx.pid; 81 | 82 | events { 83 | worker_connections 1024; 84 | } 85 | 86 | http { 87 | server { 88 | listen 80; 89 | # status interface 90 | location /status { 91 |            healthcheck_status json; 92 | } 93 | # http front 94 | location / { 95 | proxy_pass http://http-cluster; 96 | } 97 | } 98 | # as a backend server. 99 | server { 100 | listen 8080; 101 | location / { 102 | root html; 103 | } 104 | } 105 | 106 | upstream http-cluster { 107 | # simple round-robin 108 | server 127.0.0.1:8080; 109 | server 127.0.0.2:81; 110 | 111 | check interval=3000 rise=2 fall=5 timeout=5000 type=http; 112 | check_http_send "GET / HTTP/1.0\r\n\r\n"; 113 | check_http_expect_alive http_2xx http_3xx; 114 | } 115 | } 116 | 117 | stream { 118 | upstream tcp-cluster { 119 | # simple round-robin 120 | server 127.0.0.1:22; 121 | server 192.168.0.2:22; 122 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=tcp; 123 | } 124 | server { 125 | listen 522; 126 | proxy_pass tcp-cluster; 127 | } 128 | 129 | upstream udp-cluster { 130 | # simple round-robin 131 | server 127.0.0.1:53; 132 | server 8.8.8.8:53; 133 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=udp; 134 | } 135 | server { 136 | listen 53 udp; 137 | proxy_pass udp-cluster; 138 | } 139 | 140 | } 141 | ``` 142 | 143 | **status interface** 144 | 145 | One typical output is(json format) 146 | ``` python 147 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# curl localhost/status 148 | {"servers": { 149 | "total": 6, 150 | "generation": 3, 151 | "http": [ 152 | {"index": 0, "upstream": "http-cluster", "name": "127.0.0.1:8080", "status": "up", "rise": 119, "fall": 0, "type": "http", "port": 0}, 153 | {"index": 1, "upstream": "http-cluster", "name": "127.0.0.2:81", "status": "down", "rise": 0, "fall": 120, "type": "http", "port": 0} 154 | ], 155 | "stream": [ 156 | {"index": 0, "upstream": "tcp-cluster", "name": "127.0.0.1:22", "status": "up", "rise": 22, "fall": 0, "type": "tcp", "port": 0}, 157 | {"index": 1, "upstream": "tcp-cluster", "name": "192.168.0.2:22", "status": "down", "rise": 0, "fall": 7, "type": "tcp", "port": 0}, 158 | {"index": 2, "upstream": "udp-cluster", "name": "127.0.0.1:53", "status": "down", "rise": 0, "fall": 120, "type": "udp", "port": 0}, 159 | {"index": 3, "upstream": "udp-cluster", "name": "8.8.8.8:53", "status": "up", "rise": 3, "fall": 0, "type": "udp", "port": 0} 160 | ] 161 | }} 162 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# 163 | ``` 164 | or (prometheus format) 165 | ``` python 166 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# curl localhost/status 167 | # HELP nginx_upstream_count_total Nginx total number of servers 168 | # TYPE nginx_upstream_count_total gauge 169 | nginx_upstream_count_total 6 170 | # HELP nginx_upstream_count_up Nginx total number of servers that are UP 171 | # TYPE nginx_upstream_count_up gauge 172 | nginx_upstream_count_up 0 173 | # HELP nginx_upstream_count_down Nginx total number of servers that are DOWN 174 | # TYPE nginx_upstream_count_down gauge 175 | nginx_upstream_count_down 6 176 | # HELP nginx_upstream_count_generation Nginx generation 177 | # TYPE nginx_upstream_count_generation gauge 178 | nginx_upstream_count_generation 1 179 | # HELP nginx_upstream_server_rise Nginx rise counter 180 | # TYPE nginx_upstream_server_rise counter 181 | nginx_upstream_server_rise{index="0",upstream_type="http",upstream="http-cluster",name="127.0.0.1:8082",status="down",type="http",port="0"} 0 182 | nginx_upstream_server_rise{index="1",upstream_type="http",upstream="http-cluster",name="127.0.0.2:8082",status="down",type="http",port="0"} 0 183 | nginx_upstream_server_rise{index="1",upstream_type="stream",upstream="tcp-cluster",name="192.168.0.2:22",status="down",type="tcp",port="0"} 0 184 | nginx_upstream_server_rise{index="2",upstream_type="stream",upstream="udp-cluster",name="127.0.0.1:5432",status="down",type="udp",port="0"} 0 185 | nginx_upstream_server_rise{index="4",upstream_type="stream",upstream="http-cluster2",name="127.0.0.1:8082",status="down",type="http",port="0"} 0 186 | nginx_upstream_server_rise{index="5",upstream_type="stream",upstream="http-cluster2",name="127.0.0.2:8082",status="down",type="http",port="0"} 0 187 | # HELP nginx_upstream_server_fall Nginx fall counter 188 | # TYPE nginx_upstream_server_fall counter 189 | nginx_upstream_server_fall{index="0",upstream_type="http",upstream="http-cluster",name="127.0.0.1:8082",status="down",type="http",port="0"} 41 190 | nginx_upstream_server_fall{index="1",upstream_type="http",upstream="http-cluster",name="127.0.0.2:8082",status="down",type="http",port="0"} 42 191 | nginx_upstream_server_fall{index="1",upstream_type="stream",upstream="tcp-cluster",name="192.168.0.2:22",status="down",type="tcp",port="0"} 14 192 | nginx_upstream_server_fall{index="2",upstream_type="stream",upstream="udp-cluster",name="127.0.0.1:5432",status="down",type="udp",port="0"} 40 193 | nginx_upstream_server_fall{index="4",upstream_type="stream",upstream="http-cluster2",name="127.0.0.1:8082",status="down",type="http",port="0"} 40 194 | nginx_upstream_server_fall{index="5",upstream_type="stream",upstream="http-cluster2",name="127.0.0.2:8082",status="down",type="http",port="0"} 43 195 | # HELP nginx_upstream_server_active Nginx active 1 for UP / 0 for DOWN 196 | # TYPE nginx_upstream_server_active gauge 197 | nginx_upstream_server_active{index="0",upstream_type="http",upstream="http-cluster",name="127.0.0.1:8082",type="http",port="0"} 0 198 | nginx_upstream_server_active{index="1",upstream_type="http",upstream="http-cluster",name="127.0.0.2:8082",type="http",port="0"} 0 199 | nginx_upstream_server_active{index="1",upstream_type="stream",upstream="tcp-cluster",name="192.168.0.2:22",type="tcp",port="0"} 0 200 | nginx_upstream_server_active{index="2",upstream_type="stream",upstream="udp-cluster",name="127.0.0.1:5432",type="udp",port="0"} 0 201 | nginx_upstream_server_active{index="4",upstream_type="stream",upstream="http-cluster2",name="127.0.0.1:8082",type="http",port="0"} 0 202 | nginx_upstream_server_active{index="5",upstream_type="stream",upstream="http-cluster2",name="127.0.0.2:8082",type="http",port="0"} 0 203 | root@changxun-PC:~/nginx-dev/ngx_healthcheck_module# 204 | ``` 205 | 206 | [Back to TOC](#table-of-contents) 207 | 208 | Synopsis 209 | ======== 210 | 211 | check 212 | ----- 213 | 214 | `Syntax` 215 | > check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true|false] [type=tcp|udp|http] [port=check_port] 216 | 217 | `Default`: interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp 218 | 219 | `Context`: http/upstream || stream/upstream 220 | 221 | This command can open the back-end server health check function. 222 | 223 | `Detail` 224 | 225 | - `interval`: the interval of the health check packet sent to the backend. 226 | - `fall` (`fall_count`): the server is considered down if the number of consecutive failures reaches fall_count. 227 | - `rise` (`rise_count`): the server is considered up if the number of consecutive successes reaches rise_count. 228 | - `timeout`: timeout for the back-end health request. 229 | - `default_down`: set the initial state of the server, if it is true, it means that the default is down, if it is false, is up. 230 | The default value is true, which is the beginning of the server that is not available, to wait for the health check package reaches a certain number of times after the success will be considered healthy. 231 | - `type`: type of health check pack, now supports the following types 232 | - `tcp`: simple tcp connection, if the connection is successful, it shows the back-end normal. 233 | - `udp`: simple to send udp packets, if you receive icmp error (host or port unreachable), it shows the back-end exception.(Only UDP type checking is supported in the stream configuration block) 234 | - `http`: send an HTTP request, by the state of the back-end reply packet to determine whether the back-end survival. 235 | 236 | A example as followed: 237 | ```nginx 238 | stream { 239 | upstream tcp-cluster { 240 | # simple round-robin 241 | server 127.0.0.1:22; 242 | server 192.168.0.2:22; 243 | check interval=3000 rise=2 fall=5 timeout=5000 default_down=true type=tcp; 244 | } 245 | server { 246 | listen 522; 247 | proxy_pass tcp-cluster; 248 | } 249 | ... 250 | } 251 | ``` 252 | 253 | healthcheck 254 | ----------- 255 | 256 | `Syntax`: healthcheck_status [html|csv|json|prometheus] 257 | 258 | `Default`: healthcheck_status html 259 | 260 | `Context`: http/server/location 261 | 262 | A example as followed: 263 | ```nginx 264 | http { 265 | server { 266 | listen 80; 267 | 268 | # status interface 269 | location /status { 270 | healthcheck_status; 271 | } 272 | ... 273 | } 274 | ``` 275 | 276 | You can specify the default display format. The formats can be `html`, 277 | `csv` or `json`. The default type is `html`. It also supports to specify 278 | the format by the request argument. Suppose your `check_status` location 279 | is '/status', the argument of `format` can change the display page's 280 | format. You can do like this: 281 | 282 | /status?format=html 283 | 284 | /status?format=csv 285 | 286 | /status?format=json 287 | 288 | /status?format=prometheus 289 | 290 | At present, you can fetch the list of servers with the same status by 291 | the argument of `status`. For example: 292 | 293 | /status?format=json&status=down 294 | 295 | /status?format=html&status=down 296 | 297 | /status?format=csv&status=up 298 | 299 | /status?format=prometheus&status=up 300 | 301 | 302 | [Back to TOC](#table-of-contents) 303 | 304 | 305 | Todo List 306 | ========= 307 | 308 | - add testcase. 309 | - code style. 310 | - feature enhance. 311 | 312 | [Back to TOC](#table-of-contents) 313 | 314 | Bugs and Patches 315 | ================ 316 | 317 | Please report bugs 318 | 319 | - create [GitHub Issue](http://github.com/zhouchangxun/ngx_healthcheck_module/issues), 320 | 321 | or submit patches by 322 | 323 | - new [Pull request](https://github.com/zhouchangxun/ngx_healthcheck_module/pull/new/master) 324 | 325 | [Back to TOC](#table-of-contents) 326 | 327 | Author 328 | ====== 329 | 330 | Chance Chou (周长勋) . 331 | 332 | [Back to TOC](#table-of-contents) 333 | 334 | Copyright and License 335 | ===================== 336 | 337 | The health check part is based on Yaoweibin's 338 | healthcheck module nginx_upstream_check_module 339 | (); 340 | 341 | This module is licensed under the BSD license. 342 | 343 | Copyright (C) 2017-, by Changxun Zhou 344 | 345 | Copyright (C) 2014 by Weibin Yao 346 | 347 | All rights reserved. 348 | 349 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 350 | 351 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 352 | 353 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 354 | 355 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 356 | 357 | [Back to TOC](#table-of-contents) 358 | 359 | See Also 360 | ======== 361 | 362 | * nginx: http://nginx.org 363 | 364 | [Back to TOC](#table-of-contents) 365 | 366 | -------------------------------------------------------------------------------- /nginx_healthcheck_for_nginx_1.19+.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c 2 | index 6c247b5..1ae9cce 100644 3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c 4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c 5 | @@ -9,6 +9,9 @@ 6 | #include 7 | #include 8 | 9 | +#if (NGX_HTTP_UPSTREAM_CHECK) 10 | +#include "ngx_http_upstream_check_module.h" 11 | +#endif 12 | 13 | typedef struct { 14 | uint32_t hash; 15 | @@ -238,6 +241,14 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 16 | goto next; 17 | } 18 | 19 | +#if (NGX_HTTP_UPSTREAM_CHECK) 20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 21 | + "get hash peer, check_index: %ui", peer->check_index); 22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 23 | + goto next; 24 | + } 25 | +#endif 26 | + 27 | if (peer->max_fails 28 | && peer->fails >= peer->max_fails 29 | && now - peer->checked <= peer->fail_timeout) 30 | @@ -560,6 +571,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 31 | continue; 32 | } 33 | 34 | +#if (NGX_HTTP_UPSTREAM_CHECK) 35 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 36 | + "get consistent_hash peer, check_index: %ui", 37 | + peer->check_index); 38 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 39 | + continue; 40 | + } 41 | +#endif 42 | + 43 | if (peer->server.len != server->len 44 | || ngx_strncmp(peer->server.data, server->data, server->len) 45 | != 0) 46 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c 47 | index 1fa01d9..366aca9 100644 48 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c 49 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c 50 | @@ -9,6 +9,9 @@ 51 | #include 52 | #include 53 | 54 | +#if (NGX_HTTP_UPSTREAM_CHECK) 55 | +#include "ngx_http_upstream_check_module.h" 56 | +#endif 57 | 58 | typedef struct { 59 | /* the round robin data must be first */ 60 | @@ -208,6 +211,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) 61 | goto next; 62 | } 63 | 64 | +#if (NGX_HTTP_UPSTREAM_CHECK) 65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 66 | + "get ip_hash peer, check_index: %ui", 67 | + peer->check_index); 68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 69 | + goto next; 70 | + } 71 | +#endif 72 | + 73 | if (peer->max_fails 74 | && peer->fails >= peer->max_fails 75 | && now - peer->checked <= peer->fail_timeout) 76 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c 77 | index ebe0627..94f1883 100644 78 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c 79 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c 80 | @@ -9,6 +9,10 @@ 81 | #include 82 | #include 83 | 84 | +#if (NGX_HTTP_UPSTREAM_CHECK) 85 | +#include "ngx_http_upstream_check_module.h" 86 | +#endif 87 | + 88 | 89 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, 90 | ngx_http_upstream_srv_conf_t *us); 91 | @@ -147,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 92 | continue; 93 | } 94 | 95 | +#if (NGX_HTTP_UPSTREAM_CHECK) 96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 97 | + "get least_conn peer, check_index: %ui", 98 | + peer->check_index); 99 | + 100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 101 | + continue; 102 | + } 103 | +#endif 104 | + 105 | if (peer->max_fails 106 | && peer->fails >= peer->max_fails 107 | && now - peer->checked <= peer->fail_timeout) 108 | @@ -202,6 +216,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 109 | continue; 110 | } 111 | 112 | +#if (NGX_HTTP_UPSTREAM_CHECK) 113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 114 | + "get least_conn peer, check_index: %ui", 115 | + peer->check_index); 116 | + 117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 118 | + continue; 119 | + } 120 | +#endif 121 | + 122 | if (peer->conns * best->weight != best->conns * peer->weight) { 123 | continue; 124 | } 125 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c 126 | index f72de3e..601de8d 100644 127 | --- a/src/http/ngx_http_upstream_round_robin.c 128 | +++ b/src/http/ngx_http_upstream_round_robin.c 129 | @@ -9,6 +9,10 @@ 130 | #include 131 | #include 132 | 133 | +#if (NGX_HTTP_UPSTREAM_CHECK) 134 | +#include "ngx_http_upstream_check_module.h" 135 | +#endif 136 | + 137 | 138 | #define ngx_http_upstream_tries(p) ((p)->tries \ 139 | + ((p)->next ? (p)->next->tries : 0)) 140 | @@ -98,6 +102,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 141 | peer[n].down = server[i].down; 142 | peer[n].server = server[i].name; 143 | 144 | +#if (NGX_HTTP_UPSTREAM_CHECK) 145 | + if (!server[i].down) { 146 | + peer[n].check_index = 147 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 148 | + } else { 149 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 150 | + } 151 | +#endif 152 | + 153 | *peerp = &peer[n]; 154 | peerp = &peer[n].next; 155 | n++; 156 | @@ -162,6 +175,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 157 | peer[n].down = server[i].down; 158 | peer[n].server = server[i].name; 159 | 160 | +#if (NGX_HTTP_UPSTREAM_CHECK) 161 | + if (!server[i].down) { 162 | + peer[n].check_index = 163 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 164 | + } 165 | + else { 166 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 167 | + } 168 | +#endif 169 | + 170 | *peerp = &peer[n]; 171 | peerp = &peer[n].next; 172 | n++; 173 | @@ -228,6 +251,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 174 | peer[i].max_conns = 0; 175 | peer[i].max_fails = 1; 176 | peer[i].fail_timeout = 10; 177 | +#if (NGX_HTTP_UPSTREAM_CHECK) 178 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 179 | +#endif 180 | *peerp = &peer[i]; 181 | peerp = &peer[i].next; 182 | } 183 | @@ -344,6 +370,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 184 | peer[0].max_conns = 0; 185 | peer[0].max_fails = 1; 186 | peer[0].fail_timeout = 10; 187 | +#if (NGX_HTTP_UPSTREAM_CHECK) 188 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 189 | +#endif 190 | peers->peer = peer; 191 | 192 | } else { 193 | @@ -378,6 +407,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 194 | peer[i].max_conns = 0; 195 | peer[i].max_fails = 1; 196 | peer[i].fail_timeout = 10; 197 | +#if (NGX_HTTP_UPSTREAM_CHECK) 198 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 199 | +#endif 200 | *peerp = &peer[i]; 201 | peerp = &peer[i].next; 202 | } 203 | @@ -443,6 +475,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 204 | goto failed; 205 | } 206 | 207 | +#if (NGX_HTTP_UPSTREAM_CHECK) 208 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 209 | + goto failed; 210 | + } 211 | +#endif 212 | + 213 | rrp->current = peer; 214 | 215 | } else { 216 | @@ -537,6 +575,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) 217 | continue; 218 | } 219 | 220 | +#if (NGX_HTTP_UPSTREAM_CHECK) 221 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 222 | + continue; 223 | + } 224 | +#endif 225 | + 226 | if (peer->max_fails 227 | && peer->fails >= peer->max_fails 228 | && now - peer->checked <= peer->fail_timeout) 229 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h 230 | index 45f258d..dee91d0 100644 231 | --- a/src/http/ngx_http_upstream_round_robin.h 232 | +++ b/src/http/ngx_http_upstream_round_robin.h 233 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s { 234 | ngx_msec_t slow_start; 235 | ngx_msec_t start_time; 236 | 237 | +#if (NGX_HTTP_UPSTREAM_CHECK) 238 | + ngx_uint_t check_index; 239 | +#endif 240 | + 241 | ngx_uint_t down; 242 | 243 | #if (NGX_HTTP_SSL || NGX_COMPAT) 244 | diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c 245 | index 4fa9a2d..96724a1 100644 246 | --- a/src/stream/ngx_stream_upstream_hash_module.c 247 | +++ b/src/stream/ngx_stream_upstream_hash_module.c 248 | @@ -8,6 +8,9 @@ 249 | #include 250 | #include 251 | #include 252 | +#if (NGX_STREAM_UPSTREAM_CHECK) 253 | +#include "ngx_stream_upstream_check_module.h" 254 | +#endif 255 | 256 | 257 | typedef struct { 258 | @@ -236,6 +239,16 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 259 | ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); 260 | goto next; 261 | } 262 | + 263 | +#if (NGX_STREAM_UPSTREAM_CHECK) 264 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 265 | + "(stream_module)get least_conn peer, check_index: %ui", 266 | + peer->check_index); 267 | + 268 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 269 | + goto next; 270 | + } 271 | +#endif 272 | 273 | if (peer->max_fails 274 | && peer->fails >= peer->max_fails 275 | @@ -550,6 +563,16 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 276 | continue; 277 | } 278 | 279 | +#if (NGX_STREAM_UPSTREAM_CHECK) 280 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 281 | + "(stream_module)get_chash_peer, check_index: %ui", 282 | + peer->check_index); 283 | + 284 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 285 | + continue; 286 | + } 287 | +#endif 288 | + 289 | if (peer->max_fails 290 | && peer->fails >= peer->max_fails 291 | && now - peer->checked <= peer->fail_timeout) 292 | diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c 293 | index 739b20a..b805110 100644 294 | --- a/src/stream/ngx_stream_upstream_least_conn_module.c 295 | +++ b/src/stream/ngx_stream_upstream_least_conn_module.c 296 | @@ -8,6 +8,9 @@ 297 | #include 298 | #include 299 | #include 300 | +#if (NGX_STREAM_UPSTREAM_CHECK) 301 | +#include "ngx_stream_upstream_check_module.h" 302 | +#endif 303 | 304 | 305 | static ngx_int_t ngx_stream_upstream_init_least_conn_peer( 306 | @@ -142,6 +145,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 307 | if (peer->down) { 308 | continue; 309 | } 310 | +#if (NGX_STREAM_UPSTREAM_CHECK) 311 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 312 | + "(stream_module)get least_conn peer, check_index: %ui", 313 | + peer->check_index); 314 | + 315 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 316 | + continue; 317 | + } 318 | +#endif 319 | 320 | if (peer->max_fails 321 | && peer->fails >= peer->max_fails 322 | @@ -197,7 +209,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 323 | if (peer->down) { 324 | continue; 325 | } 326 | +#if (NGX_STREAM_UPSTREAM_CHECK) 327 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 328 | + "(stream_module)get least_conn peer, check_index: %ui", 329 | + peer->check_index); 330 | 331 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 332 | + continue; 333 | + } 334 | +#endif 335 | if (peer->conns * best->weight != best->conns * peer->weight) { 336 | continue; 337 | } 338 | diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c 339 | index 36e2ec5..f3e5ea7 100644 340 | --- a/src/stream/ngx_stream_upstream_round_robin.c 341 | +++ b/src/stream/ngx_stream_upstream_round_robin.c 342 | @@ -9,6 +9,10 @@ 343 | #include 344 | #include 345 | 346 | +#if (NGX_STREAM_UPSTREAM_CHECK) 347 | +#include "ngx_stream_upstream_check_module.h" 348 | +#endif 349 | + 350 | 351 | #define ngx_stream_upstream_tries(p) ((p)->tries \ 352 | + ((p)->next ? (p)->next->tries : 0)) 353 | @@ -104,6 +108,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 354 | peer[n].down = server[i].down; 355 | peer[n].server = server[i].name; 356 | 357 | +#if (NGX_STREAM_UPSTREAM_CHECK) 358 | + if (!server[i].down) { 359 | + peer[n].check_index = 360 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 361 | + } 362 | + else { 363 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 364 | + } 365 | +#endif 366 | + 367 | *peerp = &peer[n]; 368 | peerp = &peer[n].next; 369 | n++; 370 | @@ -168,6 +182,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 371 | peer[n].down = server[i].down; 372 | peer[n].server = server[i].name; 373 | 374 | +#if (NGX_STREAM_UPSTREAM_CHECK) 375 | + if (!server[i].down) { 376 | + peer[n].check_index = 377 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 378 | + } 379 | + else { 380 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 381 | + } 382 | +#endif 383 | + 384 | *peerp = &peer[n]; 385 | peerp = &peer[n].next; 386 | n++; 387 | @@ -234,6 +258,9 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 388 | peer[i].max_conns = 0; 389 | peer[i].max_fails = 1; 390 | peer[i].fail_timeout = 10; 391 | +#if (NGX_STREAM_UPSTREAM_CHECK) 392 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 393 | +#endif 394 | *peerp = &peer[i]; 395 | peerp = &peer[i].next; 396 | } 397 | @@ -354,6 +381,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 398 | peer[0].max_conns = 0; 399 | peer[0].max_fails = 1; 400 | peer[0].fail_timeout = 10; 401 | +#if (NGX_STREAM_UPSTREAM_CHECK) 402 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 403 | +#endif 404 | peers->peer = peer; 405 | 406 | } else { 407 | @@ -388,6 +418,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 408 | peer[i].max_conns = 0; 409 | peer[i].max_fails = 1; 410 | peer[i].fail_timeout = 10; 411 | +#if (NGX_STREAM_UPSTREAM_CHECK) 412 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 413 | +#endif 414 | *peerp = &peer[i]; 415 | peerp = &peer[i].next; 416 | } 417 | @@ -451,7 +484,11 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 418 | if (peer->max_conns && peer->conns >= peer->max_conns) { 419 | goto failed; 420 | } 421 | - 422 | +#if (NGX_STREAM_UPSTREAM_CHECK) 423 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 424 | + goto failed; 425 | + } 426 | +#endif 427 | rrp->current = peer; 428 | 429 | } else { 430 | @@ -556,7 +593,11 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) 431 | if (peer->max_conns && peer->conns >= peer->max_conns) { 432 | continue; 433 | } 434 | - 435 | +#if (NGX_STREAM_UPSTREAM_CHECK) 436 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 437 | + continue; 438 | + } 439 | +#endif 440 | peer->current_weight += peer->effective_weight; 441 | total += peer->effective_weight; 442 | 443 | diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h 444 | index 35d9fce..ff6398e 100644 445 | --- a/src/stream/ngx_stream_upstream_round_robin.h 446 | +++ b/src/stream/ngx_stream_upstream_round_robin.h 447 | @@ -49,6 +49,10 @@ struct ngx_stream_upstream_rr_peer_s { 448 | 449 | ngx_stream_upstream_rr_peer_t *next; 450 | 451 | +#if (NGX_STREAM_UPSTREAM_CHECK) 452 | + ngx_uint_t check_index; 453 | +#endif 454 | + 455 | NGX_COMPAT_BEGIN(25) 456 | NGX_COMPAT_END 457 | }; 458 | -------------------------------------------------------------------------------- /nginx_healthcheck_for_nginx_1.16+.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c 2 | index 6c247b5..1ae9cce 100644 3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c 4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c 5 | @@ -9,6 +9,9 @@ 6 | #include 7 | #include 8 | 9 | +#if (NGX_HTTP_UPSTREAM_CHECK) 10 | +#include "ngx_http_upstream_check_module.h" 11 | +#endif 12 | 13 | typedef struct { 14 | uint32_t hash; 15 | @@ -238,6 +241,14 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 16 | goto next; 17 | } 18 | 19 | +#if (NGX_HTTP_UPSTREAM_CHECK) 20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 21 | + "get hash peer, check_index: %ui", peer->check_index); 22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 23 | + goto next; 24 | + } 25 | +#endif 26 | + 27 | if (peer->max_fails 28 | && peer->fails >= peer->max_fails 29 | && now - peer->checked <= peer->fail_timeout) 30 | @@ -560,6 +571,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 31 | continue; 32 | } 33 | 34 | +#if (NGX_HTTP_UPSTREAM_CHECK) 35 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 36 | + "get consistent_hash peer, check_index: %ui", 37 | + peer->check_index); 38 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 39 | + continue; 40 | + } 41 | +#endif 42 | + 43 | if (peer->server.len != server->len 44 | || ngx_strncmp(peer->server.data, server->data, server->len) 45 | != 0) 46 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c 47 | index 1fa01d9..366aca9 100644 48 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c 49 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c 50 | @@ -9,6 +9,9 @@ 51 | #include 52 | #include 53 | 54 | +#if (NGX_HTTP_UPSTREAM_CHECK) 55 | +#include "ngx_http_upstream_check_module.h" 56 | +#endif 57 | 58 | typedef struct { 59 | /* the round robin data must be first */ 60 | @@ -208,6 +211,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) 61 | goto next; 62 | } 63 | 64 | +#if (NGX_HTTP_UPSTREAM_CHECK) 65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 66 | + "get ip_hash peer, check_index: %ui", 67 | + peer->check_index); 68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 69 | + goto next; 70 | + } 71 | +#endif 72 | + 73 | if (peer->max_fails 74 | && peer->fails >= peer->max_fails 75 | && now - peer->checked <= peer->fail_timeout) 76 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c 77 | index ebe0627..94f1883 100644 78 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c 79 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c 80 | @@ -9,6 +9,10 @@ 81 | #include 82 | #include 83 | 84 | +#if (NGX_HTTP_UPSTREAM_CHECK) 85 | +#include "ngx_http_upstream_check_module.h" 86 | +#endif 87 | + 88 | 89 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, 90 | ngx_http_upstream_srv_conf_t *us); 91 | @@ -147,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 92 | continue; 93 | } 94 | 95 | +#if (NGX_HTTP_UPSTREAM_CHECK) 96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 97 | + "get least_conn peer, check_index: %ui", 98 | + peer->check_index); 99 | + 100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 101 | + continue; 102 | + } 103 | +#endif 104 | + 105 | if (peer->max_fails 106 | && peer->fails >= peer->max_fails 107 | && now - peer->checked <= peer->fail_timeout) 108 | @@ -202,6 +216,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 109 | continue; 110 | } 111 | 112 | +#if (NGX_HTTP_UPSTREAM_CHECK) 113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 114 | + "get least_conn peer, check_index: %ui", 115 | + peer->check_index); 116 | + 117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 118 | + continue; 119 | + } 120 | +#endif 121 | + 122 | if (peer->conns * best->weight != best->conns * peer->weight) { 123 | continue; 124 | } 125 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c 126 | index f72de3e..601de8d 100644 127 | --- a/src/http/ngx_http_upstream_round_robin.c 128 | +++ b/src/http/ngx_http_upstream_round_robin.c 129 | @@ -9,6 +9,10 @@ 130 | #include 131 | #include 132 | 133 | +#if (NGX_HTTP_UPSTREAM_CHECK) 134 | +#include "ngx_http_upstream_check_module.h" 135 | +#endif 136 | + 137 | 138 | #define ngx_http_upstream_tries(p) ((p)->number \ 139 | + ((p)->next ? (p)->next->number : 0)) 140 | @@ -98,6 +102,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 141 | peer[n].down = server[i].down; 142 | peer[n].server = server[i].name; 143 | 144 | +#if (NGX_HTTP_UPSTREAM_CHECK) 145 | + if (!server[i].down) { 146 | + peer[n].check_index = 147 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 148 | + } else { 149 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 150 | + } 151 | +#endif 152 | + 153 | *peerp = &peer[n]; 154 | peerp = &peer[n].next; 155 | n++; 156 | @@ -162,6 +175,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 157 | peer[n].down = server[i].down; 158 | peer[n].server = server[i].name; 159 | 160 | +#if (NGX_HTTP_UPSTREAM_CHECK) 161 | + if (!server[i].down) { 162 | + peer[n].check_index = 163 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 164 | + } 165 | + else { 166 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 167 | + } 168 | +#endif 169 | + 170 | *peerp = &peer[n]; 171 | peerp = &peer[n].next; 172 | n++; 173 | @@ -228,6 +251,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 174 | peer[i].max_conns = 0; 175 | peer[i].max_fails = 1; 176 | peer[i].fail_timeout = 10; 177 | +#if (NGX_HTTP_UPSTREAM_CHECK) 178 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 179 | +#endif 180 | *peerp = &peer[i]; 181 | peerp = &peer[i].next; 182 | } 183 | @@ -344,6 +370,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 184 | peer[0].max_conns = 0; 185 | peer[0].max_fails = 1; 186 | peer[0].fail_timeout = 10; 187 | +#if (NGX_HTTP_UPSTREAM_CHECK) 188 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 189 | +#endif 190 | peers->peer = peer; 191 | 192 | } else { 193 | @@ -378,6 +407,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 194 | peer[i].max_conns = 0; 195 | peer[i].max_fails = 1; 196 | peer[i].fail_timeout = 10; 197 | +#if (NGX_HTTP_UPSTREAM_CHECK) 198 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 199 | +#endif 200 | *peerp = &peer[i]; 201 | peerp = &peer[i].next; 202 | } 203 | @@ -443,6 +475,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 204 | goto failed; 205 | } 206 | 207 | +#if (NGX_HTTP_UPSTREAM_CHECK) 208 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 209 | + goto failed; 210 | + } 211 | +#endif 212 | + 213 | rrp->current = peer; 214 | 215 | } else { 216 | @@ -537,6 +575,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) 217 | continue; 218 | } 219 | 220 | +#if (NGX_HTTP_UPSTREAM_CHECK) 221 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 222 | + continue; 223 | + } 224 | +#endif 225 | + 226 | if (peer->max_fails 227 | && peer->fails >= peer->max_fails 228 | && now - peer->checked <= peer->fail_timeout) 229 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h 230 | index 45f258d..dee91d0 100644 231 | --- a/src/http/ngx_http_upstream_round_robin.h 232 | +++ b/src/http/ngx_http_upstream_round_robin.h 233 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s { 234 | ngx_msec_t slow_start; 235 | ngx_msec_t start_time; 236 | 237 | +#if (NGX_HTTP_UPSTREAM_CHECK) 238 | + ngx_uint_t check_index; 239 | +#endif 240 | + 241 | ngx_uint_t down; 242 | 243 | #if (NGX_HTTP_SSL || NGX_COMPAT) 244 | diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c 245 | index 4fa9a2d..96724a1 100644 246 | --- a/src/stream/ngx_stream_upstream_hash_module.c 247 | +++ b/src/stream/ngx_stream_upstream_hash_module.c 248 | @@ -8,6 +8,9 @@ 249 | #include 250 | #include 251 | #include 252 | +#if (NGX_STREAM_UPSTREAM_CHECK) 253 | +#include "ngx_stream_upstream_check_module.h" 254 | +#endif 255 | 256 | 257 | typedef struct { 258 | @@ -236,6 +239,16 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 259 | ngx_stream_upstream_rr_peer_unlock(hp->rrp.peers, peer); 260 | goto next; 261 | } 262 | + 263 | +#if (NGX_STREAM_UPSTREAM_CHECK) 264 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 265 | + "(stream_module)get least_conn peer, check_index: %ui", 266 | + peer->check_index); 267 | + 268 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 269 | + goto next; 270 | + } 271 | +#endif 272 | 273 | if (peer->max_fails 274 | && peer->fails >= peer->max_fails 275 | @@ -550,6 +563,16 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 276 | continue; 277 | } 278 | 279 | +#if (NGX_STREAM_UPSTREAM_CHECK) 280 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 281 | + "(stream_module)get_chash_peer, check_index: %ui", 282 | + peer->check_index); 283 | + 284 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 285 | + continue; 286 | + } 287 | +#endif 288 | + 289 | if (peer->max_fails 290 | && peer->fails >= peer->max_fails 291 | && now - peer->checked <= peer->fail_timeout) 292 | diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c 293 | index 739b20a..b805110 100644 294 | --- a/src/stream/ngx_stream_upstream_least_conn_module.c 295 | +++ b/src/stream/ngx_stream_upstream_least_conn_module.c 296 | @@ -8,6 +8,9 @@ 297 | #include 298 | #include 299 | #include 300 | +#if (NGX_STREAM_UPSTREAM_CHECK) 301 | +#include "ngx_stream_upstream_check_module.h" 302 | +#endif 303 | 304 | 305 | static ngx_int_t ngx_stream_upstream_init_least_conn_peer( 306 | @@ -142,6 +145,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 307 | if (peer->down) { 308 | continue; 309 | } 310 | +#if (NGX_STREAM_UPSTREAM_CHECK) 311 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 312 | + "(stream_module)get least_conn peer, check_index: %ui", 313 | + peer->check_index); 314 | + 315 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 316 | + continue; 317 | + } 318 | +#endif 319 | 320 | if (peer->max_fails 321 | && peer->fails >= peer->max_fails 322 | @@ -197,7 +209,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 323 | if (peer->down) { 324 | continue; 325 | } 326 | +#if (NGX_STREAM_UPSTREAM_CHECK) 327 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 328 | + "(stream_module)get least_conn peer, check_index: %ui", 329 | + peer->check_index); 330 | 331 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 332 | + continue; 333 | + } 334 | +#endif 335 | if (peer->conns * best->weight != best->conns * peer->weight) { 336 | continue; 337 | } 338 | diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c 339 | index 36e2ec5..f3e5ea7 100644 340 | --- a/src/stream/ngx_stream_upstream_round_robin.c 341 | +++ b/src/stream/ngx_stream_upstream_round_robin.c 342 | @@ -9,6 +9,10 @@ 343 | #include 344 | #include 345 | 346 | +#if (NGX_STREAM_UPSTREAM_CHECK) 347 | +#include "ngx_stream_upstream_check_module.h" 348 | +#endif 349 | + 350 | 351 | #define ngx_stream_upstream_tries(p) ((p)->number \ 352 | + ((p)->next ? (p)->next->number : 0)) 353 | @@ -104,6 +108,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 354 | peer[n].down = server[i].down; 355 | peer[n].server = server[i].name; 356 | 357 | +#if (NGX_STREAM_UPSTREAM_CHECK) 358 | + if (!server[i].down) { 359 | + peer[n].check_index = 360 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 361 | + } 362 | + else { 363 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 364 | + } 365 | +#endif 366 | + 367 | *peerp = &peer[n]; 368 | peerp = &peer[n].next; 369 | n++; 370 | @@ -168,6 +182,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 371 | peer[n].down = server[i].down; 372 | peer[n].server = server[i].name; 373 | 374 | +#if (NGX_STREAM_UPSTREAM_CHECK) 375 | + if (!server[i].down) { 376 | + peer[n].check_index = 377 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 378 | + } 379 | + else { 380 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 381 | + } 382 | +#endif 383 | + 384 | *peerp = &peer[n]; 385 | peerp = &peer[n].next; 386 | n++; 387 | @@ -234,6 +258,9 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 388 | peer[i].max_conns = 0; 389 | peer[i].max_fails = 1; 390 | peer[i].fail_timeout = 10; 391 | +#if (NGX_STREAM_UPSTREAM_CHECK) 392 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 393 | +#endif 394 | *peerp = &peer[i]; 395 | peerp = &peer[i].next; 396 | } 397 | @@ -354,6 +381,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 398 | peer[0].max_conns = 0; 399 | peer[0].max_fails = 1; 400 | peer[0].fail_timeout = 10; 401 | +#if (NGX_STREAM_UPSTREAM_CHECK) 402 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 403 | +#endif 404 | peers->peer = peer; 405 | 406 | } else { 407 | @@ -388,6 +418,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 408 | peer[i].max_conns = 0; 409 | peer[i].max_fails = 1; 410 | peer[i].fail_timeout = 10; 411 | +#if (NGX_STREAM_UPSTREAM_CHECK) 412 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 413 | +#endif 414 | *peerp = &peer[i]; 415 | peerp = &peer[i].next; 416 | } 417 | @@ -451,7 +484,11 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 418 | if (peer->max_conns && peer->conns >= peer->max_conns) { 419 | goto failed; 420 | } 421 | - 422 | +#if (NGX_STREAM_UPSTREAM_CHECK) 423 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 424 | + goto failed; 425 | + } 426 | +#endif 427 | rrp->current = peer; 428 | 429 | } else { 430 | @@ -556,7 +593,11 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) 431 | if (peer->max_conns && peer->conns >= peer->max_conns) { 432 | continue; 433 | } 434 | - 435 | +#if (NGX_STREAM_UPSTREAM_CHECK) 436 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 437 | + continue; 438 | + } 439 | +#endif 440 | peer->current_weight += peer->effective_weight; 441 | total += peer->effective_weight; 442 | 443 | diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h 444 | index 35d9fce..ff6398e 100644 445 | --- a/src/stream/ngx_stream_upstream_round_robin.h 446 | +++ b/src/stream/ngx_stream_upstream_round_robin.h 447 | @@ -49,6 +49,10 @@ struct ngx_stream_upstream_rr_peer_s { 448 | 449 | ngx_stream_upstream_rr_peer_t *next; 450 | 451 | +#if (NGX_STREAM_UPSTREAM_CHECK) 452 | + ngx_uint_t check_index; 453 | +#endif 454 | + 455 | NGX_COMPAT_BEGIN(25) 456 | NGX_COMPAT_END 457 | }; 458 | -------------------------------------------------------------------------------- /nginx_healthcheck_for_nginx_1.14+.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c 2 | index d67f34d..5ccdbbe 100644 3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c 4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c 5 | @@ -9,6 +9,9 @@ 6 | #include 7 | #include 8 | 9 | +#if (NGX_HTTP_UPSTREAM_CHECK) 10 | +#include "ngx_http_upstream_check_module.h" 11 | +#endif 12 | 13 | typedef struct { 14 | uint32_t hash; 15 | @@ -235,6 +238,14 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 16 | goto next; 17 | } 18 | 19 | +#if (NGX_HTTP_UPSTREAM_CHECK) 20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 21 | + "get hash peer, check_index: %ui", peer->check_index); 22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 23 | + goto next; 24 | + } 25 | +#endif 26 | + 27 | if (peer->max_fails 28 | && peer->fails >= peer->max_fails 29 | && now - peer->checked <= peer->fail_timeout) 30 | @@ -554,6 +565,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 31 | continue; 32 | } 33 | 34 | +#if (NGX_HTTP_UPSTREAM_CHECK) 35 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 36 | + "get consistent_hash peer, check_index: %ui", 37 | + peer->check_index); 38 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 39 | + continue; 40 | + } 41 | +#endif 42 | + 43 | if (peer->server.len != server->len 44 | || ngx_strncmp(peer->server.data, server->data, server->len) 45 | != 0) 46 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c 47 | index 296108f..135ce5d 100644 48 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c 49 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c 50 | @@ -9,6 +9,9 @@ 51 | #include 52 | #include 53 | 54 | +#if (NGX_HTTP_UPSTREAM_CHECK) 55 | +#include "ngx_http_upstream_check_module.h" 56 | +#endif 57 | 58 | typedef struct { 59 | /* the round robin data must be first */ 60 | @@ -205,6 +208,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) 61 | goto next; 62 | } 63 | 64 | +#if (NGX_HTTP_UPSTREAM_CHECK) 65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 66 | + "get ip_hash peer, check_index: %ui", 67 | + peer->check_index); 68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 69 | + goto next; 70 | + } 71 | +#endif 72 | + 73 | if (peer->max_fails 74 | && peer->fails >= peer->max_fails 75 | && now - peer->checked <= peer->fail_timeout) 76 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c 77 | index ebe0627..94f1883 100644 78 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c 79 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c 80 | @@ -9,6 +9,10 @@ 81 | #include 82 | #include 83 | 84 | +#if (NGX_HTTP_UPSTREAM_CHECK) 85 | +#include "ngx_http_upstream_check_module.h" 86 | +#endif 87 | + 88 | 89 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, 90 | ngx_http_upstream_srv_conf_t *us); 91 | @@ -147,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 92 | continue; 93 | } 94 | 95 | +#if (NGX_HTTP_UPSTREAM_CHECK) 96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 97 | + "get least_conn peer, check_index: %ui", 98 | + peer->check_index); 99 | + 100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 101 | + continue; 102 | + } 103 | +#endif 104 | + 105 | if (peer->max_fails 106 | && peer->fails >= peer->max_fails 107 | && now - peer->checked <= peer->fail_timeout) 108 | @@ -202,6 +216,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 109 | continue; 110 | } 111 | 112 | +#if (NGX_HTTP_UPSTREAM_CHECK) 113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 114 | + "get least_conn peer, check_index: %ui", 115 | + peer->check_index); 116 | + 117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 118 | + continue; 119 | + } 120 | +#endif 121 | + 122 | if (peer->conns * best->weight != best->conns * peer->weight) { 123 | continue; 124 | } 125 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c 126 | index f6051ae..892f2b7 100644 127 | --- a/src/http/ngx_http_upstream_round_robin.c 128 | +++ b/src/http/ngx_http_upstream_round_robin.c 129 | @@ -9,6 +9,10 @@ 130 | #include 131 | #include 132 | 133 | +#if (NGX_HTTP_UPSTREAM_CHECK) 134 | +#include "ngx_http_upstream_check_module.h" 135 | +#endif 136 | + 137 | 138 | #define ngx_http_upstream_tries(p) ((p)->number \ 139 | + ((p)->next ? (p)->next->number : 0)) 140 | @@ -98,6 +102,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 141 | peer[n].down = server[i].down; 142 | peer[n].server = server[i].name; 143 | 144 | +#if (NGX_HTTP_UPSTREAM_CHECK) 145 | + if (!server[i].down) { 146 | + peer[n].check_index = 147 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 148 | + } else { 149 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 150 | + } 151 | +#endif 152 | + 153 | *peerp = &peer[n]; 154 | peerp = &peer[n].next; 155 | n++; 156 | @@ -162,6 +175,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 157 | peer[n].down = server[i].down; 158 | peer[n].server = server[i].name; 159 | 160 | +#if (NGX_HTTP_UPSTREAM_CHECK) 161 | + if (!server[i].down) { 162 | + peer[n].check_index = 163 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 164 | + } 165 | + else { 166 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 167 | + } 168 | +#endif 169 | + 170 | *peerp = &peer[n]; 171 | peerp = &peer[n].next; 172 | n++; 173 | @@ -228,6 +251,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 174 | peer[i].max_conns = 0; 175 | peer[i].max_fails = 1; 176 | peer[i].fail_timeout = 10; 177 | +#if (NGX_HTTP_UPSTREAM_CHECK) 178 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 179 | +#endif 180 | *peerp = &peer[i]; 181 | peerp = &peer[i].next; 182 | } 183 | @@ -344,6 +370,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 184 | peer[0].max_conns = 0; 185 | peer[0].max_fails = 1; 186 | peer[0].fail_timeout = 10; 187 | +#if (NGX_HTTP_UPSTREAM_CHECK) 188 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 189 | +#endif 190 | peers->peer = peer; 191 | 192 | } else { 193 | @@ -378,6 +407,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 194 | peer[i].max_conns = 0; 195 | peer[i].max_fails = 1; 196 | peer[i].fail_timeout = 10; 197 | +#if (NGX_HTTP_UPSTREAM_CHECK) 198 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 199 | +#endif 200 | *peerp = &peer[i]; 201 | peerp = &peer[i].next; 202 | } 203 | @@ -443,6 +475,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 204 | goto failed; 205 | } 206 | 207 | +#if (NGX_HTTP_UPSTREAM_CHECK) 208 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 209 | + goto failed; 210 | + } 211 | +#endif 212 | + 213 | rrp->current = peer; 214 | 215 | } else { 216 | @@ -537,6 +575,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) 217 | continue; 218 | } 219 | 220 | +#if (NGX_HTTP_UPSTREAM_CHECK) 221 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 222 | + continue; 223 | + } 224 | +#endif 225 | + 226 | if (peer->max_fails 227 | && peer->fails >= peer->max_fails 228 | && now - peer->checked <= peer->fail_timeout) 229 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h 230 | index 45f258d..dee91d0 100644 231 | --- a/src/http/ngx_http_upstream_round_robin.h 232 | +++ b/src/http/ngx_http_upstream_round_robin.h 233 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s { 234 | ngx_msec_t slow_start; 235 | ngx_msec_t start_time; 236 | 237 | +#if (NGX_HTTP_UPSTREAM_CHECK) 238 | + ngx_uint_t check_index; 239 | +#endif 240 | + 241 | ngx_uint_t down; 242 | 243 | #if (NGX_HTTP_SSL || NGX_COMPAT) 244 | diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c 245 | index 79ad742..5234b01 100644 246 | --- a/src/stream/ngx_stream_upstream_hash_module.c 247 | +++ b/src/stream/ngx_stream_upstream_hash_module.c 248 | @@ -8,6 +8,9 @@ 249 | #include 250 | #include 251 | #include 252 | +#if (NGX_STREAM_UPSTREAM_CHECK) 253 | +#include "ngx_stream_upstream_check_module.h" 254 | +#endif 255 | 256 | 257 | typedef struct { 258 | @@ -233,7 +236,15 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 259 | if (peer->down) { 260 | goto next; 261 | } 262 | +#if (NGX_STREAM_UPSTREAM_CHECK) 263 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 264 | + "(stream_module)get least_conn peer, check_index: %ui", 265 | + peer->check_index); 266 | 267 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 268 | + goto next; 269 | + } 270 | +#endif 271 | if (peer->max_fails 272 | && peer->fails >= peer->max_fails 273 | && now - peer->checked <= peer->fail_timeout) 274 | @@ -544,6 +555,16 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 275 | continue; 276 | } 277 | 278 | +#if (NGX_STREAM_UPSTREAM_CHECK) 279 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 280 | + "(stream_module)get_chash_peer, check_index: %ui", 281 | + peer->check_index); 282 | + 283 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 284 | + continue; 285 | + } 286 | +#endif 287 | + 288 | if (peer->max_fails 289 | && peer->fails >= peer->max_fails 290 | && now - peer->checked <= peer->fail_timeout) 291 | diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c 292 | index 739b20a..b805110 100644 293 | --- a/src/stream/ngx_stream_upstream_least_conn_module.c 294 | +++ b/src/stream/ngx_stream_upstream_least_conn_module.c 295 | @@ -8,6 +8,9 @@ 296 | #include 297 | #include 298 | #include 299 | +#if (NGX_STREAM_UPSTREAM_CHECK) 300 | +#include "ngx_stream_upstream_check_module.h" 301 | +#endif 302 | 303 | 304 | static ngx_int_t ngx_stream_upstream_init_least_conn_peer( 305 | @@ -142,6 +145,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 306 | if (peer->down) { 307 | continue; 308 | } 309 | +#if (NGX_STREAM_UPSTREAM_CHECK) 310 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 311 | + "(stream_module)get least_conn peer, check_index: %ui", 312 | + peer->check_index); 313 | + 314 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 315 | + continue; 316 | + } 317 | +#endif 318 | 319 | if (peer->max_fails 320 | && peer->fails >= peer->max_fails 321 | @@ -197,7 +209,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 322 | if (peer->down) { 323 | continue; 324 | } 325 | +#if (NGX_STREAM_UPSTREAM_CHECK) 326 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 327 | + "(stream_module)get least_conn peer, check_index: %ui", 328 | + peer->check_index); 329 | 330 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 331 | + continue; 332 | + } 333 | +#endif 334 | if (peer->conns * best->weight != best->conns * peer->weight) { 335 | continue; 336 | } 337 | diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c 338 | index 526de3a..13c4956 100644 339 | --- a/src/stream/ngx_stream_upstream_round_robin.c 340 | +++ b/src/stream/ngx_stream_upstream_round_robin.c 341 | @@ -9,6 +9,10 @@ 342 | #include 343 | #include 344 | 345 | +#if (NGX_STREAM_UPSTREAM_CHECK) 346 | +#include "ngx_stream_upstream_check_module.h" 347 | +#endif 348 | + 349 | 350 | #define ngx_stream_upstream_tries(p) ((p)->number \ 351 | + ((p)->next ? (p)->next->number : 0)) 352 | @@ -104,6 +108,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 353 | peer[n].down = server[i].down; 354 | peer[n].server = server[i].name; 355 | 356 | +#if (NGX_STREAM_UPSTREAM_CHECK) 357 | + if (!server[i].down) { 358 | + peer[n].check_index = 359 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 360 | + } 361 | + else { 362 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 363 | + } 364 | +#endif 365 | + 366 | *peerp = &peer[n]; 367 | peerp = &peer[n].next; 368 | n++; 369 | @@ -168,6 +182,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 370 | peer[n].down = server[i].down; 371 | peer[n].server = server[i].name; 372 | 373 | +#if (NGX_STREAM_UPSTREAM_CHECK) 374 | + if (!server[i].down) { 375 | + peer[n].check_index = 376 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 377 | + } 378 | + else { 379 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 380 | + } 381 | +#endif 382 | + 383 | *peerp = &peer[n]; 384 | peerp = &peer[n].next; 385 | n++; 386 | @@ -234,6 +258,9 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 387 | peer[i].max_conns = 0; 388 | peer[i].max_fails = 1; 389 | peer[i].fail_timeout = 10; 390 | +#if (NGX_STREAM_UPSTREAM_CHECK) 391 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 392 | +#endif 393 | *peerp = &peer[i]; 394 | peerp = &peer[i].next; 395 | } 396 | @@ -354,6 +381,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 397 | peer[0].max_conns = 0; 398 | peer[0].max_fails = 1; 399 | peer[0].fail_timeout = 10; 400 | +#if (NGX_STREAM_UPSTREAM_CHECK) 401 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 402 | +#endif 403 | peers->peer = peer; 404 | 405 | } else { 406 | @@ -388,6 +418,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 407 | peer[i].max_conns = 0; 408 | peer[i].max_fails = 1; 409 | peer[i].fail_timeout = 10; 410 | +#if (NGX_STREAM_UPSTREAM_CHECK) 411 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 412 | +#endif 413 | *peerp = &peer[i]; 414 | peerp = &peer[i].next; 415 | } 416 | @@ -451,7 +484,11 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 417 | if (peer->max_conns && peer->conns >= peer->max_conns) { 418 | goto failed; 419 | } 420 | - 421 | +#if (NGX_STREAM_UPSTREAM_CHECK) 422 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 423 | + goto failed; 424 | + } 425 | +#endif 426 | rrp->current = peer; 427 | 428 | } else { 429 | @@ -556,7 +593,11 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) 430 | if (peer->max_conns && peer->conns >= peer->max_conns) { 431 | continue; 432 | } 433 | - 434 | +#if (NGX_STREAM_UPSTREAM_CHECK) 435 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 436 | + continue; 437 | + } 438 | +#endif 439 | peer->current_weight += peer->effective_weight; 440 | total += peer->effective_weight; 441 | 442 | diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h 443 | index 35d9fce..ff6398e 100644 444 | --- a/src/stream/ngx_stream_upstream_round_robin.h 445 | +++ b/src/stream/ngx_stream_upstream_round_robin.h 446 | @@ -49,6 +49,10 @@ struct ngx_stream_upstream_rr_peer_s { 447 | 448 | ngx_stream_upstream_rr_peer_t *next; 449 | 450 | +#if (NGX_STREAM_UPSTREAM_CHECK) 451 | + ngx_uint_t check_index; 452 | +#endif 453 | + 454 | NGX_COMPAT_BEGIN(25) 455 | NGX_COMPAT_END 456 | }; 457 | -------------------------------------------------------------------------------- /nginx_healthcheck_for_nginx_1.12+.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c 2 | index 6c28c64..6212ee0 100644 3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c 4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c 5 | @@ -9,6 +9,9 @@ 6 | #include 7 | #include 8 | 9 | +#if (NGX_HTTP_UPSTREAM_CHECK) 10 | +#include "ngx_http_upstream_check_module.h" 11 | +#endif 12 | 13 | typedef struct { 14 | uint32_t hash; 15 | @@ -235,6 +238,14 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 16 | goto next; 17 | } 18 | 19 | +#if (NGX_HTTP_UPSTREAM_CHECK) 20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 21 | + "get hash peer, check_index: %ui", peer->check_index); 22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 23 | + goto next; 24 | + } 25 | +#endif 26 | + 27 | if (peer->max_fails 28 | && peer->fails >= peer->max_fails 29 | && now - peer->checked <= peer->fail_timeout) 30 | @@ -538,6 +549,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 31 | continue; 32 | } 33 | 34 | +#if (NGX_HTTP_UPSTREAM_CHECK) 35 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 36 | + "get consistent_hash peer, check_index: %ui", 37 | + peer->check_index); 38 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 39 | + continue; 40 | + } 41 | +#endif 42 | + 43 | if (peer->server.len != server->len 44 | || ngx_strncmp(peer->server.data, server->data, server->len) 45 | != 0) 46 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c 47 | index 296108f..135ce5d 100644 48 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c 49 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c 50 | @@ -9,6 +9,9 @@ 51 | #include 52 | #include 53 | 54 | +#if (NGX_HTTP_UPSTREAM_CHECK) 55 | +#include "ngx_http_upstream_check_module.h" 56 | +#endif 57 | 58 | typedef struct { 59 | /* the round robin data must be first */ 60 | @@ -205,6 +208,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) 61 | goto next; 62 | } 63 | 64 | +#if (NGX_HTTP_UPSTREAM_CHECK) 65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 66 | + "get ip_hash peer, check_index: %ui", 67 | + peer->check_index); 68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 69 | + goto next; 70 | + } 71 | +#endif 72 | + 73 | if (peer->max_fails 74 | && peer->fails >= peer->max_fails 75 | && now - peer->checked <= peer->fail_timeout) 76 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c 77 | index ebe0627..94f1883 100644 78 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c 79 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c 80 | @@ -9,6 +9,10 @@ 81 | #include 82 | #include 83 | 84 | +#if (NGX_HTTP_UPSTREAM_CHECK) 85 | +#include "ngx_http_upstream_check_module.h" 86 | +#endif 87 | + 88 | 89 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, 90 | ngx_http_upstream_srv_conf_t *us); 91 | @@ -147,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 92 | continue; 93 | } 94 | 95 | +#if (NGX_HTTP_UPSTREAM_CHECK) 96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 97 | + "get least_conn peer, check_index: %ui", 98 | + peer->check_index); 99 | + 100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 101 | + continue; 102 | + } 103 | +#endif 104 | + 105 | if (peer->max_fails 106 | && peer->fails >= peer->max_fails 107 | && now - peer->checked <= peer->fail_timeout) 108 | @@ -202,6 +216,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 109 | continue; 110 | } 111 | 112 | +#if (NGX_HTTP_UPSTREAM_CHECK) 113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 114 | + "get least_conn peer, check_index: %ui", 115 | + peer->check_index); 116 | + 117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 118 | + continue; 119 | + } 120 | +#endif 121 | + 122 | if (peer->conns * best->weight != best->conns * peer->weight) { 123 | continue; 124 | } 125 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c 126 | index f6051ae..892f2b7 100644 127 | --- a/src/http/ngx_http_upstream_round_robin.c 128 | +++ b/src/http/ngx_http_upstream_round_robin.c 129 | @@ -9,6 +9,10 @@ 130 | #include 131 | #include 132 | 133 | +#if (NGX_HTTP_UPSTREAM_CHECK) 134 | +#include "ngx_http_upstream_check_module.h" 135 | +#endif 136 | + 137 | 138 | #define ngx_http_upstream_tries(p) ((p)->number \ 139 | + ((p)->next ? (p)->next->number : 0)) 140 | @@ -98,6 +102,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 141 | peer[n].down = server[i].down; 142 | peer[n].server = server[i].name; 143 | 144 | +#if (NGX_HTTP_UPSTREAM_CHECK) 145 | + if (!server[i].down) { 146 | + peer[n].check_index = 147 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 148 | + } else { 149 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 150 | + } 151 | +#endif 152 | + 153 | *peerp = &peer[n]; 154 | peerp = &peer[n].next; 155 | n++; 156 | @@ -162,6 +175,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 157 | peer[n].down = server[i].down; 158 | peer[n].server = server[i].name; 159 | 160 | +#if (NGX_HTTP_UPSTREAM_CHECK) 161 | + if (!server[i].down) { 162 | + peer[n].check_index = 163 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 164 | + } 165 | + else { 166 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 167 | + } 168 | +#endif 169 | + 170 | *peerp = &peer[n]; 171 | peerp = &peer[n].next; 172 | n++; 173 | @@ -228,6 +251,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 174 | peer[i].max_conns = 0; 175 | peer[i].max_fails = 1; 176 | peer[i].fail_timeout = 10; 177 | +#if (NGX_HTTP_UPSTREAM_CHECK) 178 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 179 | +#endif 180 | *peerp = &peer[i]; 181 | peerp = &peer[i].next; 182 | } 183 | @@ -344,6 +370,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 184 | peer[0].max_conns = 0; 185 | peer[0].max_fails = 1; 186 | peer[0].fail_timeout = 10; 187 | +#if (NGX_HTTP_UPSTREAM_CHECK) 188 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 189 | +#endif 190 | peers->peer = peer; 191 | 192 | } else { 193 | @@ -378,6 +407,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 194 | peer[i].max_conns = 0; 195 | peer[i].max_fails = 1; 196 | peer[i].fail_timeout = 10; 197 | +#if (NGX_HTTP_UPSTREAM_CHECK) 198 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 199 | +#endif 200 | *peerp = &peer[i]; 201 | peerp = &peer[i].next; 202 | } 203 | @@ -443,6 +475,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 204 | goto failed; 205 | } 206 | 207 | +#if (NGX_HTTP_UPSTREAM_CHECK) 208 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 209 | + goto failed; 210 | + } 211 | +#endif 212 | + 213 | rrp->current = peer; 214 | 215 | } else { 216 | @@ -537,6 +575,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) 217 | continue; 218 | } 219 | 220 | +#if (NGX_HTTP_UPSTREAM_CHECK) 221 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 222 | + continue; 223 | + } 224 | +#endif 225 | + 226 | if (peer->max_fails 227 | && peer->fails >= peer->max_fails 228 | && now - peer->checked <= peer->fail_timeout) 229 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h 230 | index 45f258d..dee91d0 100644 231 | --- a/src/http/ngx_http_upstream_round_robin.h 232 | +++ b/src/http/ngx_http_upstream_round_robin.h 233 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s { 234 | ngx_msec_t slow_start; 235 | ngx_msec_t start_time; 236 | 237 | +#if (NGX_HTTP_UPSTREAM_CHECK) 238 | + ngx_uint_t check_index; 239 | +#endif 240 | + 241 | ngx_uint_t down; 242 | 243 | #if (NGX_HTTP_SSL || NGX_COMPAT) 244 | diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c 245 | index cb44fcd..5df7380 100644 246 | --- a/src/stream/ngx_stream_upstream_hash_module.c 247 | +++ b/src/stream/ngx_stream_upstream_hash_module.c 248 | @@ -8,6 +8,9 @@ 249 | #include 250 | #include 251 | #include 252 | +#if (NGX_STREAM_UPSTREAM_CHECK) 253 | +#include "ngx_stream_upstream_check_module.h" 254 | +#endif 255 | 256 | 257 | typedef struct { 258 | @@ -233,7 +236,15 @@ ngx_stream_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) 259 | if (peer->down) { 260 | goto next; 261 | } 262 | +#if (NGX_STREAM_UPSTREAM_CHECK) 263 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 264 | + "(stream_module)get least_conn peer, check_index: %ui", 265 | + peer->check_index); 266 | 267 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 268 | + goto next; 269 | + } 270 | +#endif 271 | if (peer->max_fails 272 | && peer->fails >= peer->max_fails 273 | && now - peer->checked <= peer->fail_timeout) 274 | @@ -538,7 +549,15 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) 275 | if (peer->down) { 276 | continue; 277 | } 278 | +#if (NGX_STREAM_UPSTREAM_CHECK) 279 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 280 | + "(stream_module)get least_conn peer, check_index: %ui", 281 | + peer->check_index); 282 | 283 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 284 | + continue; 285 | + } 286 | +#endif 287 | if (peer->server.len != server->len 288 | || ngx_strncmp(peer->server.data, server->data, server->len) 289 | != 0) 290 | diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c 291 | index 739b20a..b805110 100644 292 | --- a/src/stream/ngx_stream_upstream_least_conn_module.c 293 | +++ b/src/stream/ngx_stream_upstream_least_conn_module.c 294 | @@ -8,6 +8,9 @@ 295 | #include 296 | #include 297 | #include 298 | +#if (NGX_STREAM_UPSTREAM_CHECK) 299 | +#include "ngx_stream_upstream_check_module.h" 300 | +#endif 301 | 302 | 303 | static ngx_int_t ngx_stream_upstream_init_least_conn_peer( 304 | @@ -142,6 +145,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 305 | if (peer->down) { 306 | continue; 307 | } 308 | +#if (NGX_STREAM_UPSTREAM_CHECK) 309 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 310 | + "(stream_module)get least_conn peer, check_index: %ui", 311 | + peer->check_index); 312 | + 313 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 314 | + continue; 315 | + } 316 | +#endif 317 | 318 | if (peer->max_fails 319 | && peer->fails >= peer->max_fails 320 | @@ -197,7 +209,15 @@ ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) 321 | if (peer->down) { 322 | continue; 323 | } 324 | +#if (NGX_STREAM_UPSTREAM_CHECK) 325 | + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, 326 | + "(stream_module)get least_conn peer, check_index: %ui", 327 | + peer->check_index); 328 | 329 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 330 | + continue; 331 | + } 332 | +#endif 333 | if (peer->conns * best->weight != best->conns * peer->weight) { 334 | continue; 335 | } 336 | diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c 337 | index 526de3a..13c4956 100644 338 | --- a/src/stream/ngx_stream_upstream_round_robin.c 339 | +++ b/src/stream/ngx_stream_upstream_round_robin.c 340 | @@ -9,6 +9,10 @@ 341 | #include 342 | #include 343 | 344 | +#if (NGX_STREAM_UPSTREAM_CHECK) 345 | +#include "ngx_stream_upstream_check_module.h" 346 | +#endif 347 | + 348 | 349 | #define ngx_stream_upstream_tries(p) ((p)->number \ 350 | + ((p)->next ? (p)->next->number : 0)) 351 | @@ -104,6 +108,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 352 | peer[n].down = server[i].down; 353 | peer[n].server = server[i].name; 354 | 355 | +#if (NGX_STREAM_UPSTREAM_CHECK) 356 | + if (!server[i].down) { 357 | + peer[n].check_index = 358 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 359 | + } 360 | + else { 361 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 362 | + } 363 | +#endif 364 | + 365 | *peerp = &peer[n]; 366 | peerp = &peer[n].next; 367 | n++; 368 | @@ -168,6 +182,16 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 369 | peer[n].down = server[i].down; 370 | peer[n].server = server[i].name; 371 | 372 | +#if (NGX_STREAM_UPSTREAM_CHECK) 373 | + if (!server[i].down) { 374 | + peer[n].check_index = 375 | + ngx_stream_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 376 | + } 377 | + else { 378 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 379 | + } 380 | +#endif 381 | + 382 | *peerp = &peer[n]; 383 | peerp = &peer[n].next; 384 | n++; 385 | @@ -234,6 +258,9 @@ ngx_stream_upstream_init_round_robin(ngx_conf_t *cf, 386 | peer[i].max_conns = 0; 387 | peer[i].max_fails = 1; 388 | peer[i].fail_timeout = 10; 389 | +#if (NGX_STREAM_UPSTREAM_CHECK) 390 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 391 | +#endif 392 | *peerp = &peer[i]; 393 | peerp = &peer[i].next; 394 | } 395 | @@ -354,6 +381,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 396 | peer[0].max_conns = 0; 397 | peer[0].max_fails = 1; 398 | peer[0].fail_timeout = 10; 399 | +#if (NGX_STREAM_UPSTREAM_CHECK) 400 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 401 | +#endif 402 | peers->peer = peer; 403 | 404 | } else { 405 | @@ -388,6 +418,9 @@ ngx_stream_upstream_create_round_robin_peer(ngx_stream_session_t *s, 406 | peer[i].max_conns = 0; 407 | peer[i].max_fails = 1; 408 | peer[i].fail_timeout = 10; 409 | +#if (NGX_STREAM_UPSTREAM_CHECK) 410 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 411 | +#endif 412 | *peerp = &peer[i]; 413 | peerp = &peer[i].next; 414 | } 415 | @@ -451,7 +484,11 @@ ngx_stream_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) 416 | if (peer->max_conns && peer->conns >= peer->max_conns) { 417 | goto failed; 418 | } 419 | - 420 | +#if (NGX_STREAM_UPSTREAM_CHECK) 421 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 422 | + goto failed; 423 | + } 424 | +#endif 425 | rrp->current = peer; 426 | 427 | } else { 428 | @@ -556,7 +593,11 @@ ngx_stream_upstream_get_peer(ngx_stream_upstream_rr_peer_data_t *rrp) 429 | if (peer->max_conns && peer->conns >= peer->max_conns) { 430 | continue; 431 | } 432 | - 433 | +#if (NGX_STREAM_UPSTREAM_CHECK) 434 | + if (ngx_stream_upstream_check_peer_down(peer->check_index)) { 435 | + continue; 436 | + } 437 | +#endif 438 | peer->current_weight += peer->effective_weight; 439 | total += peer->effective_weight; 440 | 441 | diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h 442 | index 35d9fce..ff6398e 100644 443 | --- a/src/stream/ngx_stream_upstream_round_robin.h 444 | +++ b/src/stream/ngx_stream_upstream_round_robin.h 445 | @@ -49,6 +49,10 @@ struct ngx_stream_upstream_rr_peer_s { 446 | 447 | ngx_stream_upstream_rr_peer_t *next; 448 | 449 | +#if (NGX_STREAM_UPSTREAM_CHECK) 450 | + ngx_uint_t check_index; 451 | +#endif 452 | + 453 | NGX_COMPAT_BEGIN(25) 454 | NGX_COMPAT_END 455 | }; 456 | -------------------------------------------------------------------------------- /ngx_healthcheck_status.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017- Changxun Zhou(changxunzhou@qq.com) 3 | * desc: Healthcheck status interface 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common.h.in" 13 | 14 | 15 | #define NGX_CHECK_STATUS_DOWN 0x0001 16 | #define NGX_CHECK_STATUS_UP 0x0002 17 | 18 | typedef void (*ngx_upstream_check_status_format_pt) (ngx_buf_t *b, 19 | ngx_upstream_check_peers_t *peers, 20 | ngx_uint_t flag); 21 | typedef struct { 22 | ngx_str_t format; 23 | ngx_str_t content_type; 24 | 25 | ngx_upstream_check_status_format_pt output; 26 | } ngx_check_status_conf_t; 27 | 28 | typedef struct { 29 | ngx_check_status_conf_t *format; 30 | ngx_flag_t flag; 31 | } ngx_upstream_check_status_ctx_t; 32 | 33 | 34 | typedef ngx_int_t (*ngx_upstream_check_status_command_pt) 35 | (ngx_upstream_check_status_ctx_t *ctx, ngx_str_t *value); 36 | 37 | typedef struct { 38 | ngx_str_t name; 39 | ngx_upstream_check_status_command_pt handler; 40 | } ngx_check_status_command_t; 41 | 42 | // check module main config data. 43 | typedef struct { 44 | ngx_uint_t check_shm_size; 45 | ngx_upstream_check_peers_t *peers; 46 | } ngx_upstream_check_main_conf_t; 47 | 48 | 49 | typedef struct { 50 | ngx_check_status_conf_t *format; 51 | } ngx_upstream_check_loc_conf_t; 52 | 53 | 54 | // external var declare 55 | extern ngx_uint_t ngx_stream_upstream_check_shm_generation ; //reload counter 56 | extern ngx_upstream_check_peers_t *stream_peers_ctx ; //stream peers data 57 | extern ngx_upstream_check_peers_t *http_peers_ctx ; // http peers data 58 | 59 | 60 | //begin check_status function declare 61 | static ngx_int_t ngx_upstream_check_status_handler( 62 | ngx_http_request_t *r); 63 | static void ngx_upstream_check_status_parse_args(ngx_http_request_t *r, 64 | ngx_upstream_check_status_ctx_t *ctx); 65 | 66 | static ngx_int_t ngx_upstream_check_status_command_format( 67 | ngx_upstream_check_status_ctx_t *ctx, ngx_str_t *value); 68 | static ngx_int_t ngx_upstream_check_status_command_status( 69 | ngx_upstream_check_status_ctx_t *ctx, ngx_str_t *value); 70 | 71 | static void ngx_upstream_check_status_html_format(ngx_buf_t *b, 72 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag); 73 | static void ngx_upstream_check_status_csv_format(ngx_buf_t *b, 74 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag); 75 | static void ngx_upstream_check_status_json_format(ngx_buf_t *b, 76 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag); 77 | static void ngx_http_upstream_check_status_prometheus_format(ngx_buf_t *b, 78 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag); 79 | 80 | static ngx_check_status_conf_t *ngx_http_get_check_status_format_conf( 81 | ngx_str_t *str); 82 | 83 | static char *ngx_upstream_check_status(ngx_conf_t *cf, 84 | ngx_command_t *cmd, void *conf); 85 | static void *ngx_upstream_check_create_loc_conf(ngx_conf_t *cf); 86 | static char * ngx_upstream_check_merge_loc_conf(ngx_conf_t *cf, 87 | void *parent, void *child); 88 | //end check_status function declare 89 | 90 | //1 cmd define 91 | static ngx_command_t ngx_upstream_check_status_commands[] = { 92 | { ngx_string("healthcheck_status"), 93 | NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_NOARGS, 94 | ngx_upstream_check_status, 95 | 0, 96 | 0, 97 | NULL }, 98 | 99 | ngx_null_command 100 | }; 101 | //2 ctx define 102 | static ngx_http_module_t ngx_upstream_check_status_module_ctx = { 103 | NULL, /* preconfiguration */ 104 | NULL, /* postconfiguration */ 105 | 106 | NULL, /* create main configuration */ 107 | NULL, /* init main configuration */ 108 | 109 | NULL, /* create server configuration */ 110 | NULL, /* merge server configuration */ 111 | 112 | ngx_upstream_check_create_loc_conf, /* create location configuration */ 113 | ngx_upstream_check_merge_loc_conf /* merge location configuration */ 114 | }; 115 | //3 module define 116 | ngx_module_t ngx_upstream_check_status_module = { 117 | NGX_MODULE_V1, 118 | &ngx_upstream_check_status_module_ctx, /* module context */ 119 | ngx_upstream_check_status_commands, /* module directives */ 120 | NGX_HTTP_MODULE, /* module type */ 121 | NULL, /* init master */ 122 | NULL, /* init module */ 123 | NULL, /* init process */ 124 | NULL, /* init thread */ 125 | NULL, /* exit thread */ 126 | NULL, /* exit process */ 127 | NULL, /* exit master */ 128 | NGX_MODULE_V1_PADDING 129 | }; 130 | //health checker cmd callback. 131 | static char * 132 | ngx_upstream_check_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 133 | { 134 | ngx_str_t *value; 135 | ngx_http_core_loc_conf_t *clcf; 136 | ngx_upstream_check_loc_conf_t *uclcf; 137 | 138 | value = cf->args->elts; 139 | 140 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 141 | 142 | clcf->handler = ngx_upstream_check_status_handler; 143 | 144 | if (cf->args->nelts == 2) { 145 | uclcf = ngx_http_conf_get_module_loc_conf(cf, 146 | ngx_upstream_check_status_module); 147 | 148 | uclcf->format = ngx_http_get_check_status_format_conf(&value[1]); 149 | if (uclcf->format == NULL) { 150 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 151 | "invalid check format \"%V\"", &value[1]); 152 | 153 | return NGX_CONF_ERROR; 154 | } 155 | } 156 | 157 | return NGX_CONF_OK; 158 | } 159 | // location config callback 160 | static void * 161 | ngx_upstream_check_create_loc_conf(ngx_conf_t *cf) 162 | { 163 | ngx_upstream_check_loc_conf_t *uclcf; 164 | 165 | uclcf = ngx_pcalloc(cf->pool, sizeof(ngx_upstream_check_loc_conf_t)); 166 | if (uclcf == NULL) { 167 | return NULL; 168 | } 169 | 170 | uclcf->format = NGX_CONF_UNSET_PTR; 171 | 172 | return uclcf; 173 | } 174 | 175 | static char * 176 | ngx_upstream_check_merge_loc_conf(ngx_conf_t *cf, void *parent, 177 | void *child) 178 | { 179 | ngx_str_t format = ngx_string("html"); 180 | ngx_upstream_check_loc_conf_t *prev = parent; 181 | ngx_upstream_check_loc_conf_t *conf = child; 182 | 183 | ngx_conf_merge_ptr_value(conf->format, prev->format, 184 | ngx_http_get_check_status_format_conf(&format)); 185 | 186 | return NGX_CONF_OK; 187 | } 188 | 189 | static ngx_check_status_conf_t ngx_check_status_formats[] = { 190 | 191 | { ngx_string("html"), 192 | ngx_string("text/html"), 193 | ngx_upstream_check_status_html_format }, 194 | 195 | { ngx_string("csv"), 196 | ngx_string("text/plain"), 197 | ngx_upstream_check_status_csv_format }, 198 | 199 | { ngx_string("json"), 200 | ngx_string("application/json"), // RFC 4627 201 | ngx_upstream_check_status_json_format }, 202 | 203 | { ngx_string("prometheus"), 204 | ngx_string("text/plain"), 205 | ngx_http_upstream_check_status_prometheus_format }, 206 | 207 | { ngx_null_string, ngx_null_string, NULL } 208 | }; 209 | 210 | static ngx_check_status_command_t ngx_check_status_commands[] = { 211 | 212 | { ngx_string("format"), 213 | ngx_upstream_check_status_command_format }, 214 | 215 | { ngx_string("status"), 216 | ngx_upstream_check_status_command_status }, 217 | 218 | { ngx_null_string, NULL } 219 | }; 220 | 221 | /* http request handler. */ 222 | static ngx_int_t 223 | ngx_upstream_check_status_handler(ngx_http_request_t *r) 224 | { 225 | size_t buffer_size; 226 | ngx_int_t rc; 227 | ngx_buf_t *b; 228 | ngx_chain_t out; 229 | ngx_upstream_check_peers_t *peers; 230 | ngx_upstream_check_loc_conf_t *uclcf; 231 | ngx_upstream_check_status_ctx_t *ctx; 232 | 233 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 234 | "[ngx-healthcheck][status-interface] recv query request"); 235 | 236 | if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { 237 | return NGX_HTTP_NOT_ALLOWED; 238 | } 239 | 240 | rc = ngx_http_discard_request_body(r); 241 | 242 | if (rc != NGX_OK) { 243 | return rc; 244 | } 245 | 246 | uclcf = ngx_http_get_module_loc_conf(r, ngx_upstream_check_status_module); 247 | 248 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_upstream_check_status_ctx_t)); 249 | if (ctx == NULL) { 250 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 251 | } 252 | 253 | ngx_upstream_check_status_parse_args(r, ctx); 254 | 255 | if (ctx->format == NULL) { 256 | ctx->format = uclcf->format; 257 | } 258 | 259 | r->headers_out.content_type = ctx->format->content_type; 260 | 261 | if (r->method == NGX_HTTP_HEAD) { 262 | r->headers_out.status = NGX_HTTP_OK; 263 | 264 | rc = ngx_http_send_header(r); 265 | 266 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 267 | return rc; 268 | } 269 | } 270 | 271 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 272 | "[ngx-healthcheck][status-interface]" 273 | " stream_peers_ctx:%p, http_peers_ctx:%p", 274 | stream_peers_ctx, http_peers_ctx); 275 | peers = http_peers_ctx; 276 | /* 277 | if (peers == NULL) { 278 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 279 | "[ngx-healthcheck][status-interface] peers == NULL"); 280 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 281 | } 282 | */ 283 | // 1/4 pagesize for each record 284 | if(stream_peers_ctx == NULL){ 285 | buffer_size = http_peers_ctx->peers.nelts * ngx_pagesize / 4; 286 | }else{ 287 | buffer_size = (stream_peers_ctx->peers.nelts + http_peers_ctx->peers.nelts) * ngx_pagesize / 4; 288 | } 289 | buffer_size = ngx_align(buffer_size, ngx_pagesize) + ngx_pagesize; 290 | 291 | b = ngx_create_temp_buf(r->pool, buffer_size); 292 | if (b == NULL) { 293 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 294 | } 295 | 296 | out.buf = b; 297 | out.next = NULL; 298 | 299 | ctx->format->output(b, peers, ctx->flag); // construct status data. 300 | 301 | r->headers_out.status = NGX_HTTP_OK; 302 | r->headers_out.content_length_n = b->last - b->pos; 303 | 304 | if (r->headers_out.content_length_n == 0) { 305 | r->header_only = 1; 306 | } 307 | 308 | b->last_buf = 1; 309 | 310 | rc = ngx_http_send_header(r); 311 | 312 | if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 313 | return rc; 314 | } 315 | 316 | return ngx_http_output_filter(r, &out); 317 | } 318 | 319 | static void 320 | ngx_upstream_check_status_parse_args(ngx_http_request_t *r, 321 | ngx_upstream_check_status_ctx_t *ctx) 322 | { 323 | ngx_str_t value; 324 | ngx_uint_t i; 325 | ngx_check_status_command_t *command; 326 | 327 | if (r->args.len == 0) { 328 | return; 329 | } 330 | 331 | for (i = 0; ; i++) { 332 | 333 | command = &ngx_check_status_commands[i]; 334 | 335 | if (command->name.len == 0) { 336 | break; 337 | } 338 | 339 | if (ngx_http_arg(r, command->name.data, command->name.len, &value) 340 | == NGX_OK) { 341 | 342 | if (command->handler(ctx, &value) != NGX_OK) { 343 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 344 | "stream upstream check, bad argument: \"%V\"", 345 | &value); 346 | } 347 | } 348 | } 349 | 350 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 351 | "stream upstream check, flag: \"%ui\"", ctx->flag); 352 | } 353 | 354 | 355 | static ngx_int_t 356 | ngx_upstream_check_status_command_format( 357 | ngx_upstream_check_status_ctx_t *ctx, ngx_str_t *value) 358 | { 359 | ctx->format = ngx_http_get_check_status_format_conf(value); 360 | if (ctx->format == NULL) { 361 | return NGX_ERROR; 362 | } 363 | 364 | return NGX_OK; 365 | } 366 | 367 | 368 | static ngx_int_t 369 | ngx_upstream_check_status_command_status( 370 | ngx_upstream_check_status_ctx_t *ctx, ngx_str_t *value) 371 | { 372 | if (value->len == (sizeof("down") - 1) 373 | && ngx_strncasecmp(value->data, (u_char *) "down", value->len) == 0) { 374 | 375 | ctx->flag |= NGX_CHECK_STATUS_DOWN; 376 | 377 | } else if (value->len == (sizeof("up") - 1) 378 | && ngx_strncasecmp(value->data, (u_char *) "up", value->len) 379 | == 0) { 380 | 381 | ctx->flag |= NGX_CHECK_STATUS_UP; 382 | 383 | } else { 384 | return NGX_ERROR; 385 | } 386 | 387 | return NGX_OK; 388 | } 389 | 390 | static void 391 | ngx_upstream_check_status_html_format(ngx_buf_t *b, 392 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag) 393 | { 394 | ngx_uint_t i,stream_count,http_count,stream_up_count,http_up_count; 395 | ngx_upstream_check_peer_t *peer; 396 | 397 | stream_count = 0; 398 | http_count = 0; 399 | stream_up_count = 0; 400 | http_up_count = 0; 401 | 402 | peers = stream_peers_ctx; 403 | if(peers != NULL){ 404 | peer = peers->peers.elts; 405 | for (i = 0; i < peers->peers.nelts; i++) { 406 | if (!peer[i].shm->down) { 407 | stream_up_count ++; 408 | } 409 | stream_count++; 410 | } 411 | } 412 | 413 | peers = http_peers_ctx; //http 414 | peer = peers->peers.elts; 415 | for (i = 0; i < peers->peers.nelts; i++) { 416 | if (!peer[i].shm->down) { 417 | http_up_count ++; 418 | } 419 | http_count++; 420 | } 421 | 422 | b->last = ngx_snprintf(b->last, b->end - b->last, 423 | "\n" 425 | "\n" 426 | "\n" 427 | " Nginx upstream status checker\n" 428 | "\n" 429 | "\n" 430 | "

Nginx upstream status monitor

\n"); 431 | 432 | // =======begin http data========== 433 | b->last = ngx_snprintf(b->last, b->end - b->last, 434 | "

http upstream servers

up: %ui down: %ui total: %ui\n" 435 | "\n" 437 | " \n" 438 | " \n" 439 | " \n" 440 | " \n" 441 | " \n" 442 | " \n" 443 | " \n" 444 | " \n" 445 | " \n" 446 | " \n", 447 | http_up_count, http_count-http_up_count, http_count); 448 | 449 | for (i = 0; i < peers->peers.nelts; i++) { 450 | if (flag & NGX_CHECK_STATUS_DOWN) { 451 | if (!peer[i].shm->down) { 452 | continue; 453 | } 454 | } else if (flag & NGX_CHECK_STATUS_UP) { 455 | if (peer[i].shm->down) { 456 | continue; 457 | } 458 | } 459 | 460 | b->last = ngx_snprintf(b->last, b->end - b->last, 461 | " \n" 462 | " \n" 463 | " \n" 464 | " \n" 465 | " \n" 466 | " \n" 467 | " \n" 468 | " \n" 469 | " \n" 470 | " \n", 471 | peer[i].shm->down ? " bgcolor=\"#FF0000\"" : "", 472 | i, 473 | peer[i].upstream_name, 474 | &peer[i].peer_addr->name, 475 | peer[i].shm->down ? "down" : "up", 476 | peer[i].shm->rise_count, 477 | peer[i].shm->fall_count, 478 | &peer[i].conf->check_type_conf->name, 479 | peer[i].conf->port); 480 | } 481 | 482 | b->last = ngx_snprintf(b->last, b->end - b->last, 483 | "
IndexUpstreamNameStatusRise countsFall countsCheck typeCheck port
%ui%V%V%s%ui%ui%V%ui
\n"); 484 | 485 | // =======begin stream data========== 486 | 487 | b->last = ngx_snprintf(b->last, b->end - b->last, 488 | "

stream upstream servers

up: %ui down: %ui total: %ui\n" 489 | "\n" 491 | " \n" 492 | " \n" 493 | " \n" 494 | " \n" 495 | " \n" 496 | " \n" 497 | " \n" 498 | " \n" 499 | " \n" 500 | " \n", 501 | stream_up_count, stream_count-stream_up_count, stream_count); 502 | 503 | peers = stream_peers_ctx; //stream 504 | if(peers != NULL){ 505 | peer = peers->peers.elts; 506 | for (i = 0; i < peers->peers.nelts; i++) { 507 | if (flag & NGX_CHECK_STATUS_DOWN) { 508 | if (!peer[i].shm->down) { 509 | continue; 510 | } 511 | } else if (flag & NGX_CHECK_STATUS_UP) { 512 | if (peer[i].shm->down) { 513 | continue; 514 | } 515 | } 516 | 517 | b->last = ngx_snprintf(b->last, b->end - b->last, 518 | " \n" 519 | " \n" 520 | " \n" 521 | " \n" 522 | " \n" 523 | " \n" 524 | " \n" 525 | " \n" 526 | " \n" 527 | " \n", 528 | peer[i].shm->down ? " bgcolor=\"#FF0000\"" : "", 529 | i, 530 | peer[i].upstream_name, 531 | &peer[i].peer_addr->name, 532 | peer[i].shm->down ? "down" : "up", 533 | peer[i].shm->rise_count, 534 | peer[i].shm->fall_count, 535 | &peer[i].conf->check_type_conf->name, 536 | peer[i].conf->port); 537 | } 538 | } 539 | 540 | b->last = ngx_snprintf(b->last, b->end - b->last, 541 | "
IndexUpstreamNameStatusRise countsFall countsCheck typeCheck port
%ui%V%V%s%ui%ui%V%ui
\n" 542 | "

total servers(check enabled): %ui

\n" 543 | "\n", 544 | stream_count+http_count); 545 | } 546 | 547 | 548 | static void 549 | ngx_upstream_check_status_csv_format(ngx_buf_t *b, 550 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag) 551 | { 552 | ngx_uint_t i; 553 | ngx_upstream_check_peer_t *peer; 554 | 555 | b->last = ngx_snprintf(b->last, b->end - b->last, 556 | "index,upstream_type,upstream_name,host,rise,fall,check_type,check_port,status\n"); 557 | peers = http_peers_ctx; //http 558 | peer = peers->peers.elts; 559 | for (i = 0; i < peers->peers.nelts; i++) { 560 | 561 | if (flag & NGX_CHECK_STATUS_DOWN) { 562 | 563 | if (!peer[i].shm->down) { 564 | continue; 565 | } 566 | 567 | } else if (flag & NGX_CHECK_STATUS_UP) { 568 | 569 | if (peer[i].shm->down) { 570 | continue; 571 | } 572 | } 573 | 574 | b->last = ngx_snprintf(b->last, b->end - b->last, 575 | "%ui,http,%V,%V,%ui,%ui,%V,%ui,%s\n", 576 | i, 577 | peer[i].upstream_name, 578 | &peer[i].peer_addr->name, 579 | peer[i].shm->rise_count, 580 | peer[i].shm->fall_count, 581 | &peer[i].conf->check_type_conf->name, 582 | peer[i].conf->port, 583 | peer[i].shm->down ? "down" : "up"); 584 | } 585 | peers = stream_peers_ctx; //stream 586 | if(peers == NULL) return; 587 | peer = peers->peers.elts; 588 | for (i = 0; i < peers->peers.nelts; i++) { 589 | 590 | if (flag & NGX_CHECK_STATUS_DOWN) { 591 | 592 | if (!peer[i].shm->down) { 593 | continue; 594 | } 595 | 596 | } else if (flag & NGX_CHECK_STATUS_UP) { 597 | 598 | if (peer[i].shm->down) { 599 | continue; 600 | } 601 | } 602 | 603 | b->last = ngx_snprintf(b->last, b->end - b->last, 604 | "%ui,stream,%V,%V,%ui,%ui,%V,%ui,%s\n", 605 | i, 606 | peer[i].upstream_name, 607 | &peer[i].peer_addr->name, 608 | peer[i].shm->rise_count, 609 | peer[i].shm->fall_count, 610 | &peer[i].conf->check_type_conf->name, 611 | peer[i].conf->port, 612 | peer[i].shm->down ? "down" : "up"); 613 | } 614 | } 615 | 616 | 617 | static void 618 | ngx_upstream_check_status_json_format(ngx_buf_t *b, 619 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag) 620 | { 621 | ngx_uint_t count, i; 622 | ngx_uint_t stream_count=0, http_count=0; 623 | ngx_upstream_check_peer_t *peer; 624 | 625 | 626 | /* calc display total num after filter param*/ 627 | count = 0; 628 | 629 | peers = stream_peers_ctx; //stream 630 | if(peers != NULL){ //when no stream section, peers is NULL 631 | peer = peers->peers.elts; 632 | for (i = 0; i < peers->peers.nelts; i++) { 633 | if (flag & NGX_CHECK_STATUS_DOWN) { 634 | if (!peer[i].shm->down) { 635 | continue; 636 | } 637 | } else if (flag & NGX_CHECK_STATUS_UP) { 638 | if (peer[i].shm->down) { 639 | continue; 640 | } 641 | } 642 | count++;stream_count++; 643 | } 644 | } 645 | 646 | peers = http_peers_ctx; //http 647 | peer = peers->peers.elts; 648 | for (i = 0; i < peers->peers.nelts; i++) { 649 | if (flag & NGX_CHECK_STATUS_DOWN) { 650 | if (!peer[i].shm->down) { 651 | continue; 652 | } 653 | } else if (flag & NGX_CHECK_STATUS_UP) { 654 | if (peer[i].shm->down) { 655 | continue; 656 | } 657 | } 658 | count++;http_count++; 659 | } 660 | 661 | b->last = ngx_snprintf(b->last, b->end - b->last, 662 | "{\"servers\": {\n" 663 | " \"total\": %ui,\n" 664 | " \"generation\": %ui,\n" 665 | " \"http\": [\n", 666 | count, 667 | ngx_stream_upstream_check_shm_generation); 668 | 669 | //http 670 | count = 0; 671 | for (i = 0; i < peers->peers.nelts; i++) { 672 | if (flag & NGX_CHECK_STATUS_DOWN) { 673 | if (!peer[i].shm->down) { 674 | continue; 675 | } 676 | } else if (flag & NGX_CHECK_STATUS_UP) { 677 | if (peer[i].shm->down) { 678 | continue; 679 | } 680 | } 681 | count++; 682 | b->last = ngx_snprintf(b->last, b->end - b->last, 683 | " {\"index\": %ui, " 684 | "\"upstream\": \"%V\", " 685 | "\"name\": \"%V\", " 686 | "\"status\": \"%s\", " 687 | "\"rise\": %ui, " 688 | "\"fall\": %ui, " 689 | "\"type\": \"%V\", " 690 | "\"port\": %ui}" 691 | "%s\n", 692 | i, 693 | peer[i].upstream_name, 694 | &peer[i].peer_addr->name, 695 | peer[i].shm->down ? "down" : "up", 696 | peer[i].shm->rise_count, 697 | peer[i].shm->fall_count, 698 | &peer[i].conf->check_type_conf->name, 699 | peer[i].conf->port, 700 | (count == http_count) ? "" : ","); 701 | } 702 | 703 | //http end 704 | 705 | b->last = ngx_snprintf(b->last, b->end - b->last, 706 | " ],\n" 707 | " \"stream\": [\n"); 708 | 709 | peers = stream_peers_ctx; //stream 710 | count = 0; 711 | if(peers != NULL){ 712 | peer = peers->peers.elts; 713 | 714 | for (i = 0; i < peers->peers.nelts; i++) { 715 | if (flag & NGX_CHECK_STATUS_DOWN) { 716 | if (!peer[i].shm->down) { 717 | continue; 718 | } 719 | } else if (flag & NGX_CHECK_STATUS_UP) { 720 | if (peer[i].shm->down) { 721 | continue; 722 | } 723 | } 724 | count++; 725 | b->last = ngx_snprintf(b->last, b->end - b->last, 726 | " {\"index\": %ui, " 727 | "\"upstream\": \"%V\", " 728 | "\"name\": \"%V\", " 729 | "\"status\": \"%s\", " 730 | "\"rise\": %ui, " 731 | "\"fall\": %ui, " 732 | "\"type\": \"%V\", " 733 | "\"port\": %ui}" 734 | "%s\n", 735 | i, 736 | peer[i].upstream_name, 737 | &peer[i].peer_addr->name, 738 | peer[i].shm->down ? "down" : "up", 739 | peer[i].shm->rise_count, 740 | peer[i].shm->fall_count, 741 | &peer[i].conf->check_type_conf->name, 742 | peer[i].conf->port, 743 | (count == stream_count) ? "" : ","); 744 | } 745 | } 746 | 747 | b->last = ngx_snprintf(b->last, b->end - b->last, 748 | " ]\n"); 749 | 750 | b->last = ngx_snprintf(b->last, b->end - b->last, 751 | "}}\n"); 752 | } 753 | 754 | 755 | static void 756 | ngx_http_upstream_check_status_prometheus_format(ngx_buf_t *b, 757 | ngx_upstream_check_peers_t *peers, ngx_uint_t flag) 758 | { 759 | ngx_uint_t count, upCount, downCount, i, j; 760 | ngx_upstream_check_peer_t *peer; 761 | ngx_str_t upstream_type[2] = {ngx_string("http"), ngx_string("stream")}; 762 | ngx_upstream_check_peers_t *upstream_peers[2] = {http_peers_ctx, stream_peers_ctx}; 763 | 764 | /* 1. summary */ 765 | upCount = 0; 766 | downCount = 0; 767 | count = 0; 768 | for(j=0; j < 2; j++) { 769 | peers = upstream_peers[j]; 770 | if (peers == NULL) continue; 771 | peer = peers->peers.elts; 772 | 773 | for (i = 0; i < peers->peers.nelts; i++) { 774 | /* 775 | if (peer[i].delete) { 776 | continue; 777 | } 778 | */ 779 | if (flag & NGX_CHECK_STATUS_DOWN) { 780 | 781 | if (!peer[i].shm->down) { 782 | continue; 783 | } 784 | 785 | } else if (flag & NGX_CHECK_STATUS_UP) { 786 | 787 | if (peer[i].shm->down) { 788 | continue; 789 | } 790 | } 791 | 792 | count++; 793 | if (peer[i].shm->down) { 794 | downCount++; 795 | } else { 796 | upCount++; 797 | } 798 | } 799 | } 800 | b->last = ngx_snprintf(b->last, b->end - b->last, 801 | "# HELP nginx_upstream_count_total Nginx total number of servers\n" 802 | "# TYPE nginx_upstream_count_total gauge\n" 803 | "nginx_upstream_count_total %ui\n" 804 | "# HELP nginx_upstream_count_up Nginx total number of servers that are UP\n" 805 | "# TYPE nginx_upstream_count_up gauge\n" 806 | "nginx_upstream_count_up %ui\n" 807 | "# HELP nginx_upstream_count_down Nginx total number of servers that are DOWN\n" 808 | "# TYPE nginx_upstream_count_down gauge\n" 809 | "nginx_upstream_count_down %ui\n" 810 | "# HELP nginx_upstream_count_generation Nginx generation\n" 811 | "# TYPE nginx_upstream_count_generation gauge\n" 812 | "nginx_upstream_count_generation %ui\n", 813 | count, 814 | upCount, 815 | downCount, 816 | ngx_stream_upstream_check_shm_generation); 817 | 818 | /* 2. ngninx_upstream_server_rise */ 819 | b->last = ngx_snprintf(b->last, b->end - b->last, 820 | "# HELP nginx_upstream_server_rise Nginx rise counter\n" 821 | "# TYPE nginx_upstream_server_rise counter\n"); 822 | 823 | for(j=0; j < 2; j++) { 824 | peers = upstream_peers[j]; 825 | if (peers == NULL) continue; 826 | peer = peers->peers.elts; 827 | 828 | for (i = 0; i < peers->peers.nelts; i++) { 829 | /* 830 | if (peer[i].delete) { 831 | continue; 832 | } 833 | */ 834 | if (flag & NGX_CHECK_STATUS_DOWN) { 835 | 836 | if (!peer[i].shm->down) { 837 | continue; 838 | } 839 | 840 | } else if (flag & NGX_CHECK_STATUS_UP) { 841 | 842 | if (peer[i].shm->down) { 843 | continue; 844 | } 845 | } 846 | 847 | b->last = ngx_snprintf(b->last, b->end - b->last, 848 | "nginx_upstream_server_rise{index=\"%ui\",upstream_type=\"%V\",upstream=\"%V\",name=\"%V\",status=\"%s\",type=\"%V\",port=\"%ui\"} %ui\n", 849 | i, 850 | &upstream_type[j], 851 | peer[i].upstream_name, 852 | &peer[i].peer_addr->name, 853 | peer[i].shm->down ? "down" : "up", 854 | &peer[i].conf->check_type_conf->name, 855 | peer[i].conf->port, 856 | peer[i].shm->rise_count); 857 | } 858 | } 859 | 860 | /* 3. ngninx_upstream_server_fall */ 861 | b->last = ngx_snprintf(b->last, b->end - b->last, 862 | "# HELP nginx_upstream_server_fall Nginx fall counter\n" 863 | "# TYPE nginx_upstream_server_fall counter\n"); 864 | for(j=0; j < 2; j++) { 865 | peers = upstream_peers[j]; 866 | if (peers == NULL) continue; 867 | peer = peers->peers.elts; 868 | 869 | for (i = 0; i < peers->peers.nelts; i++) { 870 | /* 871 | if (peer[i].delete) { 872 | continue; 873 | } 874 | */ 875 | if (flag & NGX_CHECK_STATUS_DOWN) { 876 | 877 | if (!peer[i].shm->down) { 878 | continue; 879 | } 880 | 881 | } else if (flag & NGX_CHECK_STATUS_UP) { 882 | 883 | if (peer[i].shm->down) { 884 | continue; 885 | } 886 | } 887 | 888 | b->last = ngx_snprintf(b->last, b->end - b->last, 889 | "nginx_upstream_server_fall{index=\"%ui\",upstream_type=\"%V\",upstream=\"%V\",name=\"%V\",status=\"%s\",type=\"%V\",port=\"%ui\"} %ui\n", 890 | i, 891 | &upstream_type[j], 892 | peer[i].upstream_name, 893 | &peer[i].peer_addr->name, 894 | peer[i].shm->down ? "down" : "up", 895 | &peer[i].conf->check_type_conf->name, 896 | peer[i].conf->port, 897 | peer[i].shm->fall_count); 898 | } 899 | } 900 | 901 | /* 4. ngninx_upstream_server_active */ 902 | b->last = ngx_snprintf(b->last, b->end - b->last, 903 | "# HELP nginx_upstream_server_active Nginx active 1 for UP / 0 for DOWN\n" 904 | "# TYPE nginx_upstream_server_active gauge\n"); 905 | for(j=0; j < 2; j++) { 906 | peers = upstream_peers[j]; 907 | if (peers == NULL) continue; 908 | peer = peers->peers.elts; 909 | 910 | for (i = 0; i < peers->peers.nelts; i++) { 911 | /* 912 | if (peer[i].delete) { 913 | continue; 914 | } 915 | */ 916 | if (flag & NGX_CHECK_STATUS_DOWN) { 917 | 918 | if (!peer[i].shm->down) { 919 | continue; 920 | } 921 | 922 | } else if (flag & NGX_CHECK_STATUS_UP) { 923 | 924 | if (peer[i].shm->down) { 925 | continue; 926 | } 927 | } 928 | 929 | b->last = ngx_snprintf(b->last, b->end - b->last, 930 | "nginx_upstream_server_active{index=\"%ui\",upstream_type=\"%V\",upstream=\"%V\",name=\"%V\",type=\"%V\",port=\"%ui\"} %ui\n", 931 | i, 932 | &upstream_type[j], 933 | peer[i].upstream_name, 934 | &peer[i].peer_addr->name, 935 | &peer[i].conf->check_type_conf->name, 936 | peer[i].conf->port, 937 | peer[i].shm->down ? 0 : 1); 938 | } 939 | } 940 | } 941 | 942 | static ngx_check_status_conf_t * 943 | ngx_http_get_check_status_format_conf(ngx_str_t *str) 944 | { 945 | ngx_uint_t i; 946 | 947 | for (i = 0; ; i++) { 948 | 949 | if (ngx_check_status_formats[i].format.len == 0) { 950 | break; 951 | } 952 | 953 | if (str->len != ngx_check_status_formats[i].format.len) { 954 | continue; 955 | } 956 | 957 | if (ngx_strncmp(str->data, ngx_check_status_formats[i].format.data, 958 | str->len) == 0) 959 | { 960 | return &ngx_check_status_formats[i]; 961 | } 962 | } 963 | 964 | return NULL; 965 | } 966 | 967 | 968 | //end healthcheck status interface 969 | --------------------------------------------------------------------------------