当前位置: 首页 > 工具软件 > S2 Protocol > 使用案例 >

快来手写RPC S2 序列化探究

狄承望
2023-12-01

SOA

面向服务的架构(SOA)是伴随着互联网快速发展产生的 一种系统架构方法。而面向服务是一种设计范式,用于创建解决方案的逻辑单元,这些逻辑单元可组合、可复用,以支持实现面向服务计算的特定战略目标和收益。
(感觉实际上就是微服务
由于拆分了很多小的服务模块,模块之间的通信就特别重要,单纯的信息传递可以用MQ,而复杂方法调用则必须要健壮的RPC支持。
在实际生产中,我们不可能再像上一课中那样,仅凭借“线下互相问服务名方法名”的方式来运行我们的RPC功能,我们必须要有完成的系统来保证服务健康。其中至少要有以下部分:

  1. 服务注册中心
  2. 服务提供方及相关的心跳检测机制
  3. 更加严格的消费方调用、传参、异常处理机制
  4. 限流策略
  5. 轮询策略等等

则相应的,整体服务流程则应该是:

  • 服务提供端启动服务,将服务提供者信息注册到服务注册中心,服务提供者信息 一般包括服务主机地址、端口、服务接口信息等。
  • 服务消费端将服务提供者信息从服务注册中心获取到本地缓存,同时将服务消费
    者信息上报到服务注册中心。
  • 服务消费端根据某种软负载策略选择某一个服务提供者发起服务调用,服务调用 首先采用某种数据序列化方案,将调用数据序列化为可以在网络传输的字节数组,采用某种NIO框架(如 Netty、 Mina、 Grizzy)完成调用。
  • 服务治理(健康监测、限流降级、轮询等等)

序列化与反序列化

让我们从最基本的概念开始。

序列化

序列化( Serialization)是将对象的状态信息转换为可存储或传输的形式过程 。 简言之,把对象转换为字节序列的过程称为对象的序列化。

反序列化

反序列化( Deserialization)是序列化的逆过程。将字节数组反序列化为对象,把字节序列恢复为对象的过程称为对象的反序列化。

sd的必要性

  1. 使得不共享内存通过网络连接的系统之间能够能够进行对象的传输。
  2. 保证传输内容不失真

序列化须知

  • 序列化时,只对对象的状态进行保存,而不管对象的方法。
  • 当一个父类实现序列化,子类自动实现序列化,不需要显式实现 Serializable接口。
  • 叫一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列 化。
  • 当某个字段被声明为transient后,默认序列化机制就会忽略该字段。
  • 对于上述己被声明为transient的宇段,可以在类中添加私有方法writeObject()与readObject()两个方法来进行序列化 。

常见序列化方案

模仿Java的原生序列化


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @Desc
 **/
public class MineSerializer {

    public <T> byte[] serialize(T obj) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(obj);
            objectOutputStream.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return byteArrayOutputStream.toByteArray();
    }

    @SuppressWarnings("unchecked")
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

XML和JSON序列化

JSON序列化使用阿里的fastjson,google的gson均可,不多介绍。这里介绍XML序列化:

<dependencies>
        <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.19</version>
    </dependency>

</dependencies>

代码:


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

import java.nio.charset.StandardCharsets;

/**
 * @Desc
 **/
public class MineXmlSerialize {

    private static final XStream X_STREAM =new XStream(new DomDriver()) ;

    public <T> byte[] serialize(T obj) {
        return X_STREAM.toXML(obj).getBytes(StandardCharsets.UTF_8);
    }

    @SuppressWarnings("unchecked")
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        String xml = new String(data);
        return (T) X_STREAM.fromXML(xml);
    }
}

Hessian序列化

是一个跨语言的二进制序列化协议,性能强且易用,最主要是跨语言。

<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->
<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>4.0.66</version>
</dependency>

代码:


import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

/**
 * @Desc
 **/
public class MineHessianSerialize {

    public byte[] serialize(Object obj) {
        if (obj == null) {
            throw new NullPointerException();
        }
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            HessianOutput ho = new HessianOutput(os);
            ho.writeObject(obj);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T deserialize(byte[] data, Class<T> clazz) {
        if (data == null) {
            throw new NullPointerException();
        }
        try {
            ByteArrayInputStream is = new ByteArrayInputStream(data);
            HessianInput hi = new HessianInput(is);
            return (T) hi.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Thrift序列化

伴随RPC框架的配套序列化。
XML文件:

<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libfb303</artifactId>
    <version>0.9.3</version>
</dependency>
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.9.3</version>
</dependency>

代码


import org.apache.thrift.TBase;
import org.apache.thrift.TDeserializer;
import org.apache.thrift.TSerializer;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;

/**
 * @Desc
 **/
public class MineThriftSerialize {

    public <T> byte[] serialize(T obj) {
        try {
            if (!(obj instanceof TBase)) {
                throw new UnsupportedOperationException("not support");
            }
            TSerializer serializer = new TSerializer(new Factory());
            return serializer.serialize((TBase) obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public <T> T deserialize(byte[] data, Class<T> clazz) {
        try {
            if (!TBase.class.isAssignableFrom(clazz)) {
                throw new UnsupportedOperationException("not support");
            }
            TBase o = (TBase) clazz.newInstance();
            TDeserializer tDeserializer = new TDeserializer(new TBinaryProtocol.Factory());
            tDeserializer.deserialize(o, data);
            return (T) o;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

其他

还有谷歌的protobuf,不过用起来很麻烦基本没有大项目用

序列化方案选择

  1. 性能标尺(二进制的基本比xml和json快)
  2. 易用标尺(好不好学)
  3. 跨语言/平台标尺(比如go-nodejs-java-python架构)
  4. 长期支持性(母公司倒闭了…)
 类似资料: