Hessian 序列化的软肋

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 chunks
string     ::= 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秒钟!
如果你有更好的办法,请不吝指教!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值