Phprpc, 是一個聲稱在某些情境下, 效能比hessian還要高的協議.
下面url是
javaeye
andot
寫的兩個協議的效能測試報告:
http://www.javaeye.com/topic/333720
看到這個報告是有點激動的, 那麼它到底在實現上有何高明之處呢?
在這篇文章裡, 我會給大家簡單闡述一下, 為什麼phprpc在某些情境下, 效能會優於hessian.
首先, 序列化的本意是, 將不同類型的對象轉換成統一的位元組流, 便於儲存和傳輸.
Java在早期1.1版時, 就引入 Serializable 介面, 來支援java對象的序列化(通過ObjectInput/OutputStream寫入讀取).
但由於實現上過於通用和複雜, 導致其效能下降得比較厲害.
Hessian的效率高,
主要體現在針對不同類型的轉換邏輯上, 做了大量最佳化(比如數組, 綜合物件, 日期類型等)和協議更輕量級..
那要比hessian效能還高, 要麼就是轉換邏輯, 比hessian更簡單, 要麼就是協議更精簡, 代碼最佳化的更好.
當然猜測是沒有用的, 下面, 是我讀了源碼後, 對比得到的結論:
1, 拋棄OO設計帶來的效能提升.
Hessian:
不同類型的序列化/還原序列化都實現了Serializer和Deserializer介面, 然後由 SerializerFactory 根據不同類型(Class)來建立不同的
Serializer / Deserializer.
內部實現上, 也做了大量的OO抽象設計.這樣做的好處就不用多說了.
上一張hessian序列化實現的類圖(部分):
Phprpc:
一個類裡實現所有的序列化邏輯, 通過大量的ifelse來做不同類型的判斷, 然後通過私人方法來對冗長的轉換邏輯做抽象.
結論:
PHPRPC執行個體化對象的機會比較少(new對象開銷很大),
且代碼結構上設計相對精簡, 所以, 效能對比hessian有大幅提升.
2, cache重複對象帶來的效能提升.
比如 String[] str = {“aa”, “bb”,
“aa”}; 可以看到 “aa” 字串出現了兩次.
cache重複對象,
唯寫入對象的位置引用. 比如上面的例子裡, 只往位元組流裡, 寫入了 “aa”和“bb”兩個串, 第二個”aa”換成寫入位置引用, 還原序列化時, 第二個”aa”是直接引用的第一個”aa”.
Hessian:
在hessian裡, byte, char數組及基礎類型是不做cache的, 其他類型都做cache.
Phprpc:
對 byte, char數組也做了cache, 其他跟hessian一樣.
Phprpc Cache重複對象的實現:
開闢一塊單獨的cache(序列化結束時, cache會被收回), 用來儲存對象的hashcode與對象的關係, 接下來每個對象做序列化前, 會根據自身的hashcode到cache裡看看是否已存在, 如果存在, 唯寫入該對象的位置引用, 否則, 寫入對象.
結論:
Phprpc測試報告裡,
“2000次對10000個元素的位元組數組”為什麼比hessian快, 原因之一就是因為自身對byte數組也做了cache.
總的來說phprpc在這點上比hessian應該有少量提升.
總結
1, 通過最佳化代碼後的phprpc, 確實在某些情境下,
效能要略微高於hessian.
2, Phprpc在某些情境下, 效能不一定好於hessian.
比如特殊類型最佳化, 像
Class, Javabean, Calendar, Enumeration, InputStream,
Iterator, Locale, SqlDate等.
這些對象都是有特殊含義的, 如果不做特殊處理, 像phprpc那樣, 直接把這些對象內部無用的field結構都做序列化,
反而效能會更差.
3, phprpc的社區現在沒hessian成熟,
所以我的觀點是優選hessian, 除非你的系統要追求極致, 那個時候, 才考慮phprpc.
PS: 參考phprpc和hessian,
然後實現Externalizable介面, 可以自己實現某些對象的序列化, 不過有侵入性.