@@ -76,9 +76,9 @@ <h1 class="article-title">Redis(5.0.3)里一个简单请求如何被处理</h1>
76
76
< ul >
77
77
< li >
78
78
< ul >
79
- < li > < a href ="#零- 在命令进入服务之前-服务器需要先初始化好自己 "> 零、 在命令进入服务之前,服务器需要先初始化好自己</ a > </ li >
80
- < li > < a href ="#一- 现在可以发送命令了 "> 一、 现在可以发送命令了</ a > </ li >
81
- < li > < a href ="#二- 返回命令执行结果 "> 二、 返回命令执行结果</ a > </ li >
79
+ < li > < a href ="#在命令进入服务之前-服务器需要先初始化好自己 "> 在命令进入服务之前,服务器需要先初始化好自己</ a > </ li >
80
+ < li > < a href ="#现在可以发送命令了 "> 现在可以发送命令了</ a > </ li >
81
+ < li > < a href ="#返回命令执行结果 "> 返回命令执行结果</ a > </ li >
82
82
</ ul > </ li >
83
83
</ ul > </ li >
84
84
</ ul >
@@ -87,7 +87,7 @@ <h1 class="article-title">Redis(5.0.3)里一个简单请求如何被处理</h1>
87
87
< p > set text “hello world” 从进入服务器到输出结果,整个流程是怎样的?带着这个问题来看看源码。
88
88
</ p >
89
89
90
- < h3 id ="零- 在命令进入服务之前-服务器需要先初始化好自己 "> 零、 在命令进入服务之前,服务器需要先初始化好自己</ h3 >
90
+ < h3 id ="在命令进入服务之前-服务器需要先初始化好自己 "> 在命令进入服务之前,服务器需要先初始化好自己</ h3 >
91
91
92
92
< p > 与这个场景相关的,两件事比较重要:</ p >
93
93
@@ -142,11 +142,14 @@ <h3 id="零-在命令进入服务之前-服务器需要先初始化好自己">
142
142
</ span > < span class ="lnt "> 18
143
143
</ span > < span class ="lnt "> 19
144
144
</ span > < span class ="lnt "> 20
145
+ </ span > < span class ="lnt "> 21
146
+ </ span > < span class ="lnt "> 22
145
147
</ span > </ code > </ pre > </ td >
146
148
< td class ="lntd ">
147
149
< pre class ="chroma "> < code class ="language-c " data-lang ="c "> < span class ="c1 "> // src/server.c
148
150
</ span > < span class ="c1 "> </ span > < span class ="kt "> void</ span > < span class ="nf "> initServerConfig</ span > < span class ="p "> (</ span > < span class ="kt "> void</ span > < span class ="p "> )</ span > < span class ="p "> {</ span >
149
151
< span class ="c1 "> // ...
152
+ </ span > < span class ="c1 "> </ span > < span class ="c1 "> // 设置命令映射表
150
153
</ span > < span class ="c1 "> </ span > < span class ="n "> populateCommandTable</ span > < span class ="p "> ();</ span >
151
154
< span class ="c1 "> // ...
152
155
</ span > < span class ="c1 "> </ span > < span class ="p "> }</ span >
@@ -159,16 +162,17 @@ <h3 id="零-在命令进入服务之前-服务器需要先初始化好自己">
159
162
< span class ="k "> struct</ span > < span class ="n "> redisCommand</ span > < span class ="o "> *</ span > < span class ="n "> c</ span > < span class ="o "> =</ span > < span class ="n "> redisCommandTable</ span > < span class ="o "> +</ span > < span class ="n "> j</ span > < span class ="p "> ;</ span >
160
163
< span class ="c1 "> // ...
161
164
</ span > < span class ="c1 "> </ span >
162
- < span class ="c1 "> // 把每个命令放到哈希结构中
163
- </ span > < span class ="c1 "> </ span > < span class ="n "> retval1</ span > < span class ="o "> =</ span > < span class ="n "> dictAdd</ span > < span class ="p "> (</ span > < span class ="n "> server</ span > < span class ="p "> .</ span > < span class ="n "> commands</ span > < span class ="p "> ,</ span > < span class ="n "> sdsnew</ span > < span class ="p "> (</ span > < span class ="n "> c</ span > < span class ="o "> -></ span > < span class ="n "> name</ span > < span class ="p "> ),</ span > < span class ="n "> c</ span > < span class ="p "> );</ span >
164
- < span class ="n "> retval2</ span > < span class ="o "> =</ span > < span class ="n "> dictAdd</ span > < span class ="p "> (</ span > < span class ="n "> server</ span > < span class ="p "> .</ span > < span class ="n "> orig_commands</ span > < span class ="p "> ,</ span > < span class ="n "> sdsnew</ span > < span class ="p "> (</ span > < span class ="n "> c</ span > < span class ="o "> -></ span > < span class ="n "> name</ span > < span class ="p "> ),</ span > < span class ="n "> c</ span > < span class ="p "> );</ span >
165
+ < span class ="c1 "> // 把每个命令放到哈希结构中
166
+ </ span > < span class ="c1 "> </ span > < span class ="n "> retval1</ span > < span class ="o "> =</ span > < span class ="n "> dictAdd</ span > < span class ="p "> (</ span > < span class ="n "> server</ span > < span class ="p "> .</ span > < span class ="n "> commands</ span > < span class ="p "> ,</ span > < span class ="n "> sdsnew</ span > < span class ="p "> (</ span > < span class ="n "> c</ span > < span class ="o "> -></ span > < span class ="n "> name</ span > < span class ="p "> ),</ span > < span class ="n "> c</ span > < span class ="p "> );</ span >
167
+ < span class ="n "> retval2</ span > < span class ="o "> =</ span > < span class ="n "> dictAdd</ span > < span class ="p "> (</ span > < span class ="n "> server</ span > < span class ="p "> .</ span > < span class ="n "> orig_commands</ span > < span class ="p "> ,</ span > < span class ="n "> sdsnew</ span > < span class ="p "> (</ span > < span class ="n "> c</ span > < span class ="o "> -></ span > < span class ="n "> name</ span > < span class ="p "> ),</ span > < span class ="n "> c</ span > < span class ="p "> );</ span >
168
+
165
169
< span class ="p "> }</ span >
166
170
< span class ="p "> }</ span > </ code > </ pre > </ td > </ tr > </ table >
167
171
</ div >
168
172
</ div >
169
173
< p > 然后启动事件循环器,监听默认的6379端口,并设置socket为no_blocking。</ p >
170
174
171
- < p > 将监听6379的socket包装为一个aeFileEvent对象 ,通过< code > aeCreateFileEvent()</ code > 注册到事件循环器里。注册时,会还会注册一个回调函数< code > acceptTcpHandler()</ code > 。即有新连接要到来时,就调用回调函数进行accept。</ p >
175
+ < p > 将监听6379端口的socket包装为一个aeFileEvent对象 ,通过< code > aeCreateFileEvent()</ code > 注册到事件循环器里。注册时,会还会注册一个回调函数< code > acceptTcpHandler()</ code > 。即有新连接要到来时,就调用回调函数进行accept。</ p >
172
176
173
177
< p > accept到的就是client连接。accept返回一个文件描述符,也将它注册进事件循环器里。这样之后client发起一个< code > set text "hello world"</ code > 请求到达server时,文件描述符变得可读,事件循环器会捕获到此事件并调用对应的回调函数< code > readQueryFromClient()</ code > 。</ p >
174
178
@@ -384,19 +388,21 @@ <h3 id="零-在命令进入服务之前-服务器需要先初始化好自己">
384
388
</ span > < span class ="c1 "> </ span > < span class ="p "> }</ span > </ code > </ pre > </ td > </ tr > </ table >
385
389
</ div >
386
390
</ div >
387
- < h3 id ="一- 现在可以发送命令了 "> 一、 现在可以发送命令了</ h3 >
391
+ < h3 id ="现在可以发送命令了 "> 现在可以发送命令了</ h3 >
388
392
389
393
< blockquote >
390
394
< p > 127.0.0.1:6379> set text “hello world”</ p >
391
395
</ blockquote >
392
396
393
- < p > 敲下回车键,命令顺着TCP到了server后,accept到新的套接字,并且是可读状态。这下注册的回调函数< code > readQueryFromClient()</ code > 就被触发调用。它是所有命令的入口。</ p >
397
+ < p > 敲下回车键,命令通过TCP协议到了server后,accept到新的套接字,并且是可读状态。</ p >
398
+
399
+ < p > 这时注册的回调函数< code > readQueryFromClient()</ code > 就被触发调用。它是所有命令的入口。</ p >
394
400
395
401
< p > 上面的源码也能看到,注册< code > readQueryFromClient()</ code > 之前,是为新连接创建一个client对象,命令的内容,client的属性,输入/输出缓冲区等都是与这个client绑定的。</ p >
396
402
397
403
< p > < code > readQueryFromClient()</ code > 通过系统调用< code > read()</ code > 从套接字里读取命令,放在client.querybuf。读取的字节数是有限制的,读取到的内容也有长度长限,超过上限就会拒连释放client对象。</ p >
398
404
399
- < p > 对于流入流出redis的字节数,自然也是在read和write这两个环节进行记录 。</ p >
405
+ < p > 对于流入流出redis的字节数,自然也是在read和write这两个环节中被记录 。</ p >
400
406
< div class ="highlight "> < div class ="chroma ">
401
407
< table class ="lntable "> < tr > < td class ="lntd ">
402
408
< pre class ="chroma "> < code class ="language-C " data-lang ="C "> < span class ="lnt "> 1
@@ -479,7 +485,9 @@ <h3 id="一-现在可以发送命令了">一、现在可以发送命令了</h3>
479
485
</ div >
480
486
< p > < code > processInputBufferAndReplicate()</ code > 会区分client是不是master节点来响应命令,两种处理方式当然有些差别。不过这里我们先不关心replicate。</ p >
481
487
482
- < p > 读取的命令放在client.querybuf后,是需要按照redis的< a href ="https://redis.io/topics/protocol "> 通信协议</ a > 进行解析的。解析完做一些常规的检查,例如命令是否存在,命名参数是否合法等。检查是在< code > processCommand()</ code > 里进行的。通过后,就可以调用注册好的命令回调函数来处理了。逻辑入口就是< code > processInputBuffer()</ code > </ p >
488
+ < p > 读取的命令放在client.querybuf后,是需要按照redis的< a href ="https://redis.io/topics/protocol "> 通信协议</ a > 进行解析的。解析完做一些常规的检查,例如命令是否存在,命名参数是否合法等。</ p >
489
+
490
+ < p > 检查是在< code > processCommand()</ code > 里进行的。通过后,就可以调用注册好的命令回调函数来处理了。逻辑入口就是< code > processInputBuffer()</ code > </ p >
483
491
< div class ="highlight "> < div class ="chroma ">
484
492
< table class ="lntable "> < tr > < td class ="lntd ">
485
493
< pre class ="chroma "> < code class ="language-c " data-lang ="c "> < span class ="lnt "> 1
@@ -702,7 +710,7 @@ <h3 id="一-现在可以发送命令了">一、现在可以发送命令了</h3>
702
710
</ div >
703
711
< p > 看完< code > addReply()</ code > 的整个处理过程,也看不到怎样给client发送回复,都是把回复内容写到输出缓冲区里。怎么返回client结果呢?</ p >
704
712
705
- < h3 id ="二- 返回命令执行结果 "> 二、 返回命令执行结果</ h3 >
713
+ < h3 id ="返回命令执行结果 "> 返回命令执行结果</ h3 >
706
714
707
715
< p > 其实在redis里,事件的处理顺序是:</ p >
708
716
@@ -824,7 +832,8 @@ <h3 id="二-返回命令执行结果">二、返回命令执行结果</h3>
824
832
< span class ="k "> return</ span > < span class ="n "> processed</ span > < span class ="p "> ;</ span >
825
833
< span class ="p "> }</ span > </ code > </ pre > </ td > </ tr > </ table >
826
834
</ div >
827
- </ div >
835
+ </ div >
836
+ < p > 以上就是一个简单命令的处理流程。</ p >
828
837
</ article >
829
838
830
839
0 commit comments