nginx 의 output chain 처리 (2)
이 어 지난번 분석 이 계속 되 었 습 니 다. 이번 에는 filter 체인 에서 가장 관건 적 인 모듈 을 살 펴 보 겠 습 니 다. 그것 이 바로 ngx 입 니 다.http_copy_filter_module 모듈, 이 filter 는 복사 해 야 할 buf (파일 이나 메모리) 를 다시 복사 해서 나머지 body filter 에 보 내 는 데 사 용 됩 니 다. 여기 서 중요 한 부분 이 있 습 니 다. 바로 여기 서 nginx 의 나머지 body filter 가 여러 번 호출 될 수 있 습 니 다. 이 다음 에 제 가 일일이 설명 하 겠 습 니 다.초기 화 함수 먼저 보기:
static ngx_int_t
ngx_http_copy_filter_init(ngx_conf_t *cf)
{
ngx_http_next_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_copy_filter;
return NGX_OK;
}
이 필 터 는 body filter 만 있 고 header filter 가 없습니다. 즉, body filter 만 이 필 터 를 사용 할 수 있 습 니 다.
그리고 이 모듈 에 대응 하 는 명령 도 있 습 니 다. 바로 output 입 니 다.buffers, 이 명령 은 conf 의 bufs 에 저 장 됩 니 다:
typedef struct {
ngx_bufs_t bufs;
} ngx_http_copy_filter_conf_t;
nginx 설정 파일 에 있 는 모든 bufs 의 형식 이 같 고 개수 + 크기 임 을 알 아야 합 니 다.이 값 은 다음 에 filter 코드 를 분석 할 때 다시 볼 수 있 습 니 다.
그리고 대응 하 는 merge 방법 을 살 펴 보고 이 bufs 의 기본 값 이 얼마 인지 보 세 요.
static char *
ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_copy_filter_conf_t *prev = parent;
ngx_http_copy_filter_conf_t *conf = child;
// 1 buf, 32768
ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768);
return NULL;
}
copy filter 에 header filter 가 없 기 때문에 context 초기 화 도 body filter 에 놓 여 있 습 니 다. ctx 는 ngx 입 니 다.output_chain_ctx_t, 왜 이름 이 outputchain 은 copy filter 의 주요 논리 적 처리 가 모두 ngx 에 놓 여 있 기 때 문 입 니 다.output_chain 의 이 모듈 은 http 디 렉 터 리 가 아 닌 core 디 렉 터 리 에 저 장 된 것 을 볼 수 있 습 니 다.
다음은 이 context 의 구 조 를 살 펴 보 겠 습 니 다.
typedef struct {
// buf
ngx_buf_t *buf;
// chain
ngx_chain_t *in;
// chain,
ngx_chain_t *free;
// chain
ngx_chain_t *busy;
//sendfile
unsigned sendfile:1;
//directio
unsigned directio:1;
#if (NGX_HAVE_ALIGNED_DIRECTIO)
unsigned unaligned:1;
#endif
// ( sendfile , , , )
unsigned need_in_memory:1;
// buf , , 。
unsigned need_in_temp:1;
ngx_pool_t *pool;
// allocated
ngx_int_t allocated;
// bufs , loc conf bufs
ngx_bufs_t bufs;
// ( upstream output_chain)
ngx_buf_tag_t tag;
// ngx_http_next_filter, filter
ngx_output_chain_filter_pt output_filter;
// filter , upstream output_chain
void *filter_ctx;
} ngx_output_chain_ctx_t;
다음은 구체 적 인 함수 의 실현 을 보면 context 의 이 도 메 인 들 의 뜻 을 잘 이해 할 수 있 습 니 다.
보 러 copyfilter 의 body filter.
static ngx_int_t
ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_connection_t *c;
ngx_output_chain_ctx_t *ctx;
ngx_http_copy_filter_conf_t *conf;
c = r->connection;
// ctx
ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
// , ctx
if (ctx == NULL) {
conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);
//
ctx->sendfile = c->sendfile;
// request filter_need_in_memory ,ctx
ctx->need_in_memory = r->main_filter_need_in_memory
|| r->filter_need_in_memory;
//
ctx->need_in_temp = r->filter_need_temporary;
ctx->pool = r->pool;
ctx->bufs = conf->bufs;
ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module;
// output_filter body filter next
ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
// filter ctx
ctx->filter_ctx = r;
r->request_output = 1;
}
// , 。
rc = ngx_output_chain(ctx, in);
......................................................
return rc;
}
그리고 ngxoutput_chain 이 함수 입 니 다. 여기 nginx filter 의 주요 논 리 는 모두 이 함수 안에 있 습 니 다.다음은 이 함수 의 원형 이다.
ngx_int_t
ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
그 다음 에 우 리 는 그 코드 를 단계별 로 보 겠 습 니 다. 아래 코드 는 short path 라 고 할 수 있 습 니 다. 즉, 우 리 는 모든 in chain 이 복사 할 필요 가 없 을 때 우 리 는 output 를 직접 호출 할 수 있 습 니 다.filter 는 남 은 filter 에 맡 겨 처리 합 니 다.
if (ctx->in == NULL && ctx->busy == NULL) {
//
/*
* the short path for the case when the ctx->in and ctx->busy chains
* are empty, the incoming chain is empty too or has the single buf
* that does not require the copy
*/
if (in == NULL) {
return ctx->output_filter(ctx->filter_ctx, in);
}
// chain, buf
if (in->next == NULL
#if (NGX_SENDFILE_LIMIT)
&& !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
#endif
&& ngx_output_chain_as_is(ctx, in->buf))
{
return ctx->output_filter(ctx->filter_ctx, in);
}
}
위 에서 우 리 는 함수 ngx 를 보 았 다.output_chain_as_is, 이 함 수 는 매우 관건 적 입 니 다. 다음은 다시 호출 될 것 입 니 다. 이 함 수 는 주로 buf 를 복사 해 야 하 는 지 여 부 를 판단 하 는 데 사 용 됩 니 다.1 을 되 돌려 복사 할 필요 가 없다 는 뜻 입 니 다. 그렇지 않 으 면 복사 가 필요 합 니 다.
static ngx_inline ngx_int_t
ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
{
ngx_uint_t sendfile;
// specialbuf, 1,
if (ngx_buf_special(buf)) {
return 1;
}
// buf , directio , buf
if (buf->in_file && buf->file->directio) {
return 0;
}
//sendfile
sendfile = ctx->sendfile;
#if (NGX_SENDFILE_LIMIT)
// pos sendfile , 0
if (buf->in_file && buf->file_pos >= NGX_SENDFILE_LIMIT) {
sendfile = 0;
}
#endif
if (!sendfile) {
// buf , 。
if (!ngx_buf_in_memory(buf)) {
return 0;
}
// in_file 0.
buf->in_file = 0;
}
// , , 0,
if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
return 0;
}
// , mmap , 0.
if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
return 0;
}
return 1;
}
위 에 두 개의 표시 가 있 습 니 다. 하 나 는 need 입 니 다.in_memory, 이것 은 주로 우리 가 sendfile 을 사용 할 때 nginx 는 요청 파일 을 메모리 에 복사 하지 않 습 니 다. 가끔 은 파일 의 내용 을 조작 해 야 합 니 다. 이때 우 리 는 이 표 시 를 설정 해 야 합 니 다. (설정 방법 앞에서 소개 가 초기 화 되 었 습 니 다) 그리고 우 리 는 body filter 에서 내용 을 조작 할 수 있 습 니 다.
두 번 째 는 needin_temp, 이것 은 메모리 에 존재 하 는 buf 를 복사 하 는 데 사 용 됩 니 다. 여기 서 유용 한 모듈 은 charset, 즉 디 코딩 filter 가 있 습 니 다.
그리고 이 부분 은 in chain 을 ctx - > in 으로 복사 하 는 끝 입 니 다. ngx 를 호출 합 니 다.output_chain_add_copy 는 add copy 를 진행 합 니 다. 이 함 수 는 비교적 간단 합 니 다. 여 기 는 분석 하지 않 습 니 다. 그러나 주의해 야 할 것 은 buf 가 파일 에 존재 하고 filepos 가 sendfile limit 을 초과 하면 buf 를 두 개의 buf 로 자 른 다음 두 개의 chain 에 저장 하고 최종 적 으로 연결 합 니 다.
if (in) {
// ctx->in .
if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
return NGX_ERROR;
}
}
그 다음은 주요 논리 처리 단계 다.여기 서 nginx 는 매우 교묘 하고 복잡 하 게 만 들 었 습 니 다. 먼저 chain 의 재 활용, 그 다음 에 buf 의 재 활용 입 니 다.
체인 의 중용 부터 살 펴 보 자.관건 적 인 몇 가지 구조 와 도 메 인, ctx 의 free, busy 및 ctx - > pool 의 chain 도 메 인.
그 중에서 발송 이 끝나 지 않 은 chain 은 busy 에 넣 고 발송 이 끝 난 것 은 free 에 넣 고 마지막 에 호출 합 니 다. ngx_free_chain 은 free chain 을 pool - > chain 에 넣 고 ngxalloc_chain_링크 에 pool - > chain 에 chain 이 존재 한다 면 malloc 를 사용 하지 않 고 pool - > chain 으로 돌아 갑 니 다. 관련 코드 를 보 겠 습 니 다.
// cl pool->chain
#define ngx_free_chain(pool, cl) \
cl->next = pool->chain; \
pool->chain = cl
ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
{
ngx_chain_t *cl;
cl = pool->chain;
// cl , cl
if (cl) {
pool->chain = cl->next;
return cl;
}
// malloc chain
cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
}
return cl;
}
그 다음 에 buf 의 재 활용 입 니 다. 엄격 한 의미 에서 buf 의 재 활용 은 free 의 chain 에서 얻 은 것 입 니 다. free 의 buf 가 재 활용 되면 이 buf 에 대응 하 는 chain 은 ctx - > pool 에 연결 되 고 이 chain 은 재 활용 됩 니 다.
즉, buf 의 재 활용 은 첫 번 째 로 고려 되 었 습 니 다. 이 chain 의 buf 가 재 활용 되 지 않 아 도 된다 는 것 이 확실 할 때 만 chain 은 ctx - > pool 에 연결 되 어 재 활용 되 었 습 니 다.
또 하 나 는 ctx 의 allocated 도 메 인 입 니 다. 이 도 메 인 은 현재 컨 텍스트 에 몇 개의 buf 가 할당 되 었 는 지 표시 합 니 다. blog 는 처음에 output 라 고 언급 했 습 니 다.buffer 명령 은 output 의 buf 크기 와 buf 의 개 수 를 설정 하 는 데 사 용 됩 니 다.allocated 는 output 보다buffer 가 크 면 존재 하 는 buf 를 먼저 보 낸 다음 에 buf 를 다시 분배 할 수 있 습 니 다.
코드 를 보면 위 에서 말 한 중용 과 buf 의 제 어 를 보면 코드 안에서 비교적 뚜렷하게 볼 수 있다.이 코드 는 우리 가 단락 을 나 누 어 볼 때 다음 단락 은 주로 buf 를 복사 하기 전에 하 는 작업 입 니 다. 예 를 들 어 복사 여 부 를 판단 하고 buf 에 게 메모 리 를 나 누 어 주 는 등 입 니 다.
//out chain, filter chain
out = NULL;
//last_out out chain
last_out = &out;
last = NGX_NONE;
for ( ;; ) {
// chain
while (ctx->in) {
// chain buf
bsize = ngx_buf_size(ctx->in->buf);
// bsize 0 buf
if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
ngx_debug_point();
ctx->in = ctx->in->next;
continue;
}
// buf
if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
/* move the chain link to the output chain */
// , chain out,
cl = ctx->in;
ctx->in = cl->next;
*last_out = cl;
last_out = &cl->next;
cl->next = NULL;
continue;
}
// , buf, buf ctx->buf , ctx->buf
if (ctx->buf == NULL) {
// , buf, , directio , NGX_DECLINED ( )。
rc = ngx_output_chain_align_file_buf(ctx, bsize);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
// ,
if (rc != NGX_OK) {
// buf, free buf
if (ctx->free) {
/* get the free buf */
// free buf
cl = ctx->free;
ctx->buf = cl->buf;
ctx->free = cl->next;
// chain ctx->poll , chain .
ngx_free_chain(ctx->pool, cl);
} else if (out || ctx->allocated == ctx->bufs.num) {
// buf , , buf. out ,nginx , out, , nginx
break;
} else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
// , buf.
return NGX_ERROR;
}
}
}
............................................................
}
위의 코드 를 분석 할 때 매우 중요 한 함수 가 있 는데 그것 이 바로 ngx 입 니 다.output_chain_get_buf, 이 함 수 는 다시 사용 할 buf 가 없 을 때 buf 를 분배 하 는 데 사 용 됩 니 다.
여기 서 주의해 야 할 것 은 현재 buf 가 마지막 chain 에 있 으 면 특별한 처리 가 있 습 니 다.여기 서 특수 처 리 는 두 곳 이 있 습 니 다. 하 나 는 buf 의 recycled 도 메 인 이 고 하 나 는 분 배 될 buf 의 크기 입 니 다.
먼저 recycled 도 메 인 을 말 합 니 다. 이 도 메 인 은 현재 buf 가 회수 되 어야 한 다 는 것 을 표시 합 니 다.그리고 우 리 는 nginx 의 일반적인 상황 에서 (예 를 들 어 last buf 가 아 닌) 일부 buf 를 캐 시 한 다음 에 보 내 는 것 (기본 값 은 1460 바이트) 을 알 고 있 습 니 다. recycled 를 설정 하면 우 리 는 buf 를 캐 시 하지 않 습 니 다. 즉, 가능 한 한 보 낸 다음 에 재 활용 할 수 있 도록 합 니 다.
따라서 마지막 buf 라면 일반적으로 우 리 는 recycled 도 메 인 을 설정 할 필요 가 없습니다. 그렇지 않 으 면 recycled 도 메 인 을 설정 해 야 합 니 다.마지막 buf 가 아니라면 buf 를 다시 사용 해 야 할 수도 있 고, buf 는 보 내야 만 다시 사용 할 수 있 습 니 다.
그리고 사이즈.여기 에는 두 개의 크기 가 있 습 니 다. 하 나 는 우리 가 복사 해 야 할 buf 의 크기 이 고 하 나 는 nginx. conf 에 설 치 된 size 입 니 다.마지막 buf 가 아니라면, 우리 가 설정 한 buf 의 size 크기 만 할당 하면 됩 니 다.마지막 buf 라면 처리 가 다 르 고 아래 코드 를 볼 수 있 습 니 다.
static ngx_int_t
ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
{
size_t size;
ngx_buf_t *b, *in;
ngx_uint_t recycled;
in = ctx->in->buf;
// buf, nginx.conf size
size = ctx->bufs.size;
// recycled .
recycled = 1;
// buf chain 。 。
if (in->last_in_chain) {
// , .
if (bsize < (off_t) size) {
/*
* allocate a small temp buf for a small last buf
* or its small last part
*/
size = (size_t) bsize;
recycled = 0;
} else if (!ctx->directio
&& ctx->bufs.num == 1
&& (bsize < (off_t) (size + size / 4)))
{
/*
* allocate a temp buf that equals to a last buf,
* if there is no directio, the last buf size is lesser
* than 1.25 of bufs.size and the temp buf is single
*/
size = (size_t) bsize;
recycled = 0;
}
}
// buf .
b = ngx_calloc_buf(ctx->pool);
if (b == NULL) {
return NGX_ERROR;
}
if (ctx->directio) {
//directio
b->start = ngx_pmemalign(ctx->pool, size, NGX_DIRECTIO_BLOCK);
if (b->start == NULL) {
return NGX_ERROR;
}
} else {
// .
b->start = ngx_palloc(ctx->pool, size);
if (b->start == NULL) {
return NGX_ERROR;
}
}
b->pos = b->start;
b->last = b->start;
b->end = b->last + size;
// temporary.
b->temporary = 1;
b->tag = ctx->tag;
b->recycled = recycled;
ctx->buf = b;
// allocated, 1.
ctx->allocated++;
return NGX_OK;
}
그리고 이 부분 은 buf 를 복사 한 다음 filter 체인 을 호출 하여 보 내 는 것 입 니 다.
// buf.
rc = ngx_output_chain_copy_buf(ctx);
if (rc == NGX_ERROR) {
return rc;
}
// AGAIn, .
if (rc == NGX_AGAIN) {
if (out) {
break;
}
return rc;
}
/* delete the completed buf from the ctx->in chain */
// ctx->in buf buf
if (ngx_buf_size(ctx->in->buf) == 0) {
ctx->in = ctx->in->next;
}
cl = ngx_alloc_chain_link(ctx->pool);
if (cl == NULL) {
return NGX_ERROR;
}
// chain out.
cl->buf = ctx->buf;
cl->next = NULL;
*last_out = cl;
last_out = &cl->next;
ctx->buf = NULL;
}
if (out == NULL && last != NGX_NONE) {
if (ctx->in) {
return NGX_AGAIN;
}
return last;
}
// filter
last = ctx->output_filter(ctx->filter_ctx, out);
if (last == NGX_ERROR || last == NGX_DONE) {
return last;
}
//update chain, chain free, busy .
ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
last_out = &out;
ngx_chain_update_chains 이 함 수 는 제 가 예전 에 블 로 그 를 분석 한 적 이 있 습 니 다. 알 고 싶 은 것 은 제 앞의 블 로 그 를 볼 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.