한 배경
서버 개발 과정에서 우리는 필연적으로 서버가 다시 시작하는 동안 서비스가 중단되지 않도록하는 경우, 새로운 코드 나 구성을로드하도록 서비스를 다시 시작해야합니다 0으로 감소 될 수있다 비즈니스에 미치는 영향에 대해 다시 시작합니다. 최근의 연구는 GR의 nginx 조금보기에 관심있는 학생들에 대한 기록은 매우 흥미로운 찾을 수 있습니다.
둘째, 재시작 과정
- 성공 이전 및 새 수단을 다시 시작, 전환 작업 중에 공존 할 수밖에 없다 과거와 현재 서버의 경우가 있기 때문에, 다시 시작하는 대략입니다 :
- 새 서버를 시작합니다
- 함께 서비스를 제공하기 위해 요청을 처리 이전 및 새 서버의 공존,
- 모든 처리 후 기존 서버 우아한 종료를 요청
- 여기서 가장 큰 문제는 확인하는 방법입니다 이전 및 새 서버 캔 공존, 이전과 다시 시작한 후 동일한 서버 포트, 방법 모두 동일한 포트에서 수신 할 수 있는지 확인합니다.
세, 달성의 nginx
nginx를 GR을 확인하려면, 내가 먼저 다시, 결과가 표시되는 서버의 새로운 인스턴스를 시작 Nginx에 케이스를 열려고 :
분명히, 이전 및 새 서버가 80 포트를 사용하기 때문에 포트를 다중화 소켓 reuseport 옵션에서 시작되지 않았다 서버 인스턴스 가능하지를 다시 열고, 바인딩 시스템 호출 오류. nginx를 기본 바인딩은 다섯 번, 실패 후 직접 종료를 시도합니다. Nginx의 IPv4 주소 및 모니터링의 필요성 및 IPV6 주소 0.0.0.0 [::], 그래서도. (10) 인쇄 로그 EMERG 그.
그리고는 다시 시작 명령을 두 명령의 전체를 부드럽게하려고하기 시작했다 :
1
이
|
kill
-USR2 `
cat
/var/run/nginx
.pid`
kill
-QUIT `
cat
/var/run/nginx
.pid.oldbin`
|
첫 번째 명령 신호는 이전 마스터 프로세스 USR2 프로세스 파일 nginx.pid nginx.conf로 구성된 파일 경로에 저장된 PID /var/run/nginx.pid로 전송된다.
두 번째 명령은 다음 파일에 저장 /var/run/nginx.pid.oldbin PID 프로세스 이전 마스터 프로세스가 종료 이전 마스터 프로세스에 신호를 QUIT 보내는 것입니다.
질문은 그래서, 왜 PID 이전 마스터 프로세스는 두 PID 파일에 존재? 사실, 이전 마스터 USR2 프로세스에 신호를 전송 한 후, 이전 마스터 과정은 nginx.pid.oldbin에 nginx.pid 원본 파일 이름 바꾸기 이름을 변경 PID. 이러한 새로운 마스터가 nginx.pid의 파일 이름을 사용할 수 있었다.
첫 번째 명령을 실행 먼저, 그 결과를 도시 :
예, 이전 및 새 마스터의 공존 및 작업자 프로세스. 두 번째 명령은 다시 그 결과를 도시 :
당신이 볼 수 있듯이, 기존의 마스터 프로세스 8527과 작업자 프로세스 모두는 새로운 마스터 프로세스 12,740 떠나, 종료합니다.
도움이되지 수도 있지만 수동으로하지 작업, 다시 시작 신호를 달성 할 수 사용합니까 새로운 인스턴스를 열 이유에 혼동. 의 nginx 로그 파일에서 봐 :
오류 로그에 추가하기 전에, 더 통지보다 6,7의 상속 소켓, FD 값을 의미한다. 로그 모습 Nginx의 소스 nginx.c / ngx_exec_new_binary 함수에 위치 된 바와 같이,
1
이
삼
4
5
6
(7)
8
9
(10)
(11)
(12)
(13)
(14)
(15)
(16)
(17)
(18)
(19)
(20)
(21)
(22)
(23)
(24)
(25)
(26)
(27)
(28)
(29)
(30)
(31)
(32)
(33)
(34)
(35)
(36)
(37)
(38)
(39)
(40)
(41)
|
ngx_pid_t
ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
{
...
ctx.path = argv[0];
ctx.name =
"new binary process"
;
ctx.argv = argv;
n = 2;
env
= ngx_set_environment(cycle, &n);
...
var = ngx_alloc(sizeof(NGINX_VAR)
+ cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2,
cycle->log);
...
p = ngx_cpymem(var, NGINX_VAR
"="
, sizeof(NGINX_VAR));
ls
= cycle->listening.elts;
for
(i = 0; i < cycle->listening.nelts; i++) {
p = ngx_sprintf(p,
"%ud;"
,
ls
[i].fd);
}
*p =
'\0'
;
env
[n++] = var;
...
env
[n] = NULL;
...
ctx.envp = (char *const *)
env
;
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
if
(ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) {
...
return
NGX_INVALID_PID;
}
pid = ngx_execute(cycle, &ctx);
if
(pid == NGX_INVALID_PID) {
if
(ngx_rename_file(ccf->oldpid.data, ccf->pid.data)
== NGX_FILE_ERROR)
{
...
}
}
...
return
pid;
}
|
프로세스 기능입니다
- 모든 오래된 마스터 프로세스 모니터 (FD)와 새 마스터 과정 ENV 환경 변수 NGINX_VAR에 복사.
- 이름 바꾸기 이름 바꾸기 파일 PID
- ngx_execute 기능 포크의 자식 프로세스는 execve 새 서버를 시작하려면 명령 줄을 실행합니다.
- 서버 시작 프로세스 중, ngx_connection.c / ngx_add_inherited_sockets 특정 코드는 환경 변수 NGINX_VAR를 분석 포함 :
1
이
삼
4
5
6
(7)
8
9
(10)
(11)
(12)
(13)
(14)
(15)
(16)
(17)
(18)
19
20
21
22
23
24
25
26
27
28
29
30
31
|
static ngx_int_t
ngx_add_inherited_sockets(ngx_cycle_t *cycle)
{
...
inherited = (u_char *) getenv(NGINX_VAR);
if
(inherited == NULL) {
return
NGX_OK;
}
if
(ngx_array_init(&cycle->listening, cycle->pool, 10,
sizeof(ngx_listening_t))
!= NGX_OK)
{
return
NGX_ERROR;
}
for
(p = inherited,
v
= p; *p; p++) {
if
(*p ==
':'
|| *p ==
';'
) {
s = ngx_atoi(
v
, p -
v
);
...
v
= p + 1;
ls
= ngx_array_push(&cycle->listening);
if
(
ls
== NULL) {
return
NGX_ERROR;
}
ngx_memzero(
ls
, sizeof(ngx_listening_t));
ls
->fd = (ngx_socket_t) s;
}
}
...
ngx_inherited = 1;
return
ngx_set_inherited_sockets(cycle);
}
|
函数流程为:
解析环境变量NGINX_VAR的值,获取fd存入数组
fd对应的socket设为ngx_inherited,保存这些socket的信息。
也就是说,新的server压根就没重新bind端口listen,这些fd状态和值都是新的master进程fork时带过来的,新的master进程监听处理继承来的文件描述符即可,这里比较关键的一点在于listen socket文件描述符通过ENV传递。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。