• java.io.OptionalDataException的问题


    java.io.OptionalDataException
    Java的对象传输是在一个keepalive连接上传输的,就是说建立一个网络连接后可以传输很多很多的对象实例。
    譬如:A跟B通讯,A端write对象a,write对象b,write对象c;B端就要read对象a,read对象b,read对象c。
    但是B端面对的是源源不断的数据,怎么才能区分出a和b的分界点呢,这个就是应用协议要解决的问题了。通用的解决方法是在write a前用一个商定的协议头,在协议头里描述数据的长度,通过这个长度来进行数据的定界。如果在write协议头的时候,序列化的a对象被修改了,那协议头的标识的长度和正式长度就不一致了,这样导致了a对象的部分数据会被read b的时候当作协议头,这样这个连接管道原来有序的数据分界就乱了,只有重置这个连接才能恢复。怎样才能重置这个连接呢,重启是最简单的办法了,重启连接的任何一端都可以。
    什么情况下会出现“如果在write协议头的时候,序列化的a对象被修改”的情况呢,在并发环境下,一个线程在进行write对象a,另外一个线程在修改对象a就会导致这种情况。这种情况一般是因为应用使用非线程安全的类,譬如:HashMap,并且应用自身并发控制不严引起的。
    定位问题的办法:
    修改JDK 的library里的ObjectInputStream类,当出现StreamCorruptedException时把Stream里的前4K字节写到console ouput中。可以通过这个方法找到第一次破坏协议的序列化的内容,以这个序列化的内容作为线索找出应用问题发生的地方。在出现问题的系统上加上这个补丁。这个补丁需要使用-Xbootclasspath来设置,影响JVM boot ClassLoader.

    Bug之java.io.OptionalDataException

    产生背景:
    在线上的生产环境中,登录时有一个将用户的访问权限写入redis缓存的逻辑,以便后面访问接口时候,快速验证用户是否具有权限。写入的时候,没有报错提示。但是取出来的时候,偶发性的会报Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.OptionalDataException。
    分析:
    写入是没有问题的,可以从redis里面看到确实写入的数据,但是数据是加密的,看不出来具体是什么。首先,还是看看java.io.OptionalDataException这个类的介绍。
    /**
     * Exception indicating the failure of an object read operation due to
     * unread primitive data, or the end of data belonging to a serialized
     * object in the stream.  This exception may be thrown in two cases:
     *
     * <ul>
     *   <li>An attempt was made to read an object when the next element in the
     *       stream is primitive data.  In this case, the OptionalDataException's
     *       length field is set to the number of bytes of primitive data
     *       immediately readable from the stream, and the eof field is set to
     *       false.
     *
     *   <li>An attempt was made to read past the end of data consumable by a
     *       class-defined readObject or readExternal method.  In this case, the
     *       OptionalDataException's eof field is set to true, and the length field
     *       is set to 0.
     * </ul>
     *
     * @author  unascribed
     * @since   JDK1.1
     */
    123456789101112131415161718192021
    从类介绍看出的是,读取数据出现问题,有两个可能的原因,一个是读操作读取未读的原始数据,另一个是在流中的最后一个数据是序列化的对象。这两句话也看不出什么问题。网上查了一下有说要数据处理要同步。 无奈下,将存入的逻辑仔细debug好几十遍,出现这个错误的时候,存入的对象的序列化ID都是显示表明的,所以排除序列化ID不同造成的。最后,看存入的数据时,发现数据的数目总是变动,外部条件完全一致,获取的数据量总是不同,跟进去看到。使用了parallelStream,然后foreach,将元素加入到一个非线程安全的集合HashSet中,所以数据量一直变动。

  • 相关阅读:
    springMVC+freemarker中Could not resolve view with name... 问题解决
    mybatis中if test 语句 当参数类型为string时,如何写判断条件
    博科交换机升级FOS系统
    response.redirect 和Server.Transfer 的区别
    win7 安装MyGeneration版本,没有安装mdac的解决办法
    Zen Cart的sidebox机制
    ASPCMS相册 实现每张图片对应一段文字
    ZEN CART 系统想在首页调用 新闻插件 的 新闻列表的方法
    JS获得来源页
    zen cart去掉zenid的简单方法
  • 原文地址:https://www.cnblogs.com/jiangyouchen/p/14866098.html
Copyright © 2020-2023  润新知