Hessian 序列化的軟肋

來源:互聯網
上載者:User

Hessian最早是用於Java的二進位的Web服務,官方 定義:

 

The Hessian binary web service protocol makes web services usable without requiring a large framework, and without learning yet another alphabet soup of protocols. Because it is a binary protocol, it is well-suited to sending binary data without any need to extend the protocol with attachments.

 

後來被廣泛用於其它的編譯語言象Python,C++,C#,PHP,Ruby,Erlang等。

 

其實Hessian除了用於Web方法調用外,還有一個常用的功能就是跨語言的序列化。正是有了高效、緊湊的序列化,Hessian才廣為流傳。

 

Hessian序列化協議不管是1.0.2規範 還是2.0草案 都是十分完善的,但其中最大的問題就是關於字串(或者XML,在Hessian裡XML的序列化基本與字串一樣)的序列化。

下面是Hessian字串序列化的定義:

 

1.0:

string ::= (s b16 b8 utf-8-data)* S b16 b8 utf-8-data

2.0:

# UTF-8 encoded character string split into 64k chunksstring     ::= x52 b1 b0 <utf8-data> string  # non-final chunk           ::= 'S' b1 b0 <utf8-data>         # string of length                                             #  0-65535           ::= [x00-x1f] <utf8-data>         # string of length                                             #  0-31           ::= [x30-x34] <utf8-data>         # string of length                                             #  0-1023
我們看到,不管是1.0還是2.0,字串都是“分段”傳輸的。二個版本不同之處在於2.0隻是針對0-31長度和0-1023長度的短字串作了
特殊最佳化。
所謂“分段”就是單個字串的最大長度不能大於65536(2 ^ 16),如果大於這個長度就要按65536進行分段。
舉個例子,假設有個字串長度為65537,那麼Hessian序列化大致為:
s xFF xFF <UTF8-DATA> S x00 x01 <UTF8-DATA>
第一個小寫s表示是字串的分段中的一段,大寫的S表示是最後一段。在S的後面就是2個位元組的長度,注意這裡不是整段位元組的長度,
而是字串的長度!接下來就是UTF8編碼的字串。
照理說,按這個定義不會出現多大問題,為字元國際化以及長、短字串都作了相關的最佳化處理。
但事實上,當字串很大時(為何會很大?想想如果輸出一個很大的XML結果集(2M以上)),這種方案的時間會耗費大量的資源,極為低效。
(1)字元編碼問題。
Hessian字串採用了對英文友好的UTF8編碼,是為減少傳輸的大小。但UTF8是多位元組編碼,且不說對於非英文字元,它增加了傳輸的開銷,
重要的是採用UTF8編碼和解碼必須進行逐位元組的低效率的掃描。當字元多時,這個會成為整個序列化的瓶頸。
從效率的角度來講,個人覺得Hessian採用UTF16最好。UTF8雖然小了一點,處理的開銷可不只是大了一點點。

(2)分段問題。
分段帶來傳輸的一點效能優勢和分開檢驗的好處,但拆分和組合一個巨大的尤其是必須按位元組掃描的字串時,這個帶來了很大的開銷。
(3)字元長度問題。(重點)
Hessian儲存了每個字元段的字元的個數,但沒有儲存整個段位元組的長度。這樣在還原序列化時,只能逐位元組掃描,沒有辦法進行讀取最佳化。逐位元組的驗證UTF8和讀取UTF8字串,在C++、C#或者Java這樣高效率的語言來講,本身不是太大問題,但對於PHP、Python或者Ruby、Erlang等非Unicode的低效能語言來說,就是要命的事情了。
作一簡單測試,當PHP解析Hession 3M的字串(XML),耗時竟然超過30秒,30M得半小時了!而C#都不超過1秒!
看來,想要讓PHP等語言快點,除了標明標明字串的字元個數外還必須標明實際位元組大小,儘管這樣破壞了標準:
string ::= (s b16 b8 C16 C8 utf-8-data)* S b16 b8 C16 C8 utf-8-data
C16和C8就是實際字串在該段的位元組數。有了這個這個標記,PHP等語言就可高效處理Hessian大字串了,30M 1秒鐘!
如果你有更好的辦法,請不吝指教!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.