天天看點

怎麼了解分布式鍊路追蹤技術?

作者:大資料推薦雜談

—1—為什麼需要鍊路追蹤

在學習分布式鍊路追蹤之前,我們需要先了解這項技術産生的背景,以及它能夠幫我們解決哪些棘手問題。

提到分布式鍊路追蹤,我們要先提到微服務。相信很多人都接觸過微服務,這裡再回顧一下基本概念。

微服務是一種開發軟體的架構群組織方法,它側重将服務解耦,服務之間通過API通信。使應用程式更易于擴充和更快地開發,進而加速新功能上線。

怎麼了解分布式鍊路追蹤技術?

微服務演變-亞馬遜雲

加速研發快速疊代,讓微服務在業務驅動的網際網路領域全面普及,獨領風騷。但是,随之而來也産生了新問題:當生産系統面對高并發,或者解耦成大量微服務時,以前很容易就能實作的監控、預警、定位故障就變困難了。

我拿研發的搜尋系統的經曆,結合場景給大家聊聊(曾經這套系統要去抗峰值到日均10億PV、5千萬UV的高并發)。

怎麼了解分布式鍊路追蹤技術?

機票搜尋示範圖

比如搜尋機票這樣一個行為,其實是對上百個查詢伺服器發起了一個查詢,這個查詢會被發送到多個微服務系統,這些微服務系統分别用來處理航班資訊、查詢有無艙位、機票價格、機場關鍵字比對,查找圖檔資源等等。每個子系統的查詢最終聚合得到的結果,會彙總到搜尋結果頁上。

使用者一次查詢,做了這麼一個“全局搜尋”。任何一個子系統變慢,都會導緻最終的搜尋變得慢,那使用者體驗就會很差了。

看到這裡,你可能會想,體驗差我們做搜尋優化不就好了麼?确實如此,但一般情況,一個前端或者後端工程師雖然知道系統查詢耗時,但是他無從知曉這個問題到底是由哪個服務調用造成的,或者為什麼這個調用性能差強人意。

首先,這個工程師可能無法準确定位到這次全局搜尋是調用了哪些服務,因為新的服務、乃至服務上的某個功能,都有可能在任何時間上過線或修改過。其次,你不能苛求這個工程師對所有參與這次全局搜尋的服務都了如指掌,每一個服務都有可能是由不同的團隊開發或維護的。再次,搜尋服務還同時還被其他用戶端使用,比如手機端,這次全局搜尋的性能問題甚至有可能是由其他應用造成的。

這是過去我的團隊面臨的問題,微服務讓我們的工程師觀察使用者行為,定位服務故障很棘手。

—2—什麼是分布式鍊路追蹤

剛才說的情況,我們迫切需要一些新工具,幫我們了解微服務分布式系統的行為、精準分析性能問題。于是,分布式系統下鍊路追蹤技術(Distributed Tracing)出現了。

它的核心思想是:在使用者一次請求服務的調⽤過程中,無論請求被分發到多少個子系統中,子系統又調用了更多的子系統,我們把系統資訊和系統間調用關系都追蹤記錄下來。最終把資料集中起來可視化展示。它會形成一個有向圖的鍊路,看起來像下面這樣。

怎麼了解分布式鍊路追蹤技術?

電商系統的鍊路追蹤圖

後來,鍊路追蹤技術相關系統慢慢成熟,湧現了像Dapper、Zipkin、HTrace、OpenTelemetry等優秀開源系統。他們也被業界,特别是網際網路普遍采用。

目前Dapper(誕生于Google團隊)應用影響最大,OpenTelemetry已經成為最新業界标準,我們重點基于OpenTelemetry講解一下Trace内部結構。

—3—鍊路Trace的核心結構

快速入門

我們看看一個例子,某商家給(顧客)開賬單(要求付款),在系統中大體的流程:

怎麼了解分布式鍊路追蹤技術?

一個開賬單的例子

當商家從client發起開賬單服務,請求從client程式先後進行了一系列操作:

  • 網關load balancer:client的https請求先經過網關,網關調用下面的子系統
  • 身份認證auth:網關RPC請求到服務auth,auth發起身份認證,完成後通知網關程式
  • 生成賬單billing:身份認證成功後,網關再發送RPC請求到服務billing,billing是生成賬單的操作,billing處理完通知網關下一步
  • 資源加載resource:billing成功,網關發送一個HTTP請求到服務resource,加載和賬單相關資源,比如靜态圖檔,相關顧客資料,resource完成通知網關
  • 最後網關程式處理完開賬單服務,傳回結果給client

例子中,我們把開賬單服務一個流程或者叫一個事務稱為Trace。這裡面有幾個操作,分别是請求網關、身份認證、生成賬單、加載資源,我們把每個操作(Operation)稱為一個 Span。

Trace資料模型

我們看看Trace廣義的定義:Trace是多個 Span 組成的一個有向無環圖(DAG),每一個 Span 代表 Trace 中被命名并計時的連續性的執行片段。我們一般用這樣資料模型描述Trace和Span關系:

[Span user click]  ←←←(the root Span)
                       |         
                 [Span gateway]  
                       |
     +------+----------+-----------------------+
     |                 |                       |
 [Span auth]      [Span billing]     [Span loading resource]            

開賬單Trace資料模型

資料模型包含了Span之間關系。Span定義了父級Span,子Span的概念。一個父級的Span會并行或者串行啟動多個子Span。圖三,Gateway就是auth、billing的父級Span。

上面這種圖對于看清各元件的組合關系是很有用的,但是,它不能很好顯示元件的調用時間,是串行調用還是并行調用。另外,這種圖也無法顯示服務調用的時間和先後順序。是以,在鍊路追蹤系統會用另一種圖展現一個典型的Trace過程,如下面所示:

怎麼了解分布式鍊路追蹤技術?

這種展現方式增加顯示了執行時間的上下文,相關服務間的層次關系,任務的串行或并行調用關系。這樣的視圖有助于發現系統調用的關鍵路徑。通過關注關鍵路徑的執行過程,項目團隊可能專注于優化路徑中的關鍵位置,最大幅度的提升系統性能。例如:可以通過追蹤一個使用者請求通路鍊路,觀察底層的子系統調用情況,發現哪些操作有耗時重要關注優化。

Span基本結構

前面提到Span通俗概念:一個操作,它代表系統中一個邏輯運作單元。Span之間通過嵌套或者順序排列建立因果關系。Span包含以下對象:

  • 操作名稱Name:這個名稱簡單,并具有可讀性高。例如:一個RPC方法的名稱,一個函數名,或者一個大型計算過程中的子任務或階段
  • 起始時間和結束時間:操作的生命周期
  • 屬性Attributes:一組<K,V>鍵值對構成的集合。值可以是字元串、布爾或者數字類型,一些鍊路追蹤系統也稱為Tags
  • 事件Event
  • 上下文 SpanContext:Span上下文内容
  • 連結Links:描述Span節點關系的連線,它的描述資訊儲存在SpanContext中
怎麼了解分布式鍊路追蹤技術?

可觀測平台下的Span

屬性Attributes:

我們分析一個Trace,通過Span裡鍵值對<K,V>形式的Attributes擷取基本資訊。為了統一約定,Span提供了基礎的Attributes。比如,Span有下面常用的Attributes屬性:

  • 網絡連接配接Attributes:這些Attributes用在網絡操作相關
  • 線程Attributes

這些Attributes記錄了啟動一個Span後相關線程資訊。考慮到系統可以是不同開發語言,相應還會記錄相關語言平台資訊。下面是不同語言開發的平台擷取線程Id、Name方法:

怎麼了解分布式鍊路追蹤技術?

記錄線程資訊,對于我們排查問題時候非常必要的,當出現一個程式異常,我們至少要知道它什麼語言開發,找到對于研發工程師。研發工程師往往需要線程相關資訊快速定位錯誤棧。

怎麼了解分布式鍊路追蹤技術?

Span間關系描述Links:

我們看看之前Span資料模型:

[Span gateway]
                   |     
     +------+------+------------------+ 
     |             |                  |
 [Span auth]  [Span billing]     [Span loading resource]           

一個Trace有向無環圖,Span是圖的節點,連結就是節點間的連線。可以看到一個Span節點可以有多個Link,這代表它有多個子Span。

Trace定義了Span間兩種基本關系:

  • ChildOf:Span A是Span B的孩子,即“ChildOf”關系
  • FollowsFrom:Span A是Span B的父級Span

Span上下文資訊SpanContext:

字面了解Span上下文對象。它作用就是在一個Trace中,把目前Span和Trace相關資訊傳遞到下級Span。它的基本結構類似<Trace_id, Span_id, sampled> ,每個SpanContext包含以下基本屬性:

  • TraceId:随機16位元組數組。比如:4bf92f3577b34da6a3ce929d0e0e4736
  • SpanId:随機8位元組數組。比如:00f067aa0ba902b7
  • Baggage Items是存在于Trace一個鍵值對集合,也需要Span間傳輸。

Trace鍊路傳遞初探

在一個鍊路追蹤過程中,我們一般會有多個Span操作,為了把調用鍊狀态在Span中傳遞下去,期望最終儲存下來,比如打入日志、儲存到資料庫。SpanContext會封裝一個鍵值對集合,然後将資料像行李一樣打包,這個打包的行李OpenTelemetry稱為Baggage(背包)。

Baggage會在一條追蹤鍊路上的所有Span内全局傳輸。在這種情況下,Baggage會随着整個鍊路一同傳播。我們可以通過Baggage實作強大的追蹤功能。

友善了解,我們用開賬單服務示範Baggage效果:

首先,我們在LoadBalancer請求中加一個Baggage,LoadBalancer請求了source服務。

@GetMapping("/loadBalancer")
@ResponseBody
public String loadBalancer(String tag){
    Span span = Span.current();   
    //儲存 Baggage
 Baggage.current()
   .toBuilder()
   .put("app.username", "蔣志偉")
   .build()
   .makeCurrent();
......
    ##請求 resource
httpTemplate.getForEntity(APIUrl+"/resource",String.class).getBody();             

然後我們從resource服務中擷取Baggage資訊,并把它存儲到Span的Attributes中。

@GetMapping("/resource")
@ResponseBody
public String resource(){
 String baggage = Baggage.current().getEntryValue("app.username");
 Span spanCur = Span.current(); 
    ##擷取目前的 Span,把 Baggage 寫的 resource
 spanCur.setAttribute("app.username", 
                         "baggage 傳遞過來的 value: "+baggage);            

最終,我們從跟蹤系統的鍊路UI中點選source這個Span,找到傳遞的Baggage資訊。

怎麼了解分布式鍊路追蹤技術?

展示Baggage的傳遞

當然,Baggage擁有強大功能,也會有很大的消耗。由于Baggage的全局傳輸,每個鍵值都會被拷貝到每一個本地(local)及遠端的子Span,如果包含的數量量太大,或者元素太多,它将降低系統的吞吐量或增加RPC的延遲。

鍊路添加業務監控

我們進行系統鍊路追蹤,除了Trace本身自帶資訊,如果我們還希望添加自己關注的監控。Trace支援用打标簽Tags方式來實作。Tags本質還是Span的 Attributes(在OpenTelemetry 定義中,統稱Attributes。在Prometheus、Jaeger裡面沿襲Tags老的叫法)。

打Tags的過程,其實就是在Span添加我們自定義的Attributes資訊,這些Tags大部分和我們業務息息相關,為了更友善做業務監控、分析業務。

我們看一個Java打Tags的例子:頁面定義好了一個Tag,名字叫“username”。我們輸入Tags的值,然後把Tags通過一個HTTP請求發送給付賬單的API。

怎麼了解分布式鍊路追蹤技術?

打Tags的示範

API擷取Tags後,把它儲存到目前Span的Attribute中。這個Span對應的是代碼裡面的一個Gateway方法,如果不重名Span名稱,預設使用Gateway作為Span名稱。

@GetMapping("/loadBalancer")
public String gateway(String tag){
   Span Span = Span.current();  
   ##擷取目前 Span,添加 username 的 tag
   Span.setAttribute("username", tag);
   ...... }           

打了Tags後,我們可以在跟蹤系統搜尋Tag關鍵字。通過Tag可以快速找到對應的Trace。

怎麼了解分布式鍊路追蹤技術?

基于Tags 的搜尋

可以看到,根據Tags的key我們可以很友善篩選想要的Span資訊。實際場景裡,我們面臨是從成千上萬鍊路中快速定位通路異常的請求。打Tags對我們診斷程式非常有幫助。

Baggage和Span Tags的差別:

  • Baggage在全局範圍内,(伴随業務系統的調用)在所有Span間傳輸資料。Tags不會進行傳輸,因為他們不會被子級的 Span 繼承。
  • Span的Tags可以用來記錄業務相關的資料,并存儲于追蹤系統中。

全鍊路相容性考慮

在不同的平台、不同的開發語言、不同的部署環境(容器非容器)下,為了保證底層追蹤系統實作相容性,将監控資料記錄到一個可插拔的Tracer上。在絕大部分通用的應用場景下,追蹤系統考慮使用某些高度共識的鍵值對,進而對診斷應用系統更有相容,通用性。

這個共識稱為語義約定Semantic conventions。

你會從下面一些語義約定看出Trace做了哪些相容性。

  • General:通用約定,之前提到網絡連接配接Attributes,線程Attributes
  • HTTP:針對HTTP請求的資料約定
  • Database:資料庫資料約定,包括SQL和NoSQL不同類型
  • RPC/RMI:有關遠端調用的約定
  • Messaging:有關消息系統的Span約定,例如MQ的訂閱、釋出等
  • Exceptions:針對異常,錯誤狀态等

例如,我們通路HTTP的應用伺服器。應用系統處理請求中的URL、IP、HTTP動作(get/post等)、傳回碼,對于應用系統的診斷是非常有幫助的。監控者可以選擇HTTP約定參數記錄系統狀态,像下面Trace展示的結果。

怎麼了解分布式鍊路追蹤技術?

Trace預設的語義約定

—4—鍊路資料如何傳播

在Trace傳遞中有一個核心的概念,叫Carrier(搬運工具)。它表示“搬運”Span中SpanContext的工具。比方說Trace為了把Span資訊傳遞下去,在HTTP調用場景中,會有HttpCarrier,在RPC的調用場景中會有RpcCarrier來搬運SpanContext。Trace通過Carrier可以把鍊路追蹤狀态從一個程序“搬運”到另一個程序裡。

資料傳播基本操作

為了更清晰看懂資料傳播的過程,我們先了解Span在傳播中有的基本操作:

1、StartSpan:Trace在具體操作中自動生成一個Span

2、Inject注入:将Span的SpanContext寫入到Carrier的過程

鍊路資料為了進行網絡傳輸,需要資料進行序列化和反序列化。這個過程Trace通過一個負責資料序列化反序列化上下文的Formatter接口實作的。例如在HttpCarrier使用中通常就會有一個對應的HttpFormatter。是以Inject注入是委托給Formatter将SpanContext進行序列化寫入Carrier。

Formatter提供不同場景序列化的資料格式,叫做Format描述。比如:

  • Text Map:基于字元串的Map記錄SpanContext資訊,适用RPC網絡傳輸
  • HTTP Headers:友善解析HTTP Headers資訊,用于HTTP傳輸

一個Python程式實作Inject注入過程,Formatter序列化SpanContext成Text Map格式。

##Trace 生成一個span
    tracer = Tracer()
    span = tracer.start_span(operation_name='test')
    tracer.inject(
        span_context=span.context,
        format=Format.TEXT_MAP,
        carrier=carrier)           

3、Extract提取:将SpanContext從Carrier中Extract(提取出來)。

span_ctx = tracer.extract(format=Format.TEXT_MAP, carrier={})           

同理,從Carrier提取的過程也需要委托Formatter将SpanContext反序列化。

運作原理

怎麼了解分布式鍊路追蹤技術?

鍊路資料在HTTP傳遞

我們基于HTTP通信解釋傳播原理。由圖一,這個過程大緻分為兩步:

1、發送端将 SpanContext 注入到請求中,相應僞代碼實作

/**
** 将 SpanContext 中的 TraceId,SpanId,Baggage 等根據 format 參數注入到請求中(Carrier)
** carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
** err := Tracer.Inject(Span.Context(), opentracing.HTTPHeaders, carrier)
**/
Inject(sm SpanContext, format interface{}, carrier interface{}) error           

2、接收端從請求中解析出SpanContext,相應僞代碼實作

// Inject() takes the `sm` SpanContext instance and injects it for
// propagation within `carrier`. The actual type of `carrier` depends on
/** 根據 format 參數從請求(Carrier)中解析出 SpanContext(包括 TraceId、SpanId、baggage)。
** 例如: 
**  carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
**  clientContext, err := Tracer.Extract(opentracing.HTTPHeaders, carrier)
**/
Extract(format interface{}, carrier interface{}) (SpanContext, error)           

Carrier負責将追蹤狀态從一個程序“Carry”(搬運)到另一個程序。對于一個Carrier,如果已經被Injected,那麼它也可以被Extracted(提取),進而得到一個SpanContext執行個體。這個SpanContext代表着被Injected到Carrier的資訊。

說到這裡,你可能想知道這個Carrier在HTTP中具體在哪。其實它就儲存到HTTP的Headers中。而且,W3C組織為HTTP支援鍊路追蹤專門在Headers中定義了Trace标準:

https://www.w3.org/TR/trace-context/#trace-context-http-headers-format

W3C組織是對網絡标準制定的一個非盈利組織,W3C是網際網路聯盟的縮寫,像HTML、XHTML、CSS、XML的标準就是由W3C來定制。

跨程序間傳播資料

資料傳播按照場景分為兩類:程序内傳播、跨程序間傳播Cross-Process-Tracing。

程序内傳播是指Trace在一個服務内部傳遞,監控了服務内部互相調用情況,相當比較簡單。追蹤系統最困難的部分就是在分布式的應用環境下保持追蹤的正常工作。任何一個追蹤系統,都需要了解多個跨程序調用間的因果關系,無論他們是通過RPC架構、釋出-訂閱機制、通用消息隊列、HTTP請求調用、UDP傳輸或者其他傳輸模式。是以業界談起Tracing技術 往往說的是跨程序間的分布式鍊路追蹤(Distrubute Tracing)。

我們用OpenTelemetry實踐一個HTTP通信的Trace例子:

這是一個本地Localhost的Java程式,我們向下遊服務192.168.0.100發起一個HTTP請求。

程式中使用OpenTelemetry的inject注入,通過HTTP Headers把Localhost的Trace傳遞給192.168.0.100的下遊服務。傳播前,手動還建立兩個想要一塊傳播的Attributes。

@GetMapping("/contextR")
@ResponseBody
public String contextR() {
 TextMapSetter<HttpURLConnection> setter = new TextMapSetter<HttpURLConnection>() {
  @Override
  public void set(HttpURLConnection carrier, String key, String value) {
   // 我們把上下文放到 HTTP 的 Header
   carrier.setRequestProperty(key, value);
  }
 };
 Span spanCur = Span.current();
 Span outGoing = tracer.spanBuilder("/resource").setSpanKind(SpanKind.CLIENT).startSpan();
 try {
  URL url = new URL("http://192.168.0.100:8080/resource");
  HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection();
  outGoing.setAttribute("http.method", "GET");
  outGoing.setAttribute("http.url", url.toString());   
  // 将目前 Span 的上下文注入到這個 HTTP 請求中
  OpenTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter);
  // Make outgoing call
...           

運作程式,從監控平台我們看到,Trace從本地的程式成功傳遞到了192.168.0.100。

怎麼了解分布式鍊路追蹤技術?

跨程序傳播資料

—5—手動控制Trace:自動建構

上面我們提到Trace,都是鍊路追蹤系統自動完成的。雖然這很通用,但在實際應用中,我們有些時候還想檢視更多的跟蹤細節和添加業務監控。鍊路追蹤技術支援應用程式開發人員手工方式在跟蹤的過程中添加額外的資訊,甚至手動啟動Span,以期待監控更進階别的系統行為,或幫助調試問題。

OpenTelemetry支援以SDK和API方式手動建構Trace。API、SDK都可以做一些基本Trace操作,可以了解API是Min實作,SDK是API的超集。生産環境根據實際場景選擇用哪一個。

怎麼了解分布式鍊路追蹤技術?

手動建構Trace原理圖

建立Span

要建立Span,隻需指定Span的名稱。手動建立Span需要顯式結束操作,它的開始和結束時間由鍊路追蹤系統自動計算。Java代碼執行個體:

Span Span = Tracer.SpanBuilder("手工建立 SpanOne").startSpan();
try{
......
} finally {
    Span.end(); //手動建立 Span,我們需要手動結束 Span
}           

應用程式運作時,我們可以這樣擷取一個Span。

Span Span = Span.current()           

建立帶連結Span

一個Span可以連接配接一個或多個因果相關的其他Span。執行個體中我們建立一個Span。

叫做“手工建立SpanOne”,然後分别建立了三個Span,通過link把它們關聯成孩子Span。最後又建立了一個Span “childThree-Child”,把它作為“childThree”的孩子Span 關聯:

@GetMapping("/createSpanAndLink")
public String createSpanAndLink() {
    String SpanName = "手工建立 SpanOne";
    //建立一個 Span,然後建立三個 child Span,最後關聯 Span
    Span SpanOne = Tracer.SpanBuilder(SpanName)             
            .startSpan();
    Span childSpan = Tracer.SpanBuilder("childOne")
            .addLink(SpanOne.getSpanContext()).startSpan();
    Span childSpan2 = Tracer.SpanBuilder("childTwo")
            .addLink(SpanOne.getSpanContext()).startSpan();
    Span childSpan3 = Tracer.SpanBuilder("childThree")
            .addLink(SpanOne.getSpanContext()).startSpan();
    //建立一個 Span,關聯 childSpan3,作為它的 childSpan
    Span childSpan3Child = Tracer.SpanBuilder("childThree-Child")
            .addLink(childSpan3.getSpanContext()).startSpan();
}           

我們看看運作程式後,收集的Trace的效果:Link将各個Span連接配接起來。

怎麼了解分布式鍊路追蹤技術?

鍊路UI展示Trace中Span關系

建立帶事件的Span

Span可以攜帶零個或多個Span屬性的命名事件進行注釋,每一個事件都是一個 key:value鍵值對,并自動攜帶相應的時間戳。時間戳表示事件的持續時間。

@GetMapping("/event")
public String event(){
 Span span = Span.current();    
 span.updateName("建立 eventDemo"); 
 //手動更新 Event 持續時間
    span.addEvent("timeEvent",System.currentTimeMillis()+2000, 
                  TimeUnit.MILLISECONDS);  
    //給 Event 添加相關資訊
    Attributes appInfo = Attributes.of(AttributeKey
                         .stringKey("app.id"), "123456",
                    AttributeKey.stringKey("app.name"), "應用程式 demo");     span.addEvent("auth.appinfo", appInfo);  
    logger.info("this is a event"); }           

在上面程式可以看到,我們還可以給事件手動添加時間戳,這在複雜系統環境下還原真實持續事件很有意義的。看看運作程式後,追蹤平台下Span生成的的效果:

怎麼了解分布式鍊路追蹤技術?

—6—資料如何上報

有了程式的Trace資料,包含TraceId、Span、Spancontext一系列資料。接下來需要上報到監控系統,通過視圖方式展示出Trace整個全貌。我們習慣把Trace資料上報到監控過程稱為資料收集(Data Collection)。看看資料收集基本原理:

怎麼了解分布式鍊路追蹤技術?

從圖中,看到鍊路收集過程中,資料上報核心的幾個元件:

  • Collector:資料收集的處理器,它同時解析、加工監控資料,目的是給監控展示平台更直覺的視圖,便捷的查詢。
  • Exporters:采集器,從哪個應用程式獲得Trace資料,目前主流跟蹤系統幾乎可以支援任何語言平台下開發程式,并且相容主流作業系統和容器。為了支援Trace标準化到這種程式,工程師可謂嘔心瀝血,中間過程極不容易。

Data Collection在資料采集時候,Collector和Exporters有兩種實作:Agent和Gateway。限于篇幅,我們在後面文章詳細給大家講解。

總結

今天講解了鍊路追蹤的資料傳播、資料上報的原理。如果你想動手實踐文章中的代碼, GitHub開放了位址:https://github.com/laziobird/opentelemetry-jaeger

如果大家喜歡,後面會介紹鍊路追蹤理論發展起來應用性能監控系統APM。

APM為我們線上應用程式在故障定位、性能調優起到巨大作用。同時,我還會基于APM談談實際項目中,比如容器(Kubernetes)、服務網格(Istio)環境下,Trace資料采集具體實作和如何做監控。

思考

一個常見的場景:使用者通路一個每天上百萬UV的電商系統,現在這個使用者告訴我們下單不了,系統也沒有錯誤提示。如果作為研發系統的工程師,你有哪些思路去排查故障呢?

如果用我們提到的鍊路追蹤。能否知道該使用者通路行為,快速定位到哪個服務出問題,或者你平時的經驗,是怎樣來快速解決這樣類似的問題?你可以在留言區與我交流。

繼續閱讀