[英]Why does protocol buffer performance worse than JSON in my case?
我正在 protocol buffers 和 json 之間進行測試,但我發現 protocol buffers 的性能超出了我的預期。 我想知道我的 http 請求是否太復雜或協議緩沖區不適合我的情況。 這是我的 http 請求:
{
"LogId": "ABC165416515166165484165164132",
"ci_came": "uvInYKaMbhcyBm4p",
"ci_cme": "GWPMzgSwKzEZ5Mmz",
"ci_me": "gqHVRaSDTeksgijHM18QzajcVh21bBAq0TkknIXBQnkGKAPQbsZG35cDG6usAxwoxxiey9AnKbsN",
"ci_pi": "U6dpu0828Q0NNP5JRgVvCMgnn41poxfPlzhwU6FdBOrFsujzskD0HKTcQAXBcXgaOuYcckGtZDs9roJsK",
"th_logic": "IUPPORTxr_17_iIT_yiIS=[LthyOy.gitg.warmh;@6icy855 vxrsionCorx=1 uiyRr=msm8953 uiOTLOyrxR=unknown uPx=ujij Ir=N2G47H TIMx=1541178617000 iRyNr=gitrI TyG=iuilr HyRrWyRx=qyum jijIyL=1743iC101955 SUPPORTxr_yiIS=[Lhug.hxng.warmh;@5ic26y CPU_yiI=yrm17-v8y IS_rxiUGGyiLx=fylsx RyrIO=unknown MyNUFyCTURxR=gitrI IS_xMULyTOR=fylsx SUPPORTxr_32_iIT_yiIS=[Lhug.gitg.warmh;@xr9170c TyGS=txst-kxys CPU_yiI2= UNKNOWN=unknown PxRMISSIONS_RxVIxW_RxQUIRxr=fylsx Ujij=iuilrxr FINGxRPRINT=firxtruck/msm8953_17/msm8953_17:7.1.2/N2G47H/iuilrx11081144:ujij/txst-kxys HltT=gitriXM-iuilrxr-03 vxrsionNymx=1.0 PROrUCT=yxCR C10 rISPLyY=N2G47H txst-kxys MOrxL=yxCR C10 rxVICx=yxCR C10 hug.gitg.yrithmxticxxcxption: rivirx iy hxro yt yum.upspacepyy.fycxpyy.yummxnt.vixw.SxttingItxmFrygmxnt.onClick(SxttingItxmFrygmxnt.hug:117) yt ynrroir.vixw.Vixw.pxrformClick(Vixw.hug:5637) yt ynrroir.vixw.Vixw$PxrformClick.run(Vixw.hug:22433) yt ynrroir.lt.Hynrlxr.hynrlxCylliyck(Hynrlxr.hug:751) yt ynrroir.lt.Hynrlxr.rispytchMxssygx(Hynrlxr.hug:95)rimrgrilsTiiUxpXiHxXoOxX8kRituil",
"th_ideal": "TqpXdC5NQF",
"th_sth": "YTVMYUSuprQzHaQLgRdvxp0g8nLWdEZBc0UfrcyrQv09CKPBuacEesMfoiXqXHP2G2Duvmnzmv20iBBQKCuAk1piKvS9MvR9ymxD5YYahyBsdoWetqKjAuTBS115rqwDGhe2qDWMcRnZF3QF9f4WF5sJsFlmxroZzprR",
"th_err": "StGMzqIW1YGg44GC",
"th_code": "zrhwEaVmVlNPTUZCCO0j62bFjL6Sjnb8JxNng645fQOMlxA5ceKOwH67aYkK0FnM3vKMpXAbdLwCWAyVUjuvcH1",
"th_req": "ZWZXPUr6O4jYrXjLXlXskem7jHQ6D",
"th_index": "6546546546",
"th_log": "3Gt8V7LMxUMlvHPzcVUYCQl8zvwaDfDEzWn7GxOHbzf9quoZFTl2WwFRpMox2V8zfjbOQiIg4dxjf0x1vWGKHhvnmabXCO5jDWVE33TgI0YTJO14uYEnezdzYDoeR51",
"th_order": "T28XGCx1O3LCGa98lAtWc33",
"message": "Crash",
"time": "2019-11-11 18:23:00",
"ci_vi": "RCgdDu5874sJohjEVy7i72Kcp98rCOJvl",
"t_mNo": "1.9",
"t_tNo": "Gxk9Vb3zblp2PHpYTQzTXmzx43WaEtZmA3CWFfXtPsDZFgaAIug5mbX73w4wQvwNL65BEOW3fd7wExndzm3eilp4jODtHZQaV5G574FPfK",
"t_fd": "k58xs1eYKTvDxbRMWfPJMdB6tfBnGaOLAnmDUZxo2URebvtd8F",
"t_pd": "jWl7CTWdmgVFZxA",
"t_oer": "HHoLyXNYxKHqZgpev9vi",
"t_ar": "J6m4X9ATlADGaKUzi1eb",
"t_sr": "daP",
"t_sd": "AgXPBAaOrA95b9PM4196BQaLsVN9j9",
"t_sn": "1Ai4lFVObo0MymeJ894m0jItjiwhcD",
"t_dd": "zLuh1p1G",
"timeS": "2019-11-11 18:22:58"
}
這是我的原型文件:
message Scada {
TechInfo tInfo = 1;
string time = 2;
string message = 3;
Thought thought = 4;
}
message TechInfo {
string mNo = 1;
string tNo = 2;
string fd = 3;
string pd = 4;
string oer = 5;
string ar = 6;
Ci cd = 7;
string sr = 8;
string sd = 9;
string sn = 10;
string dd = 11;
}
message Ci{
string pi = 1;
string vi = 2;
string me = 3;
string cme = 4;
string came = 5;
}
message Thought{
string logic = 1;
string ideal = 2;
string sth = 3;
string err = 4;
string code = 5;
string req = 6;
string index = 7;
string log = 8;
string order = 9;
}
我使用協議緩沖區 parseFrom() 方法反序列化請求:
public static Scada pbDeSerialize(byte[] pbBytes) throws InvalidProtocolBufferException {
Scada scada = ScadaObj.Scada.parseFrom(pbBytes);
return scada;
}
我使用 json 工具反序列化請求:
public static PbScadaJsonObj jsonDeserialize(byte[] jsonBytes) {
String str = new String(jsonBytes, utf8Charset);
return JsonUtil.deserialize(str, PbScadaJsonObj.class);
}
public static <T> T deserialize(String json, Class<T> clazz) {
return JSON.parseObject(json, clazz);
}
我用jmeter來測試這兩種方法。 測試由一個線程和100個線程組成。 一條請求消息大約3KB。 Json ProtoBuf(PB)反序列化消息在 1024MB 堆大小中進行了測試。 在每次執行之前,我總是添加一個隨機數以使消息彼此不同。 我的機器是2C4G。
+---------------------+----------+------+
| 100k loops 1 thread | FastJson | PB |
+---------------------+----------+------+
| TIME(s) | 360 | 309 |
+---------------------+----------+------+
| CPU(%) | 104 | 99.8 |
+---------------------+----------+------+
| MEM(%) | 7.2 | 6.6 |
+---------------------+----------+------+
+------------+----------+-------+
| 100threads | FastJson | PB |
+------------+----------+-------+
| TPS(/s) | 274.3 | 321.9 |
+------------+----------+-------+
| CPU(%) | 185.8 | 168.6 |
+------------+----------+-------+
| MEM(%) | 9.1 | 28.6 |
+------------+----------+-------+
從測試中,我無法判斷協議緩沖區的改進,它消耗了更多的 memory,而 TPS 僅增加了 50/s。有人可以為我解釋一下嗎? 或者有人做過像這個測試這樣的東西嗎?
這種比較是不公平的。 您的 Protobuf 定義是嵌套的,而您的 JSON 定義是扁平的。 如果你想做一個公平的比較,讓你的 JSON 嵌套或讓 Protobuf 扁平化:
使 JSON 嵌套:
{
"tInfo" : {"mNo" : "xxxx", "tNo" : "xxxx", "other" : "fields"},
"time" : "2019-11-11 18:23:00",
"message" : "Crash",
"thought" : {"logic" : "xxx", "other" : "fields"}
}
每種序列化機制都有優點和缺點。 從 memory 我會說它看起來大致是這樣的:
序列化:便宜 (+) / 昂貴 (-) | 協議緩沖區 | JSON |
---|---|---|
原語(數字/布爾/枚舉) | + |
- |
原始字節 | + |
- |
跳過內容 | + |
- |
嵌套消息 | - |
+ |
字符串 | - |
+ |
Protobuf 將字符串和嵌套消息編碼為長度分隔數據,因此每個字符串都以字符串長度(以字節為單位)作為前綴。 這是一個深思熟慮的選擇,在解析時有好處(例如,惰性解析字符串和高效跳過),但它確實增加了序列化的成本。 實現可能需要預先計算長度並有效地將字符串轉換為字節兩次。 JSON使用了起始字符和結束字符,所以它可以直接將stream放入一個output緩沖區中。 使用緩存時差異會變小,但 Protobuf 總是必須比 JSON 做更多的工作來編碼字符串。
鑒於您的原型僅包含字符串和嵌套消息,我不希望純粹通過切換到 Protobuf 獲得很多性能提升。 它可能會在字段標識符上獲得一些速度,但是您的字段名稱已經縮短到人類幾乎無法閱讀的程度。
另一方面,您的幾個字符串看起來像數字和 base64 編碼數據。 將它們切換為 Protobuf 的primitive
類型和bytes
類型會更有效率,並且應該提供顯着的良好加速。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.