`
javatar
  • 浏览: 1705039 次
  • 性别: Icon_minigender_1
  • 来自: 杭州699号
社区版块
存档分类
最新评论

Hessian序列化不设SerializerFactory性能问题

阅读更多
转于自己在公司的Blog:
http://pt.alibaba-inc.com/wp/experience_1089/hessian-set-serializerfactory-performance.html

服务框架全面重构后,因换了通讯协议,采用Magic头识别新旧版本,
性能测试发现,在兼容旧版本模式下,性能下降10倍,
原来一个1ms到2ms的请求,现在需要11ms到12ms,
对比新旧版本代码,发现四个不同点:
(1) UnsafeByteArrayOutputStream是不是比ByteArrayOutputStream慢很多?
(2) 通过java.nio.ByteBuffer转换到mina的ByteBuffer映射写入慢很多?
(3) 重复使用一个ByteArrayOutputStream是不是比多个ByteArrayOutputStream慢很多?
(4) 没有设置SerializerFactory会比设置了慢很多?
逐个验证,前面三个对性能几乎没有影响,修改第四个,性能立马提升。
旧版本代码:
private static final SerializerFactory _serializerFactory = new SerializerFactory();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
Hessian2Output h2out = new Hessian2Output(bout);
h2out.setSerializerFactory(_serializerFactory); // 问题所在
h2out.writeObject(msg);
h2out.flush();
byte[] content = bout.toByteArray();

新版本代码:
UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);
Hessian2Output h2o = new Hessian2Output(bos);
h2o.writeObject(connReq);
h2o.flush();
byte[] content = bos.toByteArray();

新代码没有调用h2o.setSerializerFactory(serializerFactory);
就因为这一句,性能下降10倍。
我们来看一下Hessian3.2.1的源代码:
  public void writeObject(Object object)
    throws IOException
  {
    if (object == null) {
      writeNull();
      return;
    }

    Serializer serializer;

    serializer = findSerializerFactory().getSerializer(object.getClass());

    serializer.writeObject(object, this);
  }

  public final SerializerFactory findSerializerFactory()
  {
    SerializerFactory factory = _serializerFactory;

    if (factory == null)
      _serializerFactory = factory = new SerializerFactory();

    return factory;
  }

看代码,在writeObject()时,如果发现没有设置SerializerFactory,会自动设一个SerializerFactory,
看起来好像没有问题,我们自己设的SerializerFactory也是直接new出来的,没做什么手脚,
那为什么性能会下降这么快呢?开始还真被这行代码唬住了,看起来没啥区别,
仔细一想,才发现,Hessian2Output对象是prototype的,
每次请求,都会创建一个实例,用完即销毁,这样的话,基于下面的方式:
if (factory == null)
      _serializerFactory = factory = new SerializerFactory(); // 问题所在

每一个Hessian2Output内部都会重新new SerializerFactory();
应改为:
private static final SerializerFactory DEFAULT_SERIALIZER_FACTORY =new SerializerFactory();
if (factory == null)
      _serializerFactory = factory = DEFAULT_SERIALIZER_FACTORY;

从这里可以看出是创建SerializerFactory的开销非常大,导致性能下降严重,
这个应该算是Hessian的BUG,这种线程安全的工厂类,就不应该在设默认值时,每次都new一个。
大家用Hessian的时候请小心这个问题。
后续还发现,不设置SerializerFactory,会出现大量线程被阻塞:
(下图为VisualVM截图,红色标识的片断为Blocked状态)

  • 大小: 47.9 KB
分享到:
评论
3 楼 chozee 2015-10-09  
真正影响性能的是如下代码而不是new Factory,因为new的Factory需要重新缓存Serializer,请指教。
public Serializer getSerializer(Class cl)
    throws HessianProtocolException
  {
    Serializer serializer;

    serializer = (Serializer) _staticSerializerMap.get(cl);
    if (serializer != null)
      return serializer;

    if (_cachedSerializerMap != null) {
      synchronized (_cachedSerializerMap) {
	serializer = (Serializer) _cachedSerializerMap.get(cl);
      }
      
      if (serializer != null)
	return serializer;
    }

    for (int i = 0;
	 serializer == null && _factories != null && i < _factories.size();
	 i++) {
      AbstractSerializerFactory factory;

      factory = (AbstractSerializerFactory) _factories.get(i);

      serializer = factory.getSerializer(cl);
    }

    if (serializer != null) {
    }

    else if (JavaSerializer.getWriteReplace(cl) != null)
      serializer = new JavaSerializer(cl, _loader);

    else if (HessianRemoteObject.class.isAssignableFrom(cl))
      serializer = new RemoteSerializer();

//    else if (BurlapRemoteObject.class.isAssignableFrom(cl))
//      serializer = new RemoteSerializer();

    else if (Map.class.isAssignableFrom(cl)) {
      if (_mapSerializer == null)
	_mapSerializer = new MapSerializer();
      
      serializer = _mapSerializer;
    }
    else if (Collection.class.isAssignableFrom(cl)) {
      if (_collectionSerializer == null) {
	_collectionSerializer = new CollectionSerializer();
      }

      serializer = _collectionSerializer;
    }

    else if (cl.isArray())
      serializer = new ArraySerializer();

    else if (Throwable.class.isAssignableFrom(cl))
      serializer = new ThrowableSerializer(cl, getClassLoader());

    else if (InputStream.class.isAssignableFrom(cl))
      serializer = new InputStreamSerializer();

    else if (Iterator.class.isAssignableFrom(cl))
      serializer = IteratorSerializer.create();

    else if (Enumeration.class.isAssignableFrom(cl))
      serializer = EnumerationSerializer.create();
    
    else if (Calendar.class.isAssignableFrom(cl))
      serializer = CalendarSerializer.create();
    
    else if (Locale.class.isAssignableFrom(cl))
      serializer = LocaleSerializer.create();
    
    else if (Enum.class.isAssignableFrom(cl))
      serializer = new EnumSerializer(cl);

    if (serializer == null)
      serializer = getDefaultSerializer(cl);

    if (_cachedSerializerMap == null)
      _cachedSerializerMap = new HashMap(8);

    synchronized (_cachedSerializerMap) {
      _cachedSerializerMap.put(cl, serializer);
    }

    return serializer;
  }
2 楼 czltx224 2013-01-24  
...能具体说明在哪个类里面吗?这样我找不到,另外你说的新版和旧版具体指的是哪个版本?
1 楼 may_cauc 2011-02-14  
楼主看代码很细啊。

我发现hessian文档极度匮乏,社区也不行。我现在整合seam和hessian,来回协议不一致,已经开始读源代码好几天了,也没啥头绪。

相关推荐

    hessian学习基础篇——序列化和反序列化

    这对于优化自定义序列化逻辑或者解决Hessian使用中遇到的问题非常有帮助。 总结起来,Hessian是一种高效、轻量级的二进制序列化协议,特别适合于跨语言的网络通信。理解并掌握Hessian的基本概念和使用方法,能够...

    hessian序列化规范

    3. **轻量级**:Hessian不需要XML的繁琐结构,简化了序列化和反序列化的实现,降低了内存和CPU的使用。 4. **自描述性**:虽然Hessian不是完全的自描述协议,但通过一定的编码规则,接收方可以根据字节流解析出数据...

    Hessian 的字段序列化小记

    虽然默认不序列化private字段,但可以通过注解或配置来指定需要序列化的私有字段。 - 在处理字段时,Hessian会检查字段是否为空。如果字段值为null,它会发送一个特殊的标记来表示,从而避免不必要的网络流量。 3....

    S25-hessian反序列化1

    在使用Hessian时,需要注意其安全问题,因为不正确的序列化处理可能导致潜在的安全风险,例如远程代码执行(RCE)漏洞。因此,在实际开发中,应确保了解并正确使用Hessian,以防止潜在的安全隐患。

    浅谈Java序列化和hessian序列化的差异

    同时,Hessian序列化也存在一定的不一致性,例如遇到通过Collections.synchronizedMap得到的map时。 应用场景 那么,在什么情况下应该使用Java序列化,而什么情况下应该使用Hessian序列化?如果你需要序列化复杂...

    Hessian 2.0序列化协议规范.docx

    《Hessian 2.0序列化协议规范》 在分布式计算和网络通信中,数据的序列化和反序列化是至关重要的环节。Hessian 2.0是一种高效的二进制序列化协议,它旨在减少网络传输的数据量,提高数据交换的效率。本文将详细介绍...

    Nacos JRaft Hessian 反序列化 RCE 分析.pdf

    这一安全问题的核心在于 Nacos JRaft 在处理来自客户端的特定构造的数据时未能正确地验证或过滤这些数据,从而允许攻击者通过发送恶意构造的 Hessian 数据包来触发反序列化操作,进而执行任意代码。 #### 三、漏洞...

    removal RCE、Hessian 反序列化、Yaml反序列化、密码解密、部分常用敏感路径(漏洞更新截止2024.9.12)

    removal RCE、Hessian 反序列化、Yaml反序列化、密码解密、部分常用敏感路径(漏洞更新截止2024.9.12)

    Spring中集成Hessian的问题

    在Spring框架中集成Hessian是为了实现远程方法调用(Remote Method Invocation, RMI),这是一种轻量级的序列化协议,可以高效地传输Java对象。Hessian使得服务提供者和服务消费者之间能够通过网络进行快速的数据...

    Hessian

    2. **简单类型支持**:Hessian支持基本的Java数据类型,如整型、浮点型、字符串、日期等,并且可以序列化和反序列化复杂对象。 3. **流式传输**:Hessian协议允许数据分块传输,这意味着服务端可以立即响应部分结果...

    Hessian应用

    这样,客户端通过网络发送一个Hessian序列化的请求,服务端接收后反序列化为本地对象,然后执行相应的操作,再序列化结果返回给客户端。 在实际应用中,Hessian主要应用于以下场景: 1. **分布式服务调用**:通过...

    hessian4.0.7结合spring2.5.6的bug

    2. **序列化/反序列化问题**:Hessian基于二进制序列化,如果Spring中的bean或者数据模型在序列化过程中出现问题,可能导致服务调用失败或者数据解析错误。例如,自定义类型的序列化没有正确实现,或者某些字段在反...

    34_dubbo都支持哪些通信协议以及序列化协议?.zip

    4. **Hessian2**:基于二进制的轻量级协议,它将Java对象序列化成字节流,适用于对性能有较高要求且不关心跨语言性的场景。 5. **Protobuf-Netty**:Google的Protocol Buffers结合Netty实现的通信协议,具有高效率...

    Hessian 学习 例子 实例

    在IT行业中,Hessian是一种二进制序列化协议,它被广泛用于远程方法调用(RMI)和Web服务中,以提高数据传输效率。Hessian由Caucho Technology开发,其目标是提供轻量级、高效的通信方式,特别是在网络带宽有限的...

    dubbo-hessian协议http请求demo(java)

    - 在实际开发中,我们可能会需要编写一些辅助工具类来处理Hessian的相关操作,例如Hessian2Input和Hessian2Output,它们用于读写Hessian序列化的二进制流。 6. **安全性与优化**: - 虽然Hessian协议效率高,但其...

    Hessian多个版本打包下载

    这包括设置服务器端和客户端的Hessian服务,定义服务接口,处理序列化和反序列化的过程,以及调试可能出现的问题。在进行版本升级时,要注意兼容性问题,确保旧版本的服务仍能正常工作,同时充分利用新版本带来的...

    dubbo-hessian-lite

    Alibaba 的 Dubbo 是一个高性能、轻量级的 RPC 框架,而 Hessian-lite 是 Dubbo 在网络通信中使用的序列化技术之一。了解这些知识点对于深入理解和使用 Dubbo 服务是至关重要的。通过手动处理依赖,开发者可以在各种...

    hessian-4.0.38.jar

    java hessian-3.0.38.jar。修改了原生的jar包,解决了hessian 序列化BigDecimal的精度问题。注意,请在hessian服务端和客户端中分别替换此jar包哦!! 只替换服务端hessian jar包还是会有问题。

    Hessian学习简单demo

    Hessian的目标是提供一种快速、简洁的数据序列化和远程方法调用(RPC)机制。在这个简单的demo中,我们将探讨Hessian的核心概念,以及如何在实际应用中使用它。 首先,我们需要理解什么是数据序列化。数据序列化是...

Global site tag (gtag.js) - Google Analytics