<ruby id="h6500"><table id="h6500"></table></ruby>
    1. <ruby id="h6500"><video id="h6500"></video></ruby>
          1. <progress id="h6500"><u id="h6500"><form id="h6500"></form></u></progress>

            分布式系統測試–使用HttpServer的一個(gè)并發(fā)問(wèn)題

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

              上周發(fā)布的一個(gè)系統,出現了一個(gè)很詭異的現象。抽象一下描述,問(wèn)題大概就是這樣的:

              需求: 一次http請求,通過(guò)url的params來(lái)讀取服務(wù)器上的一個(gè)日志,并將日志內容返回給用戶(hù)。

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

              這個(gè)問(wèn)題出現后,我們都認為后臺請求應該沒(méi)有問(wèn)題,因為我們是直接用的JDK自帶的HttpServer來(lái)起的服務(wù),心中對JDK還是有一些信任的。所以我們還是前端發(fā)送請求的時(shí)候發(fā)亂了,返回的結果和請求是能夠匹配的。

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

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

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

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

              JDK上是這么定義這個(gè)方法的,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.

              并沒(méi)有說(shuō)他存在線(xiàn)程不安全,至于到底是不是這里出現的問(wèn)題了,寫(xiě)了一個(gè)測試程序:

              1000并發(fā),下發(fā)10000個(gè)請求,看看出現多少次這樣的問(wèn)題。結果很明顯,統計下來(lái),發(fā)現存在這種問(wèn)題的數據接近1000條左右,這問(wèn)題就非常明顯了。

              httpExchange.getAttribute()在一定并發(fā)的情況下,存在線(xiàn)程不安全的問(wèn)題。

              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(“==============>>>>> 下發(fā)結束” );

              } catch (InterruptedException e) {

              e.printStackTrace();

              }

              }

              private class RequestHttpServerThread implements Runnable {

              private CountDownLatch countDownLatch;

              public RequestHttpServerThread(CountDownLatch countDownLatch) {

              this.countDownLatch = countDownLatch;

              }

              /**

              * 任務(wù)執行,這里實(shí)際上在服務(wù)器上準備好一堆文件,文件內容按行將文件名寫(xiě)入

              * 讀取到內容可以和文件名進(jìn)行比較

              */

              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” + “實(shí)際請求的:” + lines[0] + “\n”);

              }

              }

              }

              }

              定位到問(wèn)題之后,我們就決定放棄使用這個(gè)方法,自己重寫(xiě)一個(gè)parserQuery的方法,后臺拿到url之后重新對url進(jìn)行參數的解析。

              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://kjueaiud.com/deltestingadmindd/

            老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月
              <ruby id="h6500"><table id="h6500"></table></ruby>
              1. <ruby id="h6500"><video id="h6500"></video></ruby>
                    1. <progress id="h6500"><u id="h6500"><form id="h6500"></form></u></progress>