分佈式基礎-序列化性能對比

序列化理解

序列化就是將java對象轉化爲字節文件;反序列化就是將字節文件轉化爲java對象。

比如我們用到Entity都是需要實現序列化接口的。java平臺允許我們在內存中創建一些可服用的對象(例如Entity),也即是在一個JVM進程中允許創建可複用對象。如果在同一個JVM進程中(可以理解爲架構?),如果需要用此對象,直接傳遞該對象的引用就可以了。如果需要將對象保存到磁盤,需要序列化後,從內存保存到磁盤。

但是對於分佈式架構,就相當於多個JVM進程在通信,這時候如果需要對象從一個進程傳到另一個進程,並且可以讀取出來,然後使用,這是不同的內存空間,怎麼辦?這時候就需要用到序列化技術,實現的手段是通過Object流,傳輸的時候,將對象序列化爲二進制流,然後通過網絡傳輸,接收端進程接收到序列化後的字節文件,經過反序列,轉換成對象使用。

序列化技術

現在主流的序列化技術包括:JSON、Hessian、xml、protobuf、kryo、MsgPack、FST、thrift、protostuff、Avro等。

除FST、kryo默認只支持java外,其他序列化技術都是跨語言的。Java序列化機制Serialize接口也是隻支持java語言。

性能對比

分佈式應用系統中,系統之間的通訊質量決定了系統的可用性。在傳輸數據的過程中,數據包越小,時間越少,效率就越高。數據包越小,佔用的寬帶就越少,同等條件下資源利用就會越小。

接下來會對比jackson、FastJson、protobuf、hessian之間的性能。
1、相比json-lib框架,Jackson所依賴的jar包較少,簡單易用並且性能也要相對高些。而且Jackson社區相對比較活躍,更新速度也比較快。
2、Fastjson是一個Java語言編寫的高性能的JSON處理器,由阿里巴巴公司開發。無依賴,不需要例外額外的jar,能夠直接跑在JDK上。
3、protobuf是谷歌出的一款開源項目,序列化文件會經過壓縮,減小存儲空間,從而提高傳輸效率,另外使用了緩衝,可以提高性能
4、hessian序列化的字節文件偏大,會佔用太多存儲空間。

引入四種方式用到的jar包

<!--json實現序列化-谷歌-->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.13</version>
        </dependency>
        <!--fastjson實現序列化-阿里-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
        <!--protobuf實現序列化-谷歌-阿里提供的包jprotobuf-->
        <dependency>
            <groupId>com.baidu</groupId>
            <artifactId>jprotobuf</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!--hessian實現序列化-->
        <dependency>
            <groupId>com.caucho</groupId>
            <artifactId>hessian</artifactId>
            <version>4.0.51</version>
        </dependency>

創建Person對象

public class Person implements Serializable {

    private static final long serialVersionUID = -4015446837465554319L;

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

Jackson實現序列化

public class JsonTest {

    //初始化
    private static Person init(){
        Person person = new Person();
        person.setName("Lv");
        person.setAge(18);
        return person;
    }

    public static void main(String[] args) throws IOException {
        excuteWithJson();
    }

    /**
     * Json實現序列化,驗證效率和總大小
     *
     * TODO 結果如下:
     * Json序列化:67ms:總大小:22
     * Json反序列化:Person{name='Lv', age=18, height=2}
     * @throws IOException
     */
    private static void excuteWithJson() throws IOException {
        Person person = init();

        //jackson包裏的序列化工具
        ObjectMapper mapper = new ObjectMapper();
        byte[] bytes = null;
        Long start = System.currentTimeMillis();
        //循環序列化100次,統計最後的總時間
        for (int i= 0; i<100; i++){
            bytes = mapper.writeValueAsBytes(person);
        }

        System.out.println("Json序列化:" + (System.currentTimeMillis() - start) + "ms:" + "總大小:" + bytes.length);

        //反序列化
        Person person1 = mapper.readValue(bytes, Person.class);
        System.out.println("Json反序列化:" +person1);
    }
    }

結果如下:
在這裏插入圖片描述

FastJson實現序列化

public class JsonTest {

    //初始化
    private static Person init(){
        Person person = new Person();
        person.setName("Lv");
        person.setAge(18);
        return person;
    }

    public static void main(String[] args) throws IOException {
        excuteWithJson();
        excuteWithFastJson();
        excuteWithHessian();
    }

    /**
     * FastJson實現序列化,驗證效率和總大小
     *
     * TODO 結果如下:
     * FastJson序列化:132ms:總大小:22
     * FastJson反序列化:Person{name='Lv', age=18, height=2}
     * @throws IOException
     */
    private static void excuteWithFastJson() throws IOException {
        Person person = init();


        String text = null;
        Long start = System.currentTimeMillis();
        //循環序列化100次,統計最後的總時間
        for (int i= 0; i<100; i++){
            text = JSON.toJSONString(person);
        }

        System.out.println("FastJson序列化:" + (System.currentTimeMillis() - start) + "ms:" + "總大小:" + text.getBytes().length);

        //反序列化
        Person person1 = JSON.parseObject(text,Person.class);
        System.out.println("FastJson反序列化:" +person1);
    }

結果如下:
在這裏插入圖片描述

Hessian實現序列化

public class JsonTest {

    //初始化
    private static Person init(){
        Person person = new Person();
        person.setName("Lv");
        person.setAge(18);
        return person;
    }

    public static void main(String[] args) throws IOException {
        excuteWithJson();
        excuteWithFastJson();
        excuteWithHessian();
    }

    /**
     * FastJson實現序列化,驗證效率和總大小
     *
     * TODO 結果如下:
     * Hessian序列化:3ms:總大小:63
     * Hessian反序列化:Person{name='Lv', age=18, height=2}
     * 效率最高,但是佔用空間最大
     * @throws IOException
     */
    private static void excuteWithHessian() throws IOException {
        Person person = init();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        HessianOutput ho = new HessianOutput(os);

        Long start = System.currentTimeMillis();
        //循環序列化100次,統計最後的總時間,Hessian是累加的,所以需要讀取第一次的大小
        for (int i= 0; i<100; i++){
            ho.writeObject(person);
            if(i==0){
                System.out.println(os.toByteArray().length);
            }
        }

        System.out.println("Hessian序列化:" + (System.currentTimeMillis() - start) + "ms:" + "總大小:" + os.toByteArray().length);

        //反序列化
        HessianInput hi = new HessianInput(new ByteArrayInputStream(os.toByteArray()));
        Person person1 = (Person) hi.readObject();
        System.out.println("Hessian反序列化:" +person1);
    }
}

結果如下
在這裏插入圖片描述

Protobuf實現序列化
Protobuf使用比較麻煩,實體字段需要使用@Protobuf註解

@Protobuf(fieldType = FieldType.STRING)
    private String name;

    @Protobuf(fieldType = FieldType.INT32)
    private int age;
public class ProtobufTest {
    //初始化
    private static Person init(){
        Person person = new Person();
        person.setName("Lv");
        person.setAge(18);
        return person;
    }

    public static void main(String[] args) throws IOException {
        excuteWithProtobuf();
    }

    /**
     * Protobuf實現序列化,驗證效率和總大小
     *
     * TODO 結果如下:
     * Protobuf序列化:10ms:總大小:6
     * Protobuf反序列化:Person{name='Lv', age=18}
     * 效率高,佔用空間小
     * @throws IOException
     */
    private static void excuteWithProtobuf() throws IOException {
        Person person = init();

        Codec<Person> personCodec = ProtobufProxy.create(Person.class,false);

        byte[] bytes = null;
        Long start = System.currentTimeMillis();
        //循環序列化100次,統計最後的總時間
        for (int i= 0; i<100; i++){
            bytes = personCodec.encode(person);
        }

        System.out.println("Protobuf序列化:" + (System.currentTimeMillis() - start) + "ms:" + "總大小:" + bytes.length);

        //反序列化
        Person person1 = personCodec.decode(bytes);
        System.out.println("Protobuf反序列化:" +person1);
    }
}

結果如下
在這裏插入圖片描述

對比

Json序列化:65ms:總大小:22
Json反序列化:Person{name='Lv', age=18, height=2}

FastJson序列化:143ms:總大小:22
FastJson反序列化:Person{name='Lv', age=18, height=2}

Hessian序列化:2ms:總大小:63
Hessian反序列化:Person{name='Lv', age=18, height=2}

Protobuf序列化:11ms:總大小:6
Protobuf反序列化:Person{name='Lv', age=18}

由以上結果可知:
文件大小:Protobuf最小,傳輸寬帶方法佔有優勢;Hessian最大。
時間:Hessian和Protobuf都小。
總體來講,json是我們常用的,也是最流行的,而Protobuf是後起之秀,性能更好,但是Protobuf的操作比較麻煩。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章