更新文档,代码注释,以及上传断点文件

jfu
j.fu 6 months ago
parent 5d93d90cbc
commit 8fa73c40f6

@ -0,0 +1,16 @@
break ngx_http_upstream_check_timeout_handler
break ngx_http_upstream_check_http_reinit
disable $bpnum
break ngx_http_upstream_check_http_parse
break ngx_http_upstream_check_http_init
disable $bpnum
break ngx_http_upstream_check_recv_handler
break ngx_http_upstream_check_send_handler
break /workspaces/cpp-5/nginx_upstream_check_module/ngx_http_upstream_check_module.c:1332
disable $bpnum
watch check_peers_ctx
break /workspaces/cpp-5/nginx_upstream_check_module/ngx_http_upstream_check_module.c:3757
watch check_peers_ctx
watch check_peers_ctx
break ngx_http_upstream_check_begin_handler
break ngx_http_upstream_check_connect_handler

@ -117,7 +117,7 @@ typedef ngx_int_t (*ngx_http_upstream_check_packet_parse_pt)
typedef void (*ngx_http_upstream_check_packet_clean_pt) typedef void (*ngx_http_upstream_check_packet_clean_pt)
(ngx_http_upstream_check_peer_t *peer); (ngx_http_upstream_check_peer_t *peer);
struct ngx_http_upstream_check_peer_s { /*peer关键配置类包括一组回调函数*/ struct ngx_http_upstream_check_peer_s {
ngx_flag_t state; ngx_flag_t state;
ngx_pool_t *pool; ngx_pool_t *pool;
ngx_uint_t index; ngx_uint_t index;
@ -125,17 +125,17 @@ struct ngx_http_upstream_check_peer_s { /*peer关键配置类包括一组回
ngx_str_t *upstream_name; ngx_str_t *upstream_name;
ngx_addr_t *check_peer_addr; ngx_addr_t *check_peer_addr;
ngx_addr_t *peer_addr; ngx_addr_t *peer_addr;
ngx_event_t check_ev; /*关键数据结构check event*/ ngx_event_t check_ev; /* 主动探测事件 */
ngx_event_t check_timeout_ev; /*关键数据结构: check timeout event*/ ngx_event_t check_timeout_ev; /* 主动探测超时事件 */
ngx_peer_connection_t pc; ngx_peer_connection_t pc; /* 保存与后端服务器的连接 */
void *check_data; void *check_data;
ngx_event_handler_pt send_handler; /*TODO: ???*/ ngx_event_handler_pt send_handler; /* ngx_connection_t中的write事件handler向后端服务器发送探测数据 */
ngx_event_handler_pt recv_handler; /*TODO: ???*/ ngx_event_handler_pt recv_handler; /* ngx_connection_t中的read事件handler从后端服务器接收探测结果数据 */
ngx_http_upstream_check_packet_init_pt init; /*TODO: ???*/ ngx_http_upstream_check_packet_init_pt init;
ngx_http_upstream_check_packet_parse_pt parse; /*TODO: ???*/ ngx_http_upstream_check_packet_parse_pt parse;
ngx_http_upstream_check_packet_clean_pt reinit; /*TODO: ???*/ ngx_http_upstream_check_packet_clean_pt reinit;
ngx_http_upstream_check_peer_shm_t *shm; ngx_http_upstream_check_peer_shm_t *shm;
ngx_http_upstream_check_srv_conf_t *conf; ngx_http_upstream_check_srv_conf_t *conf;
@ -163,7 +163,7 @@ typedef struct {
#define NGX_CHECK_HTTP_5XX 0x0010 #define NGX_CHECK_HTTP_5XX 0x0010
#define NGX_CHECK_HTTP_ERR 0x8000 #define NGX_CHECK_HTTP_ERR 0x8000
typedef struct {/*核心配置包括了check相关的回调函数*/ typedef struct {
ngx_uint_t type; ngx_uint_t type;
ngx_str_t name; ngx_str_t name;
@ -173,12 +173,12 @@ typedef struct {/*核心配置包括了check相关的回调函数*/
/* HTTP */ /* HTTP */
ngx_uint_t default_status_alive; ngx_uint_t default_status_alive;
ngx_event_handler_pt send_handler; /*TODO: ???*/ ngx_event_handler_pt send_handler;
ngx_event_handler_pt recv_handler; /*TODO: ???*/ ngx_event_handler_pt recv_handler;
ngx_http_upstream_check_packet_init_pt init; /*TODO: ???*/ ngx_http_upstream_check_packet_init_pt init;
ngx_http_upstream_check_packet_parse_pt parse; /*TODO: ???*/ ngx_http_upstream_check_packet_parse_pt parse;
ngx_http_upstream_check_packet_clean_pt reinit; /*TODO: ???*/ ngx_http_upstream_check_packet_clean_pt reinit;
unsigned need_pool; unsigned need_pool;
unsigned need_keepalive; unsigned need_keepalive;
@ -941,9 +941,9 @@ ngx_http_upstream_check_free_peer(ngx_uint_t index)
ngx_shmtx_unlock(&peer[index].shm->mutex); ngx_shmtx_unlock(&peer[index].shm->mutex);
} }
/*核心函数根据当前配置加载peer对象为各个peer对象注册回调函数*/
static ngx_int_t static ngx_int_t
ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle) ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle) /*此函数被调用的时间是master进程创建出worker进程时在初始化当前module的cycle对象时被调用*/
{ {
ngx_uint_t i; ngx_uint_t i;
ngx_msec_t t, delay; ngx_msec_t t, delay;
@ -978,7 +978,7 @@ ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle)
for (i = 0; i < peers->peers.nelts; i++) { for (i = 0; i < peers->peers.nelts; i++) {
peer[i].shm = &peer_shm[i]; peer[i].shm = &peer_shm[i];
peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler; /* TODO 整个回调函数处理什么事件event*/ peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler; /* 回调函数处理定时check后端服务器的事件*/
peer[i].check_ev.log = cycle->log; peer[i].check_ev.log = cycle->log;
peer[i].check_ev.data = &peer[i]; peer[i].check_ev.data = &peer[i];
peer[i].check_ev.timer_set = 0; peer[i].check_ev.timer_set = 0;
@ -999,8 +999,8 @@ ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle)
} }
} }
peer[i].send_handler = cf->send_handler; peer[i].send_handler = cf->send_handler; /* send event handler*/
peer[i].recv_handler = cf->recv_handler; peer[i].recv_handler = cf->recv_handler; /* recv event handler*/
peer[i].init = cf->init; peer[i].init = cf->init;
peer[i].parse = cf->parse; peer[i].parse = cf->parse;
@ -1013,13 +1013,13 @@ ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle)
delay = ucscf->check_interval > 1000 ? ucscf->check_interval : 1000; delay = ucscf->check_interval > 1000 ? ucscf->check_interval : 1000;
t = ngx_random() % delay; t = ngx_random() % delay;
ngx_add_timer(&peer[i].check_ev, t); ngx_add_timer(&peer[i].check_ev, t); /*为每个后端服务器即peer添加timernginx后端会计时时间到就触发事件的回调函数*/
} }
return NGX_OK; return NGX_OK;
} }
/* 处理check相关event*/ /* timer event定期check的事件*/
static void static void
ngx_http_upstream_check_begin_handler(ngx_event_t *event) ngx_http_upstream_check_begin_handler(ngx_event_t *event)
{ {
@ -1055,7 +1055,7 @@ ngx_http_upstream_check_begin_handler(ngx_event_t *event)
return; return;
} }
interval = ngx_current_msec - peer->shm->access_time; interval = ngx_current_msec - peer->shm->access_time; /* 距离上一次检测过去了多少毫秒 */
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, event->log, 0, ngx_log_debug5(NGX_LOG_DEBUG_HTTP, event->log, 0,
"http check begin handler index: %ui, owner: %P, " "http check begin handler index: %ui, owner: %P, "
"ngx_pid: %P, interval: %M, check_interval: %M", "ngx_pid: %P, interval: %M, check_interval: %M",
@ -1111,7 +1111,7 @@ ngx_http_upstream_check_connect_handler(ngx_event_t *event)
peer = event->data; peer = event->data;
ucscf = peer->conf; ucscf = peer->conf;
if (peer->pc.connection != NULL) { if (peer->pc.connection != NULL) { /* 已与后端服务器建立连接 */
c = peer->pc.connection; c = peer->pc.connection;
if ((rc = ngx_http_upstream_check_peek_one_byte(c)) == NGX_OK) { if ((rc = ngx_http_upstream_check_peek_one_byte(c)) == NGX_OK) {
goto upstream_check_connect_done; goto upstream_check_connect_done;
@ -1122,20 +1122,20 @@ ngx_http_upstream_check_connect_handler(ngx_event_t *event)
} }
ngx_memzero(&peer->pc, sizeof(ngx_peer_connection_t)); ngx_memzero(&peer->pc, sizeof(ngx_peer_connection_t));
peer->pc.sockaddr = peer->check_peer_addr->sockaddr; /*TODO 挑选后端服务器*/ peer->pc.sockaddr = peer->check_peer_addr->sockaddr;
peer->pc.socklen = peer->check_peer_addr->socklen; peer->pc.socklen = peer->check_peer_addr->socklen;
peer->pc.name = &peer->check_peer_addr->name; peer->pc.name = &peer->check_peer_addr->name;
peer->pc.get = ngx_event_get_peer; peer->pc.get = ngx_event_get_peer; /* 如何挑选后端服务器由Nginx内置的轮询round robin和IP哈希ip hash模块提供 */
peer->pc.log = event->log; peer->pc.log = event->log;
peer->pc.log_error = NGX_ERROR_ERR; peer->pc.log_error = NGX_ERROR_ERR;
peer->pc.cached = 0; peer->pc.cached = 0;
peer->pc.connection = NULL; peer->pc.connection = NULL;
rc = ngx_event_connect_peer(&peer->pc); rc = ngx_event_connect_peer(&peer->pc); /* 连接后端服务器等待触发write和send事件的回调函数 */
if (rc == NGX_ERROR || rc == NGX_DECLINED) { if (rc == NGX_ERROR || rc == NGX_DECLINED) { /* 检测后端服务器失败 */
ngx_http_upstream_check_status_update(peer, 0); ngx_http_upstream_check_status_update(peer, 0);
ngx_http_upstream_check_clean_event(peer); ngx_http_upstream_check_clean_event(peer);
return; return;
@ -1171,7 +1171,7 @@ ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c)
ngx_int_t n; ngx_int_t n;
ngx_err_t err; ngx_err_t err;
n = recv(c->fd, buf, 1, MSG_PEEK); n = recv(c->fd, buf, 1, MSG_PEEK); /* 系统调用从指定socket接收数据 */
err = ngx_socket_errno; err = ngx_socket_errno;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err,
@ -1315,7 +1315,7 @@ ngx_http_upstream_check_send_handler(ngx_event_t *event)
goto check_send_fail; goto check_send_fail;
} }
if (peer->init == NULL || peer->init(peer) != NGX_OK) { if (peer->init == NULL || peer->init(peer) != NGX_OK) { /* 初始化peer调用ngx_http_upstream_check_http_init */
ngx_log_error(NGX_LOG_ERR, event->log, 0, ngx_log_error(NGX_LOG_ERR, event->log, 0,
"check init error with peer: %V ", "check init error with peer: %V ",
@ -1329,7 +1329,7 @@ ngx_http_upstream_check_send_handler(ngx_event_t *event)
while (ctx->send.pos < ctx->send.last) { while (ctx->send.pos < ctx->send.last) {
size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos); size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos); /* 向后端服务器发送探测数据 */
#if (NGX_DEBUG) #if (NGX_DEBUG)
{ {
@ -1360,14 +1360,14 @@ ngx_http_upstream_check_send_handler(ngx_event_t *event)
return; return;
check_send_fail: check_send_fail: /*心跳数据发送失败*/
ngx_http_upstream_check_status_update(peer, 0); ngx_http_upstream_check_status_update(peer, 0);
ngx_http_upstream_check_clean_event(peer); ngx_http_upstream_check_clean_event(peer);
} }
static void static void
ngx_http_upstream_check_recv_handler(ngx_event_t *event) ngx_http_upstream_check_recv_handler(ngx_event_t *event) /*处理后端服务器返回的响应数据*/
{ {
u_char *new_buf; u_char *new_buf;
ssize_t size, n; ssize_t size, n;
@ -1381,7 +1381,7 @@ ngx_http_upstream_check_recv_handler(ngx_event_t *event)
} }
c = event->data; c = event->data;
peer = c->data; peer = c->data; /*响应数据被nginx封装在event中rev event的data中是connection类型connection的data中是自定义的peer数据如何关联上的呢在ngx_http_upstream_check_begin_handler处理check事件时peer中有check上下文数据其中就包含了send和recv数据*/
if (peer->state != NGX_HTTP_CHECK_SEND_DONE) { if (peer->state != NGX_HTTP_CHECK_SEND_DONE) {
@ -1392,7 +1392,7 @@ ngx_http_upstream_check_recv_handler(ngx_event_t *event)
return; return;
} }
ctx = peer->check_data; ctx = peer->check_data; /*健康检测上下文*/
if (ctx->recv.start == NULL) { if (ctx->recv.start == NULL) {
/* 1/2 of the page_size, is it enough? */ /* 1/2 of the page_size, is it enough? */
@ -1449,7 +1449,7 @@ ngx_http_upstream_check_recv_handler(ngx_event_t *event)
} }
} }
rc = peer->parse(peer); rc = peer->parse(peer); /*解析响应数据调用ngx_http_upstream_check_http_parse*/
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http check parse rc: %i, peer: %V ", "http check parse rc: %i, peer: %V ",
@ -2516,19 +2516,19 @@ ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t *peer,
ucscf = peer->conf; ucscf = peer->conf;
if (result) { if (result) { /* 1 检测成功 */
peer->shm->rise_count++; peer->shm->rise_count++;
peer->shm->fall_count = 0; peer->shm->fall_count = 0;
if (peer->shm->down && peer->shm->rise_count >= ucscf->rise_count) { if (peer->shm->down && peer->shm->rise_count >= ucscf->rise_count) { /* 成功次数达到复活阈值,复活后端服务器 */
peer->shm->down = 0; peer->shm->down = 0;
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"enable check peer: %V ", "enable check peer: %V ",
&peer->check_peer_addr->name); &peer->check_peer_addr->name);
} }
} else { } else { /* 0 检测失败 */
peer->shm->rise_count = 0; peer->shm->rise_count = 0;
peer->shm->fall_count++; peer->shm->fall_count++;
if (!peer->shm->down && peer->shm->fall_count >= ucscf->fall_count) { if (!peer->shm->down && peer->shm->fall_count >= ucscf->fall_count) { /* 失败次数达到关停阈值,关停后端服务器 */
peer->shm->down = 1; peer->shm->down = 1;
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"disable check peer: %V ", "disable check peer: %V ",
@ -2536,7 +2536,7 @@ ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t *peer,
} }
} }
peer->shm->access_time = ngx_current_msec; peer->shm->access_time = ngx_current_msec; /* 记录检测时间,以毫秒为单位*/
} }
@ -2574,7 +2574,7 @@ ngx_http_upstream_check_clean_event(ngx_http_upstream_check_peer_t *peer)
peer->state = NGX_HTTP_CHECK_ALL_DONE; peer->state = NGX_HTTP_CHECK_ALL_DONE;
if (peer->check_data != NULL && peer->reinit) { if (peer->check_data != NULL && peer->reinit) {
peer->reinit(peer); peer->reinit(peer); /*重新初始化peer调用ngx_http_upstream_check_http_reinit函数*/
} }
peer->shm->owner = NGX_INVALID_PID; peer->shm->owner = NGX_INVALID_PID;
@ -2614,7 +2614,7 @@ ngx_http_upstream_check_finish_handler(ngx_event_t *event)
static ngx_int_t static ngx_int_t
ngx_http_upstream_check_need_exit() ngx_http_upstream_check_need_exit()
{ {
if (ngx_terminate || ngx_exiting || ngx_quit) { if (ngx_terminate || ngx_exiting || ngx_quit) { /* 当nginx正在终止时清空所有相关event */
ngx_http_upstream_check_clear_all_events(); ngx_http_upstream_check_clear_all_events();
return 1; return 1;
} }
@ -2624,7 +2624,7 @@ ngx_http_upstream_check_need_exit()
static void static void
ngx_http_upstream_check_clear_all_events() ngx_http_upstream_check_clear_all_events() /* 删除timer关闭connection销毁peer的内存pool */
{ {
ngx_uint_t i; ngx_uint_t i;
ngx_connection_t *c; ngx_connection_t *c;
@ -3089,7 +3089,7 @@ ngx_http_upstream_check(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;/*数组指针,指向:{{len = 5, data = 0x555555706795 "check"}, {len = 13, data = 0x55555570679b "interval=1000"}, {len = 6, data = 0x5555557067a9 "rise=1"}, {len = 6, data = 0x5555557067b0 "fall=3"}, {len = 12, data = 0x5555557067b7 "timeout=2000"}, {len = 9, data = 0x5555557067c4 "type=http"}}*/ value = cf->args->elts;/*数组指针,指向:{{len = 5, data = 0x555555706795 "check"}, {len = 13, data = 0x55555570679b "interval=1000"}, {len = 6, data = 0x5555557067a9 "rise=1"}, {len = 6, data = 0x5555557067b0 "fall=3"}, {len = 12, data = 0x5555557067b7 "timeout=2000"}, {len = 9, data = 0x5555557067c4 "type=http"}}*/
/* 获取已经注册的自定义configuration结构体, TODO: 那么在哪里注册的configuration结构体呢*/ /* 获取已经注册的自定义configuration结构体, 那么在哪里注册的configuration结构体呢在ngx_http_upstream_check_module_ctx变量中*/
ucscf = ngx_http_conf_get_module_srv_conf(cf, ucscf = ngx_http_conf_get_module_srv_conf(cf,
ngx_http_upstream_check_module); ngx_http_upstream_check_module);
if (ucscf == NULL) { if (ucscf == NULL) {
@ -3754,7 +3754,7 @@ ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf)
shm_name, shm_size); shm_name, shm_size);
shm_zone->data = cf->pool; shm_zone->data = cf->pool;
check_peers_ctx = ucmcf->peers; check_peers_ctx = ucmcf->peers; /*获取后端服务器列表*/
shm_zone->init = ngx_http_upstream_check_init_shm_zone; shm_zone->init = ngx_http_upstream_check_init_shm_zone;
} }

@ -77,7 +77,15 @@ image::./imgs/nginx-src-structure.png[Nginx源码结构]
=== 3. 一个开源实例模块 === 3. 一个开源实例模块
开源地址link:https://github.com/yaoweibin/nginx_upstream_check_module[nginx_upstream_check_module] 开源地址link:https://github.com/yaoweibin/nginx_upstream_check_module[nginx_upstream_check_module]
=== 4. 编译开源组件 === 4. 编译开源模块
在编译之前需要参照开源模块的README文件对nginx源码打补丁否则主动探测功能会失败
[source,shell]
----
cd /path/to/nginx_source_code/nginx-1.26.0/
patch -p1 < /path/to/nginx_http_upstream_check_module/check_1.20.1+.patch
----
为了便于编译我们将编译命令和参数写成shell脚本`configure-health-check.sh` 为了便于编译我们将编译命令和参数写成shell脚本`configure-health-check.sh`
[source,shell] [source,shell]
---- ----
@ -158,6 +166,7 @@ image::./imgs/debug-nginx.png[调试nginx]
=== 3.1 源码解读 === 3.1 源码解读
==== 3.1.1 配置与编译 ==== 3.1.1 配置与编译
ngx_http_upstream_check_module模块的 `config` 文件内容如下: ngx_http_upstream_check_module模块的 `config` 文件内容如下:
@ -234,72 +243,197 @@ fi
1. `ngx_feature="ngx_http_upstream_check_module"` 1. `ngx_feature="ngx_http_upstream_check_module"`
定义了正在配置的 Nginx 模块的名称。 定义了正在配置的 Nginx 模块的名称。
2. `ngx_feature_name=` 2. `ngx_feature_name=`
通常用于定义一个宏名称,但这里留空,表示可能不需要定义特定的宏。 通常用于定义一个宏名称,但这里留空,表示可能不需要定义特定的宏。
3. `ngx_feature_run=no` 3. `ngx_feature_run=no`
表示不需要执行编译后的测试程序来验证特性。这可能是因为模块的存在与否不依赖于运行时检测。 表示不需要执行编译后的测试程序来验证特性。这可能是因为模块的存在与否不依赖于运行时检测。
4. `ngx_feature_incs=` 4. `ngx_feature_incs=`
留空,表示没有特定的头文件需要包含。 留空,表示没有特定的头文件需要包含。
5. `ngx_feature_libs=""` 5. `ngx_feature_libs=""`
留空,表示没有特定的库需要链接。 留空,表示没有特定的库需要链接。
6. `ngx_feature_path="$ngx_addon_dir"` 6. `ngx_feature_path="$ngx_addon_dir"`
设置模块的路径为 `ngx_addon_dir` 变量的值,这通常是模块的安装目录。 设置模块的路径为 `ngx_addon_dir` 变量的值,这通常是模块的安装目录。
7. `ngx_feature_deps="$ngx_addon_dir/ngx_http_upstream_check_module.h"` 7. `ngx_feature_deps="$ngx_addon_dir/ngx_http_upstream_check_module.h"`
定义模块的依赖头文件,这里是模块的头文件。 定义模块的依赖头文件,这里是模块的头文件。
8. `ngx_check_src="$ngx_addon_dir/ngx_http_upstream_check_module.c"` 8. `ngx_check_src="$ngx_addon_dir/ngx_http_upstream_check_module.c"`
指定模块的源文件路径。 指定模块的源文件路径。
9. `ngx_feature_test="int a;"` 9. `ngx_feature_test="int a;"`
提供一个非常简单的测试代码,这里仅仅声明了一个整型变量,实际上这个测试可能不会对模块的检测产生实际作用。 提供一个非常简单的测试代码,这里仅仅声明了一个整型变量,实际上这个测试可能不会对模块的检测产生实际作用。
10. `. auto/feature` 10. `. auto/feature`
执行 Nginx 的 `auto/feature` 脚本来处理配置。 执行 Nginx 的 `auto/feature` 脚本来处理配置。
11. `if [ $ngx_found = yes ]; then` 11. `if [ $ngx_found = yes ]; then`
如果 `auto/feature` 脚本执行后 `ngx_found` 变量被设置为 `yes`,则继续执行以下命令。 如果 `auto/feature` 脚本执行后 `ngx_found` 变量被设置为 `yes`,则继续执行以下命令。
12. `have=NGX_HTTP_UPSTREAM_CHECK . auto/have` 12. `have=NGX_HTTP_UPSTREAM_CHECK . auto/have`
使用 `auto/have` 脚本定义一个宏,表示检测到 `ngx_http_upstream_check_module`。 使用 `auto/have` 脚本定义一个宏,表示检测到 `ngx_http_upstream_check_module`。
13. `CORE_INCS="$CORE_INCS $ngx_feature_path"` 13. `CORE_INCS="$CORE_INCS $ngx_feature_path"`
将模块的路径添加到 Nginx 核心的头文件搜索路径中。 将模块的路径添加到 Nginx 核心的头文件搜索路径中。
14. `ngx_addon_name=ngx_http_upstream_check_module` 14. `ngx_addon_name=ngx_http_upstream_check_module`
设置第三方模块的名称。 设置第三方模块的名称。
15. `HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_check_module"` 15. `HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_check_module"`
将模块名称添加到 HTTP 模块列表中。 将模块名称添加到 HTTP 模块列表中。
16. `NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_feature_deps"` 16. `NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_feature_deps"`
将模块的依赖项添加到第三方模块的依赖列表中。 将模块的依赖项添加到第三方模块的依赖列表中。
17. `NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_check_src"` 17. `NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_check_src"`
将模块的源文件添加到第三方模块的源文件列表中。 将模块的源文件添加到第三方模块的源文件列表中。
18. `else` 18. `else`
如果 `ngx_found` 不是 `yes`,执行错误处理。 如果 `ngx_found` 不是 `yes`,执行错误处理。
19. `cat << END ... END` 19. `cat << END ... END`
输出错误信息,指出 `ngx_http_upstream_check_module` 模块的添加出现错误。 输出错误信息,指出 `ngx_http_upstream_check_module` 模块的添加出现错误。
20. `exit 1` 20. `exit 1`
退出脚本并返回状态码 1表示配置过程中出现错误。 退出脚本并返回状态码 1表示配置过程中出现错误。
整体来看,这个 `config` 文件的作用是检测 `ngx_http_upstream_check_module` 是否可以被添加到 Nginx 中,并根据检测结果更新 Nginx 的配置,以便在编译时包含这个模块。如果检测失败,则输出错误信息并退出配置过程。 整体来看,这个 `config` 文件的作用是检测 `ngx_http_upstream_check_module` 是否可以被添加到 Nginx 中,并根据检测结果更新 Nginx 的配置,以便在编译时包含这个模块。如果检测失败,则输出错误信息并退出配置过程。
---- ----
== 四. 开发流程 ==== 3.1.2 代码调试与跟踪
== 五. 其他 首先使用gdb对编译后的nginx进行debugging
[source,shell]
----
# 调式nginx
gdb /opt/nginx/sbin/nginx
# 载入事先准备好的断点
source gdb.cfg
# 开启子进程调试
set follow-fork-mode child
set set detach-on-fork on
# 终端显示更加友好
set print pretty
# 开始运行nginx
run
----
【此处忽略阅读代码过程...】
==== 3.1.3 代码总结
===== 3.1.3.1 关键数据结构
结构体: `ngx_module_t` 结构体,名为 `ngx_http_upstream_check_module` 的变量
[source,c]
----
ngx_module_t ngx_http_upstream_check_module = {
NGX_MODULE_V1,
&ngx_http_upstream_check_module_ctx, /* module context */
ngx_http_upstream_check_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
ngx_http_upstream_check_init_process, /* init process: 在master进程fork出workder进程的时候调用 */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
----
注意: **其中的回调函数 `ngx_http_upstream_check_init_process`是在Nginx master进程创建worker进程后开始执行的是`ngx_http_uptstream_check_module`模块的入口** ,我们看看这个函数做了什么?
===== 3.1.3.2 模块入口
[source,c]
----
static ngx_int_t
ngx_http_upstream_check_init_process(ngx_cycle_t *cycle)
{
ngx_http_upstream_check_main_conf_t *ucmcf;
if (ngx_process != NGX_PROCESS_WORKER) {
return NGX_OK;
}
ucmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_check_module);
if (ucmcf == NULL) {
return NGX_OK;
}
return ngx_http_upstream_check_add_timers(cycle);
}
----
1. 首先判断当前进程是不是worker进程如果不是worker进程则直接返回
2. 然后获取当前module的、已经**事先装载的配置数据**“事先”的意思是在创建worker进程之前、在初始化和装载配置数据阶段此处暂略后面再讲
3. 最后进入 `ngx_http_upstream_check_add_timers` 函数这是核心函数为当前模块注册timer定时向后端服务器发送健康检测请求并统计检测结果。关键代码如下
[source,c]
----
static ngx_int_t ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle)
{
...
for (i = 0; i < peers->peers.nelts; i++) {
peer[i].shm = &peer_shm[i];
peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler; /* 注册check事件的回调函数 */
...
peer[i].check_timeout_ev.handler = ngx_http_upstream_check_timeout_handler; /* 注册check事件的超时回调函数 */
...
cf = ucscf->check_type_conf; /* check_type_conf的赋值来自于全局变量ngx_check_types[] */
...
peer[i].send_handler = cf->send_handler; /* 发送check数据的回调函数 */
peer[i].recv_handler = cf->recv_handler; /* 接收check响应数据的回调函数 */
...
ngx_add_timer(&peer[i].check_ev, t); /* 为check事件添加定时器 */
}
return NGX_OK;
}
----
需要注意几点:
- 首先Nginx的高性能秘诀是其Event模型和Event Loop机制读者可自行查阅资料同样地这个模块为主动探测也创建了两个event变量`ngx_http_upstream_check_peer_s` 中的 `check_ev` 和 `check_timeout_ev` 变量),当前函数就为这两个事件各注册一个回调函数(handler)
- 除此以外还有nginx内置的两个事件`ngx_connection_t` 中的 `write` 和 `read` 事件主要完成网络连接的IO操作Nginx规定每个event都必须注册一个回调函数当前函数也为 `write` 和 `read` 事件注册回调函数,回调函数的指派来自全局变量数组: `ngx_check_types` (细节藏在 `ngx_http_upstream_check_begin_handler` 函数中)我们暂时只关注通过http协议的主动探测
[source,c]
----
static ngx_check_conf_t ngx_check_types[] = {
...
{ NGX_HTTP_CHECK_HTTP,
ngx_string("http"),
ngx_string("GET / HTTP/1.0\r\n\r\n"),
NGX_CONF_BITMASK_SET | NGX_CHECK_HTTP_2XX | NGX_CHECK_HTTP_3XX,
ngx_http_upstream_check_send_handler, /* ngx_connection_t结构体中 write 事件的回调函数 */
ngx_http_upstream_check_recv_handler, /* ngx_connection_t结构体中 send 事件的回调函数 */
...
1,
1 },
...
----
- 最后,调用 `ngx_add_timer()` 为 `check_ev` 事件注册定时器Nginx会定时调用 `ngx_http_upstream_check_begin_handler()` 函数,一旦发现超时,则会调用 `ngx_http_upstream_check_timeout_handler`。
===== 3.1.3.3 主动检测逻辑
继续跟踪 `ngx_http_upstream_check_begin_handler()` 函数即可,注意其中一个点:
1. 如何保证多个worker进程之间的互斥操作的
2. 如何挑选后端服务器peer 在此文中peer的选择主要由nginx内置负载均衡模块完成例如 `ngx_http_upstream_round_robin` 模块或ip hash模块 `ngx_http_upstream_check` 模块只完成地后端服务器的主动探测和探测结果汇总。 通过给nginx源码打补丁 `ngx_http_upstream_check` 模块将 `ngx_http_upstream_check_add_peer()` 的调用插入到nginx原生round_robin模块中 `ngx_http_upstream_round_robin.c` 的初始化函数 `ngx_http_upstream_init_round_robin()` 中。
3. 如何解析后端服务器的响应数据的? 跟踪 `ngx_http_upstream_check_recv_handler()` 函数。
===== 3.1.3.4 检测超时逻辑
跟踪 `ngx_http_upstream_check_timeout_handler()` 函数即可
===== 3.1.3.5 配置初始化逻辑
一个数据结构:注册模块配置指令的数据接口
[source,c]
----
static ngx_command_t ngx_http_upstream_check_commands[] = {
{ ngx_string("check"),
NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
ngx_http_upstream_check, /* 从配置文件中解析check指令的参数即主动探测的配置*/
0,
0,
NULL },
...
----
接下来,跟踪 `ngx_http_upstream_check()` 函数即可。
== 六. 参考资料 == . 参考资料
1. 负载均衡解释link:https://www.nginx.org.cn/article/detail/440[] 1. 负载均衡解释link:https://www.nginx.org.cn/article/detail/440[]
2. nginx中文配置手册link:https://wizardforcel.gitbooks.io/nginx-doc/content/index.html[] 2. nginx中文配置手册link:https://wizardforcel.gitbooks.io/nginx-doc/content/index.html[]
3. 高可用配置示例link:https://blog.csdn.net/IT_10/article/details/89365436[] 3. 高可用配置示例link:https://blog.csdn.net/IT_10/article/details/89365436[]

Loading…
Cancel
Save