프 록 시 서버 의 콘 텐 츠 복사 방지 기술
nginx 의 이 처 리 는 주로 두 함수 에서 발생 하거나 한 쌍 의 함수: ngxevent_pipe_read_upstream 과 ngxevent_pipe_write_downstream。여기 서 는 그들 이 upstream 에서 맡 은 역할 에 대해 서 는 논의 하지 않 습 니 다. 우 리 는 그들 이 어떻게 복잡 한 절 차 를 아름 답 게 조작 하고 각종 buffer 와 chain 을 조율 하 는 지 만 봅 니 다.
백 엔 드 데 이 터 를 읽 을 때 nginx 는 recv 를 사용 합 니 다.chain, 이 인 터 페 이 스 는 chain 을 사용 하기 때문에 호출 하기 전에 해당 하 는 chain 을 수신 도구 로 준비 해 야 합 니 다. 그 중 하 나 는 p - > free 입 니 다.raw_bufs (p 형식 은 ngx event pipe t) 입 니 다.이 chain 들 은 recvchain 은 반드시 다 쓸 수 있 는 것 이 아 닙 니 다. nginx 는 이러한 순환 에서 처리 합 니 다.
cl = chain;
p->free_raw_bufs = NULL;
while (cl && n > 0) {
ngx_event_pipe_remove_shadow_links(cl->buf);
size = cl->buf->end - cl->buf->last;
if (n >= size) {
cl->buf->last = cl->buf->end;
if (p->input_filter(p, cl->buf) == NGX_ERROR) {
return NGX_ABORT;
}
n -= size;
ln = cl;
cl = cl->next;
ngx_free_chain(p->pool, ln);
} else {
cl->buf->last += n;
n = 0;
}
}
if (cl) {
for (ln = cl; ln->next; ln = ln->next) { /* void */ }
ln->next = p->free_raw_bufs;
p->free_raw_bufs = cl;
}
위의 이 코드 안에 현재 recvchain 다 쓴 chain 은 pool 에 회수 하고 나머지 는 다시 p - > freeraw_bufs (즉 코드 중의 ngx free chain (p - > pool, ln).여기 서 문제 가 있 습 니 다. recvchain 이 사용 하 는 chain 들 은 아직 더 이상 처리 하지 않 았 잖 아 요. 왜 회수 하 셨 어 요?사실 회수 한 것 은 buffer 가 아니 라 chain 입 니 다. 이들 의 신분 이 다 릅 니 다. chain 은 기차 가죽 에 해당 하고 buffer 야 말로 실제 운송 의 원료 입 니 다.그래서 이곳 의 기차 가죽 은 확실히 다 썼 고 우 리 는 회수 기 에 가서 준비 했다.그럼 버퍼 는 요?이 문장 봐 p - > inputfilter (p, cl - > buf), 이 안 이 처리 하 는 실제 buffer 입 니 다. 우 리 는 ngx 로http_proxy_copy_filter 를 예 로 들 어 무슨 일이 일 어 났 는 지 살 펴 보 자. 물론 다른 input 가 들 어 있다.filter。
static ngx_int_t
ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
{
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_http_request_t *r;
if (buf->pos == buf->last) {
return NGX_OK;
}
if (p->free) {
cl = p->free;
b = cl->buf;
p->free = cl->next;
ngx_free_chain(p->pool, cl);
} else {
b = ngx_alloc_buf(p->pool);
if (b == NULL) {
return NGX_ERROR;
}
}
ngx_memcpy(b, buf, sizeof(ngx_buf_t));
b->shadow = buf;
b->tag = p->tag;
b->last_shadow = 1;
b->recycled = 1;
buf->shadow = b;
cl = ngx_alloc_chain_link(p->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
cl->next = NULL;
if (p->in) {
*p->last_in = cl;
} else {
p->in = cl;
}
p->last_in = &cl->next;
if (p->length == -1) {
return NGX_OK;
}
...
return NGX_OK;
}
이 안 은 실제 적 으로 모든 buffer 에 그림자 (즉 shadow buffer) 를 만 들 고 이 shadow 를 p - > in 위 에 걸 었 습 니 다.물론 시작 할 때 이 shadow buffer 는 우리 alloc 공간 이 필요 합 니 다. 뒤쪽 p - > free 에는 기 존의 buffer 가 많이 있 습 니 다.shadow buffer 설정 에 주의 하 십시오:
ngx_memcpy(b, buf, sizeof(ngx_buf_t));
b->shadow = buf;
b->tag = p->tag;
b->last_shadow = 1;
b->recycled = 1;
buf->shadow = b;
원본 buffer, 우 리 는 raw buffer 라 고 부 릅 니 다. 전체 값 은 그림자 buffer (구성원 도 함께 복사), 즉 shadow buffer 입 니 다.그리고 둘 은 shadow 멤버 를 통 해 서로 관련 되 었 다.그렇다면 누가 raw buffer 이 고 누가 진정한 그림자 인지 어떻게 구분 할 수 있 을 까?정 답 은 lastshadow, 이 괴상 한 것 은 다음 에 더 토론 할 것 입 니 다.
여기에서 우 리 는 백 엔 드 에서 읽 은 원본 데이터 가 원래 의 buffer 안에 있 는 것 을 보 았 다.지금 은 또 한 줄 의 그림자 가 나 왔 다. 그들 은 새 기차 가죽 을 옮 겨 p - > in 열 차 를 탔 다.계속 토론 하기 전에 이 p 의 몇 명의 멤버 를 붙 여 라.
struct ngx_event_pipe_s {
...
ngx_chain_t *free_raw_bufs;
ngx_chain_t *in;
ngx_chain_t **last_in;
ngx_chain_t *out;
ngx_chain_t *free;
ngx_chain_t *busy;
...
}
후속 수신 내용 에서 더 많은 raw buffer 를 신청 할 때 p - > in 의 데 이 터 를 임시 파일 에 기록 합 니 다. 이 shadow (p - > in) 는 p - > free 에 놓 여 있 습 니 다. 이 물건 은 shadow buffer 의 휴지통 으로 볼 수 있 습 니 다.먼저 이곳 에 와 서 물건 이 있 는 지 없 는 지 볼 수 있 습 니 다. pool 에 도움 을 청 하지 않 았 습 니 다alloc。그리고 원래 데 이 터 를 저 장 했 던 raw buffer 도 freeraw_bufs 에서 메모리 가 다시 사용 되 었 습 니 다.디스크 파일 에 적 힌 데 이 터 는 buffer (in file 태그) 로 추상 화 되 지만 p - > out 에 걸 립 니 다.구조 중의 lastin 은 말 할 필요 도 없 이 p - > in 의 마지막 chain 을 가리킨다.
위의 분석 을 통 해 우 리 는 처리 해 야 할 buffer 가 p - > in 또는 p - > out 에 있 을 수 있다 는 것 을 알 게 되 었 습 니 다. 다음은 그것들 을 보 내 는 것 입 니 다. 당신 은 ngx 를 볼 수 있 습 니 다.event_pipe_write_to_다운 스 트림 은 이 일 을 전문 적 으로 하 는 사람 이다.주석 코드 대신 대체적인 윤곽 과 개별 디 테 일 을 묘사 합 니 다.내 가 게 으 른 것 이 아니 라, 네가 한 과정의 윤곽 을 알 게 된 후에 코드 를 읽 는 것 이 매우 쉬 워 질 것 이다. 그러면 나 는 손가락 의 마 모 를 줄 이 고, 너 도 더 많은 것 을 배 울 수 있다. "hi honey, open your mouth!" 뿐만 아니 라.
선발 p - > out.왜?원래 데 이 터 는 p - > in 에 있 습 니 다. 그 다음 에는 특수 한 상황 으로 임시 파일 에 기록 되 어 있 지 않 습 니까?혹시 p - > out 에 데이터 가 있 나 요? p - > in 에 도 있 나 요?물론 p - > out 으로 인해 많은 buffer 를 비 워 후속 처리 에 사용 할 수 있 습 니 다.실제 발송 동작 은 p - > outputfilter (p - > output ctx, out) 를 완성 합 니 다.이것 은 말 하지 않 겠 습 니 다. 말하자면 끝 이 없습니다. 모 르 는 것 은 구 글 이 될 수 있 습 니 다.
물론 우리 가 보 내 고 싶 은 데 이 터 는 한 번 에 다 보 내지 않 을 수도 있 습 니 다. 즉, p - > in 또는 p - > out 의 데 이 터 는 일부분 보 낼 수 있 지만 일부분 은 보 내지 않 을 수도 있 습 니 다.이미 보 냈 습 니 다. 관련 chain 은 p - > free 에 넣 을 것 입 니 다. 억 눌 린 것 은 p - > busy 에 넣 을 것 입 니 다. (busy! 조급해 요..)이 일 들 은 모두 ngx 에서 발생 한다.chain_update_chains 에 서 는 코드 를 자세히 읽 을 수 있 습 니 다.이 p - > free 안 에는 shadow buffer, 조끼 가 들 어 있 는 것 이 분명 합 니 다.데이터 가 전송 되 었 으 니 실제 raw buffer 도 p - > free 로 회수 되 어야 합 니 다.raw_bufs。
한 마디 로 하면 이 두 개의 차 이 는 많 지 않 습 니 다. 이런 큰 절차 에 대해 아직도 헷 갈 리 는 사람 이 있다 면 제 가 그림 을 그 려 서 더 묘사 하 기 를 바 랍 니 다. 이것 은 당신 이 어 딘 가 에 잠시 걸 렸 을 수도 있 습 니 다. 코드 나 댓 글 을 읽 고 토론 하 겠 습 니 다. 어쨌든 한 가지 사실은 제 가 게 을 러 서 그림 을 그리고 싶 지 않다 는 것 입 니 다. (솔직히 이 그림 은 이해 하기 쉽 습 니 다!)
나머지 는 세부 사항 입 니 다. 예 를 들 어 buf 구조 체 에 있 는 여러 가지 표 시 를 보 여 줍 니 다.http://tengine.taobao.org/book/chapter_4.html):
unsigned recycled:1; /* */
unsigned in_file:1; /* buffer */
/* buffer , gzip */
unsigned flush:1;
/*
* buffer , ,
* buffer
*/
unsigned sync:1;
/* buffer, */
unsigned last_buf:1;
/* buffer */
unsigned last_in_chain:1;
/* shadow buffer, buffer */
unsigned last_shadow:1;
/* */
unsigned temp_file:1;
이 표기 들 에 대해 어떻게 그들의 용도 와 의 미 를 확정 합 니까?다른 방법 은 없다. 첫째, 어떤 곳 을 찾 아 그들 을 설 치 했 는 지 (위치 설정 과 제거).둘째, 어떤 곳 을 찾 아 그들 에 대해 판단 처 리 를 했 는 지, 물론 이 두 곳 에 표 시 된 문맥 에 대해 서도 알 아야 한다. 어쨌든 매우 번거롭다.내 가 보기에 그 sync 표 시 는 가장 모호 하고 말 그대로 동기 화 되 었 으 나 사용 할 때 동기 화 와 무슨 관계 가 있 는 지 전혀 발견 하지 못 했다. * * * (욕).
그리고 함수 ngxevent_pipe_remove_shadow_링크 스, 그 안에 처리 가 있 습 니 다:
ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf)
{
...
while (!b->last_shadow) {
next = b->shadow;
b->temporary = 0;
b->recycled = 0;
b->shadow = NULL;
b = next;
}
...
}
보아하니 이 buf 들 은 shadow 를 통 해 하나의 사슬 을 구성 한 것 같은 데 어떻게 설명 합 니까?앞의 분석 에는 전혀 관련 과정 이 없다.하하, 여기 보 세 요: ngxhttp_proxy_chunked_filter
이 함수 에 서 는 원본 데 이 터 를 포함 한 raw buf (즉, ngx http proxy chunked filter 두 번 째 매개 변수 buf) 에 여러 개의 chunk 블록 이 포 함 될 수 있 습 니 다. 그들 은 각각 새로운 buf 로 관리 하고 서로 shadow 를 통 해 연결 되 며 마지막 buf (last shadow 설정) 는 이 raw buf 와 shadow 관 계 를 맺 습 니 다.왜 이 buf 가 진짜 raw buf 의 shadow 일 까요?진정한 shadow buf 의 멤버 들 은 raw buf 와 완전히 미 러 이기 때문에 중간 에 chunk 를 관리 하 는 buf 들 은 스스로 'shadow' 라 고 부 르 지만 그들의 것 은 raw buf 의 일부분, 반제품 에 불과 하 다.다시 말 하면 진정한 shadow 는 lastshadow。
chunk 로 인 한 이러한 내부 관 계 는 외부 에 투명 하기 때문에 (input filter) 우 리 는 free buf 를 받 아 처리 할 때 이러한 잠재 적 인 shadow 와 관련 된 것 을 제거 해 야 합 니 다. 그것 은 모두 과거의 일이 기 때문에 계산 이 잘 되 지 않 았 을 뿐 입 니 다.그리고 ngxevent_pipe_remove_shadow_링크 스 는 바로 이런 청소부 역할 을 맡 는 다.
nginx 의 이 연결 방식 은 상류의 응답 을 하류 로 전송 하 는 단계 에 만 사 용 됩 니 다. 요청 체 가 함 유 된 요청, 예 를 들 어 post 요청 등 은 이 메커니즘 을 사용 하지 않 았 습 니 다. 왜 그런 지 생각 합 니 다.이 렇 겠 지. nginx 는 상류 데 이 터 를 하류 로 나 누 어 주 는 것 은 무조건 이 며, 요청 을 받 은 후 가능 한 한 빨리 하류 에 데 이 터 를 토 해 야 한다.한편, post 요청 에 대해 서 는 상류의 승인 ("100 - continue" 응답) 을 받 아야 할 수도 있 고, 하류 에서 제출 한 데 이 터 를 빨리 받 아들 여야 할 수도 있 습 니 다.일반적으로 상류 와 먼저 소통 할 필요 가 없 으 며, nginx 는 먼저 요청 체 를 받 아들 인 다음 에 뒤의 일 을 하 는 것 을 선택한다.하지만 읽 은 내용 을 첫 번 째 시간 에 상위 권 에 넘 기 려 는 수요 도 많다. 어 떡 하지?
tengine 은 이들 의 1.5.0 버 전에 서 no buffered request body sent 를 실현 했다. 즉, 일부 요청 체 를 받 으 면 백 엔 드 서버 에 전송 할 수 있 고 작 가 는 야 오 웨 이 빈 이다.
Tengine-1.5.0 [2013-07-31]
...
Feature: ,HTTP FastCGI [yaoweibin]
...
저 는 대충 살 펴 보 았 습 니 다. 아마도 request 에 free, busy, out 등 chain 멤버 를 도입 한 다음 에 앞에서 우리 가 토론 한 상류 에서 하류 로 전달 하 는 논 리 를 모방 한 것 같 습 니 다.더 많은 세부 사항 은 도착 할 수 있 습 니 다.http://tengine.taobao.org/changelog_cn.html#1_5_검사 하 다.
우리 의 cache 시스템 에 서 는 nginx 라 는 논 리 를 참고 하지 않 았 다.왜 요? 혹시 물건 이 있 나 요?정말 있다!우 리 는 시스템 호출 splice, 이른바 제로 복사 기술 을 사용 했다.이 물건 은 처음에 Liux 2.6.17 버 전에 나 타 났 습 니 다. 이 버 전 은 2006 년 에 출시 되 었 고 우리 cache 프로젝트 도 그때 부터 시작 되 었 습 니 다. 마침 도움 이 되 었 습 니 다!왜 다시 nginx 의 복잡 한 체 제 를 사용 하여 스스로 재 미 를 찾 습 니까?반면에 nginx 는 가장 먼저 시 작 된 것 은 2002 년 이 었 고 그 때 는 Liux 2.6.0x 의 시 대 였 으 며 소 B 의 물건 을 사용 할 수 있 는 것 이 별로 없 었 다.나 는 Igor 도 찾 아 봤 다 고 생각한다. 두 손 이 텅 비어 있 을 것 같 아서 스스로 하기 로 결정 했다.nginx 의 이 논 리 는 타 오 바 오 가 buffer 복사 방지 기술 이라는 이름 을 지어 주 었 는데 처음에 들 었 을 때 순간 위협 을 받 았 다.위 에서 말 한 그 물건 이라는 것 을 알 게 되 었 다.
멀리 갔 어.여기 서 splice 의 용법 을 살짝 말씀 드 리 겠 습 니 다.
splice() moves data between two file descriptors without copying between kernel address space and user address space. It transfers up to len bytes of data from the file descriptor fd_in to the file descriptor fd_out, where one of the descriptors must refer to a pipe.
/* splice pipe, pipe */
int pdf[2];
pipe(pfd);
/* rfd socket fd, wfd socket fd */
/* rfd pfd[1] , */
splice(rfd, NULL, pfd[1], NULL, size, flags);
/* pfd[0] , rfd wfd */
splice(pfd[0], NULL, wfd, NULL, size, flags);
다른 매개 변 수 는 man 매 뉴 얼 을 찾 아 보 세 요. 인터넷 에 도 예제 코드 가 많 으 니 배 워 보 세 요.아이고, 기술 의 진보 가 우리 로 하여 금 일 을 갈수 록 가볍게 한다.지금 커 널 이 지원 하 는 제로 복사 기술 이 없다 면 igro 의 논 리 를 쓸 자신 이 있 습 니까?어쨌든 저 는 없습니다. 만약 당신 이 그 능력 이 있다 면, 메 시 지 를 남 겨 주세요. 우 리 는 친구 가 되 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.