nginx 소스 코드 분석 스 레 드 탱크 상세 설명
머리말
nginx 는 다 중 프로 세 스 모델 을 사용 합 니 다. master 와 worker 는 주로 pipe 파 이 프 를 통 해 통신 을 합 니 다. 다 중 프로 세 스 의 장점 은 각 프로 세 스 가 서로 영향 을 주지 않 는 다 는 것 입 니 다.하지만 nginx 는 왜 다 중 스 레 드 모델 을 사용 하지 않 느 냐 는 질문 이 자주 나온다.사실 nginx 코드 에 thread 를 제공 합 니 다.pool (라인 풀) 의 핵심 모듈 로 다 중 작업 을 처리 합 니 다.다음은 본인 이 이 threadpool 이 모듈 의 이 해 를 통 해 여러분 과 공유 하 겠 습 니 다.
2. threadpool 스 레 드 탱크 모듈 소개
nginx 의 주요 기능 은 하나의 모듈 로 구성 되 어 있 습 니 다. threadpool 도 예 외 는 아니다.스 레 드 탱크 는 주로 파일 을 읽 고 보 내 는 등 IO 작업 에 사용 되 며 느 린 속도 의 IO 가 worker 의 정상 적 인 운행 에 영향 을 주지 않도록 합 니 다.먼저 공식 설정 예 시 를 참조 하 십시오.
Syntax: thread_pool name threads=number [max_queue=number];
Default: thread_pool default threads=32 max_queue=65536;
Context: main
위 설정 설명 에 따 르 면 threadpool 은 이름 이 있 습 니 다. 위의 스 레 드 수 와 대기 열 크기 는 모든 워 커 프로 세 스 의 스 레 드 를 말 합 니 다. 모든 워 커 의 스 레 드 총수 가 아 닙 니 다.하나의 스 레 드 탱크 에 있 는 모든 스 레 드 가 하나의 대기 열 을 공유 합 니 다. 대기 열의 최대 인원 수 는 위 에서 정의 한 max 입 니 다.quue, 대기 열 이 가득 차 면 대기 열 에 작업 을 추가 하면 오류 가 발생 합 니 다.
앞서 말 한 모듈 에 따라 프로 세 스 초기 화 (master 가 worker 를 시작 하기 전에) createconf--> command_set 함수 -- > initconf, 다음은 이 절차 에 따라 threadpool 모듈 초기 화
/******************* nginx/src/core/ngx_thread_pool.c ************************/
//
static void * ngx_thread_pool_create_conf(ngx_cycle_t *cycle)
{
ngx_thread_pool_conf_t *tcf;
// cycle->pool
tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));
if (tcf == NULL) {
return NULL;
}
// 4 ngx_thread_pool_t
//ngx_thread_pool_t
if (ngx_array_init(&tcf->pools, cycle->pool, 4,
sizeof(ngx_thread_pool_t *))
!= NGX_OK)
{
return NULL;
}
return tcf;
}
// thread_pool , ngx_thread_pool_t
static char * ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_str_t *value;
ngx_uint_t i;
ngx_thread_pool_t *tp;
value = cf->args->elts;
// thread_pool name ( , )
// ngx_thread_pool_t
// ,nginx name
tp = ngx_thread_pool_add(cf, &value[1]);
.......
// thread_pool
for (i = 2; i < cf->args->nelts; i++) {
//
if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {
.......
}
//
if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {
.......
}
}
......
}
//
static char * ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf)
{
....
ngx_thread_pool_t **tpp;
tpp = tcf->pools.elts;
// ,
for (i = 0; i < tcf->pools.nelts; i++) {
.....
}
return NGX_CONF_OK;
}
상기 프로 세 스 가 끝 난 후에 nginx 의 master 는 모든 스 레 드 탱크 의 설정 (tcf - > pools) 을 저장 합 니 다. 이 설정 은 worker 를 만 들 때 도 계 승 됩 니 다.그리고 모든 worker 에서 각 핵심 모듈 의 init 를 호출 합 니 다.process 함수.
/******************* nginx/src/core/ngx_thread_pool.c ************************/
//
static ngx_int_t
ngx_thread_pool_init_worker(ngx_cycle_t *cycle)
{
ngx_uint_t i;
ngx_thread_pool_t **tpp;
ngx_thread_pool_conf_t *tcf;
// worker worker
if (ngx_process != NGX_PROCESS_WORKER
&& ngx_process != NGX_PROCESS_SINGLE)
{
return NGX_OK;
}
//
ngx_thread_pool_queue_init(&ngx_thread_pool_done);
tpp = tcf->pools.elts;
for (i = 0; i < tcf->pools.nelts; i++) {
//
if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {
return NGX_ERROR;
}
}
return NGX_OK;
}
//
static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool)
{
.....
//
ngx_thread_pool_queue_init(&tp->queue);
//
if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {
return NGX_ERROR;
}
//
if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {
(void) ngx_thread_mutex_destroy(&tp->mtx, log);
return NGX_ERROR;
}
......
for (n = 0; n < tp->threads; n++) {
//
err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);
if (err) {
ngx_log_error(NGX_LOG_ALERT, log, err,
"pthread_create() failed");
return NGX_ERROR;
}
}
......
}
//
static void *ngx_thread_pool_cycle(void *data)
{
......
for ( ;; ) {
//
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
return NULL;
}
/* the number may become negative */
tp->waiting--;
// , cond_wait cond_signal/broadcast
while (tp->queue.first == NULL) {
if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)
!= NGX_OK)
{
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
return NULL;
}
}
// task,
task = tp->queue.first;
tp->queue.first = task->next;
if (tp->queue.first == NULL) {
tp->queue.last = &tp->queue.first;
}
if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {
return NULL;
}
......
//task
task->handler(task->ctx, tp->log);
.....
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
// done event
*ngx_thread_pool_done.last = task;
ngx_thread_pool_done.last = &task->next;
// ,
ngx_memory_barrier();
ngx_unlock(&ngx_thread_pool_done_lock);
(void) ngx_notify(ngx_thread_pool_handler);
}
}
// pool_done task event
static void ngx_thread_pool_handler(ngx_event_t *ev)
{
.....
ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
//
task = ngx_thread_pool_done.first;
ngx_thread_pool_done.first = NULL;
ngx_thread_pool_done.last = &ngx_thread_pool_done.first;
ngx_memory_barrier();
ngx_unlock(&ngx_thread_pool_done_lock);
while (task) {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
"run completion handler for task #%ui", task->id);
//
event = &task->event;
task = task->next;
event->complete = 1;
event->active = 0;
// event
event->handler(event);
}
}
3. threadpool 스 레 드 탱크 사용 예시
앞에서 말 한 바 와 같이 nginx 의 스 레 드 탱크 는 주로 파일 을 조작 하 는 IO 작업 에 사 용 됩 니 다.그래서 nginx 에서 자체 적 으로 가지 고 있 는 모듈 ngxhttp_file_cache. c 파일 에서 스 레 드 탱크 의 사용 을 보 았 습 니 다.
/*********************** nginx/src/os/unix/ngx_files.c **********************/
//file_cache ( )
static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
{
.......
#if (NGX_THREADS)
if (clcf->aio == NGX_HTTP_AIO_THREADS) {
c->file.thread_task = c->thread_task;
// ngx_thread_read
c->file.thread_handler = ngx_http_cache_thread_handler;
c->file.thread_ctx = r;
// , , task
n = ngx_thread_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
c->thread_task = c->file.thread_task;
c->reading = (n == NGX_AGAIN);
return n;
}
#endif
return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
}
//task
static ngx_int_t ngx_http_cache_thread_handler(ngx_thread_task_t *task, ngx_file_t *file)
{
.......
tp = clcf->thread_pool;
.......
task->event.data = r;
// thread_event_handler , pool_done event
task->event.handler = ngx_http_cache_thread_event_handler;
//
if (ngx_thread_task_post(tp, task) != NGX_OK) {
return NGX_ERROR;
}
......
}
/*********************** nginx/src/core/ngx_thread_pool.c **********************/
//
ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task)
{
//
if (task->event.active) {
ngx_log_error(NGX_LOG_ALERT, tp->log, 0,
"task #%ui already active", task->id);
return NGX_ERROR;
}
if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
return NGX_ERROR;
}
//
if (tp->waiting >= tp->max_queue) {
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
ngx_log_error(NGX_LOG_ERR, tp->log, 0,
"thread pool \"%V\" queue overflow: %i tasks waiting",
&tp->name, tp->waiting);
return NGX_ERROR;
}
//
task->event.active = 1;
task->id = ngx_thread_pool_task_id++;
task->next = NULL;
// ,
if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
return NGX_ERROR;
}
*tp->queue.last = task;
tp->queue.last = &task->next;
tp->waiting++;
(void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
"task #%ui added to thread pool \"%V\"",
task->id, &tp->name);
return NGX_OK;
}
위의 예 는 nginx 가 현재 스 레 드 탱크 에 대한 사용 방법 을 기본적으로 보 여 주 었 고 스 레 드 탱크 로 IO 와 같은 느 린 속도 조작 을 처리 하면 worker 의 메 인 스 레 드 의 집행 효율 을 향상 시 킬 수 있다.물론 사용자 스스로 모듈 을 개발 할 때 file 를 참조 할 수 있 습 니 다.cache 모듈 에 서 는 스 레 드 탱크 의 방법 을 사용 하여 다 중 스 레 드 를 호출 하여 프로그램의 성능 을 향상 시 킵 니 다.(많은 비판 과 지적 을 환영 합 니 다)
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다. 본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.