nginx 놀 라 움 현상
10074 단어 linux네트워크LINUX 고성능 서버 프로 그래 밍
놀 라 움:
다 중 스 레 드 나 다 중 프로 세 스 의 경우 여러 워 커 가 같은 socket 이 벤트 를 기다 리 고 있 습 니 다. 이벤트 가 발생 했 을 때 이 스 레 드 는 커 널 스케줄 에 의 해 동시에 깨 어 났 습 니 다. 그러나 단지...
이 벤트 를 처리 하 는 워 커 가 있 습 니 다. 다른 워 커 들 은 accept () 가 실패 한 후에 다시 휴면 합 니 다. 이러한 성능 낭비 현상 은 바로 놀 라 움 입 니 다. 상상 할 수 있 습 니 다.
현상의 효율 이 매우 낮다.
저 희 는 서버 와 클 라 이언 트 의 통신 을 예 로 들 었 습 니 다.
놀 라 운 현상 은 서버 에서 발생 합 니 다. 주 스 레 드 (부모 프로 세 스) 는 포트 번호 감청 소켓 을 연결 한 다음 스 레 드 (하위 프로 세 스 생 성) 를 만 듭 니 다.
스 레 드 는 accept 연결 의 소켓 을 동시에 순환 처리 합 니 다. 클 라 이언 트 가 TCP 링크 를 시작 할 때마다 이 부분 스 레 드 는 동시에 깨 어 나 서 선택 합 니 다.
중 하위 스 레 드 에서 accept 연결 을 하면 다른 스 레 드 는 연결 에 실패 하고 휴면 기 에 다시 들 어 갑 니 다.
그러면 어떤 사람 이 말 했다. 왜 메 인 스 레 드 만 accept 로 연결 시 키 지 않 고 동기 화 된 실현 방법 으로 하위 프로 세 스 에 게 새로운 링크 를 처리 하 게 하 는 것 이 아니 냐 는 것 이다.
놀 라 움 을 피 할 수 있 습 니 다. 하지만 그렇다면 accept 연결 에 만 사용 할 수 있 습 니 다. 하지만 이 는 cpu 에 일종 의 자원 입 니 다.
낭비, 그래서 놀 라 운 현상 은 반드시 해결 해 야 한다.
Liux 에서 우 리 는 보통 epoll 로 비 차단 socket 을 해결 하기 때문에 accept 호출 은 놀 라 운 현상 이 없 지만, 우 리 는 epoll 을 호출 하면wait, 새로운 것 이 있 을 때
연결, 여러 스 레 드 가 epoll 에 있 습 니 다.wait 후 깨 어 납 니 다.(epoll wait 가 준 비 된 fd 의 개 수 를 되 돌려 줍 니 다)
nginx
eg: 주 프로 세 스 (또는 스 레 드) 연결 포트 번호 와 ip, 모든 nginx worker 프로 세 스 호출 epollwait 에서 이 벤트 를 처리 합 니 다. 보호 하지 않 으 면 새로운 연결 이 됩 니 다.
다가 오 면 많은 프로 세 스 가 epollwait 후에 깨 어 나 서 accept 가 실 패 했 습 니 다..................................................
그럼 nginx 가 놀 라 움 을 어떻게 해결 하 는 지 살 펴 보 겠 습 니 다.
모든 worker 프로 세 스 는 ngxprocess_events_and_timers 에서 이벤트 처리,
ngx_process_이벤트 (cycle, timer, flags) 는 서로 다른 이벤트 의 처리 체 제 를 패키지 합 니 다.
void ngx_process_events_and_timers(ngx_ctcle_t *cycle)
{
/*
accept
nginx worker >1
accept_mutex
*/
if(ngx_use_accept_mutex)
{
/*
ngx_accept_disabled 0
ngx_accept_disabled == 1/8-
nginx.conf nginx worker ,
7/8 ,nginx_accept_disabled ,
,( )
disabled accept_mutex; ,
*/
if(ngx_accept_disabled > 0)
{
ngx_accept_disabled--;
}
else
{
/*
accept, (accept ) worker epoll
*/
if(NGX_ERRNO == ngx_trylock_accept_mutex(cycle))
{
return ;
}
if(ngx_accept_mutex_held)
{
/*
, flag NGX_POXT_EVENTS, accept
ngx_posted_accept_events 。EPOLLIN EPOLLOUT
ngx_posted_events , ,
。
*/
flags |= NGX_POSTED_EVENTS;
}
else
{
/*
, , timer
ngx_accept_mutex_delay, ,
worker 。
*/
if(timer == NGX_TIMER_INFINITE ||timer >ngx_accept_mutex_delay)
{
timer = ngx_accept_mutex_delay
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
/*
ngx_epoll_process_events
*/
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_postet_events)
{
if(ngx_threaded)
ngx_wakeup_worker_thread(cycle);
else
ngx_event_process_posted(cycle,&ngx_posted_events);
}
}
여러분 들 의 마음 이 좀 혼 란 스 러 우 실 수도 있 습 니 다. 제 가 위의 코드 를 먼저 정리 하 겠 습 니 다.
1 > 우선 flags 즉 ngx 판단use_accept_mutex 가 1 보다 클 지 여부: ngix worker 만 프로 세 스 수가 1 보다 많 고
프로필 에서 accept 열기mutex 자 물 쇠 를 잠 글 때 만 자 물 쇠 를 넣 을 지 말 지 를 고려 합 니 다.
2 > 그리고 판단 ngxaccept_disabled 가 0 보다 클 지 여부: nginx. conf 에서 모든 프로 세 스 가 이벤트 에 연결 할 수 있 는 최대 수 를 설정 합 니 다.
최대 수의 7 / 8 에 도달 하면, ngxaccept_disabled 는 정 (만부 하 표시) 입 니 다. 이 숫자 가 클 수록 양보 합 니 다.
기회 가 클 수록 disabled 를 통 해 경쟁 여 부 를 제어 acceptmutex, 이 숫자 가 0 보다 적 을 때 accpet 를 경쟁 합 니 다.mutex
부하 균형
3 > 획득 자물쇠: ngxtrylock_accept_mutex();그리고 현재 워 커 의 epoll 에 감청 핸들 을 넣 고,
4 > 자 물 쇠 를 가 져 온 후, 우 리 는 flags 를 NGX 로 설치한다.POSITED_EVENTS, accept 이 벤트 를 ngx 에 넣 습 니 다.posted_accept_events
링크 에서 EPOLLIN | EPOLLOUT 이 벤트 를 ngx 에 넣 습 니 다.posted_이벤트 중 제거 (읽 기 및 쓰기 이벤트 시간 이 오래 걸 리 며 잠 금 해제 후 지연 처리)
5 > 자 물 쇠 를 받 지 못 한 worker, timer 는 ngx 로 수정accept_mutex_delay, 더 짧 은 시간 초과 로 돌아 와 자 물 쇠 를 얻 지 못 하 게 합 니 다.
워 커 가 자 물 쇠 를 가 져 오 는 빈도 가 더 높 아 요.
6 > 그리고 처 리 를 시작 합 니 다. ngxposted_accept_이벤트 에 데이터 가 있 을 때 새로운 연결 을 하고 자 물 쇠 를 풀 고 처리 합 니 다.
읽 기와 쓰기 동작.(여기 지연 과정 이 있 습 니 다)
위의 코드 주석 에서 알 수 있 듯 이:
nginx worker 프로 세 스 가 아무리 많 더 라 도 같은 시간 에 하나의 worker 프로 세 스 만 자신의 epoll 에 감청 핸들 을 추가 할 수 있 습 니 다. 이 처리 accept
nginx worker 프로 세 스 가 flags 를 NGX 로 설정 합 니 다.POST_EVENTS, 그렇다면 그 는 다음 ngxprocess_이벤트 함수
ngx epoll process events 함수) 에서 이 벤트 를 즉시 처리 하지 않 습 니 다. 지연 되 며, 모든 accept 를 처리 한 후 자 물 쇠 를 풀 고 나 서 다시 시작 합 니 다.
정상 적 인 읽 기와 쓰기 이벤트 처리 하기;
7 > 우 리 는 ngx 를 보기 시작 했다.epoll_process_events 는 accept 를 어떻게 처리 합 니까?::::::::::::::
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
/*
epoll_wait fd 。
*/
events = epoll_wait(ep, event_list, (int) nevents, timer);
/*
(accept )
*/
ngx_mutex_lock(ngx_posted_events_mutex);
for (i = 0; i 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;
}
ngx_use_accept_mutex 는 어떤 상황 에서 열 립 니까?
nginx worker 의 수량 이 1 보다 많 을 때 여러 프로 세 스 가 동시에 accept 연결 을 할 수 있 습 니 다. 이 설정 파일 의 acceptmutex 스위치 가 열 렸 습 니 다.
바로 ngxuse_accept_mutex 를 1 로 설정 합 니 다.
그리고 제 가 아까 위 에 쓴 것 은 부하 균형 과 비슷 합 니 다: ngxaccept_disabled 는 어떻게 제어 하나 요??
ngx_accept_disabled = ngx_cycle->connection_n /8-ngx_cycle->free_connect_n;
표시: 사용 한 연결 수가 전체 7 / 8 이상 을 차지 할 때, ngxaccept_disabled 가 바 뀌 었 습 니 다.
worker 장 ngxaccept_disabled 에서 1 을 줄 이 고 이번 에는 이 새 연결 을 처리 하지 않 습 니 다.
다음은 제 가 쓴 일반적인 epoll 구현 코드 입 니 다.
생각 을 정리 하 다
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 10
void main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = (6500);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res != -1);
listen(sockfd,5);
int epfd = epoll_create(10);
struct epoll_event events[MAX];
events.event = EPOLLIN|EPOLLET;
event.data.fd = sockfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&events);
while(1)
{
int n = epoll_wait(epfd,events,MAX,-1);
if(n<=0)
{
continue;
}
int i = 0;
for(;i
하하, 여러분 이 어느 정도 알 게 되 었 을 거 라 고 믿 습 니 다. 다만 한 가 지 는 그들 이 어떤 방식 으로 자 물 쇠 를 빼 앗 았 는 지 잘 모 르 겠 습 니 다.
뭔 가 특별한 알고리즘 이 있 을 거 야.
여기 제 가 본 몇 가지 문제 가 있 습 니 다. 여러분 과 공유 하 겠 습 니 다.
1. 새 사용자 의 연결 이 벤트 를 처리 하고 새 연결 을 처리 하 는 자 물 쇠 를 풀 어 줍 니 다. 왜 이렇게 디자인 합 니까?자 물 쇠 를 풀 자마자 새로운 연결 이 있 습 니 다. 자 물 쇠 를 얻 은 프로 세 스 가 대기 열 에 sockfd 를 추가 하려 면 원래 자 물 쇠 를 얻 은 프로 세 스 도 대기 열 에서 sockfd 를 삭제 해 야 합 니 다.
TCP 의 세 번 의 악수 연결 은 비 스 레 드 가 안전 합 니 다.오류 가 발생 하지 않도록 sockfd 를 대기 열 에서 삭제 한 후 새로운 프로 세 스 가 자 물 쇠 를 선점 하여 새로운 연결 을 처리 합 니 다.
2. 자 물 쇠 를 가 져 와 임 무 를 퀘 스 트 대기 열 에 두 고 바로 처리 하 는 것 이 아니 라 왜 이렇게 설계 합 니까?
모든 프로 세 스 가 새 연결 이 벤트 를 처리 하려 면 자 물 쇠 를 가 져 와 야 합 니 다. 현재 프로 세 스 는 새 연결 이벤트 의 sokect 를 작업 대기 열 에 추가 하고 자 물 쇠 를 즉시 풀 어 다른 프로 세 스 가 빨리 자 물 쇠 를 가 져 올 수 있 도록 합 니 다.
사용자 의 연결 을 처리 합 니 다.
잠 금 을 추가 하지 않 으 면 새 이벤트 연결 이 있 을 때 모든 프로 세 스 가 깨 어 나 accept 를 실행 합 니 다. 있 고 하나의 프로 세 스 만 accept 를 되 돌려 줍 니 다.
다른 프로 세 스 는 모두 다시 수면 상태 로 들어간다.현재 자물쇠 가 있 습 니 다. accept 가 발생 하기 전에 프로 세 스 들 이 자 물 쇠 를 선점 해 야 합 니 다. 또한 하나의 프로 세 스 만 자 물 쇠 를 빼 앗 습 니 다.
다른 프로 세 스 도 다시 수면 상태 로 들어간다.
즉, accept 자물쇠 가 있 든 없 든 많은 과정 이 깨 어 나 다시 수면 상태 로 들 어 갈 것 이다. 그 놀 라 운 현상 은 해결 할 수 없 는 것 일 까??????
사실 자 물 쇠 는 놀 라 움 현상 을 해결 하지 못 하고 놀 라 움 현상 은 해결 할 수 없 으 며 많은 과정 이 동시에 깨 어 나 는 것 은 필연 적 인 과정 이다.
Nginx 에 서 는 현재 프로 세 스 의 연결 수 > 최대 연결 수 * 7 / 8 을 검사 하여 현재 프로 세 스 가 새 연결 을 처리 할 수 있 는 지, 깨 어 난 프로 세 스 의 수 를 줄 일 수 있 는 지 판단 합 니 다.
간단 한 부하 균형 도 이 루 었 다.잠 금 은 모든 프로 세 스 가 accept 함 수 를 호출 하지 않도록 보장 할 수 있 습 니 다. 많은 프로 세 스 가 accept 를 호출 하여 오 류 를 되 돌려 줍 니 다.
자물쇠 가 해결 한 것 은 놀 라 움 현상의 잘못 이지 놀 라 움 현상 을 해결 한 것 이 아니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
용감한 바로 가기 및 우분투 응용 프로그램안녕하세요 여러분, 이 기사에서는 모든 사이트에서 pwa를 생성하고 실행기 응용 프로그램으로 추가하는 방법을 설명하고 싶습니다. 일부 웹사이트는 PWA로 설치를 허용하지 않지만 유사한 애플리케이션을 원합니다. 1. ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.