本周問題:
1. 連接、讀取和寫入超時什么區別?一般出現這3個超時如何排查?
2. Spring MVC和Webflux區別是什么?Reactor是什么意思?
3. 請問全鏈路監控SkyWalking的原理?
1. 連接、讀取和寫入超時什么區別?一般出現這3個超時如何排查?
連接超時:連接是發送請求開始到連接上目標URL主機地址的時間,連接超過預設時間仍沒連接上,稱為連接超時(同步阻塞的)。
讀取超時:讀取超時是已經連接到了目標服務器,進行內容獲取的時候超時,服務器在一段時間內沒有任何數據發送給客戶端,read操作會一直阻塞而掛起線程,直到有新的數據或異常產生(如果設置了超時時間就會拋出一個異常)。需要注意的是:客戶端讀取超時時,服務端邏輯可能還在處理。
寫入超時:Socket寫超時,是基於TCP的超時重傳,超時重傳是保證數據可靠性的一個重要機制,是在發送報文時開啟一個計時器,在一定時間內如果沒有收到確認ACK,就重新發送報文,如果多次發送仍沒有確認報文,就關閉連接,Socket寫超時是基於TCP協議棧的超時重傳機制,不需要設置超時時間。
超時排查:
連接超時:檢查客戶端是否設置超時時間太短,檢查客戶端網絡環境 ,可能客戶端連接的是Nginx,檢查Nginx設置的超時時間,檢查防火牆配置(可能會導致連接超時,或者被連接被重置)
讀取超時排查:一般是讀取的數據量大,或是目標服務器本身的問題(讀取數據庫慢,並發量大),設置讀取超時時間太短
寫入超時排查:是否寫入了超大量的數據
可以首先使用ping、telnet排查與服務器之間、與服務器特定端口之間的網絡是否通暢,如果不通,則可依次排查客戶端側、服務器側是否能正常上網、防火牆是否進行了攔截,服務器進程是否在正常運行、是否在服務器側監聽特定端口。
排查讀取/寫入超時,首先依次排查欲讀取/寫入的數據量、與服務器之間的帶寬、服務器處理能力、服務器的負荷,而后排查連接超時設置的時間是否合理(並非越長越好)。
2.Spring MVC和Webflux區別是什么?Reactor是什么意思?
SpringMVC是SpringFrameWork的開源Web框架,是圍繞Servlet設計的,將請求發給控制器(Controller),通過模型對象(Model),展示結果視圖(View),核心類是DispatcherServlet,頂層是實現Servlet接口,是同步阻塞IO模型
Spring WebFlux是 Spring5中新增加的基於Reactive Streams(反應式的異步組件之間的交互,主要目的是讓訂閱者控制發布者生成數據的速度或速率(負壓),阻塞調用強調調用者等待,非阻塞控制事件的速率)的Web框架
Spring WebFlux是:異步非阻塞(非阻塞式的Web堆棧來處理少量線程的並發並使用更少的硬件資源進行擴展),反應式(reactive 是指圍繞反應變化而構建的編程模型-網絡組件響應I/O事件,處於響應通知的模式,而不是被阻塞),Spring WebFlux不局限與Servlet容器可以在Netty,Undertow和Servlet 3.1+容器運行
反應式編程:類似與生產者對消費者提供訂閱接口,當有事件發生的時候,生產者會通過回調消費者的方法來通知消費者相應的事件
負壓:在基本的消息推送模式中,當消息發布者產生數據的速度過快時,會使得消息訂閱者的處理速度無法跟上產生的速度,從而給訂閱者造成很大的壓力。當壓力過大時,有可能造成訂閱者本身的奔潰,所產生的級聯效應甚至可能造成整個系統的癱瘓。負壓的作用在於提供一種從訂閱者到生產者的反饋渠道。訂閱者可以通過request()方法來聲明其一次所能處理的消息數量,而生產者就只會產生相應數量的消息,直到下一次 request()方法調用。這實際上變成了推拉結合的模式。
Reactive Streams: 一種支持負壓(Backpressure)的異步數據流處理標准,主流實現有RxJava和Reactor
Reactor是SpringWebFlux的首選反應式庫,WebFlux需要Reactor作為核心依賴項,WebFlux默認集成的Reactive Streams組件是Reactor,Reactor 是一個輕量級 JVM 基礎庫,幫助你的服務或應用高效(消息從A傳遞到B時,產生很少的內存垃圾,甚至不產生。解決消費者處理消息的效率低於生產者時帶來的溢出問題。盡可能提供非阻塞異步流。),異步地傳遞消息。
3.請問全鏈路監控SkyWalking的原理?
通過java agent+Byte Buddy+plugins方式實現的。可以下載SkyWalking源碼,查看入口類:SkyWalkingAgent
java探針java agen技術,在加載類的時候,對字節碼進行修改,class被加載之前對其攔截,插入自己的代碼在啟動的時候指定SkyWalking的jar:java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -jar yourApp.jar
1. Skywalking Agent:鏈路數據采集tracing(調用鏈數據)和metric(指標)信息並上報,上報通過HTTP或者gRPC方式發送數據到Skywalking Collector
2. Skywalking Collector : 鏈路數據收集器,對agent傳過來的tracing和metric數據進行整合分析通過Analysis Core模塊處理並落入相關的數據存儲中,同時會通過Query Core模塊進行二次統計和監控告警
3. Storage: Skywalking的存儲,支持以ElasticSearch、Mysql、TiDB、H2等主流存儲作為存儲介質進行數據存儲,H2僅作為臨時演示單機用。
4. SkyWalking UI: Web可視化平台,用來展示落地的數據,目前官方采納了RocketBot作為SkyWalking的主UI
SkyWalkingAgent入口類:

public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException { final PluginFinder pluginFinder; SnifferConfigInitializer.initialize(agentArgs); //加載Plugins pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins()); //bytebuddy final ByteBuddy byteBuddy = new ByteBuddy() .with(TypeValidation.of(Config.Agent.IS_OPEN_DEBUGGING_CLASS)); new AgentBuilder.Default(byteBuddy) .ignore( nameStartsWith("net.bytebuddy.") .or(nameStartsWith("org.slf4j.")) .or(nameStartsWith("org.apache.logging.")) .or(nameStartsWith("org.groovy.")) .or(nameContains("javassist")) .or(nameContains(".asm.")) .or(nameStartsWith("sun.reflect")) .or(allSkyWalkingAgentExcludeToolkit()) .or(ElementMatchers.<TypeDescription>isSynthetic())) .type(pluginFinder.buildMatch()) .transform(new Transformer(pluginFinder)) .with(new Listener()) .installOn(instrumentation); try { ServiceManager.INSTANCE.boot(); } catch (Exception e) { logger.error(e, "Skywalking agent boot failure."); } Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { ServiceManager.INSTANCE.shutdown(); } }, "skywalking service shutdown thread")); }