OpenResty 에서 프로 세 스 간 통신 실현
6219 단어 openresty
폴 링
간단 하고 거 칠 지만 보편적으로 사용 되 는 방안 은 모든 프로 세 스 가 자신의 list 형식 에 속 하 는 shdict key 를 나 누 어 일정 시간 마다 새로운 메시지 가 있 는 지 확인 하 는 것 이다.이런 방식 의 장점 은 실현 이 간단 하 다 는 데 있 고, 단점 은 실시 간성 을 보장 하기 어렵 다 는 데 있다.물론 프로 세 스 간 통신 이 필요 한 대부분의 장면 에 대해 0.1 번 에 한 번 씩 타이머 로 새로운 정 보 를 처리 하 는 것 만으로 도 충분 하 다.0. 1 초의 지연 은 길 지 않 기 때문에 1 초 에 10 개의 timer 비용 도 많 지 않 고 일반적인 통 신 량 에 대처 하기에 충분 하 다.
용병
폴 링 이 밀 린 다 고 생각 하거나 환경 에서 폴 링 이 밀 린 다 면 외부 의존 을 도입 해 실시 간 으로 개선 하 는 것 도 고려 할 수 있다.예 를 들 어 로 컬 에서 redis 를 시작 하여 유 닉 스 socket 을 감청 한 다음 에 모든 프로 세 스 는 Pub / Sub 또는 stream 형식 을 통 해 최신 정 보 를 발표 하거나 가 져 옵 니 다.이런 방안 은 실현 하기 도 간단 하고 실시 성과 성능 도 충분 하 며 단지 redis 서 비 스 를 도입 해 야 한다.
ngx_lua_ipc
만약 당신 이 미니 멀리 즘 자라 면 외부 의존 도입 에 대해 극도로 증오 하고 모든 것 이 Nginx 에서 이 루어 지 기 를 원한 다 면, ngxlua_ipc 는 광범 위 하 게 사용 되 는 선택 이다.
ngx_lua_ipc
는 제3자 Nginx C 모듈 로 OpenResty 코드 에서 프로 세 스 간 통신 (IPC) 을 완성 할 수 있 는 Lua API 를 제공 합 니 다.Nginx init 단계 에서 worker process + helper process 대 pipe fd 를 만 듭 니 다.각각 fd 는 read fd 로 데 이 터 를 수신 하고 다른 하 나 는 write fd 로 데 이 터 를 보 내 는 데 사 용 됩 니 다.Nginx 가 worker 프로 세 스 를 만 들 때 모든 worker 프로 세 스 는 이 pipe fd 를 계승 하여 프로 세 스 간 통신 을 실현 할 수 있 습 니 다.관심 있 는 독 자 는
man 7 pipe
pipe 를 바탕 으로 하 는 프로 세 스 간 통신 이 어떻게 실현 되 는 지 알 수 있다.물론
ngx_lua_ipc
pipe 의 read fd 를 ngx_connection_t
을 통 해 Nginx 의 이벤트 순환 체제 에 접속 하여 구체 적 으로 실현 해 야 한다 ipc_channel_setup_conn
. c = ngx_get_connection(chan->pipe[conn_type == IPC_CONN_READ ? 0 : 1], cycle->log);
c->data = data;
if(conn_type == IPC_CONN_READ) {
c->read->handler = event_handler;
c->read->log = cycle->log;
c->write->handler = NULL;
ngx_add_event(c->read, NGX_READ_EVENT, 0);
chan->read_conn=c;
}
else if(conn_type == IPC_CONN_WRITE) {
c->read->handler = NULL;
c->write->log = cycle->log;
c->write->handler = ipc_write_handler;
chan->write_conn=c;
}
else {
return NGX_ERROR;
}
return NGX_OK;
write fd 는 Lua 코드 로 작 동 되 기 때문에 Nginx 의 이벤트 순환 메커니즘 에 가입 할 필요 가 없습니다.
재 미 있 는 디 테 일 이 있 습 니 다. pipe fd 는 쓰기 데이터 가
PIPE_BUF
보다 적 을 때 만 쓰기 작업 의 원자 성 을 확보 할 수 있 습 니 다.만약 에 하나의 메시지 가 PIPE_BUF
(Linux 에서 4K 이상) 을 초과 하면 그 메 시 지 는 원자 가 아 닙 니 다. 앞 PIPE_BUF
에 기록 한 후에 다른 worker 도 같은 프로 세 스에 메 시 지 를 기록 할 수 있 습 니 다.서로 다른 워 커 프로 세 스 의 메시지 가 연결 되 지 않도록
ngx_lua_ipc
패 킷 개념 을 정의 합 니 다.모든 패 킷 은 PIPE_BUF
보다 크 지 않 고 하나의 메시지 가 여러 패 킷 으로 나 뉘 어 다시 포장 할 수 있 도록 헤더 가 있 습 니 다.수신 단 에 서 는 메 시 지 를 받 은 후에 대응 하 는 Lua handler 를 실행 할 수 있 도록
ngx_lua_ipc
함 수 를 사용 하 였 으 며, 이 함 수 는 메시지 유형 에 따라 대응 하 는 handler 에 배 포 됩 니 다.이런 문 제 는 배달 이 완 료 될 수 있 느 냐 없 느 냐 하 는 것 이다. ngx.timer.at
집행 여부 에 달 려 있다.그리고 ngx.timer.at
집행 여 부 는 두 가지 요소 에 제한 을 받는다.ngx.timer.at
크 지 않 으 면 lua_max_pending_timer
timer ngx.timer.at
크 지 않 거나 timer 를 실행 할 충분 한 자원 이 없 으 면 lua_max_running_timer
만 든 timer 가 실행 되 지 않 을 수 있 습 니 다.사실 timer 가 실행 되 지 않 으 면 현재 단계 의 OpenResty 에 오류 로 그 를 기록 하지 않 을 수 있 습 니 다.잘못된 로 그 를 기록 하 는 PR 을 전 제 했 습 니 다.https://github.com/openresty/...그러나 합병 은 계속 되 지 않 았 다.
그래서 엄격 한 의미 에서
ngx.timer.at
소식 이 배 달 될 수 있다 는 보장 도 없고 소식 배달 실패 타 임 스 가 틀 릴 수도 없다.근 데 이 냄비 는 ngx_lua_ipc
가 짊 어 져 야 돼 요.ngx.timer.at
그런 거 안 써 도 돼 요?이것 은 lua - nginx - module 에서 큰 코드 를 복사 하고 가끔 동기 화 해 야 합 니 다.복사 붙 여 넣 기 는 Nginx C 모듈 이 개발 한 오의 입 니 다.동적 감청 유 닉 스 소켓
위의 방법 은 Redis 용병 법 을 제외 하고 응용 코드 에 로 그 를 추가 하지 않 으 면 외부 에서 메 시 지 를 배달 하 는 과정 을 보 려 면 gdb / systemtap / bcc 에 의존 해 야 합 니 다.인터넷 으로 연결 하면 tcpdump 와 같은 서민 기술 을 사용 하여 메시지 의 흐름 을 추적 할 수 있다.물론 유 닉 스 socket 이 라면 TCP proxy 를 임시로 만들어 야 하지만 조작 난이 도 는 앞의 큰 방법 보다 훨씬 낮 아 졌 다.
그렇다면 IPC 를 네트워크 로 연결 시 킬 방법 은 없 지만 외부 의존 을 빌 릴 필 요 는 없 을 까?
Redis 용병 법 을 떠 올 리 면 우리 가 Nginx 의 네트워크 요청 을 직접 할 수 없 는 이 유 는 Nginx 의 모든 worker 프로 세 스 가 평등 하기 때 문 입 니 다. 당신 의 요청 이 어느 프로 세 스에 떨 어 질 지 모 르 고 Redis 를 요청 하 는 것 은 문제 가 없습니다.그러면 우 리 는 서로 다른 워 커 프로 세 스 가 서로 다른 유 닉 스 socket 을 동적 으로 감청 하도록 할 수 있 습 니까?
답 은 긍정 적 이다.우 리 는 이와 유사 한 인 터 페 이 스 를 실현 할 수 있다.
ln = ngx.socket.listen(...)
sock = ln.accept()
sock:read(...)
누군가가 비슷 한 PR 을 언급 한 적 이 있다.https://github.com/openresty/...나 자신 도 회사 프로젝트 에서 많 지 않 은 것 을 이 룬 적 이 있다.이 방법 으로 IPC 를 만 들 지 말 라 고 성명 하 세 요.위의 실현 에 치 명 적 인 문제 가 있 습 니 다. 바로 ln 과 뒤에서 만 든 모든 sock 은 같은 Nginx 요청 에 있 습 니 다.
나 는 일찍이 Nginx 요청 에서 너무 많은 일 을 하면 자원 배분 에 문제 가 생 길 것 이 라 고 쓴 적 이 있다.https://segmentfault.com/a/11...이후 IPC 의 횟수 가 늘 어 나 면서 이런 문 제 는 더욱 뚜렷 해 질 것 이다.
이 문 제 를 해결 하려 면 모든 sock 을 독립 된 fake request 에 넣 고 달 릴 수 있 습 니 다. 이렇게:
ln = ngx.socket.listen(...)
-- ngx.timer.at
ln.register_handler(function(sock)
sock:read(...)
end)
근 데 또 문제 가 있어 요.워 커 id 를 감청 된 유 닉 스 socket 의 ID 로 사용 하면 이 유 닉 스 socket 은 워 커 프로 세 스 에서 동적 으로 감청 되 기 때문에 Nginx reload 나 binary upgrade 의 경우 여러 워 커 프로 세 스 가 같은 워 커 id 를 가지 고 있 기 때문에 같은 유 닉 스 socket 을 감청 하려 고 시도 하여 주소 가 점용 되 는 오류 가 발생 합 니 다.해결 방법 은 PID 를 감청 된 유 닉 스 socket 의 ID 로 바 꾸 고 처음 보 낼 때 PID 를 worker id 로 초기 화 하 는 것 입 니 다.reload 에서 정상적으로 메 시 지 를 보 내 는 것 을 지원 하 는 수요 가 있 으 면 신 구 두 그룹의 worker 를 기록 해 야 합 니 다. 예 를 들 어:
1111 => old worker ID 1
1123 => new worker ID 2
워 커 마다 다른 유 닉 스 소켓 을 할당 합 니 다.
워 커 마다 다른 유 닉 스 socket 을 통 해 프로 세 스 간 통신 을 실현 하 는 방법 도 있다.이런 방법 은 이렇게 교묘 한데, 나 는 단지 내 가 생각 한 것 이 아니 라 는 것 을 원망 할 뿐이다.이 방법 은 위의 동적 감청 유 닉 스 socket 방안 을 도태 시 킬 수 있다.
우 리 는 Nginx 프로필 에서 설명 할 수 있 습 니 다.
ngx_lua_ipc
그리고 Nginx 를 수정 하여 ngx.timer.at
차이 가 많 지 않 은 표 시 를 볼 때 특정한 프로 세 스 가 특정한 유 닉 스 sock 을 감청 하도록 합 니 다. 예 를 들 어 listen unix:xxx.sock use_as_ipc_blah_blah
, use_as_ipc_blah_blah
등 입 니 다.그것 은 동적 감청 유 닉 스 socket 방법 에 비해 실현 이 더욱 간단 하기 때문에 더욱 믿 을 만하 다.물론 reload 나 binary upgrade 에서 정확 한 워 커 에 게 메 시 지 를 보 낼 수 있 도록 하려 면 워 커 id 가 아 닌 PID 로 접미사 로 구분 하고 둘 사이 의 매 핑 을 유지 하 세 요.
이 방법 은 datavisor 의 동업자 가 제시 한 것 으로 최근 에 개 원 될 것 으로 예상 된다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Openresty 및 Google BigQuery를 사용한 마이크로서비스 사용량 로깅Descartes Labs에서는 플랫폼 구축에 마이크로서비스 아키텍처를 사용해 왔습니다. Descartes Labs의 마이크로서비스 로깅, 특히 사용 로깅의 주요 요구 사항은 전체 위성 이미지 모음에 대한 API 액...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.