• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 分布式系統測試–使用HttpServer的一個并發問題

    發表于:2014-02-27來源:豆瓣作者:@行知-追尋技術之美點擊數: 標簽:HttpServer
    分布式系統測試–使用HttpServer的一個并發問題 上周發布的一個系統,出現了一個很詭異的現象。抽象一下描述,問題大概就是這樣的: 需求: 一次http請求,通過url的params來讀取服務器上的一個日志,并將日志內容返回給用戶。

      上周發布的一個系統,出現了一個很詭異的現象。抽象一下描述,問題大概就是這樣的:

      需求: 一次http請求,通過url的params來讀取服務器上的一個日志,并將日志內容返回給用戶。

      問題表現:存在一定的機率,一次請求返回的內容,與期望的內容不一致。也就是所謂的串日志問題。

      這個問題出現后,我們都認為后臺請求應該沒有問題,因為我們是直接用的JDK自帶的HttpServer來起的服務,心中對JDK還是有一些信任的。所以我們還是前端發送請求的時候發亂了,返回的結果和請求是能夠匹配的。

      為了定位問題,我們在后臺加了些日志,對比了每次請求和請求的返回內容。在1~2天的監控下,發現真的出現了請求和返回內容之間存在不一致的地方,而前端發送的請求沒有錯,問題直接定位到后臺處理的問題。

      簡單說來,大致就類似這樣:前端發送請求 http://127.0.0.1/getlog?id=123&path=testlog&type=r,期望是讀取的是testlog文件,但是實際確是把devlog的內容返回給前端了。由于定位到這個現象,問題也就可以定位到后臺讀文件拿參數是錯的。

      我們怎么獲取url中的參數呢,翻下源碼,如下:

      Map Params = (Map) httpExchange.getAttribute(“parameters”);

      JDK上是這么定義這個方法的,getAttribute:

      Filter modules may store arbitrary objects with HttpExchange instances as an out-of-band communication mechanism. Other Filters or the exchange handler may then access these objects.

      并沒有說他存在線程不安全,至于到底是不是這里出現的問題了,寫了一個測試程序:

      1000并發,下發10000個請求,看看出現多少次這樣的問題。結果很明顯,統計下來,發現存在這種問題的數據接近1000條左右,這問題就非常明顯了。

      httpExchange.getAttribute()在一定并發的情況下,存在線程不安全的問題。

      public class HttpServersPerfTest extends BaseCase {

      private static final Log logger = LogFactory.getLog(AlisaNodeHttpServersPerfTest.class);

      int maxThread = 1000;

      private int totalTask = 1000;

      @Test

      public void testRequestRunningLog() throws InterruptedException {

      execute();

      }

      private void execute() throws InterruptedException {

      ExecutorService pool = Executors.newFixedThreadPool(maxThread);

      final CountDownLatch countDownLatch = new CountDownLatch(totalTask);

      for (int n = 0; n < totalTask; n++) {

      pool.execute(new RequestHttpServerThread(countDownLatch));

      }

      try {

      countDownLatch.await();

      System.err.println(“==============>>>>> 下發結束” );

      } catch (InterruptedException e) {

      e.printStackTrace();

      }

      }

      private class RequestHttpServerThread implements Runnable {

      private CountDownLatch countDownLatch;

      public RequestHttpServerThread(CountDownLatch countDownLatch) {

      this.countDownLatch = countDownLatch;

      }

      /**

      * 任務執行,這里實際上在服務器上準備好一堆文件,文件內容按行將文件名寫入

      * 讀取到內容可以和文件名進行比較

      */

      public void run() {

      Random rd = new Random();

      int index = rd.nextInt(60);

      if (index < 10){

      index = index + 10;

      }

      String indexStr = Integer.toString(index);

      String path = indexStr+”-”+indexStr+”-”+indexStr+”/”;

      LogGetter logGetter = new LogGetter();

      logGetter.setPath(path);

      String runningLog = logGetter.getRunningLog(0L);

      if(runningLog.contains( “T3_000000000″ + indexStr)){

      System.out.println(“==============>”+”exit”);

      }else

      {

      String[] lines = runningLog.split(“\n”);

      System.out.println(“期望:” + indexStr + “\n” + “實際請求的:” + lines[0] + “\n”);

      }

      }

      }

      }

      定位到問題之后,我們就決定放棄使用這個方法,自己重寫一個parserQuery的方法,后臺拿到url之后重新對url進行參數的解析。

      Map params = HttpUtils.parseQuery(httpExchange.getRequestURI().getQuery());

      public static Map parserQuery(String query) throws UnsupportedEncodingException {

      Map parameters = new HashMap();

      if (query != null) {

      String pairs[] = query.split(“[&]“);

      for (String pair : pairs) {

      String param[] = pair.split(“[=]“);

      String key = null;

      String value = null;

    原文轉自:http://www.kjueaiud.com/deltestingadmindd/

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>