今天上班的路上在對比Tomcat和Jety的鏈接模型。Tomcat使用多線程處理請求,一個請求一個線程;Jetty則採用NIO。有文章說,對於邏輯複雜、處理時間較長的鏈接,Tomcat有優點,可是對於處理時間較短的鏈接,Jetty有優點。毫無疑問DNS的處理時間是很短的,看來把以前connector部分多線程的處理模型換成NIO的,應該性能會有一些提高。之後幾天一個大的開發計劃,就是調研Java NIO和Jetty裏的實現,寫一個完整的NIO connector。Cache機制開發延後。java
上午在網上找了點資料,磕磕碰碰把基於NIO的服務器模型搭出來了。由於DNS使用的是UDP協議,同時數據量很小,因此NIO並無起到理想中的效果。git
主要服務器部分代碼在https://github.com/flashsword20/blackhole/blob/nio/src/main/java/us/codecraft/blackhole/connector/UDPSocketMonitor.java。測試以後的效果讓人失望,NIO效率比多線程+BIO更低,只有24000~28000qps,而且由於代碼不熟悉,系統變得很不穩定。因此暫時保留到NIO分支了。github
結論是這樣的:緩存
一個DNS query的包大小大約是幾十byte,而response也不超過100 byte,如此小的傳輸量,同時由於UDP包也不涉及鏈接創建等東西,發送速度也很快,因此NIO發揮不了效率。服務器
晚上回家,嘗試加入cache機制:網絡
使用了ehcache,可是死活都存在UDP包亂序的問題。後來發現數據結構
對於同一key,ehcache獲取出來的對象老是同一個,這也是進程內緩存的特殊之處,不妨將其想一想爲一個Map多線程
而我會嘗試改變其ID值,結果就致使看起來ID變了,其實也改變了其餘線程獲取到的值,出現了不肯定性!併發
後來改進了數據結構,嘗試寫一個CopyOnWriteMessage(Message是dnsjava中DNS報文的抽象類),結果由於其不少方法都是私有,因此失敗了。後來構建了一個UDPPackage的對象,嘗試將byte[]用CopyOnWrite和訪問鎖的方式解決併發問題,測試結果CopyOnWrite性能會好一點,這也是由於數據量較小,並且Arrays.copyOf是本地方法吧。性能
後來測試,值得高興的是有緩存的狀況下,轉發模式效率達到了40000qps,可喜可賀!
家裏連公司,benchmark裏,UDP丟包率大概在10%,效果至關差,因此說網絡纔是第一要素!