"놀 라 움 군", nginx 가 어떻게 해결 하 는 지 보 세 요.
8647 단어 nginx
놀 라 운 그룹 은 보통 server 에서 발생 합 니 다. 부모 프로 세 스 가 포트 를 연결 하여 socket 을 감청 한 다음 에 fork 에서 여러 개의 키 프로 세 스 를 내 고 하위 프로 세 스 들 은 순환 처리 (예 를 들 어 accept) 라 는 socket 을 시작 합 니 다.사용자 가 TCP 연결 을 시작 할 때마다 여러 개의 키 프로 세 스 가 동시에 깨 어 난 다음 에 한 개의 키 프로 세 스 accept 가 새 연결 에 성공 하면 나머지 는 실패 하고 다시 휴면 합 니 다.
그럼, 우 리 는 하나의 프로 세 스 로 만 새 연결 을 수락 할 수 없 습 니까?그리고 메시지 대기 열 등 동기 화 방식 을 통 해 다른 하위 프로 세 스 로 하여 금 이 새로운 연결 을 처리 하 게 하면 놀 라 움 을 피 할 수 있 지 않 습 니까?맞 아, 놀 라 움 은 피 했 지만 효율 이 떨 어 졌 다. 이 프로 세 스 는 accept 연결 에 만 사용 할 수 있 기 때문이다.다 핵 기계 에 있어 서 하나의 프로 세 스 만 accept 를 하 는 것 도 프로그래머 가 스스로 accept 병목 을 만 드 는 것 이다.그래서 저 는 accept 사건 을 다 중 프로 세 스 로 처리 해 야 한다 고 주장 합 니 다.
사실 linux 2.6 커 널 에서 accept 시스템 호출 은 놀 라 운 그룹 이 존재 하지 않 습 니 다 (적어도 저 는 2.6.18 커 널 버 전에 존재 하지 않 습 니 다).부모 프로 세 스에 서 bind, listen, 그리고 fork 에서 하위 프로 세 스 를 내 보 냅 니 다. 모든 하위 프로 세 스 가 이 감청 핸들 을 수락 합 니 다.이렇게 하면 새 연결 이 왔 을 때, 하위 프로 세 스 만 새 연결 로 돌아 가 고, 다른 하위 프로 세 스 는 accept 호출 에서 계속 휴면 하 며, 깨 어 나 지 않 는 것 을 발견 할 수 있 습 니 다.
그러나 불행 하 게 도, 일반적으로 우리 의 프로그램 은 그렇게 간단 하지 않 습 니 다. accept 호출 을 막 으 려 고 하지 않 습 니 다. 우 리 는 다른 네트워크 읽 기와 쓰기 사건 을 처리 해 야 합 니 다. Liux 에서 우 리 는 epoll 로 비 차단 socket 을 해결 하 는 것 을 좋아 합 니 다.그래서 accept 호출 이 놀 라 지 않 더 라 도 놀 라 운 일 을 처리 해 야 합 니 다. epoll 에 문제 가 있 기 때 문 입 니 다.위 에서 말 한 테스트 프로그램 입 니 다. 만약 우리 가 하위 프로 세 스 내 에서 accept 호출 을 막 는 것 이 아니 라 epoll 을 사용 합 니 다.wait, 새로 연 결 될 때 여러 개의 하위 프로 세 스 가 epoll 에 있 음 을 발견 할 수 있 습 니 다.wait 후 깨 우기!
nginx 는 이 렇 습 니 다. master 프로 세 스 감청 포트 번호 (예 를 들 어 80), 모든 nginx worker 프로 세 스 는 epoll 을 사용 하기 시 작 했 습 니 다.wait 에서 새 이벤트 (Liux 아래) 를 처리 합 니 다. 보호 하지 않 으 면 새로운 연결 이 올 때 여러 worker 프로 세 스 가 epoll 에 있 습 니 다.wait 후 깨 어 나 서 accept 가 실 패 했 습 니 다.이제 우 리 는 nginx 가 이 놀 라 운 문 제 를 어떻게 처리 하 는 지 볼 수 있다.
nginx 의 모든 worker 프로 세 스 는 함수 ngxprocess_events_and_timers 에서 이벤트 처리, (void) ngxprocess_events(cycle, timer, flags);서로 다른 이벤트 처리 체 제 를 봉 인 했 습 니 다. Liux 에 서 는 기본적으로 epoll 을 봉 인 했 습 니 다.wait 호출.우리 ngxprocess_events_and_timers 는 놀 라 움 을 해결 하기 위해 무엇 을 했 습 니까?
void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
。。。 。。。
//ngx_use_accept_mutex accept 。 nginx worker >1 accept_mutex , 1
if (ngx_use_accept_mutex) {
//ngx_accept_disabled , , nginx.conf nginx worker , 7/8 ,ngx_accept_disabled , nginx worker , ,
if (ngx_accept_disabled > 0) {
ngx_accept_disabled--;
} else {
// accept , worker 。 , , ngx_accept_mutex_held 1。 , epoll , , epoll 。
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
// , flag NGX_POST_EVENTS, ngx_process_events , , accept ngx_posted_accept_events ,epollin|epollout ngx_posted_events
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS;
} else {
// , , timer epoll_wait , ngx_accept_mutex_delay epoll_wait ,
if (timer == NGX_TIMER_INFINITE
|| timer > ngx_accept_mutex_delay)
{
timer = ngx_accept_mutex_delay;
}
}
}
}
。。。 。。。
//linux , ngx_epoll_process_events
(void) ngx_process_events(cycle, timer, flags);
。。。 。。。
// ngx_posted_accept_events , accept
if (ngx_posted_accept_events) {
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}
// EPOLLIN EPOLLOUT
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
}
if (delta) {
ngx_event_expire_timers();
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"posted events %p", ngx_posted_events);
// 。 , ngx_process_events NGX_POST_EVENTS ngx_posted_events , 。
if (ngx_posted_events) {
if (ngx_threaded) {
ngx_wakeup_worker_thread(cycle);
} else {
ngx_event_process_posted(cycle, &ngx_posted_events);
}
}
}
위의 설명 을 통 해 알 수 있 듯 이 몇 개의 nginx worker 프로 세 스 가 있 든 같은 시간 에 하나의 worker 프로 세 스 만 자신의 epoll 에 감청 핸들 을 추가 할 수 있 습 니 다.accept 를 처리 하 는 nginx worker 프로 세 스 는 flag 를 NGX 로 설정 합 니 다.POST_EVENTS, 이렇게 하면 다음 ngxprocess_이벤트 함수 (linux 에서 ngx epoll process events 함수) 에 서 는 이 벤트 를 즉시 처리 하지 않 습 니 다. 뒤로 미 루 고 모든 accept 이 벤트 를 처리 한 후 자 물 쇠 를 풀 고 정상 적 인 읽 기와 쓰기 socket 이 벤트 를 처리 합 니 다.우리 ngxepoll_process_이벤트 어떻게 하 는 지:
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
。。。 。。。
events = epoll_wait(ep, event_list, (int) nevents, timer);
。。。 。。。
ngx_mutex_lock(ngx_posted_events_mutex);
for (i = 0; i < events; i++) {
c = event_list[i].data.ptr;
。。。 。。。
rev = c->read;
if ((revents & EPOLLIN) && rev->active) {
。。。 。。。
// NGX_POST_EVENTS , accept ngx_posted_accept_events , ngx_posted_events
if (flags & NGX_POST_EVENTS) {
queue = (ngx_event_t **) (rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);
ngx_locked_post_event(rev, queue);
} else {
rev->handler(rev);
}
}
wev = c->write;
if ((revents & EPOLLOUT) && wev->active) {
。。。 。。。
// , NGX_POST_EVENTS , , ngx_posted_events
if (flags & NGX_POST_EVENTS) {
ngx_locked_post_event(wev, &ngx_posted_events);
} else {
wev->handler(wev);
}
}
}
ngx_mutex_unlock(ngx_posted_events_mutex);
return NGX_OK;
}
봐 봐 ngxuse_accept_mutex 는 어떤 상황 에서 열 립 니까?
if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
ngx_use_accept_mutex = 1;
ngx_accept_mutex_held = 0;
ngx_accept_mutex_delay = ecf->accept_mutex_delay;
} else {
ngx_use_accept_mutex = 0;
}
nginx worker 수량 이 1 보다 많 을 때 여러 프로 세 스 가 같은 감청 핸들 을 수락 할 수 있 습 니 다. 이 때 설정 파일 에 acceptmutex 스위치 가 열 리 면 ngxuse_accept_mutex 를 1 로 설정 합 니 다.
부하 균형 작용 이 있 는 ngxaccept_disabled 는 어떻게 유지 합 니까?event_accept 함수 중:
ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n;
사용 한 연결 수가 nginx. conf 에 설 정 된 worker 를 차지 할 때connections 총수 의 7 / 8 이상 시, ngxaccept_disabled 가 바 르 면 이 worker 는 ngxaccept_disabled 에서 1 을 줄 이 고 이번 에는 새 연결 을 처리 하지 않 습 니 다.
마지막 으로, 우리 ngxtrylock_accept_mutex 함 수 는 어떻게 합 니까?
ngx_int_t
ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
{
//ngx_shmtx_trylock , 1 ,0
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
//ngx_enable_accept_events worker epoll
if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
ngx_shmtx_unlock(&ngx_accept_mutex);
return NGX_ERROR;
}
//ngx_accept_mutex_held 1, ,
ngx_accept_events = 0;
ngx_accept_mutex_held = 1;
return NGX_OK;
}
// ,ngx_disable_accept_events epoll
if (ngx_accept_mutex_held) {
if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
return NGX_ERROR;
}
ngx_accept_mutex_held = 0;
}
return NGX_OK;
}
OK, 자물쇠 의 디 테 일이 어떻게 이 루어 졌 는 지 에 대해 서 는 편폭 에 한 하여 말 하지 않 겠 습 니 다. 다음 글 은 다시 이야기 하 겠 습 니 다.이제 nginx 가 놀 라 움 을 어떻게 처리 하 는 지 아 시 죠?쉽게 말 하면 같은 시간 에 하나의 nginx worker 만 자신의 epoll 에서 감청 핸들 을 처리 할 수 있 습 니 다.부하 균형 도 간단 합 니 다. 최대 connection 의 7 / 8 에 이 르 렀 을 때 이 worker 는 accept 자 물 쇠 를 가 져 오 려 고 하지 않 고 새로운 연결 을 처리 하지 않 습 니 다. 그러면 다른 nginx worker 프로 세 스 는 감청 핸들 을 처리 하고 새로운 연결 을 만 들 수 있 습 니 다.그리고 timeout 의 설정 으로 인해 자 물 쇠 를 가 져 오지 못 한 worker 프로 세 스 는 자 물 쇠 를 가 져 오 는 빈도 가 더욱 높 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
간단! Certbot을 사용하여 웹 사이트를 SSL(HTTPS)화하는 방법초보자가 인프라 주위를 정돈하는 것은 매우 어렵습니다. 이번은 사이트를 간단하게 SSL화(HTTP에서 HTTPS통신)로 변경하는 방법을 소개합니다! 이번에는 소프트웨어 시스템 Nginx CentOS7 의 환경에서 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.