FlatBuffers使用小結

一柒微笑發表於2021-01-18

  最近做一個Android APP,由於離線業務需求,需要在啟動APP時候同步大量資料到APP上,遇到了JSON效能瓶頸。從下方的圖片中可以看出,當使用 json 傳輸資料,在解析json的時候會產生大量的物件,使得記憶體瘋狂飆升,不論是配置低端的平板還是配置比較高階的手機都會 GC 。而在使用 flatbuffers 的時候不論是平板還是手機,都沒有 GC,並且在時間是數量級的差別。0.5s與0.05s的差距對你而言或許並不大,但是1s和10s的差距就很明顯了噻,應該沒人能忍受一個app的反應時間需要10s之久吧...

  下面是我測試的引數與測試結果,對比提升可以說是相當的明顯了。注(這裡的解析時間是指:從發起請求到響應後把資料解析成物件的時間,也就是說除去相差不多的網路傳輸時間,單純的對資料的解析時間 faltbuffers 提升會更加明顯 )

 

什麼是 FlatBuffers ?

  FlatBuffers是一個高效的跨平臺序列化庫,適用於C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, Rust 和Swift。它們最早由谷歌創立,用來開發遊戲和其他一些需要高效能的程式。

為什麼使用 FlatBuffers 會這麼快?

  無需解析/拆包即可訪問序列化資料-FlatBuffers的與眾不同之處在於,它在平坦的二進位制緩衝區中表示層次結構資料,使得無需解析/拆包就可以直接訪問它,同時還支援資料結構的演進(forward /向後相容)

如何使用 FlatBuffers ?

1.編譯器下載地址:https://github.com/google/flatbuffers/releases

2.編寫Schema檔案 demo.fbs

namespace com.zxz.demo.flatbuffer;

table User {
id : long;
name : string;
gender : string;
departmentId : long;
createTime : string;
enabled : bool;
status : string;
}

table Account {
id : long;
userId : long;
login : string;
password : string;
loginCount : int;
}


table Data {
userList : [User];
accountList : [Account];
}

root_type Data;

3.生成javaBean檔案:flatc.exe --java demo.fbs

4.下載 FlatBuffers 原始碼:  https://github.com/google/flatbuffers/tree/master/java,或者看看maven倉庫有沒有依賴包引入專案

5.服務端建立資料

public void service() throws Exception {
    HttpServletResponse response = ActionContext.get().getResponse();
    // 1.建立builder
    FlatBufferBuilder builder = new FlatBufferBuilder(1024);
    List<Integer> list1 = new ArrayList<Integer>();
    for (int i = 0; i < 10; i++) {
        long id = 0L;
        int nameOffset = builder.createString("name");
        int genderOffset = builder.createString("gender");
        long departmentId = 0L;
        int createTimeOffset = builder.createString("2021-01-10");
        boolean enabled = true;
        int statusOffset = builder.createString("status");
        // 2.建立User物件返回 offset值
        int createUser = User.createUser(builder, id, nameOffset, genderOffset, departmentId,
                createTimeOffset, enabled, statusOffset);
        list1.add(createUser);
    }
    // 3.把儲存物件offset值的集合轉成陣列
    int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();
    // 4.構建User的資料
    int createUsersVector = Data.createUsersVector(builder, arr1);
    // 5.構建Data物件(Data中包含[User])
    Data.startData(builder);
    // 6.新增User的集合
    Data.addUsers(builder, createUsersVector);
    int offset = Data.endData(builder);
    Data.finishDataBuffer(builder, offset);
    // 7.把DataBuffer寫入到IO中
    ServletOutputStream os = response.getOutputStream();
    os.write(builder.dataBuffer().array(), builder.dataBuffer().position(), builder.offset());
    os.close();
}

6.客戶端接收資料

public void onResponse(Call call, Response response) throws IOException {
   byte[] bytes = response.body().bytes(); ByteBuffer bb = ByteBuffer.wrap(bytes); Data data = Data.getRootAsData(bb); }

 

 

==================================END==================================

==============================測試結果截圖===============================

圖一、平板上使用 json 傳輸資料

圖二、手機上使用 json 傳輸資料

圖三、平板上使用 flatbuffers 傳輸資料

 圖四、手機上使用 flatbuffers 傳輸資料

相關文章