轉載地址:http://blog.csdn.net/yinwenjie/article/details/49685763
(接上文《架構設計:系統間通信(11)——RPC實例Apache Thrift 上篇》)
3、Aapche Thrift詳解
在《架構設計:系統間通信(10)——RPC的基本概念》一文中,我專門介紹了一款RPC規範的具體實現中哪些要素和性能息息相關。包括了RPC通訊採用的數據封裝格式、RPC通訊採用的網絡IO模型和RPC所採用的請求處理方式。這個小節我們對Apache Thrift中的這三個要素,這樣讀者就可以知曉爲什麼Apache Thrift的性能如此高效了。
3-1、Aapche Thrift與消息格式
Apache Thrift支持多種消息格式封裝。這些消息格式是如果進行編碼和解碼的是不需要使用者關心的,只需要根據自己的需要制定不同的消息封裝格式即可。Apache Thrift所有消息格式封裝的實現,都繼承與TProtocol這個抽象類,如下圖所示:
3-1-1、TBinaryProtocol
二進制流的編碼格式。由於需要支持跨語言,所以Apache Thrift支持有限的幾種通用類型,包括基本類型(Float、Double、Integer、Long、String、Short)、集合類型(Map、Set、List)還有Pojo類型(實際上就是前兩者若干類型的組合形式)。
那麼這個類所生成的二進制流和傳統的java序列化後生成的二進制流有什麼樣的區別(或者是優勢)呢?我們可以通過閱讀TBinaryProtocol的源代碼進行研究。
我們以TBinaryProtocol中,對Integer的序列化過程進行詳細的解釋,來對比java提供的其他幾種序列化的方式找到不同。首先java中,如果要將一個Integer對象通過網絡發送出去,要做的第一件事情就是序列化,那麼我們常用的序列化方式有兩種,如下所示:
- java中序列化Integer對象的第一種方法:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">Integer integerObject = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10066329</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> integerObject<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.toString</span>()<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getBytes</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
- java中序列化Integer對象的第二種方法:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ByteArrayOutputStream aStream = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ByteArrayOutputStream(); ObjectOutputStream oStream = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ObjectOutputStream(aStream); oStream.writeObject(integerObject); aStream.toByteArray();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
第一種方式是將Integer對象中的值序列化;第二種方式,是將Integer整個對象序列化。這兩種方式雖然都產生byte[],實際上性質是完全不一樣的。我們來看一下這兩種方式產生的byte[]的內容:
- 序列化Integer的值:
[49, 48, 48, 54, 54, 51, 50, 57]
- 序列化整個Integer對象:
[-84, -19, 0, 5, 115, 114, 0, 17, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 73, 110, 116, 101, 103, 101, 114, 18, -30, -96, -92, -9, -127, -121, 56, 2, 0, 1, 73, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, -103, -103, -103]
第一種方式序列化後,byte數組有8個byte元素(因爲是首先轉換成字符串的,所以實際上這個大小會隨着Integer值的大小增加而增加);第二中方式序列化後,byte數組一共有 > 20 個byte元素,其中除了記錄Integer的值以外,還包括描述這個類型的其他屬性。
那麼我們再來看看TBinaryProtocol中,是如何序列化Integer類型的。首先我們來看一下TBinaryProtocol進行Integer序列化的這部分源代碼,如下圖所示:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[] i32out = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">writeI32</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i32) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> TException { i32out[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span> & (i32 >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>)); i32out[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span> & (i32 >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>)); i32out[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span> & (i32 >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>)); i32out[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span> & (i32)); trans_.write(i32out, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
計算過程可以通過下圖來表示:
通過4次位計算,得到了一個長度爲4個byte數組,並且這個數組的大小並不會隨着整數大小的增加而變化。並且位運算的速度是所有計算中速度最快的一種計算。反序列化的過程相似,對這個大小爲4的byte[]數組重新進行位計算即可:
<code class="hljs vbnet has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">((buf[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">off</span>] & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span>) << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>) | ((buf[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">off</span>+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span>) << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>) | ((buf[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">off</span>+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span>) << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>) | ((buf[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">off</span>+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>] & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span>));</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
由於本文的篇幅和寫作目的所限,不能一一介紹TBinaryProtocol的各種序列化方式,但是通過對TBinaryProtocol中Integer的序列化過程,我們可以找到TBinaryProtocol處理過程的優勢,包括速度和大小的優勢。所以,如果您的使用環境對序列化過程沒有特別的要求(例如後面要提到的大量的負數情況),那麼直接使用TBinaryProtocol進行數據格式的封裝的就可以了。
byte是一個8位二進制描述(一個字節),在java中,一個int需要4個byte進行表示,而。“0x”的前綴表示16進制數字,那麼0xff的二進制表示就是 1111 1111;“&”是“與”運算符,這個運算符用於二進制計算,1 & 1 = 1,其餘情況都 = 0;“<<” 表示左移運算,0011 << 2 = 1100;”>>”表示右移運算,1100 >> 2 = 0011;
3-1-2、TCompactProtocol
使用zigzag編碼方式緊湊傳輸協議。zigzag編碼的優勢在於記錄數字類型(整數、單精度浮點和雙精度浮點),最特別的是zigzag編碼對負數的記錄。在計算機中,都會使用很大的數字表示負數,爲了保證節約傳輸量,zigzag編碼採用正數與負數交錯的方式,把負數轉換爲一個正數進行記錄。下面我們具體來分析一下TCompactProtocol中對32位整數的序列化方式,以下是TCompactProtocol中對32爲整數的處理代碼:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Write an i32 as a zigzag varint. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">writeI32</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i32) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> TException { writeVarint32(intToZigZag(i32)); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Convert n into a zigzag int. This allows negative numbers to be * represented compactly as a varint. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">intToZigZag</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> n) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> (n << <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) ^ (n >> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Write an i32 as a varint. Results in 1-5 bytes on the wire. * TODO: make a permanent buffer like writeVarint64? */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[] i32buf = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">writeVarint32</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> n) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> TException { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> idx = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ((n & ~<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x7F</span>) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { i32buf[idx++] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)n; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// writeByteDirect((byte)n);</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { i32buf[idx++] = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>)((n & <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x7F</span>) | <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x80</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// writeByteDirect((byte)((n & 0x7F) | 0x80));</span> n >>>= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>; } } trans_.write(i32buf, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, idx); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li></ul>
以上代碼片段一共有一個對外的調用方法,和兩個分別名爲intToZigZag和writeVarint32的私有方法。從字面上的意義我們可以知道:當對一個32位整數進行編碼時,首先將這個32位整數轉成ZigZag編碼格式,然後在序列化爲“變長的32位整數”。那麼這個處理的具體過程是什麼樣的呢?我們以一個較大的32位整數(161061273,二進制計數爲:1001100110011001100110011001)爲例,進行講解:
-
首先將整個這個整數做成ZigZag編碼格式:
-
然後進行“變長”處理:
-
可以看到,上面的“變長”計算一共進行了5次,比TBinaryProtocol中的32位整數序列化還要多出一個byte。這是爲什麼呢?因爲這個數字比較長。
-
但實際處理中,我們一般使用的數據都是比較小的。這也是爲什麼首先要使用ZigZag編碼把某個負數的符號位從高位移動到低位的原因。實際上,在實際過程中,變長計算一般只會進行二至三次就完成。這樣,在大多數情況下,完成一個32位整數的序列化,TCompactProtocol做使用的空間就比TBinaryProtocol要小。
-
那麼經過分析,對於TCompactProtocol和TBinaryProtocol的選擇的經驗是:如果傳輸的信息中,基本都是字符串,那麼使用TCompactProtocol還是使用TBinaryProtocol基本上都是差不多的;如果需要傳輸的信息中,會有較多的“低位數字”,那麼建議使用TCompactProtocol。
3-1-3、其他傳輸格式封裝:
當然Apache Thrift還提供其他的傳輸格式封裝。不同的需求場景下,您可以使用根據需要選用這些信息傳輸格式:
3-2、Aapche Thrift與通信模型
Apache Thrift支持阻塞式同步IO通訊模型和非阻塞式異步IO通信模型。這裏說明一下,我在這個系列的文章中,已經詳細講述了各種IO模型的特點和工作原理(請參見我另外幾篇文章《架構設計:系統間通信(3)——IO通信模型和JAVA實踐 上篇》、《架構設計:系統間通信(4)——IO通信模型和JAVA實踐 中篇》、《架構設計:系統間通信(5)——IO通信模型和JAVA實踐 下篇》)。所以讀者您如果度過本人的拙作,那麼您一定清楚,要發揮Apache Thrift性能上的優勢,那麼一定要在正式生產環境中採用Apache Thrift對非阻塞式異步IO通信模型的支持。下面的代碼我們將向您展示Apache Thrift的這種特性:
在給出示例代碼之前一定要再強調一次,Apache Thrift的服務器端和客戶端一定要採用相同的通信模型。這就是說如果Apache Thrift的服務器端採用的是非阻塞異步通信模型,那麼Apache Thrift客戶端也一定要採用非阻塞異步通信模型,否則就無法通信。
- 服務器的非阻塞異步通信代碼:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> testThrift.man; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.nio.channels.Selector; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.concurrent.Executors; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.commons.logging.Log; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.commons.logging.LogFactory; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.log4j.BasicConfigurator; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.TProcessor; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.protocol.TBinaryProtocol; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.server.THsHaServer; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.transport.TNonblockingServerSocket; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.HelloWorldService; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.HelloWorldService.Iface; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.impl.HelloWorldServiceImpl; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HelloNonServerDemo</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> { BasicConfigurator.configure(); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 日誌 */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Log LOGGER = LogFactory.getLog(HelloNonServerDemo.class); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> SERVER_PORT = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8090</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">startServer</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// log4j日誌,如果您工程裏面沒有加入log4j的支持,請待用system.out</span> HelloNonServerDemo.LOGGER.info(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"HelloWorld TSimpleServer start ...."</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 服務執行控制器(告訴apache thrift,實現了HelloWorldService.Iface接口的是具體的哪一個類)</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// HelloWorldServiceImpl類的代碼,就不在贅述了,無論採用哪種通信模型,它的代碼都不會變化</span> TProcessor tprocessor = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloWorldService.Processor<Iface>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloWorldServiceImpl()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 非阻塞異步通訊模型(服務器端)</span> TNonblockingServerSocket serverTransport = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TNonblockingServerSocket(HelloNonServerDemo.SERVER_PORT); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Selector這個類,是不是很熟悉。</span> serverTransport.registerSelector(Selector.open()); THsHaServer.Args tArgs = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> THsHaServer.Args(serverTransport); tArgs.processor(tprocessor); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 指定消息的封裝格式(採用二進制流封裝)</span> tArgs.protocolFactory(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TBinaryProtocol.Factory()); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 指定處理器的所使用的線程池。</span> tArgs.executorService(Executors.newFixedThreadPool(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>)); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 啓動服務</span> THsHaServer server = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> THsHaServer(tArgs); server.serve(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { HelloNonServerDemo.LOGGER.error(e); } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> args */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) { HelloNonServerDemo server = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloNonServerDemo(); server.startServer(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li></ul>
- 客戶端的非阻塞異步通信代碼:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> testThrift.client; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.commons.logging.Log; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.commons.logging.LogFactory; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.log4j.BasicConfigurator; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.TException; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.async.AsyncMethodCallback; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.async.TAsyncClientManager; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.protocol.TBinaryProtocol; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> org.apache.thrift.transport.TNonblockingSocket; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.HelloWorldService; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.Reponse; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.HelloWorldService.AsyncClient; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.HelloWorldService.AsyncClient.send_call; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> testThrift.iface.Request; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HelloNonClient</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> { BasicConfigurator.configure(); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 日誌 */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Log LOGGER = LogFactory.getLog(HelloNonClient.class); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> Object WAITOBJECT = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Object(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throws</span> Exception { TNonblockingSocket transport = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TNonblockingSocket(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"127.0.0.1"</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8090</span>); TAsyncClientManager clientManager = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TAsyncClientManager(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 準備調用參數(這個testThrift.iface.Request,是我們通過IDL定義,並且生成的)</span> Request request = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Request(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"{\"param\":\"field1\"}"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\\mySerivce\\queryService"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 這是客戶端對非阻塞異步網絡通信方式的支持。</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 注意使用的消息封裝格式,一定要和服務器端使用的一致</span> HelloWorldService.AsyncClient asyncClient = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloWorldService.AsyncClient.Factory(clientManager, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TBinaryProtocol.Factory()).getAsyncClient(transport); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 既然是非阻塞異步模式,所以客戶端一定是通過“事件回調”方式,接收到服務器的響應通知的</span> asyncClient.send(request,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AsyncMethodCallback<AsyncClient.send_call>() { <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 當服務器正確響應了客戶端的請求後,這個事件被觸發 */</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onComplete</span>(send_call call) { Reponse response = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { response = call.getResult(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (TException e) { HelloNonClient.LOGGER.error(e); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } HelloNonClient.LOGGER.info(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"response = "</span> + response); } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 當服務器沒有正確響應了客戶端的請求,或者其中過程中出現了不可控制的情況。 * 那麼這個事件會被觸發 */</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onError</span>(Exception exception) { HelloNonClient.LOGGER.info(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"exception = "</span> + exception); } }); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//這段代碼保證客戶端在得到服務器回覆前,應用程序本身不會終止</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (HelloNonClient.WAITOBJECT) { HelloNonClient.WAITOBJECT.wait(); } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li></ul>
以上代碼是可以直接工作的。讀者可以直接在自己的工程中執行。運行的結果和Apache Thrift上一節中Apache Thrift阻塞模式下的運行結果是一致的,只是運行過程不一樣。目前各種主流的RPC框架基本都支持非阻塞式異步IO網絡通信,如果您有興趣進行這些RPC框架的性能比較,一定要在相同的IO通信模型下進行。
3-3、Aapche Thrift與線程池
在之前的文章(《架構設計:系統間通信(10)——RPC的基本概念》),我們已經提到影響一款RPC框架性能的主要指標。除了RPC框架實現的數據封裝格式、RPC框架支持的網絡通信模型外,還有一個重要的指標就是它如何執行客戶端的請求。
在Apache Thrift中,它使用線程池技術運行具體的接口實現,響應客戶端請求(無論Apahce Thrift使用哪種數據封裝格式、使用哪種網絡通信模型)。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">org<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.apache</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.thrift</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.server</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.THsHaServer</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Args</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.executorService</span>(ExecutorService executorService)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
可以看到,實際上Apache Thrift中設置線程池的方法,所要求的參數類型是java.util.concurrent.ExecutorService接口,也就是說只要實現了ExecutorService接口的類都可以被傳入。一般我們常使用的是java.util.concurrent.ThreadPoolExecutor這個類。
4、下文預告
在本篇文章中,我們詳細描述了Apache Thrift中和性能息息相關的三個要素:數據封裝格式的實現、網絡IO模型的支持 和 處理客戶端請求的方式。正式有這些實現的細節,才使Apache Thrift成爲一款主流的RPC框架。那麼我們在正式生產環境中,應該如何使用RPC框架才科學呢?在下文中,我們將結合RPC的特點和我自己的工作經歷,向各位讀者進行介紹。