從Traceroute看網路問題

一、概述

1.1 什麼是Traceroute

當遇到網路問題,通常會用Traceroute去排查,但Traceroute是什麼?

根據百度百科定義,Traceroute是一種電腦網路工具,它可顯示數據包在IP網路經過的路由器的IP地址。

Traceroute有三大特點

  1. 跨平台。Traceroute工具存在與各個操作系統平台,包括主流系統MAC OS、Windows、Linux、Android、IOS等;

  2. 使用方便。只要在Traceroute後輸入IP或域名即可;

  3. 信息全面。Traceroute能夠顯示跳數、丟包情況、延時等信息。

但使用Traceroute並根據路由跟蹤情況就能排查出問題?答案是否定的。

1.2 Traceroute的問題所在

使用Traceroute並根據路由跟蹤情況也不能排查出問題,到底是怎麼回事?

  1. 現代商業網路運行情況良好。低級的問題如擁塞、環路,在實際問題中占非常低的概率;更多的問題是非常複雜以至於只靠單純的Traceroute已無法準確排查;

  2. 很少人是真正的理解Traceroute並且利用其分析問題。大部分ISP NOC甚至是專業的網路工程師也難以解釋一個複雜的路由;有非常多的誤判報告充斥著世界各地NOC;高誤判率導致幾乎無法從這些報告中判斷出真正最根本的網路問題。

二、Traceroute原理

2.1 Traceroute實現原理

  1. 從SRC發出一個探測包到DST,並將TTL設置為1;

  2. 每一跳TTL將會減一;

  3. 當TTL變為0時,包被丟棄,路由器向SRC發回一個ICMP TTL Exceed包;

  4. 當SRC收到該ICMP包時,顯示這一跳信息;

  5. 重複1~5,並每次TTL加1;

  6. 直至DST收到探測數據包,並返回ICMP Dest Unreachable包;

  7. 當SRC收到ICMP Dest Unreachable包時停止traceroute。

2.2 Traceroute實現細節

  1. 傳統UNIX系統使用UDP包進行探測,目標埠號為33434,每次探測目標埠號增加1;Windows的tracert.exe和MTR則使用ICMP Echo Request包探測;

  2. 如果DST沒有返回ICMP Dest Unreachable包則不能探測到DST。這是會發生在某些情況下,如DST前有防火牆,或者DST進行了配置,或者是DST上有一個真實的應用在監聽該埠;

  3. 通過設置UDP/TCP/ICMP包中的CLI標識位都能夠實現Traceroute,一般來說,不推薦使用TCP包,因為通常會被過濾掉;

  4. 不同的實現方式通常都會向每跳發送多個探測包,典型的Traceroute默認發送3個探測包,如果沒有收到那一跳的回應,延時數據將會輸出3個*號;MTR會循環發送無數個探測包;

  5. 每個探測包都有唯一的標識號,使得Traceroute能夠識別返回的包,UDP/TCP使用遞增的目標埠號進行標識,ICMP使用seq #;

  6. 由於4層哈希能使每個探測包走不同的路由,對於Traceroute來說,在三層的等價多路徑(ECMP)下可見,在二層的聚合鏈路LAG下不可見;

  7. 雖然探測包走不同路徑引起不同的結果,但TTL還是相同的。

2.3 Traceroute延時計算

  1. 在探測包發出時打上時間戳;

  2. 當收到ICMP響應時打上時間戳;

  3. 根據兩個時間戳計算往返時間;

路由器不對包的時間做任何處理,只是單純的轉發數據;

延時計算的是包的往返時間,但Traceroute顯示的是去的路徑上所經過的路由。

2.4 每一跳產生原理

  1. SRC發送TTL為1的包給Router 1;

  2. Router 1收到包後將TTL減1,Router 1發現TTL=0後,丟棄該包,不再轉發,並向SRC發送ICMP TTL Exceed包,該包目標IP為SRC的IP,源IP為Router 1的Ingress Interface的IP,Traceroute就會根據ICMP TTL Exceed包的源IP顯示一跳;

  3. 在上圖中SRC會顯示兩跳,172.16.2.1 10.3.2.2;

  4. 你無法從Traceroute中得知包返回的路徑以及路由器使用的ICMP Return Interface和Egress Interface的IP。

值得一提的是在RFC1812 4.3.2.4 ICMP Message Source Address中提到,ICMP包的源地址必須是傳包出去的物理介面綁定的其中一個IP(Except where this document specifies otherwise, the IP source address in an ICMP message originated by the router MUST be one of the IP addresses associated with the physical interface over which the ICMP message is transmitted.)。

經過實驗證實了這個問題。一個探測包確實會有可能從路由器的一個介面進,ICMP TTL Exceed包從另外一個介面出,並且源IP是進的介面IP,按照個人理解其原因是路由器會把進的介面產生的TTL超時包當作外來的包並遵循路由表進行路由轉發,轉發過程不會改變包的源目IP。因此在外部看來這個ICMP包並不符合RFC文檔的定義。

三、Traceroute中的DNS反向解析

理解Traceroute中的DNS反向解析是使用Traceroute的一個非常重要的一個方面。

在Traceroute中的DNS反向解析我們能夠獲取到以下信息:

  1. 路由器地理位置

  2. 介面類型與帶寬

  3. 路由類型與角色

  4. 網路自治系統的邊界與關係

對於推斷問題原因,以上信息顯得尤為重要。

3.1 路由器地理位置

為什麼我們需要知道地理位置?

  1. 確定不對或者是不太合適的路由。從亞特蘭大到邁阿密經過紐約,那就不太理想了。

  2. 確定高延時是否合理。從印度到美國要300ms,但從日本到美國並不需要300ms。

  3. 幫助你理解網路互聯的節點。

我們常用的幫助識別位置信息的有:

  1. IATA Airport Codes(International Air Transport Association Airport Codes)

  2. CLLI Codes(Common Language Location Identifier)

  3. 非標準簡寫的城市名

  4. Country Codes

  5. 還有一些其他的信息

3.2 介面類型與帶寬

很多網路都會嘗試將介面信息放在DNS,需要注意的是:

  1. 介面信息通常是幫助他們排查自己網路的問題;

  2. 介面信息有可能不是最新的。雖然很多大型網路會自動產生DNS,但其餘的不會;

  3. 可以幫助你識別介面的類型,通過介面類型甚至可以知道路由器的型號。

例子

xe-11-1-0.edge1.NewYork1.Level3.net

  • xe-11-1-0是Juniper 10GE埠,該設備至少有12個板卡槽

  • 至少一台40G/板卡槽的路由器,因為它有一塊10GE板卡在板卡槽1

常見介面類型對照表

Interface TypeCisco IOSCisco IOS XRJuniperFast EthernetFa#/#fe-#/#/#

Gigabit EthernetGi#/#Gi#/#/#/#ge-#/#/#10 Gigabit EthernetTe#/#Te#/#/#/#xe-#/#/# (*)SONETPos#/#POS#/#/#/#so-#/#/#T1Se#/#

t1-#/#/#T3

t3-#/#/#Ethernet BundlePo# / Port-channel#BE####ae#SONET BundlePosCh#BS####as#TunnelTu#TT# or TI#ip-#/#/# or gr-#/#/#ATMATM#/#AT#/#/#/#at-#/#/#VlanVl###Gi#/#/#/#.###ge-#-#-#.###

3.3 路由類型與角色

知道路由器角色是非常有用的,但每個AS都不一樣,使用不同的角色命名,並且他們也不會一直遵循自己的命名規則。

總的來說,你只能通過你的網路知識去猜路由器的角色。

通常來說有以下規律:

  • Core routers – CR, Core, GBR, BB, CCR, EBR

  • Peering routers – BR, Border, Edge, IR, IGR, Peer

  • Customer routers – AR, Aggr, Cust, CAR, HSA, GW

3.4 網路自治系統的邊界與關係

識別網路自治系統邊緣很重要:

  1. 能幫助你知道路由策略變化的地方。如:不同的返迴路徑是基於本地優先順序的;

  2. 能幫助你知道帶寬與路由最差的地方,這些地方可能就是產生問題的地方;

  3. 當然也能幫助你知道應該去聯繫誰。

識別網路自治系統的關係同樣有所幫助:

  1. 典型三個角色:Transit Provider、Peer、Customer

  2. 很多網路都會嘗試將以上信息寫在DNS上。如etworkname.customer.alter.net

有時能夠看到反解域名的明顯變化:

4 te1-2-10g.ar3.DCA3.gblx.net (67.17.108.146)

5 sl-st21-ash-8-0-0.sprintlink.net (144.232.18.65)

有時能夠看到DNS的某一部分變化:

4 po2-20G.ar5.DCA3.gblx.net (67.16.133.90)

5 cogent-1.ar5.DCA3.gblx.net (64.212.107.90)

當然有時DNS的信息根本沒有用:

2 po2-20G.ar4.DCA3.gblx.net (67.16.133.82)

3 192.205.34.109 (192.205.34.109)

4 cr2.wswdc.ip.att.net (12.122.84.46)

以上無法判斷GBLX的邊界,同時無法判斷192.205.34.109是在哪裡。

來看更多的信息:

4 po2-20G.ar5.DCA3.gblx.net (67.16.133.90)

5 cogent-1.ar5.DCA3.gblx.net (64.212.107.90)

> nslookup 64.212.107.89 = te2-3-10GE.ar5.DCA3.gblx.net

ar5.DCA3.gblx.net有多個DNS域名解析,通過以上分析,就算第5跳的DNS中沒有cogent字眼提示也能判斷第5跳與第4跳分屬兩個自治系統(命名規則發生變化)。

以上分析涉及到一個關鍵點,根據/30掩碼獲取對端IP

如上圖,兩個介面雖然同在一個/30掩碼網段內,但路由器並不會收集或維護鄰居的DNS信息,所以當一個包發出時路由器並不知道鄰居的DNS信息,這時就會填充上自己介面的DNS信息而不是留空白讓鄰居去填充。因此通過分析對端的介面信息,就能夠知道路由器所屬自治系統(若64.212.107.89的域名是cogent-0.ar5.DCA3.gblx.net,那麼ar5.DCA3路由器將屬於兩個自治系統)。

四、網路延時

三種主要網路延時:

  1. 串列延時。該延時是路由器或交換機發送數據包的時間,串列延時=包大小(bits)/傳輸速率(bps);

  2. 排隊延時。該延時是數據包在路由器隊列中等待發出的時間,非擁塞情況下排隊延時可忽略不計;

  3. 傳播延時。該延時是數據包在傳播介質中傳播所用時間,該延時主要取決於光或電磁的傳播速度。

4.1 串列延時

該延時產生在轉發數據包的時候,產生原因:

  1. 一個數據包被移動到網路上的時候是一個不可分的單元;

  2. 在一個數據包傳輸完畢之前另外一個數據包無法發送。

在高速網路中該延時非常小

  • 1500 bytes over a 56k link (56Kbps) = 214.2ms delay

  • 1500 bytes over a T1 (1.536Mbps) = 7.8ms delay

  • 1500 bytes over a FastE (100Mbps) = 0.12ms delay

  • 1500 bytes over a GigE (1Gbps) = 0.012ms delay

4.2 排隊延時

1. 利用率

1G的介面跑到500Mbps我們會說利用率是50%,但實際上,一個介面只能進行轉發數據(100%利用)或者不能轉發數據(0%利用),故所謂的50%利用率實際上是指1s內有0.5s用來了傳輸數據。

2. 排隊

當一個介面在被使用,下一個包必須排隊等待被發送。通常來說,一個介面90%使用率等於將要轉發的包90%都在排隊。當一個介面達到飽和時,排隊時間將迅速增加,當一個介面過飽和時,一個包排隊可能要耗費幾百甚至幾千毫秒,排隊延時通常與擁塞程度相關聯。

4.3 傳播延時

該延時由光信號或電磁信號在介質中的傳播速度與距離決定。光速(真空狀態下傳播)約為300,000km/s,但光纖是由玻璃製作,非真空,故光在光纖內傳播速度較真空狀態慢,約為0.67c,即200,000km/s,1ms的往返延時距離為100km。

例子

環地球赤道一圈(約為40000km)傳播延時大概為200ms(往返延時為400ms)。

知道以上數據,通過traceroute的每一跳地理位置信息,通過距離計算傳播延時就知道延時是否正常了。

3 xe-3-0-0.cr1.nyc3.us.nlayer.net (69.22.142.74) 6.570ms

4 xe-0-0-0.cr1.lhr1.uk.nlayer.net (69.22.142.10) 74.144ms

美國紐約到英國倫敦只需要67.6ms,兩地相距約6759km,延時正常。

5 cr2.wswdc.ip.att.net (12.122.3.38) [MPLS: Label 17221 Exp 0] 8 msec 8 msec 8 msec

6 tbr2.wswdc.ip.att.net (12.122.16.102) [MPLS: Label 32760 Exp 0] 8 msec 8 msec 8 msec

7 ggr3.wswdc.ip.att.net (12.122.80.69) 8 msec 8 msec 8 msec

8 192.205.34.106 [AS 7018] 228 msec 228 msec 228 msec

9 te1-4.mpd01.iad01.atlas.cogentco.com (154.54.3.222) [AS 174] 228 msec 228 msec 228 msec

在美國本土傳播耗時220ms,延時不正常。

五、優先順序與限速

5.1 Traceroute延時判斷影響因素

Traceroute延時包括三點:

  1. 探測包到達一個特定路由器的時間

  2. 路由器生成IPMI TTL Exceed的時間

  3. ICMP TTL Exceed返回到SRC的時間

第一個和第三個時間都是受實際網路情況影響的,而第二個時間不是。能夠對網路問題的判斷起到幫助作用的僅僅只有第一個和第三個時間,第二個時間往往起到誤導的作用。

5.2 路由器工作原理

路由器有轉發(data-plane)和接收(control-plane)的功能。

路由器轉發包有兩種模式:

  1. Fast Path:硬體實現轉發源包(幾乎所有的網路的數據包)

  2. Slow Path:軟體實現處理「異常」包(IP Options, ICMP generation <--Traceroute發生在這裡)

路由器能夠接收直接發送到路由器上綁定的IP的包,接收的包可以是BGP、IGP、SNMP、CLI訪問(telnet/ssh)、ping等

但是,路由器的CPU性能是比較差的。一個320-640+Gbps背板的路由器,卻只有一個單核600MHz MIPS CPU,通常CPU用來做其他事而不是做Traceroute,因此ICMP Generation在路由器看來優先順序較低,大多數情況下更是有速度限制和降級的處理。

1. 降級

在一些常見的路由器平台上,Slow path中的轉發與接收是公用資源,同時沒有使用最好的軟體調度器。因此一些控制性的數據處理比如BGP churn、CLI等會消耗CPU資源,使得ICMP TTL Exceed包的產生延遲。

2. 限速

大部分路由器會限制他們的ICMP包產生,不同廠商會有不同的並且不可設置的限速值,這大大影響了Traceroute的效果,特別是在很多用戶同時使用MTR時。

例子

Foundry MLX/XMR:Hard-coded limit of 400pps per interface.

Force10 E-series:Hard-coded limit of 200pps or 600pps per interface.

5.3 排除假延時

那麼有辦法排除第二個時間對整個延時的影響嗎?答案是有的。最重要的一個規則:如果在某一跳中發生問題,那麼所有後續跳的延時將會持續或增長。

下面例子中第二跳並沒有問題

1 ae3.cr2.iad1.us.nlayer.net 0.275ms 0.264 ms 0.137 ms

2 xe-1-2-0.cr1.ord1.us.nlayer.net 18.271 ms 68.257 ms 18.001 ms

3 tge2-1.ar1.slc1.us.nlayer.net 53.373 ms 53.213 ms 53.227 ms

在Traceroute過程中出現的延時突高並不是什麼問題,造成這種現象主要有兩種原因:

  1. 通常是路由器的限速與優先順序問題;

  2. 最壞情況是路由器回包過程中走的路徑不同導致的(非對稱轉發路徑)。

六、非對稱的轉發路徑

網路中的路由是沒法保證對稱的轉發路徑,即往返的路徑完全相同。而Traceroute顯示的只是去的方向的路徑,但仍然要注意延時是往返的耗時。對於Traceroute來說,返回的路徑是完全不可見的,返回的每一跳可能跟去的時候完全不一樣。排查問題的時候可以進行反向的Traceroute,看返回的路徑上是否出現問題,當然,這樣也不能保證路徑是一樣的。

6.1 非對稱轉發路徑與AS邊界

非對稱路徑通常是在AS邊界開始的。為什麼?那是因為AS邊界通常是AS管理策略改變的地方。

te1-1.ar2.DCA3.gblx.net (69.31.31.209) 0.719 ms 0.560 ms 0.428 ms

te1-2-10g.ar3.DCA3.gblx.net (67.17.108.146) 0.574 ms 0.557 ms 0.576 ms

sl-st21-ash-8-0-0.sprintlink.net(144.232.18.65) 100.280 ms 100.265 ms 100.282 ms

144.232.20.149 (144.232.20.149) 102.037 ms 101.876 ms 101.892 ms

sl-bb20-dc-15-0-0.sprintlink.net(144.232.15.0) 101.888 ms 101.876 ms 101.890 ms

上面例子中有什麼問題?

  1. 在GBLX和Sprint的邊界出現擁塞;

  2. 可能是由於正向或反向路徑出現擁塞。

由於兩個AS出口策略不一致造成的擁塞是很常見的。

6.2 多路徑互聯

非對稱的路徑可出現在每一跳,特別是有多條路徑到達的節點。

第一跳(紫色):折回點為Washington DC

第二跳(紅色):折回點為Chicago IL

第三跳(綠色):折回點為San Jose CA

可以看到第三跳不是原路返回的,如果Chicago IL返回的路徑上出現擁塞,那麼第三跳上將不會出現擁塞情況,故在Traceroute時可能會看到第二跳延時高於第三跳

如果出現以上情況時,該如何去排查問題?

假設如下的情況,你有多條路徑可到達Sprint,但Traceroute顯示You->Global Crossing->Sprint,並且問題出現在第三跳的Sprint。

如何證明問題不是出現在GX這邊的路徑?

  1. 使用之前提到的/30掩碼方法,使用Global Crossing的/30掩碼找到對端IP,並作為SRC進行Traceroute,那麼就能保證返迴路徑為Sprint->Global Crossing;

  2. 同樣的方法Traceroute另外一跳路徑;

  3. 兩邊的延時對比後,就知道哪條路徑出現問題。

當然/30掩碼方法不一定能夠準確找到對端IP,這完全取決於路由的配置。

為什麼Traceroute設置源IP後能夠保證第一跳的返迴路徑?

當Traceroute的源IP為你IP空間的IP時(比如是loopback),回包的時候可回到任一介面。但如果在對端路由器配置了/30掩碼的IP在IGP時,那麼就會強制回包至指定IP的介面。

七、等價路由

7.1 等價路由

基於流的哈希演算法能夠保證同一個TCP/UDP數據流通過相同的路徑。而UDP/TCP Traceroute的探測包的目標埠是遞增的,在路由器看來可能不是同一個數據流,這可能造成探測包會走不同的平行路徑。

以上圖來說,Traceroute的結果可能與實際完全不同,正常應該是A -> B1 -> C1 -> D或A -> B2 -> C2 -> D,但結果可能是A -> B1 -> C2 -> D,這跟拓撲完全不一樣。

例如:

6 ldn-bb2-link.telia.net (80.91.251.14) 74.139 ms 74.126 ms

ldn-bb1-link.telia.net (80.91.249.77) 74.144 ms

7 hbg-bb1-link.telia.net (80.91.249.11) 89.773 ms

hbg-bb2-link.telia.net (80.91.250.150) 88.459 ms 88.456 ms

8 s-bb2-link.telia.net (80.91.249.13) 105.002 ms

s-bb2-link.telia.net (80.239.147.169) 102.647 ms 102.501 ms

這對於正常的數據流流來說是有好處的,基於流的哈希演算法能夠避免了數據包的重組,但對於Traceroute來說就有點問題了。

7.2 等價不等長路由

這種情況會令Traceroute看上去令人覺得跳來跳去,這使得排查問題難上加難。

以上圖來說,正常應該是A -> B1 -> C 或 A -> B2 -> X -> C,這樣測出來已經令人迷惑了,究竟是三跳還是四跳?

但實際情況可能更加糟糕,可能是 A -> B1 -> X -> C,這完全與拓撲不相符;同時也可能是 A -> B1 -> C -> C,看到了嗎,出現「迴路」了。對於上面一條路來說,TTL=3時是C,對於下面一條路來說,TTL=4時是C,兩個探測包剛好走了兩條不同的路,所以正好出現了這樣的「迴路」。

7.3 單路徑Traceroute

那麼有辦法能夠讓Traceroute固定走一條路嗎?有的。

利用Traceroute強大的參數設置,固定目標埠不變,就能夠Traceroute出同一條路徑了(Traceroute 2.0.14版本,-U可固定目標埠不變,-p指定目標埠)。但是需要注意Traceroute出來的路徑不一定是實際數據包走的路徑。可以通過目標IP加1或減1進行多次Traceroute來完成多路徑的Traceroute。網路中區分數據流的策略很多,三層網路通常是根據源IP、目標IP來區分一個數據流,因此固定目標埠,更改目標IP能夠讓探測包走不同的路徑,從而讓Traceroute更加準確。

上圖是我從實際環境截獲的包。gz-ganglia2向gz-ganglia1進行Traceroute,在gz-ganglia1上截包,從上圖能夠看到固定埠為55555,且收到多個TTL大於1的UDP包,這跟Traceroute的原理有關,Traceroute每跳默認發3個包,超時時間為5s,每三個包TTL增加1,直至收到ICMP Dest Unreachable包後停止發包,故在收到ICMP Dest Unreachable包之間,Traceroute還是認為沒有到達目標,仍然繼續發包,故目標主機可以收到TTL大於1的包。若Traceroute一直沒有收到ICMP Dest Unreachable包則默認會一直發到TTL=30停止發送。

八、多協議標籤交換(MPLS)與Traceroute

8.1 MPLS ICMP隧道

很多大型網路都有運用MPLS,有些路由器只根據MPLS的標籤進行轉發而沒有IP路由表,當ICMP包產生時問題就出現了,這些路由器要怎麼去轉發這些ICMP包?其中一種解決方案是MPLS ICMP隧道。

當一個ICMP包產生並打上標籤時,路由器會根據標籤交換路徑(LSP)轉發表將ICMP包轉發至下一跳,這會導致Traceroute的結果看起來非常奇怪,你會看到中間很多跳的延時會跟某一跳的延時是一樣的,如下例。

1. te2-4.ar5.PAO2.gblx.net (69.22.153.209) 1.160 ms 1.060 ms 1.029 ms

2. 192.205.34.245 (192.205.34.245) 3.984 ms 3.810 ms 3.786 ms

3. tbr1.sffca.ip.att.net (12.123.12.25) 74.848 ms 74.859 ms 74.936 ms

4. cr1.sffca.ip.att.net (12.122.19.1) 74.344 ms 74.612 ms 74.072 ms

5. cr1.cgcil.ip.att.net (12.122.4.122) 74.827 ms 75.061 ms 74.640 ms

6. cr2.cgcil.ip.att.net (12.122.2.54) 75.279 ms 74.839 ms 75.238 ms

7. cr1.n54ny.ip.att.net (12.122.1.1) 74.667 ms 74.501 ms 77.266 ms

8. gbr7.n54ny.ip.att.net (12.122.4.133) 74.443 ms 74.357 ms 75.397 ms

9. ar3.n54ny.ip.att.net (12.123.0.77) 74.648 ms 74.369 ms 74.415 ms

10.12.126.0.29 (12.126.0.29) 76.104 ms 76.283 ms 76.174 ms

11.route-server.cbbtier3.att.net (12.0.1.28) 74.360 ms 74.303 ms 74.272 ms

為什麼會這樣?

根據Traceroute原理ICMP TTL Exceed包應該是由每一跳的路由直接返回給SRC。

但是,在MPLS ICMP隧道中,ICMP包會一直走到MPLS的出口才會返回給SRC,這就造成在MPLS上的所有跳的延時都是幾乎一樣的。

九、結語

一個看似簡單的Traceroute裡面包含如此多的網路知識,有那麼多的因素導致Traceroute無法正確嗅探出網路拓撲,那麼是否真的沒有辦法?不是的,Paris Traceroute就是一種新式的Traceroute,它能夠更加準確的嗅探出網路拓撲,為網路排障提供更加準確的依據。等我研究完了Paris traceroute再做分享。

參考文獻:

    A Practical Guide to (Correctly) Troubleshooting with TracerouteAvoiding traceroute anomalies with Paris traceroute

  1. RFC1812

  2. 百度百科

  3. 維基百科

推薦閱讀:

哪種Linux發行版適合程序員做開發?
如何用c++監控windows和linux文件夾中文件的變化,有沒有什麼api可以讓系統在保存文件的時候通知程序?
基於 Coroutine 的非同步 RPC 框架示例(C++)
國外專家總結20條經典Linux命令面試問答

TAG:Linux | Linux運維 | 計算機網路 |