Nginx 시간 초과 이벤트 처리 메커니즘
nginx 에 대해 말하자면 이벤트 메커니즘 의 처 리 는 단지 몇 가지 부분 일 뿐이다.
1. nginx 의 시간 캐 시
우선, 초기 리 눅 스에 서 gettimeofday () 자 체 는 시스템 호출 이 었 기 때문에 잦 은 호출 에 비용 이 많이 들 었 기 때문에 Nginx 는 로 컬 캐 시 시간 을 사용 했다.
Nginx 는 몇 개의 전역 변수 로 시간 을 캐 시 합 니 다.
volatile ngx_msec_t ngx_current_msec;
volatile ngx_time_t *ngx_cached_time;
volatile ngx_str_t ngx_cached_err_log_time;
volatile ngx_str_t ngx_cached_http_time;
volatile ngx_str_t ngx_cached_http_log_time;
이름과 유형 에서 도 알 수 있 듯 이 Nginx 는 각 모듈 에 다양한 유형의 캐 시 변 수 를 제공 하여 호출
ngx_time()
과 ngx_timeofday()
모듈 에 현재 시간 을 제공 하여 gettimeofday()
등 시스템 호출 비용 (물론 새로운 버 전의 Linux gettimeofday()
을 피 할 수 있 습 니 다.이미 전통 적 인 의미 의 시스템 호출 은 아니 지만, 비교적 새로운 Nginx 소스 코드 는 나 도 보지 않 았 다.Nginx 는 시간 을 캐 시 할 수 있 는 몇 개의 대기 열 을 제공 합 니 다.
static ngx_time_t cached_time[NGX_TIME_SLOTS];
static u_char cached_err_log_time[NGX_TIME_SLOTS]
[sizeof("1970/09/28 12:00:00")];
static u_char cached_http_time[NGX_TIME_SLOTS]
[sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
static u_char cached_http_log_time[NGX_TIME_SLOTS]
[sizeof("28/Sep/1970:12:00:00 +0600")];
사실 위의 캐 시 변수의 실제 값 은 최종 적 으로 이 대기 열 에 있 는 값 을 가리 키 고 있 습 니 다. 그러나 저 는 grep 를 했 습 니 다. 이 대기 열 들 은 다른 곳 에서 사용 되 지 않 은 것 같 습 니 다. 그래서 그들 에 게 도 상세 하 게 소개 하지 않 았 습 니 다. 쉽게 말 하면 Nginx 는 하나의
slot
전역 변 수 를 유지 하고 매번 ngx_time_update
함수 에서 호출 gettimeofday()
하여 현재 시간 을 가 져 왔 습 니 다.대기 열 뒤에 새 시간 을 삽입 하고 이동 slot
해서 현재 캐 시 값 을 표시 하고 ngx_cache_time
등 바늘 을 최신 cache_time[slot]
으로 가리 키 면 됩 니 다.구체 적 으로
ngx_time_update()
의 실현 을 보면 된다.2. Nginx 는 캐 시 를 언제 업데이트 합 니까?
여기 서 우리 가 주목 하 는 문 제 는 Nginx 가 시간 캐 시 를 업데이트 하 는 시기 가 언제 입 니까?
물론 초기 시작 과 cycle 의 초기 화 는 몇 번 의 업데이트 시기 가 있 습 니 다. 여기 서 저 희 는 주로 사건 처리 과정 에서 시간 이 업데이트 되 는 시 기 를 고려 합 니 다.
여기 서 Nginx 는 두 가지 서로 다른 해결 방안 을 제 시 했 고
ngx_time_resolution
변수 에 의 해 결정 된다.ngx_timer_resolution
이 0 일 때 Nginx 는 호출 epoll_wait
할 때마다 시간 캐 시 업데이트 ngx_timer_resolution
이 0 이 아 닐 때 이 값 은 시간 정밀도, 즉 '캐 시 를 얼마나 자주 업데이트 합 니까?' 를 나타 낸다. 이때 Nginx 는 시간 모듈 이 초기 화 될 때 타 이 머 를 설정 하여 타이머 의 중단 시간 을 ngx_timer_resolution
에 규정된 밀리초 로 한 번 SIGALRM
신 호 를 터치 할 때마다 한 번 ngx_time_update()
호출 한다.물론, 우 리 는 신호 처리 함수 자체 가 CPU 시간 을 너무 많이 차지 하 는 것 을 절대로 허용 하지 않 기 때문에, 그 신호 처리 함수 의 실현 은 매우 간단 하 다.
void
ngx_timer_signal_handler(int signo)
{
ngx_event_timer_alarm = 1;
#if 1
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "timer signal");
#endif
}
실제 호출
ngx_time_update()
은 ngx_process_events()
에서:static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
int events;
uint32_t revents;
ngx_int_t instance, i;
ngx_uint_t level;
ngx_err_t err;
ngx_log_t *log;
ngx_event_t *rev, *wev, **queue;
ngx_connection_t *c;
/* NGX_TIMER_INFINITE == INFTIM */
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll timer: %M", timer);
// epoll_wait
events = epoll_wait(ep, event_list, (int) nevents, timer);
err = (events == -1) ? ngx_errno : 0;
//
// SIGALRM , ngx_event_timer_alarm 1,
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
ngx_time_update();
}
if (err) {
if (err == NGX_EINTR) {
// , NGX_OK
if (ngx_event_timer_alarm) {
ngx_event_timer_alarm = 0;
return NGX_OK;
}
level = NGX_LOG_INFO;
} else {
level = NGX_LOG_ALERT;
}
ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
return NGX_ERROR;
}
/* */
}
함수 에서 먼저
flag
인자 의 NGX_UPDATE_TIME
표지 위 치 를 검사 하 는 것 을 볼 수 있 습 니 다. 이것 은 ngx_timer_resolution
이 0 일 때 만 설정 하 는 위치 로 이벤트 처리 때마다 시간 캐 시 를 업데이트 하 는 것 을 의미 합 니 다.그 밖 에 ngx_timer_resolution
이 0 이 아니 라 소프트 인 터 럽 트 에서 플래그 위 치 를 설정 해 야 시간 캐 시 업 데 이 트 를 촉발 할 수 있 습 니 다.여기 서도 신호 가 중 단 된 경우
epoll_wait
가 마침 EINTR
이 고 ngx_event_timer_alarm
가 1 이 라면 이 신호 가 중 단 된 것 으로 보고 epoll_wait
을 0 으로 정리 했다.3. 정시 이벤트 의 조직 방식
정시 사건 이나 시간 초과 사건 의 처리 에 대해 우 리 는 매우 간단 한 직관 을 가지 고 있다. 모든 정시 사건 에 타 이 머 를 등록 하고 타이머 리 셋 에서 만 료 사건 을 처리 하면 되 지 않 겠 는가?코드 를 쓰 는 것 이 얼마나 간단 합 니까? lambda 표현 식 이 하나 더 있 으 면...
안 타 깝 게 도 시스템 밑바닥 에서 제공 하 는 타이머 의 수량 은 곱 창 에 한계 가 있 지만, 우 리 는 오히려 API 를 이렇게 설계 할 수 있다.
Nginx 는 간단 하고 효과 적 인 전략 을 사용 합 니 다. 적당 한 시 기 를 선택 하고 최근 에 만 료 될 사건 이 만 료 되 었 는 지 가능 한 한 검사 합 니 다. 있 으 면 처리 하고 없 으 면 건 너 뜁 니 다.
그러면 '최근 에 만 료 될 구조' 를 빨리 얻 는 것 이 중요 하 다. 또한 복잡 한 사건 처리 과정 에서 정시 사건 이 무 작위 로 삽입 되 기 때문에 간단 한 대기 열 도 감당 할 수 없다. 이때 데이터 구 조 를 잘 아 는 학생 들 은 빨 간 검 은 나 무 를 곧 생각 할 것 이다.
맞 아, Nginx 는 빨 간 검 은 나무 로 정시 사건 을 관리 하 는 거 야.만 료 시간 을 키 로 하여 이 붉 은 검 은 나 무 를 관리 합 니 다. 그러면 붉 은 검 은 나무 중 가장 왼쪽 에 있 는 사건 은 기한 을 넘 기 는 사건 입 니 다.한편, 사건 의 소비자 가 사건 을 삽입 하고 소비 가 끝 난 후에 사건 을 삭제 해 야 한다. 이 는 기한 이 지난 사건 을 찾 는 것 을 포함한다. 이런 작업 의 시간 복잡 도 는 모두 O (logN) 내 에서 통제 되 고 효율 이 상당히 높다.(붉 은 검 은 나무 와 같은 데이터 구조 에 대한 세부 사항 은 데이터 구조의 전문 저 서 를 참고 하 시기 바 랍 니 다)
Nginx 가 시간 초과 이 벤트 를 관리 하 는 기조 다.구체 적 인 코드 실현 은
ngx_event_timer_alarm
의 세 가지 함 수 를 참조 할 수 있 는데 기본적으로 일부 붉 은 검 은 나무의 첨삭 과 수정 을 한 다음 에 조정 하 는 것 이다.4. 정시 사건 을 처리 할 시기
시간 초과 사건 의 처리 시 기 는 물론 큰 사건 순환 에 두 어야 합 니 다. accept 자물쇠 의 점용 시간 을 줄 이기 위해 시간 초과 사건 의 처 리 는 당연히 accept 자 물 쇠 를 풀 때 이후 에 두 어야 합 니 다.
오픈 하지 않 는 경우
src/event/ngx_event_timer.c
를 방지 하기 위해 timer_resolution
너무 많은 시간 을 차지 합 니 다. 호출 epoll_wait()
하기 전에 Nginx 는 가장 가 까 운 시간 초과 사건 의 시간 을 계산 한 다음 에 이 시간 을 timer 변수 에 기록 하여 ngx_process_events(cycle, timer, flags)
의 시간 초과 매개 변 수 를 제어 합 니 다 epoll_wait
의 점용 시간 을 제어 합 니 다.또한 Nginx 는
epoll_wait
호출 이 차지 하 는 시간 ngx_process_events
변 수 를 계산 delta
하고 delta > 0
의 경우 에 만 호출 ngx_event_expire_timers()
을 사용 하여 시간 초과 사건 을 처리 함으로써 무의미 한 검색 을 피 할 수 있 습 니 다 (정말 고심 하 셨 습 니 다).다음은 이벤트 순환 에서 시간 초과 이벤트 처리 가 차지 하 는 위 치 를 전체적으로 볼 수 있 습 니 다.
void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
ngx_uint_t flags;
ngx_msec_t timer, delta;
if (ngx_timer_resolution) {
timer = NGX_TIMER_INFINITE;
flags = 0;
} else {
// timer
timer = ngx_event_find_timer();
flags = NGX_UPDATE_TIME;
}
// accept
/* accept */
delta = ngx_current_msec;
// process_events, epoll_wait
(void) ngx_process_events(cycle, timer, flags);
delta = ngx_current_msec - delta; // events
// accept ,
if (ngx_posted_accept_events) {
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}
// accept
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
}
//
if (delta) {
ngx_event_expire_timers();
}
/* */
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.