一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

調試大規(guī)模服務器集群的五大策略

 WindySky 2016-06-24

【編者按】隨著互聯(lián)網(wǎng)迅速發(fā)展,用戶訪問量以及服務器規(guī)模的越來越大,因此,創(chuàng)建一個可靠、穩(wěn)定、優(yōu)質的互聯(lián)網(wǎng)服務是開發(fā)者的首要目標。而對于開發(fā)者而言,是否具備一個完善的服務器調試策略將對整個部署維護工作有著至關重要的影響。作者Alex Zhitnitsky現(xiàn)就職于Takipi,其經(jīng)常幫助Java、Scala開發(fā)人員解決服務器端的錯誤和對常用軟件進行測試。本文是Alex分享的一些經(jīng)驗。


譯文如下:

對運行中的真實環(huán)境進行調試,比在IDE中進行要困難很多。斷點,單步執(zhí)行等都會變得非常奢侈。因此要做的第一件事是要做出周密的調試計劃,否則漫無目的單純依靠日志記錄的做法,將是非常低效的。其次,規(guī)模越大的架構會更容易出現(xiàn)差錯。因此,如何篩查出錯誤源頭,明確哪個步驟出錯是非常重要的。

一、分布式日志

對于每條記錄,我們需要認真分析并了解其背后的含義。但是對于龐大的日志記錄我們需要高效的方法來處理,具體請參考這篇文章Logback調節(jié)的7個方法。


什么樣的記錄是真正需要的?

答案是全部!因為代碼會影響到整個應用的方方面面。此外,事務ID也是很重要的。它能有助于處理異常,因為事務ID經(jīng)常會貫穿于節(jié)點、進程、線程之間。一個較好的處理方法是在App的每個線程入口生成一個UUID。然后把該ID附加到日志記錄中,進行全程監(jiān)視。該方法在分布式和異步日志中起著舉足輕重的作用,特別是與日志管理工具如Logstash和Loggly等一起使用時。

異常處理

未知異常很容易會導致系統(tǒng)崩潰。所以建議在代碼末端設置一個全局異常處理句柄,例如在Java中進行下面的代碼編寫:

  1. public static void Thread.setDefaultUncaughtExceptionHandler(  
  2.   
  3.    UncaughtExceptionHandler eh);  
  4.   
  5. void uncaughtException( Thread t, Throwable e) {  
  6.   
  7.    logger.error(“Uncaught error in thread “ + t.getName(), e);  
  8.   
  9. }  

這或許看起來與Tomcat或Akka框架有點類似。最后這里給出三種處理未知異常時的方法:

1.  線程名:根據(jù)需要處理的請求來變更線程名是個巧妙的方法。例如在事務處理的任何時間,把事務ID先附加到線程,然后在結束時移除掉。

2.  本地線程存儲(Thread-local storage,TLS):這是一種使線程特定數(shù)據(jù)從線程對象分離的方法。借助這些特定數(shù)據(jù)能便于對出現(xiàn)的錯誤進行排查。例如事務ID,時間或用戶名。否則在欠缺這些數(shù)據(jù)和線程名的情況下,我們將不得不花費更多時間來處理未知異常。

3.  線程映射表(Mapped Diagnostic Context,MDC):MDC類似于本地線程概念,是日志框架的一部分如Log4j或Logback。它在日志級別生成了一個靜態(tài)映射表,能夠較TLS實現(xiàn)更多高級特性。

二、快人一步的Jstack

Jstack對Java開發(fā)者來說并不陌生,這是一款強大的JDK工具。簡單來說,Jstack能夠進入一個正在運行的進程然后輸出所有的線程meta信息,例如堆跟蹤,框架,鎖等等。此外它能夠對已銷毀的進程進行heap dumps或core dumps分析。

不過很多時候Jstack是用在回顧的環(huán)節(jié),如果錯誤已經(jīng)發(fā)生,它反饋的可能是過時的信息。因此如何更主動地使用Jstack是關鍵所在。例如,設置一個吞吐量閥值然后在該值下降時啟動jstack。

  1. public void startScheduleTask() {  
  2.   
  3.   
  4.    scheduler.scheduleAtFixedRate(new Runnable() {  
  5.   
  6.        public void run() {  
  7.   
  8.   
  9.            checkThroughput();  
  10.   
  11.   
  12.        }  
  13.   
  14.    }, APP_WARMUP, POLLING_CYCLE, TimeUnit.SECONDS);  
  15.   
  16. }  
  17.   
  18.   
  19. private void checkThroughput()  
  20.   
  21. {  
  22.   
  23.    int throughput = adder.intValue(); //the adder is inc’d when a message is processed  
  24.   
  25.   
  26.    if (throughput < MIN_THROUGHPUT) {  
  27.   
  28.        Thread.currentThread().setName("Throughput jstack thread: " + throughput);  
  29.   
  30.        System.err.println("Minimal throughput failed: executing jstack");  
  31.   
  32.        executeJstack();  // See the code on GitHub to learn how this is done  
  33.   
  34.    }  
  35.   
  36.   
  37.    adder.reset();  
  38. }  
三、 Stateful Jstack

Jstack應用時需要注意的另一個問題是由于它會返回非常多的線程meta數(shù)據(jù),如果缺乏相關的實際狀態(tài)數(shù)據(jù),將會對錯誤排查造成不便。以數(shù)據(jù)庫查詢?yōu)槔?,可以加上如下一行代碼:

  1. Thread.currentThread().setName(Context + TID + Params + current Time, ...);  

我們來比較加入前后的數(shù)據(jù)輸出:

加入前:

pool-1-thread-1 #17 prio=5 os_prio=31 tid=0x00007f9d620c9800 nid=0x6d03 in Object.wait() [0x000000013ebcc000]

加入后:

”Queue Processing Thread, MessageID: AB5CAD, type: AnalyzeGraph, queue: ACTIVE_PROD, Transaction_ID: 5678956, Start Time: 10/8/2014 18:34″ #17 prio=5 os_prio=31 tid=0x00007f9d620c9800 nid=0x6d03 in Object.wait() [0x000000013ebcc000]

不難看出,加入代碼后的信息輸出顯得更加清晰了。例如線程正在做什么,接收了什么參數(shù)如事務ID和消息ID。這些對后續(xù)的回滾,錯誤重現(xiàn)、分離等步驟都是很有幫助的。

四、 開源追蹤工具BTrace

如果在不依靠日志和改變代碼的前提下,如何去追蹤運行時JVM狀態(tài)呢?答案是BTrace Java代理。在添加該代理后,可使用BTrace腳本語言來獲取相關信息。

例如以下腳本:

  1. @BTrace public class Classload {  
  2.   
  3.    @OnMethod(  
  4.   
  5.        Clazz=”+java.lang.ClassLoader”,  
  6.   
  7.        method=”defineClass”,  
  8.   
  9.        location=@Location(Kind.RETURN)  
  10.   
  11.     )  
  12.   
  13.     public static void defineClass(@Return class cl) {  
  14.   
  15.        println(Strings.strcat(“l(fā)oaded ”, Reflective.name(cl)));  
  16.   
  17.        Threads.jstack();  
  18.   
  19.       println(“==============================”);  
  20.   
  21.    }  
  22.   
  23. }  

上述代碼對全部ClassLoaders及其子類進行跟蹤,當defineClass返回時,該腳本會列出載入的類并啟動JStack。但是我們不建議在實際環(huán)境中長期使用BTrace。因為Java代理會造成一定的資源開銷,同時需要編寫不同的腳本來進行追蹤。不過在想避免重啟JVM的情況下在運行時環(huán)境修改跟蹤腳本,BTrace是個不錯的選擇。

五、自定義JVM代理

在不改動服務器代碼的前提下進行調試,JVM代理是最佳選擇。類似于BTrace,我們可以嘗試編寫自定義Java代理。這種代理可以進入對象結構體然后在對象實例化的時候進行堆追蹤。然后我們可以對結果進行分析并掌握具體的載入過程。這是BTrace所不具備的,因為BTrace有限制和只能進行讀操作。請看下面的示例代碼:

  1. private static void internalPremain(String agentArgs, Instrumentation inst) throws IOException {  
  2.   
  3. ….  
  4.   
  5.    Transformer transformer = new Transformer(targetClassName);  
  6.   
  7.    inst.addTransformer(transformer, true); // the true flag let’s the agent hotswap running classes  
  8.   
  9. }  

這里創(chuàng)建了一個transformer對象,并注冊到一個能對類進行變更的對象之上。完整代碼請點擊這里進行查看。


小結

綜上所述,獲得的有價值數(shù)據(jù)越多,解決問題的速度就越快。在當今信息為王的時代,宕機時間的影響幾以秒計,因此是否具備一個完善的服務器調試策略將對整個部署維護工作有著至關重要的影響。

文章出自:Highscalability

(責編/夏夢竹)

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    夫妻性生活黄色录像视频| 欧美黑人精品一区二区在线| 中文字幕乱码免费人妻av| 国产视频一区二区三区四区| 欧美一区二区三区99| 日本不卡在线视频你懂的 | 国产成人精品在线一区二区三区| 欧美成人精品国产成人综合| 日韩国产精品激情一区| 国产91人妻精品一区二区三区| 激情内射亚洲一区二区三区| 偷自拍亚洲欧美一区二页| 国产又色又爽又黄又免费| 婷婷色网视频在线播放| 中字幕一区二区三区久久蜜桃| 欧洲偷拍视频中文字幕| 日韩欧美综合在线播放| 亚洲欧美视频欧美视频| 亚洲黑人精品一区二区欧美| 91亚洲国产成人久久| 国产一区二区久久综合| 人妻巨大乳一二三区麻豆| 国产91麻豆精品成人区| 一区二区三区免费公开| 最新国产欧美精品91| 最新69国产精品视频| 欧美色婷婷综合狠狠爱| 亚洲av成人一区二区三区在线| 99久久国产综合精品二区| 狠狠做深爱婷婷久久综合| 国产一区二区精品丝袜| 麻豆看片麻豆免费视频| 日韩中文字幕欧美亚洲| 亚洲日本中文字幕视频在线观看| 欧美一级特黄大片做受大屁股| 亚洲妇女黄色三级视频| 亚洲欧美国产网爆精品| 五月婷婷六月丁香狠狠| 日韩成人免费性生活视频| 午夜亚洲少妇福利诱惑| 亚洲精品黄色片中文字幕|