[Nginx 소스 분석] Nginx 에서 http2 에 대한 분석

8911 단어 nginx
장사 화 개발 을 운영 하 다.
본 고 는 작은 예 를 통 해 nginx 가 http 2 를 처리 하 는 절 차 를 한 번 연결 합 니 다.주로 http 2 의 프로 토 콜 과 nginx 의 처리 절차 와 관련된다.
안내
http 2 비교 http 1.1 은 주로 다음 과 같은 다섯 가지 측면 이 다르다.
바 이 너 리 프로 토 콜
http 1.1 요청 줄 과 요청 머리 는 모두 일반 텍스트 인 코딩 입 니 다. 즉, ascii 문자 로 직접 설명 할 수 있 고 http 2 는 자신의 인 코딩 형식 이 있 습 니 다.또한 nginx 에서 http 2 는 ssl 프로 토 콜 위 에 세 워 야 합 니 다.
두부 압축
예 를 들 어 HTTP 1.1 에서 header 를 전송 하려 면 11 글자 가 필요 합 니 다. http 2 에 정적 색인 표 가 있 습 니 다. 클 라 이언 트 가 색인 키 를 전달 합 니 다. 예 를 들 어 1. nginx 는 체크 표를 통 해 1 대표 method: GET. nginx 에서 이 정적 표를 제외 하고 host 와 같은 변 화 된 머리 를 저장 할 수 있 습 니 다.
다 중 재 활용
http 1.1 한 연결 에 하나의 요청 만 전송 할 수 있 습 니 다. 요청 이 끝 난 후에 야 다음 요청 을 전송 할 수 있 습 니 다.따라서 http 1.1 프로 토 콜 의 서비스 에 요청 할 때 일반 브 라 우 저 는 6 개의 연결 을 만 들 고 서로 다른 자원 을 요청 합 니 다.한편, http2 의 바 이 너 리 프로 토 콜 에는 frame 개념 이 있 습 니 다. 각 frame 은 자신의 id 가 있 기 때문에 하나의 연결 에 여러 개의 서로 다른 id 를 동시에 다 중 으로 전송 할 수 있 습 니 다. frame
액 티 브 푸 시
http 1.1 은 요청 - 응답 모델 이 고 http 2 는 클 라 이언 트 에 자원 을 자발적으로 전송 할 수 있 습 니 다.
우선 순위
다 중 재 활용 한 이상 모든 데이터 가 한 채널 에 달 렸 으 니 반드시 우선 순위 의 수요 가 있 을 것 이다.
본 논문 의 예 는 주로 메시지 해석 을 통 해 첫 세 가지 특성 을 설명 한다.
환경 설정
NGINX 설정 은 다음 과 같 습 니 다.
    server {
        listen 8443 ssl http2;
        access_log  logs/host_server2.access.log  main;
        ssl_certificate /home/xiaoju/nginx-2/nginx-selfsigned.crt;
        ssl_certificate_key /home/xiaoju/nginx-2/nginx-selfsigned.key;
        ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;

        location / {
            root   html;
            index  index.html index.htm /abc.html;
            access_log  logs/host_location3.access.log  main;
            http2_push /favicon.ico;
            http2_push /nginx.png;
        }
    }

클 라 이언 트 는 다음 과 같은 방식 으로 요청 합 니 다.
curl  -k  -I   -L https://IP:8443
HTTP/2 200  //    ,   http/2
server: nginx/1.14.0
date: Tue, 11 Dec 2018 09:20:33 GMT
content-type: text/html
content-length: 664
last-modified: Tue, 11 Dec 2018 04:19:32 GMT
etag: "5c0f3ad4-298"
accept-ranges: bytes

해석 요청
질문
먼저 문 제 를 생각해 보 세 요. 상기 설정 에서 curl 로 요청 을 보 낼 때 http / 1.1 이 아 닌 http / 2 를 직접 되 돌려 주 는 이 유 는 무엇 입 니까?
nginx 에서 http 2 는 ssl 위 에 있어 야 하기 때문에 우 리 는 먼저 nginx 코드 의 ssl 악수 부분 을 통 해 gdb 를 끊 고 따라 갑 니 다.
(gdb) b ngx_ssl_handshake_handler  //ssl    
Breakpoint 1 at 0x47ddb5: file src/event/ngx_event_openssl.c, line 1373.
(gdb) c
Continuing.
Breakpoint 1, ngx_ssl_handshake_handler (ev=0x16141f0) at src/event/ngx_event_openssl.c:1373
1373    {

1390        c->ssl->handler(c); //        ngx_http_ssl_handshake_handler
(gdb) s
ngx_http_ssl_handshake_handler (c=0x15da400) at src/http/ngx_http_request.c:782
782    {

(gdb) n
805            if (hc->addr_conf->http2) { //  http2 hc->addr_conf->http2    1

(gdb) n
808                SSL_get0_alpn_selected(c->ssl->connection, &data, &len);// ssl     alpn


(gdb) n
820                if (len == 2 && data[0] == 'h' && data[1] == '2') { //   h2,          http2  

(gdb) n
821                    ngx_http_v2_init(c->read);//    http2      

쉽게 말 하면 ssl 프로 토 콜 악수 단 계 를 통 해 alpn 과 관련 된 설정 을 얻 고 h2 라면 http 2 의 처리 절차 에 들 어 갑 니 다.우 리 는 wireshark 클러치 를 통 해 이 절 차 를 더욱 직관 적 으로 볼 수 있다.
위의 그림 과 같이 ssl 악수 의 Client Hello 단계 에서 alpn 확장 프로 토 콜 이 있 습 니 다.
메시지 형식
http2 는 하나의 preface 로 시작 하고 그 다음 에 하나의 frame 입 니 다. 그 중에서 모든 frame 은 하나의 header 가 있 습 니 다. 다음 과 같 습 니 다.
그 중에서 length 는 frame 내용 의 길 이 를 대표 하고 type 은 frame 의 유형 을 나타 내 며 flag 는 frame 에 특수 한 표 시 를 합 니 다. sid 는 frame 의 id 를 대표 합 니 다.
그 중에서 frame 은 다음 과 같은 10 가지 유형 이 있 습 니 다.
#define NGX_HTTP_V2_DATA_FRAME           0x0 //body  
#define NGX_HTTP_V2_HEADERS_FRAME        0x1 //header  
#define NGX_HTTP_V2_PRIORITY_FRAME       0x2 //     
#define NGX_HTTP_V2_RST_STREAM_FRAME     0x3 //    stream
#define NGX_HTTP_V2_SETTINGS_FRAME       0x4 //     ,      push,       stream   
#define NGX_HTTP_V2_PUSH_PROMISE_FRAME   0x5 //push
#define NGX_HTTP_V2_PING_FRAME           0x6 //ping
#define NGX_HTTP_V2_GOAWAY_FRAME         0x7 //goaway.   frame        
#define NGX_HTTP_V2_WINDOW_UPDATE_FRAME  0x8 //         
#define NGX_HTTP_V2_CONTINUATION_FRAME   0x9 //   frame       ,   continuation      

frame ID 는 클 라 이언 트 가 홀수 에 따라 증가 합 니 다. 예 를 들 어 1, 3, 5, 짝수 형 id 가 서버 에 push 를 전송 할 때 사용 합 니 다. 연결 속성 과 관련 된 frame id 를 0 으로 설정 합 니 다.
flags 는 다음 과 같은 정의 가 있 습 니 다.
#define NGX_HTTP_V2_NO_FLAG              0x00 //   
#define NGX_HTTP_V2_ACK_FLAG             0x01 //ack flag
#define NGX_HTTP_V2_END_STREAM_FLAG      0x01 //  stream
#define NGX_HTTP_V2_END_HEADERS_FLAG     0x04 //  headers
#define NGX_HTTP_V2_PADDED_FLAG          0x08 //  flag
#define NGX_HTTP_V2_PRIORITY_FLAG        0x20 //     flag

다음은 http 헤드 형식 frame 의 구체 적 인 내용 형식 입 니 다.
padded 와 priority 는 위의 머리 에 있 는 flag 에서 이 두 필드 가 있 는 지 여 부 를 결정 합 니 다.다음은 8bit 를 차지 하 는 flag 는 header 에 색인 이 필요 한 지, 필요 하 다 면 색인 번호 가 얼마 인지 결정 합 니 다.
Huff (1) 는 이 필드 가 Huff man 인 코딩 을 사 용 했 는 지 여 부 를 나타 낸다.header_value_len (7) 과 headervalue 는 구체 적 인 헤드 필드 의 value 값 입 니 다.
다음 설정 과 관련 된 frame 입 니 다.
다음 창 이 업 데 이 트 된 frame 입 니 다.
다음 에 우 리 는 구체 적 인 예 를 보고 더욱 직관 적 으로 이해 해 보 자.
http 2 메시지 분석
새 버 전의 curl 에는 http 2 인자 가 있 습 니 다. http 2 를 사용 하여 통신 하 는 것 을 직접 가리 킬 수 있 습 니 다.클 라 이언 트 명령 을 다음 과 같이 수정 합 니 다.
curl --http2 -k  -I   -L https://10.96.79.14:8443

위의 gdb 추적 을 통 해 http 2 가 입구 함 수 를 ngx 로 초기 화 하 는 것 을 보 았 습 니 다.http_v2_init, 여기 서 점 을 끊 고 코드 를 계속 추적 합 니 다. 추적 과정 은 더 이상 상세 하 게 설명 하지 않 습 니 다. 메 시 지 를 캐 시 에 읽 은 후에 저 희 는 gdb 에서 bt 에서 호출 경 로 를 직접 봅 니 다. 다음 과 같 습 니 다.
#0  ngx_http_v2_state_preface (h2c=0x15a9310, pos=0x164b0b0 "PRI * HTTP/2.0\r
\r
SM\r
\r
", end=0x164b11e "") at src/http/v2/ngx_http_v2.c:713 #1 0x00000000004bca20 in ngx_http_v2_read_handler (rev=0x16141f0) at src/http/v2/ngx_http_v2.c:415 #2 0x00000000004bcf8a in ngx_http_v2_init (rev=0x16141f0) at src/http/v2/ngx_http_v2.c:328 #3 0x0000000000490a13 in ngx_http_ssl_handshake_handler (c=0x15da400) at src/http/ngx_http_request.c:821 #4 0x000000000047de24 in ngx_ssl_handshake_handler (ev=0x16141f0) at src/event/ngx_event_openssl.c:1390 #5 0x0000000000479637 in ngx_epoll_process_events (cycle=0x1597e30, timer=, flags=) at src/event/modules/ngx_epoll_module.c:902 #6 0x000000000046f9db in ngx_process_events_and_timers (cycle=0x1597e30) at src/event/ngx_event.c:242 #7 0x000000000047761c in ngx_worker_process_cycle (cycle=0x1597e30, data=) at src/os/unix/ngx_process_cycle.c:750 #8 0x0000000000475c50 in ngx_spawn_process (cycle=0x1597e30, proc=0x477589 , data=0x0, name=0x684922 "worker process", respawn=-3) at src/os/unix/ngx_process.c:199 #9 0x00000000004769aa in ngx_start_worker_processes (cycle=0x1597e30, n=1, type=-3) at src/os/unix/ngx_process_cycle.c:359 #10 0x0000000000477cb0 in ngx_master_process_cycle (cycle=0x1597e30) at src/os/unix/ngx_process_cycle.c:131 #11 0x0000000000450ea4 in main (argc=, argv=) at src/core/nginx.c:382

ngx 로 호출http_v2_state_preface 이 함수 이후 http 2 요청 을 처리 하기 시 작 했 습 니 다. 요청 내용 을 인쇄 해 보 겠 습 니 다.
(gdb) p end-pos
$1 = 110
(gdb) p *pos@110
$2 = "PRI * HTTP/2.0\r
\r
SM\r
\r
\000\000\022\004\000\000\000\000\000\000\003\000\000\000d\000\004@\000\000\000\000\002\000\000\000\000\000\000\004\b\000\000\000\000\000?\377\000\001\000\000%\001\005\000\000\000\001B\004HEAD\204\207A\214\b\027}\305\335}p\265q\346\232gz\210%\266Pë\266\322\340S\003*/*"

nginx 다음 에 http 2 요청 을 처리 합 니 다. 처리 방법 은 상기 방법 에 따라 계속 추적 할 수 있 습 니 다. 우 리 는 http 2 프로 토 콜 에 따라 상기 메 시 지 를 분석 할 수 있 습 니 다. 다음 과 같 습 니 다.
gdb 가 출력 한 것 은 8 진 형식 입 니 다.
http push 클러치
위의 nginx 설정 에 http2 두 개가 설정 되 어 있 음 을 주의 하 십시오.push 명령, 즉 서버 에서 index. html 를 요청 할 때 favicon. ico 와 nginx. png 두 그림 push 를 주동 적 으로 내 려 갑 니 다.
wireshark 의 스냅 백 은 다음 과 같 습 니 다:
서버 에서 먼저 push 보 내기promise 메시지, 메시지 에는 push 의 파일 경로 와 frame id 가 포 함 됩 니 다. 두 번 째 와 세 번 째 빨 간 상 자 는 push 의 구체 적 인 정 보 를 시작 합 니 다. frame id 는 각각 2 와 4 입 니 다.
브 라 우 저 에서 push 요청 을 보 겠 습 니 다.
액 티 브 push 요청 은 다음 과 같 습 니 다.
브 라 우 저 는 index. html 를 먼저 불 러 와 야 다음 에 어떤 자원 을 요청 하 는 지 알 수 있 습 니 다. 따라서 favicon. ico 와 ngix. png 는 불 러 오 는 것 을 지연 시 킵 니 다.
문제.
HTTP 2 서버 에서 동적 색인 header 를 사용 하면 http 를 상태 있 는 서비스 로 만 들 수 있 습 니 다. 클 러 스 터 간 에 header 헤드 캐 시 문 제 를 어떻게 해결 합 니까?정적 자원 파일 이 처음 요청 한 후 브 라 우 저 쪽 에 캐 시 됩 니 다. push 는 어떻게 한 번 만 푸 시 할 수 있 습 니까?참고 자료 1.https://www.nginx.com/blog/ht...
2.https://httpwg.org/specs/rfc7540

좋은 웹페이지 즐겨찾기