控源碼深度解析)
目錄SkyWalking 源碼復盤 ?從一次請求到監(jiān)控結果的完整源碼地圖一、SkyWalking 整體分層二、第一階段JVM 啟動 Agent三、第二階段插件匹配與字節(jié)碼增強四、第三階段HTTP 請求創(chuàng)建 EntrySpan五、第四階段ContextManager 管理當前 TraceSpan 棧六、第五階段Trace 創(chuàng)建業(yè)務 LocalSpan七、第六階段HikariCP 與 JDBC 拆分數(shù)據(jù)庫耗時1. 獲取連接2. 執(zhí)行 SQL3. 歸還連接你的兩個實驗SSH 隧道斷開/order/slowSql?time2八、第七階段Feign 創(chuàng)建 ExitSpan 并傳播上下文九、第八階段TraceSegment 異步上報緩沖區(qū)滿了怎么辦十、OAP 接收并解析 Segment十一、為什么一條 Trace 能產(chǎn)生儀表盤指標十二、拓撲圖是如何形成的十三、原始 Trace 與 Metrics 是兩條不同鏈路十四、日志關聯(lián)鏈路1. %tid 輸出 Trace ID2. GRPCLogClientAppender 上傳日志控制臺有 TID但 UI 沒日志十五、告警鏈路為什么 WebHook 是 JSON 數(shù)組十六、你的告警完整鏈路十七、Trace Profiling 鏈路三個核心指標Dump CountDurationSelf Duration判斷方法十八、四條核心數(shù)據(jù)鏈鏈路一Trace鏈路二Metrics 與拓撲鏈路三日志鏈路四告警十九、故障排查的標準順序1. UI 看不到服務2. 服務有指標但沒有 Trace3. Trace 斷鏈4. Trace 顯示數(shù)據(jù)庫慢5. 控制臺有 TID但 UI 沒日志6. 告警不觸發(fā)7. Profiling 沒數(shù)據(jù)二十、整套源碼中的核心類二十一、一段完整的面試回答二十二、你目前對 SkyWalking 的掌握層次二十三、最終記憶圖SkyWalking 源碼復盤 ?從一次請求到監(jiān)控結果的完整源碼地圖這一節(jié)把前面所有內(nèi)容收束成一條完整主線。以你的請求為例GET /order/query/1最終可能產(chǎn)生服務監(jiān)控指標 端點指標 分布式 Trace 服務拓撲 數(shù)據(jù)庫調(diào)用記錄 帶 TID 的業(yè)務日志 日志與 Trace 關聯(lián) 告警 WebHook Trace Profiling 線程棧這些并不是一個模塊一次性完成的而是由Agent 采集、OAP 分析、存儲、UI 查詢四個階段共同完成。一、SkyWalking 整體分層┌─────────────────────────────────────────┐ │ 業(yè)務應用 │ │ order / account / storage / alarm │ └─────────────────────────────────────────┘ │ │ -javaagent ▼ ┌─────────────────────────────────────────┐ │ Java Agent │ │ │ │ 插件匹配 │ │ 字節(jié)碼增強 │ │ 創(chuàng)建 Span │ │ 傳播 Trace Context │ │ 采集日志、JVM、Profiling 數(shù)據(jù) │ │ 異步上報 │ └─────────────────────────────────────────┘ │ │ gRPC 11800 ▼ ┌─────────────────────────────────────────┐ │ OAP │ │ │ │ 接收 Segment / Log / Profile Snapshot │ │ 分析 Span │ │ 生成 Source │ │ OAL 聚合 Metrics │ │ 執(zhí)行告警規(guī)則 │ │ 寫入存儲 │ └─────────────────────────────────────────┘ │ │ HTTP 12800 ▼ ┌─────────────────────────────────────────┐ │ SkyWalking UI 8080 │ │ │ │ 服務儀表盤 │ │ 拓撲圖 │ │ Trace │ │ 日志 │ │ 告警 │ │ Profiling │ └─────────────────────────────────────────┘端口必須記住端口用途11800Agent 向 OAP 上報數(shù)據(jù)12800UI 查詢 OAP8080SkyWalking UI8084你的告警接收服務二、第一階段JVM 啟動 Agent你的啟動參數(shù)類似-javaagent:H:\tools\...\skywalking-agent.jar -Dskywalking.agent.service_nameorder-service -Dskywalking.collector.backend_service127.0.0.1:11800JVM 啟動順序JVM 啟動 → 加載 skywalking-agent.jar → 調(diào)用 SkyWalkingAgent.premain() → 讀取 Agent 配置 → 掃描插件 → 構造 Byte Buddy Transformer → 注冊 Instrumentation → 啟動 Agent 內(nèi)部服務 → 執(zhí)行業(yè)務應用 main()核心邏輯可概括為public static void premain( String agentArgs, Instrumentation instrumentation ) { initializeConfig(agentArgs); loadPlugins(); installClassTransformer(instrumentation); ServiceManager.INSTANCE.boot(); }這里要區(qū)分Maven 依賴 → 讓項目能編譯和調(diào)用 Toolkit API -javaagent → 真正修改目標類字節(jié)碼并采集數(shù)據(jù)所以只添加 Maven 依賴 ≠ 已經(jīng)啟用 SkyWalking Agent三、第二階段插件匹配與字節(jié)碼增強Agent 不會修改所有類。它會根據(jù)插件規(guī)則匹配Tomcat Feign JDBC HikariCP Logback Trace 線程池 ……例如Tomcat 插件 → 增強 StandardHostValve.invoke() Feign 插件 → 增強 HTTP Client execute() HikariCP 插件 → 增強 getConnection()、close() JDBC 插件 → 包裝 PreparedStatement.execute() Toolkit 插件 → 增強帶 Trace 的方法運行時可以近似理解為beforeMethod(); try { return originalMethod(); } catch (Throwable e) { handleException(e); throw e; } finally { afterMethod(); }SkyWalking 沒有修改你的業(yè)務源代碼但 JVM 實際執(zhí)行的方法已經(jīng)插入了追蹤邏輯。四、第三階段HTTP 請求創(chuàng)建 EntrySpan瀏覽器訪問GET http://127.0.0.1:8083/order/query/1進入Tomcat → StandardHostValve.invoke() → TomcatInvokeInterceptor請求前ContextCarrier carrier readHeaders(request); AbstractSpan span ContextManager.createEntrySpan( GET:/order/query/1, carrier );隨后記錄URL HTTP Method Tomcat Component HTTP Layer形成EntrySpan └─ GET:/order/query/1如果這是瀏覽器發(fā)起的首個請求請求頭沒有有效上游上下文 → 創(chuàng)建一條新的 Trace如果是上游微服務調(diào)用請求頭中存在傳播信息 → 恢復上游 Trace五、第四階段ContextManager管理當前 Trace第一次創(chuàng)建 Span 時CONTEXT.get() null → 創(chuàng)建 TracingContext → 創(chuàng)建 TraceSegment → 寫入 ThreadLocal關鍵結構ContextManager └─ ThreadLocalTracingContext ├─ TraceSegment ├─ activeSpanStack └─ spanIdGenerator不同 Tomcat 工作線程線程 A → TracingContext A 線程 B → TracingContext B 線程 C → TracingContext C因此并發(fā)請求不會互相串鏈。Span 棧你的請求執(zhí)行時GET:/order/query/1 → queryOrder → HikariCP getConnection → JDBC execute對應入棧Tomcat Tomcat → queryOrder Tomcat → queryOrder → HikariCP Tomcat → queryOrder → JDBC創(chuàng)建子 Span 時AbstractSpan parent activeSpanStack.getLast(); newSpan.parentSpanId parent.getSpanId();結束時必須嚴格后進先出先結束 JDBC 再結束 queryOrder 最后結束 TomcatSpan 棧為空后TraceSegment 完成 → ThreadLocal.remove()六、第五階段Trace創(chuàng)建業(yè)務 LocalSpan業(yè)務方法Trace(operationName queryOrder) Tags({ Tag(key orderId, value arg[0]), Tag(key result, value returnedObj) }) public OrderInfo queryOrder(Integer orderId) { return orderMapper.selectById(orderId); }執(zhí)行過程進入方法 → createLocalSpan(queryOrder) → 讀取 arg[0] → 執(zhí)行業(yè)務邏輯 → 讀取 returnedObj → stopSpan()結果GET:/order/query/1 EntrySpan └─ queryOrder LocalSpan ├─ orderId 1 └─ result OrderInfo(...)這里不是 Spring AOP而是 Agent 直接增強方法字節(jié)碼。七、第六階段HikariCP 與 JDBC 拆分數(shù)據(jù)庫耗時數(shù)據(jù)庫調(diào)用過程MyBatis → HikariDataSource.getConnection() → PreparedStatement.execute() → Connection.close()形成queryOrder ├─ HikariCP/Connection/getConnection LocalSpan ├─ Mysql/JDBC/PreparedStatement/execute ExitSpan └─ HikariCP/Connection/close LocalSpan1. 獲取連接HikariCP/Connection/getConnection回答應用拿到數(shù)據(jù)庫連接花了多久慢時重點排查連接池耗盡 等待其他線程歸還連接 數(shù)據(jù)庫不可達 SSH 隧道斷開 建立新連接過慢 連接泄漏2. 執(zhí)行 SQLMysql/JDBC/PreparedStatement/execute回答從調(diào)用 JDBC 到數(shù)據(jù)庫返回整體花了多久慢時重點排查SQL 缺少索引 鎖等待或死鎖 掃描行數(shù)過多 數(shù)據(jù)庫 CPU、磁盤 IO 高 網(wǎng)絡延遲 SSH 隧道擁塞 結果集過大3. 歸還連接HikariCP/Connection/close一般不是關閉物理連接而是清理連接狀態(tài) → 歸還連接池 → 供其他請求復用你的兩個實驗SSH 隧道斷開HikariCP/getConnection ≈ 30 秒結論SQL 尚未真正執(zhí)行 主要慢在獲取或創(chuàng)建連接/order/slowSql?time2getConnection 很短 JDBC execute ≈ 2 秒 close 很短結論連接正常 主要慢在 SQL 或數(shù)據(jù)庫網(wǎng)絡調(diào)用八、第七階段Feign 創(chuàng)建 ExitSpan 并傳播上下文order-service調(diào)用accountApi.deduct(...);Feign 請求發(fā)送前ContextCarrier carrier new ContextCarrier(); AbstractSpan span ContextManager.createExitSpan( /account/deduct, carrier, 127.0.0.1:8082 );隨后將 Carrier 中的數(shù)據(jù)寫入 HTTP Header。調(diào)用鏈order-service ├─ EntrySpanPOST:/order/create └─ ExitSpan/account/deduct │ │ Trace Header ▼ account-service └─ EntrySpanPUT:/account/deduct兩個服務擁有相同 Trace ID 不同 Segment ID 不同 Span ID不是共享同一個 Span 對象。九、第八階段TraceSegment 異步上報最后一個 Span 結束activeSpanStack 為空 → TraceSegment.finish() → 通知 TraceSegmentServiceClient業(yè)務線程只執(zhí)行carrier.produce(traceSegment);真正的處理由后臺線程完成DataCarrier → Agent 后臺消費者 → TraceSegment.transform() → SegmentObject → gRPC → OAP 11800這種設計避免OAP 慢 → Tomcat 請求線程也被阻塞緩沖區(qū)滿了怎么辦默認策略偏向緩沖區(qū)有空間 → 正常放入 緩沖區(qū)滿 → 丟棄部分 Segment → 不長期阻塞業(yè)務線程SkyWalking 的取舍是業(yè)務穩(wěn)定性 遙測數(shù)據(jù)絕對完整性所以接口成功 ≠ 這條 Trace 一定成功上報十、OAP 接收并解析 SegmentOAP 接收路徑TraceSegmentReportServiceHandler → SegmentParserService → TraceAnalyzerTraceAnalyzer遍歷EntrySpan ExitSpan LocalSpan Segment并通知不同監(jiān)聽器RPCAnalysisListener SegmentAnalysisListener VirtualServiceAnalysisListener ……監(jiān)聽器再生成統(tǒng)一的 SourceService ServiceInstance Endpoint ServiceRelation EndpointRelation DatabaseAccess Segment隨后SourceReceiver → Dispatcher → OAL → Metrics → Storage十一、為什么一條 Trace 能產(chǎn)生儀表盤指標入口 SpanGET:/order/slowSql Duration ≈ 2100 ms可以生成Serviceorder-service ServiceInstanceorder 實例 EndpointGET:/order/slowSqlOAL 再計算service_resp_time service_sla service_cpm service_percentile service_instance_resp_time endpoint_resp_time endpoint_sla endpoint_cpm endpoint_percentile所以Trace Duration是單次請求時間而endpoint_resp_time是一定時間窗口內(nèi)的聚合指標。十二、拓撲圖是如何形成的拓撲并不是直接打開一條 Trace 繪制。真實過程大量 EntrySpan 和 ExitSpan → 生成 ServiceRelation → 按時間窗口聚合 → UI 查詢關系指標 → 展示拓撲例如order-service → account-service → MySQL分別來自Feign ExitSpan / 下游 EntrySpan JDBC Database ExitSpanMySQL 沒有安裝 Java Agent但 JDBC Span 中存在peer database type latency SQL statement所以 OAP 可以創(chuàng)建Virtual Database Service并顯示order-service ↓ 127.0.0.1:13306十三、原始 Trace 與 Metrics 是兩條不同鏈路同一個 Segment 會被不同監(jiān)聽器處理RPCAnalysisListener → 生成服務、端點、關系和指標 SegmentAnalysisListener → 根據(jù)采樣策略決定是否保存原始 Trace因此可能出現(xiàn)服務儀表盤有數(shù)據(jù) 拓撲圖有關系 但 Trace 列表中找不到某次請求原因可能是Metrics 已參與計算 但原始 Segment 因采樣沒有保存這不是矛盾。十四、日志關聯(lián)鏈路業(yè)務代碼log.info(查詢訂單orderId{}, orderId);分成兩部分。1.%tid輸出 Trace IDLogback Pattern → %tid → Agent 增強 PatternConverter → ContextManager.getGlobalTraceId() → 輸出到控制臺例如[TID:abc123] 查詢訂單orderId1它主要方便人肉排查。2.GRPCLogClientAppender上傳日志Appender 將日志轉換為LogData ├─ service ├─ serviceInstance ├─ endpoint ├─ timestamp ├─ body ├─ level ├─ logger ├─ thread └─ traceContext ├─ traceId ├─ segmentId └─ spanId然后DataCarrier → 后臺線程 → gRPC 11800 → OAP Log Receiver → Log Analyzer → Storage系統(tǒng)關聯(lián)日志與 Trace依靠的是結構化traceId segmentId spanId不是簡單搜索日志字符串中的 TID??刂婆_有 TID但 UI 沒日志常見原因只配置了 %tid沒有配置 gRPC Appender Root Logger 未引用 SkyWalking Appender 服務沒有掛 Agent 11800 不通 Agent 日志隊列已滿 OAP 日志 Receiver 異常 UI 時間或服務篩選錯誤十五、告警鏈路OAP 生成分鐘級 Metrics 后Metrics → RunningRule.in() → 每個 AlarmEntity 維護一個 Window → AlarmCore 定時檢查 → MQE 表達式判斷 → AlarmMessage → WebhookCallback例如expression: sum(endpoint_resp_time 1000) 2 period: 10 silence-period: 10含義最近 10 個分鐘桶中 至少有 2 個分鐘桶 端點平均響應時間超過 1000 ms所以不是一條請求超過 1000 ms → 立即告警而是分鐘級指標進入滑動窗口 → 時間窗口滿足規(guī)則 → 告警為什么 WebHook 是 JSON 數(shù)組一次定時檢查可能同時產(chǎn)生端點告警 數(shù)據(jù)庫告警 服務實例告警OAP 統(tǒng)一保存到ListAlarmMessage然后gson.toJson(messages)所以請求體是[ { scope: ENDPOINT, name: GET:/order/slowSql }, { scope: DATABASE, name: 127.0.0.1:13306 } ]你的 Controller 應使用RequestBody ListAlarmMessage messages十六、你的告警完整鏈路PowerShell 循環(huán)請求 → GET /order/slowSql?time2 → JDBC execute 約 2 秒 → Agent 上報 Segment → OAP 生成分鐘級 Metrics → RunningRule 窗口滿足條件 → 創(chuàng)建 ListAlarmMessage → POST alarm-service:8084 → AlarmController → 郵件服務 → QQ SMTP → 郵件到達WebHook 或郵件發(fā)送失敗不會直接影響 order-service 請求因為告警發(fā)生在 OAP 的獨立鏈路中。但 WebHook 本身仍應快速返回郵件發(fā)送最好異步化。十七、Trace Profiling 鏈路任務創(chuàng)建UI → OAP 保存 ProfileTaskAgent 定時查詢ProfileTaskChannelService → getProfileTaskCommands()收到任務后校驗任務 → 等待 Start Time → 啟動 ProfileTaskExecutionContext新的請求到達創(chuàng)建 TracingContext → firstSpanOPName 與任務 Endpoint 匹配 → 創(chuàng)建 ThreadProfiler → 狀態(tài) PENDING請求運行超過Min Duration Threshold后PENDING → PROFILINGProfiler 周期執(zhí)行targetThread.getStackTrace();生成taskId segmentId sequence dumpTime stack異步上傳 OAP。OAP 再將大量采樣棧合并為樹。三個核心指標Dump Count該方法出現(xiàn)在多少次線程棧采樣中不是方法調(diào)用次數(shù)。Duration該節(jié)點在連續(xù)采樣區(qū)間中出現(xiàn)的近似總時間不是精確方法計時。Self Duration節(jié)點 Duration - 直接子節(jié)點 Duration 之和表示盡量排除子調(diào)用后當前方法自身消耗的近似時間。判斷方法Duration 高Self Duration 低 → 主要慢在子調(diào)用 Duration 高Self Duration 高 → 當前方法自身更可能是熱點 Socket read 高 → 主要等待網(wǎng)絡 JDBC Driver 高 → 主要等待數(shù)據(jù)庫 Thread.sleep 高 → 線程主要處于休眠狀態(tài)十八、四條核心數(shù)據(jù)鏈學完 SkyWalking 后應該把它拆成四條鏈理解。鏈路一Trace插件攔截 → Entry / Local / Exit Span → TracingContext → TraceSegment → DataCarrier → gRPC → OAP → Trace UI鏈路二Metrics 與拓撲Span → TraceAnalyzer → Source → OAL → Metrics → Storage → Dashboard / Topology鏈路三日志ILoggingEvent → %tid → GRPCLogClientAppender → LogData → gRPC → OAP Log Analyzer → Log UI鏈路四告警Metrics → RunningRule → Window → MQE Expression → AlarmMessage → WebHook → 郵件Profiling 則是第五條專項診斷鏈ProfileTask → Endpoint 匹配 → Thread Stack Sampling → Snapshot → OAP 合并分析十九、故障排查的標準順序1. UI 看不到服務先檢查服務是否掛載 -javaagent service_name 是否正確 Agent 是否啟動成功 Agent 到 OAP 11800 是否連通 是否真正訪問過接口 UI 時間范圍是否正確2. 服務有指標但沒有 Trace檢查是否被采樣丟棄 Agent Segment 緩沖區(qū)是否滿 OAP Trace 存儲是否正常 Trace 時間范圍和服務篩選 請求是否真正經(jīng)過支持的插件3. Trace 斷鏈檢查調(diào)用方是否創(chuàng)建 ExitSpan 是否注入跨進程 Header 下游是否掛載 Agent 下游是否讀取 Header 是否經(jīng)過不支持的客戶端或網(wǎng)關 異步線程是否傳播上下文4. Trace 顯示數(shù)據(jù)庫慢先區(qū)分HikariCP/getConnection 慢 還是 JDBC/execute 慢這是你當前已經(jīng)掌握的高價值診斷能力。5. 控制臺有 TID但 UI 沒日志檢查GRPCLogClientAppender Root Logger Agent Activation 11800 OAP 日志接收器 時間與服務篩選6. 告警不觸發(fā)檢查告警 Metric 名稱是否正確 表達式是否正確 period 是否滿足 請求是否跨多個分鐘桶 規(guī)則是否限定了 include-names alarm-settings.yml 是否被 OAP 加載 Webhook URL 是否正確 alarm-service 是否監(jiān)聽 80847. Profiling 沒數(shù)據(jù)檢查Agent Profiling 是否啟用 OAP receiver-profile 是否啟用 任務 Endpoint 是否與真實 Operation Name 一致 任務是否在有效時間內(nèi) 請求是否超過 Min Duration Threshold Max Sampling Count 是否已達到 請求是否在任務創(chuàng)建后重新發(fā)起二十、整套源碼中的核心類領域核心類Agent 啟動SkyWalkingAgent插件發(fā)現(xiàn)PluginFinder字節(jié)碼增強Transformer上下文入口ContextManager本地追蹤上下文TracingContext一段本地追蹤TraceSegmentHTTP 入口Tomcat Interceptor跨服務出口Feign/HTTP Client InterceptorJDBC 追蹤JDBC Statement WrapperHikariCPPooling InterceptorToolkitTrace Annotation InterceptorTrace 上報TraceSegmentServiceClientOAP Trace 接收TraceSegmentReportServiceHandlerOAP 解析TraceAnalyzer服務關系分析RPCAnalysisListener日志上傳LogReportServiceClient告警核心AlarmCore、RunningRuleProfiling 執(zhí)行ProfileTaskExecutionService線程采樣ThreadProfilerProfiling 分析ProfileAnalyzer二十一、一段完整的面試回答面試官問請整體介紹 SkyWalking 的工作原理??梢曰卮餝kyWalking 主要由 Java Agent、OAP、存儲和 UI 組成。Java 應用通過-javaagent在啟動階段執(zhí)行 Agent 的premainAgent 加載插件并使用 Byte Buddy 與 Instrumentation 對 Tomcat、Feign、JDBC、連接池等框架類進行字節(jié)碼增強。請求進入 Tomcat 時創(chuàng)建 EntrySpan業(yè)務內(nèi)部通過 Toolkit 可以創(chuàng)建 LocalSpan對外調(diào)用 Feign 或數(shù)據(jù)庫時創(chuàng)建 ExitSpan。ContextManager使用 ThreadLocal 為每個請求線程維護獨立的TracingContext并通過活動 Span 棧確定父子關系??绶諘r調(diào)用方將 Trace 上下文注入 HTTP Header下游從 Header 中恢復上下文從而生成屬于同一 Trace 的不同 Segment。當所有 Span 結束后Agent 將 TraceSegment 放入內(nèi)存緩沖區(qū)由后臺線程轉換成 Protobuf 對象并通過 gRPC 上報 OAP避免網(wǎng)絡發(fā)送阻塞業(yè)務線程。OAP 對 Segment 中的 Entry、Exit 和 Local Span 進行分析生成 Service、Endpoint、ServiceRelation、DatabaseAccess 等 Source再通過 OAL 聚合成響應時間、成功率、CPM、百分位等 Metrics用于儀表盤、拓撲和告警。日志可通過 Toolkit 獲取 Trace ID并以結構化 LogData 攜帶 Trace ID、Segment ID 和 Span ID 上傳實現(xiàn)日志與鏈路關聯(lián)。告警模塊對分鐘級 Metrics 維護滑動窗口規(guī)則命中后通過 WebHook 通知外部系統(tǒng)。對于 Span 內(nèi)部難以定位的慢方法還可以通過 Trace Profiling 周期采樣目標請求線程棧由 OAP 合并計算 Duration、Self Duration 和 Dump Count。二十二、你目前對 SkyWalking 的掌握層次現(xiàn)在已經(jīng)不只是會啟動 OAP 打開 UI 查看 Trace而是已經(jīng)貫通了-javaagent 啟動 插件匹配 字節(jié)碼增強 Entry / Local / Exit Span ThreadLocal 上下文 Span 棧 跨服務傳播 數(shù)據(jù)庫分層診斷 Segment 異步上報 OAP Source 與 Metrics 服務拓撲 日志關聯(lián) 告警時間窗口 Trace Profiling按后端面試標準可以歸納為三個層次層次當前狀態(tài)會部署和使用已掌握會根據(jù) Trace 定位問題已掌握能解釋 Agent 與 OAP 核心原理已形成完整主線能獨立修改 Agent/OAP 源碼尚需專項源碼工程訓練二十三、最終記憶圖-javaagent ↓ premain ↓ 配置加載 插件掃描 ↓ Byte Buddy Instrumentation ↓ 框架類被增強 ↓ HTTP 請求進入 ↓ EntrySpan ↓ LocalSpan / ExitSpan ↓ ContextManager ThreadLocal Span Stack ↓ 跨服務 ContextCarrier ↓ TraceSegment ↓ Agent 內(nèi)存隊列 ↓ gRPC 11800 ↓ OAP TraceAnalyzer ↓ Source ↓ OAL Metrics ├─ Dashboard ├─ Topology ├─ Alarm └─ Storage 同時 業(yè)務日志 → LogData → TraceContext → OAP 日志關聯(lián) Profiling Task → Thread.getStackTrace() → Snapshot → OAP 合并分析下一階段建議不再繼續(xù)平鋪源碼而是進入SkyWalking 面試拷打與故障實戰(zhàn)復盤從 Agent 不上報、鏈路斷裂、連接池耗盡、慢 SQL、日志丟失、告警不觸發(fā)等場景要求你先判斷問題層級再給出排查順序。