Skip to content

Commit ccc998e

Browse files
author
yazhou.yang
committed
http2 stream dependency and stream priority analyze
1 parent 5ffeb8a commit ccc998e

File tree

8 files changed

+200
-20
lines changed

8 files changed

+200
-20
lines changed

nginx-1.9.2/http2相关/SSL+HTTP2 nginx处理流程完整日志(有函数名、行号).txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ http2
33
Դ�밲װ���� Nginx �����°棨��ǰ��1.9.14�� http://www.tuicool.com/articles/aqyMve Nginx+HTTPS(SSL/TLS) http://www.cnblogs.com/doseoer/p/5663203.html
44
SSL/TLSЭ�����л��Ƶĸ��� http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
55
HTTP2֡��ʽ http://www.blogjava.net/yongboy/archive/2015/03/20/423655.html
6-
6+
HTTP/2�ʼ�֮���Ͷ�·���� http://www.blogjava.net/yongboy/archive/2015/03/19/423611.aspx
77

88
2017/03/08 15:31:43[ ngx_epoll_process_events, 1715] [debug] 2906#2906: epoll: fd:6 EPOLLIN (ev:0001) d:00007FD79218D010
99
2017/03/08 15:31:43[ ngx_epoll_process_events, 1761] [debug] 2906#2906: post event 00007FD78E58D010
49.4 KB
Binary file not shown.

nginx-1.9.2/http2相关/一些参考.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,16 @@ HPACK
22
HPACK https://imququ.com/post/header-compression-in-http2.html
33
ʹ�� nghttp2 ���� HTTP/2 ���� https://imququ.com/post/intro-to-nghttp2.html
44
NGINX HTTP2�ٷ�˵��:https://www.nginx.com/blog/http2-r7/
5-
Rules of Thumb for HTTP/2 Push:https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/edit#
5+
Rules of Thumb for HTTP/2 Push:https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/edit#
6+
�ٶ��Ŷӷ����http2����Э�飺https://github.com/fex-team/http2-spec/blob/master/HTTP2%E4%B8%AD%E8%8B%B1%E5%AF%B9%E7%85%A7%E7%89%88(06-29).md
7+
8+
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' TCP״̬ͳ��
9+
10+
11+
12+
http2�����:
13+
����ʹ��nginx �http2.0 http://www.open-open.com/lib/view/open1452660300917.html
14+
Դ�밲װ���� Nginx �����°棨��ǰ��1.9.14�� http://www.tuicool.com/articles/aqyMve Nginx+HTTPS(SSL/TLS) http://www.cnblogs.com/doseoer/p/5663203.html
15+
SSL/TLSЭ�����л��Ƶĸ��� http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
16+
HTTP2֡��ʽ http://www.blogjava.net/yongboy/archive/2015/03/20/423655.html
17+
HTTP/2�ʼ�֮���Ͷ�·���� http://www.blogjava.net/yongboy/archive/2015/03/19/423611.aspx

nginx-1.9.2/src/core/ngx_queue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ struct ngx_queue_s {
131131

132132
#define ngx_queue_insert_after ngx_queue_insert_head
133133

134-
134+
/* x插入h节点前面 */
135135
#define ngx_queue_insert_tail(h, x) \
136136
(x)->prev = (h)->prev; \
137137
(x)->prev->next = x; \

nginx-1.9.2/src/http/v2/ngx_http_v2.c

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
#include <ngx_http_v2_module.h>
1212

1313

14+
/*
15+
NO_ERROR (0) : 相关的条件并不是错误的结果。例如超时帧可以携带此错误码指示连接的平滑关闭。
16+
PROTOCOL_ERROR (1) : 终端检测到一个不确定的协议错误。这个错误用在一个更具体的错误码不可用的时候。
17+
INTERNAL_ERROR (2) : 终端遇到意外的内部错误。
18+
FLOW_CONTROL_ERROR (3) : 终端检测到对等端违反了流量控制协议。
19+
SETTINGS_TIMEOUT (4) : 终端发送了设置帧,但是没有及时收到响应。见Settings Synchronization。
20+
STREAM_CLOSED (5) : 终端在流半封闭的时候收到帧。
21+
FRAME_SIZE_ERROR (6) : 终端收到大小超过最大尺寸的帧。
22+
REFUSED_STREAM (7) : 终端拒绝流在它执行任何应用处理之前,详见Reliability(章节 8.1.4)
23+
CANCEL (8) : 终端使用这个标示某个流不再需要。
24+
COMPRESSION_ERROR (9) : 终端无法维持报头压缩上下文的连接
25+
CONNECT_ERROR (10) : 响应某个连接请求建立的连接被服为异常关闭。
26+
ENHANCE_YOUR_CALM (11) : 终端检测出对等端在表现出可能会产生过大负荷的行为。
27+
INADEQUATE_SECURITY (12) : 基础传输包含属性不满足文档或者终端申明的最小要求。
28+
*/
1429
/* errors */
1530
#define NGX_HTTP_V2_NO_ERROR 0x0
1631
#define NGX_HTTP_V2_PROTOCOL_ERROR 0x1
@@ -54,6 +69,24 @@
5469
#define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1)
5570
#define NGX_HTTP_V2_DEFAULT_WINDOW 65535
5671

72+
73+
/*
74+
NGX_HTTP_V2_ROOT
75+
/|\ /|\
76+
/ \
77+
/ \parent
78+
/ \
79+
(代表一个连接)h2c->dependencies h2c->dependencies(代表一个连接)
80+
| |
81+
| |
82+
| |children
83+
| |
84+
queue \|/ \|/ queue queue (A先依赖parent,过后B又依赖parent,过后C又依赖parent)
85+
nodeA<--------nodeB nodeC-------->nodeB------->nodeA (同一个父节点下的子节点,例如某个A B C都依赖于节点dependencies)
86+
87+
88+
所有的ngx_http_v2_node_t节点最终都挂接到root下面组成树形结构,见ngx_http_v2_set_dependency
89+
*/
5790
#define NGX_HTTP_V2_ROOT (void *) -1
5891

5992

@@ -397,6 +430,16 @@ ngx_http_v2_read_handler(ngx_event_t *rev)
397430
}
398431

399432

433+
/*
434+
客户端一次uri请求发送过来header帧后,nginx应答给客户端的header帧和数据帧的stream id就是客户端请求header帧的id信息
435+
436+
HEADER帧发送流程:ngx_http_v2_filter_send->ngx_http_v2_send_output_queue
437+
DATA帧发送流程:ngx_http_v2_send_chain->ngx_http_v2_send_output_queue
438+
一次发送不完(例如协议栈写满返回AGAIN)则下次通过ngx_http_v2_write_handler->ngx_http_v2_send_output_queue再次发送
439+
440+
例如通过同一个connect来下载两个文件,则2个文件的相关信息会被组成一个一个交替的帧挂载到该链表上,通过该函数进行交替发送
441+
发送队列last_out中的数据
442+
*/
400443
static void
401444
ngx_http_v2_write_handler(ngx_event_t *wev)
402445
{
@@ -454,12 +497,18 @@ ngx_http_v2_write_handler(ngx_event_t *wev)
454497
}
455498

456499
/*
457-
EADER帧发送流程:ngx_http_v2_filter_send->ngx_http_v2_send_output_queue
500+
客户端一次uri请求发送过来header帧后,nginx应答给客户端的header帧和数据帧的stream id就是客户端请求header帧的id信息
501+
502+
客户端一次uri请求发送过来header帧后,nginx应答给客户端的header帧和数据帧的stream id就是客户端请求header帧的id信息
503+
504+
HEADER帧发送流程:ngx_http_v2_filter_send->ngx_http_v2_send_output_queue
458505
DATA帧发送流程:ngx_http_v2_send_chain->ngx_http_v2_send_output_queue
459506
一次发送不完(例如协议栈写满返回AGAIN)则下次通过ngx_http_v2_write_handler->ngx_http_v2_send_output_queue再次发送
460507
461508
例如通过同一个connect来下载两个文件,则2个文件的相关信息会被组成一个一个交替的帧挂载到该链表上,通过该函数进行交替发送
462509
发送队列last_out中的数据
510+
511+
ngx_http_v2_queue_frame对需要发送的帧进行优先级控制,权限高的放入队列首部,低的放入尾部,真正发送在ngx_http_v2_send_output_queue
463512
*/
464513
ngx_int_t
465514
ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c)
@@ -1874,9 +1923,18 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
18741923
ngx_http_v2_state_priority);
18751924
}
18761925

1926+
/* stream流依赖参考http://www.blogjava.net/yongboy/archive/2015/03/19/423611.aspx */
18771927
dependency = ngx_http_v2_parse_uint32(pos);
18781928

18791929
depend = dependency & 0x7fffffff;
1930+
/*
1931+
独家专属标志(exclusive flag)将为现有依赖插入一个水平的依赖关系,其父级流只能被插入的新流所依赖。比如流D设置专属标志并依赖于流A:
1932+
A
1933+
A |
1934+
/ \ ==> D
1935+
B C / \
1936+
B C
1937+
*/
18801938
excl = dependency >> 31;
18811939
weight = pos[4] + 1;
18821940

@@ -1886,7 +1944,7 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
18861944
"http2 PRIORITY frame sid:%ui on %ui excl:%ui weight:%ui",
18871945
h2c->state.sid, depend, excl, weight);
18881946

1889-
if (h2c->state.sid == 0) {
1947+
if (h2c->state.sid == 0) { //stream id为0的不能设置依赖
18901948
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
18911949
"client sent PRIORITY frame with incorrect identifier");
18921950

@@ -2658,7 +2716,6 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack)
26582716
return NGX_OK;
26592717
}
26602718

2661-
26622719
static ngx_int_t
26632720
ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c,
26642721
ngx_http_v2_out_frame_t *frame)
@@ -2960,7 +3017,7 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c)
29603017
return stream;
29613018
}
29623019

2963-
/* 根据sid查找对应的node,如果找到直接返回,找不到则创建一个node节点 */
3020+
/* 根据sid查找对应的node,如果找到直接返回,找不到并在alloc=1(允许开辟新的空间创建新的node节点)则创建一个node节点 */
29643021
static ngx_http_v2_node_t *
29653022
ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
29663023
ngx_uint_t alloc)
@@ -4096,23 +4153,49 @@ static ngx_int_t
40964153
}
40974154

40984155

4156+
/*
4157+
exclusive:独家专属标志(exclusive flag)将为现有依赖插入一个水平的依赖关系,其父级流只能被插入的新流所依赖。比如流D设置专属标志并依赖于流A:
4158+
A
4159+
A |
4160+
/ \ ==> D
4161+
B C / \
4162+
B C
4163+
流依赖可以参考:http://www.blogjava.net/yongboy/archive/2015/03/19/423611.aspx
4164+
4165+
NGX_HTTP_V2_ROOT
4166+
/|\ /|\
4167+
/ \
4168+
/ \parent
4169+
/ \
4170+
(代表一个连接)h2c->dependencies h2c->dependencies(代表一个连接)
4171+
| |
4172+
| |
4173+
| |children
4174+
| |
4175+
queue \|/ \|/ queue queue (A先依赖parent,过后B又依赖parent,过后C又依赖parent)
4176+
nodeA<--------nodeB nodeC-------->nodeB------->nodeA (同一个父节点下的子节点,例如某个A B C都依赖于节点dependencies)
4177+
4178+
*/
40994179
static void
41004180
ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
41014181
ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive)
41024182
{
41034183
ngx_queue_t *children;
41044184
ngx_http_v2_node_t *parent, *next;
41054185

4186+
/* 根据depend查找parent对应的node节点,如果depend为0,则parent=NGX_HTTP_V2_ROOT */
41064187
parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL;
41074188

41084189
if (parent == NULL) {
4190+
//这里可以看出所有连接是公用了同一个ROOT跟节点,而且权重也是共用的
41094191
parent = NGX_HTTP_V2_ROOT;
41104192

41114193
if (depend != 0) {
41124194
exclusive = 0;
41134195
}
41144196

4115-
node->rank = 1;
4197+
node->rank = 1; //跟ROOT下的第一层节点
4198+
//该node权重占总权重256的百分之多少呢
41164199
node->rel_weight = (1.0 / 256) * node->weight;
41174200

41184201
children = &h2c->dependencies;
@@ -4152,6 +4235,7 @@ ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
41524235
}
41534236

41544237
node->rank = parent->rank + 1;
4238+
//占整个父节点权重的百分比,例如父节点权重比为0.5,本节点weight为128,则本节点真实权重为0.5*0.5也就是0.25
41554239
node->rel_weight = (parent->rel_weight / 256) * node->weight;
41564240

41574241
if (parent->stream == NULL) {
@@ -4162,23 +4246,49 @@ ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
41624246
children = &parent->children;
41634247
}
41644248

4249+
/*
4250+
一旦设置独家专属标志(exclusive flag)将为现有依赖插入一个水平的依赖关系,其父级流只能被插入的新流所依赖。比如流D设置专属标志并依赖于流A:
4251+
A
4252+
A |
4253+
/ \ ==> D
4254+
B C / \
4255+
B C
4256+
*/
41654257
if (exclusive) {
41664258
ngx_queue_add(&node->children, children);
41674259
ngx_queue_init(children);
41684260
}
41694261

4170-
if (node->parent != NULL) {
4262+
if (node->parent != NULL) { //之前node依赖A,现在改为依赖D了,则先清除依赖关系
41714263
ngx_queue_remove(&node->queue);
41724264
}
41734265

4266+
//把children(也就是父节点的children节点)指向node节点,如果有多个node依赖parent节点,则这多个node节点通过queue连接在一起,如下图:
4267+
/*
4268+
parent
4269+
|
4270+
|children
4271+
|
4272+
| queue queue
4273+
nodeC--------nodeB-------nodeA (A先依赖parent,过后B又依赖parent,过后C又依赖parent)
4274+
*/
41744275
ngx_queue_insert_tail(children, &node->queue);
41754276

4176-
node->parent = parent;
4277+
node->parent = parent; //指定父节点
41774278

4178-
ngx_http_v2_node_children_update(node);
4279+
ngx_http_v2_node_children_update(node); //例如上面exclusive置1的时候,就需要从新计算D下面B C的真实权重
41794280
}
41804281

4181-
4282+
/*
4283+
children权重更新,例如如下情况:
4284+
4285+
一旦设置独家专属标志(exclusive flag)将为现有依赖插入一个水平的依赖关系,其父级流只能被插入的新流所依赖。比如流D设置专属标志并依赖于流A:
4286+
A
4287+
A |
4288+
/ \ ==> D
4289+
B C / \
4290+
B C
4291+
*/
41824292
static void
41834293
ngx_http_v2_node_children_update(ngx_http_v2_node_t *node)
41844294
{

0 commit comments

Comments
 (0)