使用 Protocol Buffers 代替 JSON 的五個原因
在Ruby和Rails開發者中,面向服務(Service-Oriented)架構有一個當之無愧的名聲,它是一個緩解程式規模惡性增長的一個強有力的途徑,可在大量應用程式中提取關注點。這些新生小巧的服務通常繼續使用Rails或Sinatra,並使用JSON在HTTP上通訊。儘管JSON作為一個資料相互交換格式,有很多優點:人類可讀、可理解,並通常表現出色。
瀏覽器和JS並不直接處理資料--尤其是遇到內部服務時。我的觀點是,結構化格式,例如谷歌的Protocol Buffers,是一個比JSON在編碼方面更好的選擇。如果你從來沒有使用過Protocol Buffers,你可以參看 這裡。不要擔心,在說明為什麼要選擇Protocol Buffers而不是JSON之前,本文會簡介如何使用在Ruby上使用它 。
Protocal Buffers的簡短介紹
首先,什麼是Protocol Buffers?文件中說:
“Protocol Buffers是一種以有效並可擴充套件的格式編碼結構化資料的方式。”
Google開發了Protocol Buffers使用於內部的服務。 它是一種二進位制格式允許你使用規範的語言定義一個模式,例如:
message Person { required int32 id = 1; required string name = 2; optional string email = 3; }
你能在名稱空間中封裝他們或者用上面的方式在頂層宣告他們。這個片段定義了Person資料型別的模式,有三個欄位:id, name和email。除了命名欄位,你能提供一個型別決定資料怎樣編碼和線上上傳送,在上面我們看到有int32型別和string型別。還提供了關鍵字進行驗證和結構化(required 和optional )。欄位被編號,這有助於向後相容,我將在以後詳細的介紹。
Protocol Buffers規範已被多種語言實現:Java,C,Go等。如果你四處找找最現代的語言都有實現的方式。Ruby也不例外,有幾個不同的Gems使用Protocol Buffers編碼和解碼資料。這就意味著,這個規範可以在不同語言實現的系統間傳遞資料。
例如,Ruby Gem安裝被稱為ruby-protoc的二進位制可以和主Protocol Buffers庫組合使用(在OSX中brew install protobuf),自動的產生樁類檔案用於編碼和解碼資料。正在執行的二進位制proto檔案產生以下的Ruby類:
#!/usr/bin/env ruby # Generated by the protocol buffer compiler. DO NOT EDIT! require 'protocol_buffers' # forward declarations class Person < ::ProtocolBuffers::Message; end class Person < ::ProtocolBuffers::Message set_fully_qualified_name "Person" required :int32, :id, 1 required :string, :name, 2 optional :string, :email, 3 end
正如你所見,通過支援這種模式(Protocol Buffer格式),用來編碼和解碼資訊,我們就能自動得到一個類(檢視程式碼ProtocolBuffers::Message的基類在Gem中有更多細節的介紹)。我們已經看到了一些資訊,那麼就讓我們再來仔細看看這些特徵點,讓我嘗試說服你考慮Protocol Buffers——這裡有5個理由。
原因 #1: 模式本身很不錯
有一種痛苦的諷刺指向一個事實,我們小心謹慎地在我們的資料庫裡面編寫資料模型,維護各個層次的程式碼,保持這些資料模型處於控制之中,當我們想要傳送資料連線到另一個服務的時候,要求所有的疑慮都要被考慮到。然而,我們往往依靠的是在邊界上與我們的系統之間不一致的程式碼,我們的系統不能強制結構化我們的資料元件,這是如此的重要,編碼的語義是你曾經的業務物件,在proto格式中,它足以幫助並保證應用程式之間的訊號不會丟失,而界限就在你所建立並執行的業務規則。
原因 #2: 無償地向後相容
被編號的欄位在proto的定義中排除了所需的版本檢查,這是其中一個被明確表述的動機(為什麼這樣設計和實現Protocol Buffers)。如同開發者文件中宣告的那樣,協議被設計成能在一定程度上避免出現像下面這樣的“醜陋的程式碼”,下面的程式碼用來檢測協議的版本:
if (version == 3) { ... } else if (version > 4) { if (version == 5) { ... } ... }
同編號欄位一樣, 你必須改變編碼習慣,朝著能向老版本維護和向後相容的方向改變。正如在文件中的宣告那樣,曾經 Protocol Buffers 是這樣被介紹的:
“新的欄位可以很容易被引入,並且不需要中間服務去檢查資料就能被解析,通過資料不必知道所有的欄位。”
已經部署各種JSON的伺服器已經遭受各種與發展模式以及向後相容的相關問題。我現在深信編號欄位能防止錯誤,並且能在新功能和服務的推出上做到簡化。
原因 #3: 更少的樣本程式碼
除了顯式的版本檢查和缺乏後續的相容性,JSON終端在HTTP上的基礎服務通常依賴專門的手寫樣板程式碼去處理Ruby物件的編碼和解碼。解析和反解析類常常包含隱藏的業務邏輯,它暴露了手動解析每個新的資料型別的缺陷,當一個類通過Protocol Buffers產生(你一般就不會再去觸碰它),它能提供大量相似的方法,還避免了大量頭痛的事情。隨著模式的發展,你將會用proto產生類(應當承認,一旦你更新他們),你可以把更多的空間留給你所關注的挑戰(保持你的應用執行和持續構建產品)。
原因 #4: 驗證和可擴充套件性
required,optional 和 repeated關鍵字在Protocol Buffers中的定義是非常強大的。它們允許你去編碼,在模式級別,形象化你的資料結構和去實現類怎樣工作(每種程式語言處理)的細節。Ruby的protocol_buffers庫將會提升異常,例如:如果一個物件例項沒有填寫必填的欄位,你試著去對這樣一個物件例項編碼,就會提升異常。通過簡單地編輯一個新的編號欄位的值,你可以把一個欄位從required變成optional或者反之亦然。有了這種靈活編碼的語義序列化格式,大大增強了其功能。
因為你還可以嵌入proto,定義內部的其他成員,你也可以擁有通用的Request和Response結構,它還允許其他資料結構的傳輸並確保傳輸連線上,它為伺服器間通訊實現真正的靈活性和安全的資料傳輸提供了機會。類似Riak的資料庫系統使用Protocol Buffers有巨大的效果——因為有了一些啟示,我建議重新審視那些介面。
原因#5:建議的語言互操作性
因為Protocol Buffers已經被多種語言實現,在你的架構中多語言混合的應用程式之間的互操作性變得更簡單。如果你引入了一個新的服務在JAVA或者GO中,甚至和用Node或者Clojure或者Scala實現的後端通訊,你只需簡單的把proto檔案交給目標語言編寫的程式碼生成器,你將在這些架構之間獲得較好的安全和互操作性。平臺特定資料型別的細節被目標語言處理,你將更多的關注你的問題的困難部分,而不是匹配欄位和資料型別在JSON的編碼和解碼方案中。
什麼時候更適合使用JSON?
有些時候JSON比Protocol Buffers更適合,包括如下的場景:
-
你需要或者想讓資料對人是可讀的
-
來自於服務的資料是直接傳送到web瀏覽器
-
你的服務端應用程式是用javaScript編寫的
-
你不準備把資料模型繫結到模式上
-
你沒有頻寬新增另外一個工具到你的軍火庫
-
執行不同型別的網路服務的運營負擔過大
可能還有更多的情況。最後,總之,這是很重要的在心裡權衡和不要盲目的選擇一項技術
結論
Protocol Buffers提供了幾種相對JSON在內部服務之間線上傳輸資料的引人注目的優勢。並沒有完全的替換JSON,特別是服務和web瀏覽器直接通訊的情況,Protocol Buffers提供了真正的優勢不僅在上面概述的方法,也編解碼的速度和資料大小上有更多的優勢。
你可以從你的應用程式中提取出哪些服務?如果你今天不得不做出選擇,你會選擇JSON還是Protocol Buffers?讓我們討論討論-我們願意在下面的評論中聽到更多關於你在使用JSON和Protocol Buffers上的經驗。
原文地址:http://blog.codeclimate.com/blog/2014/06/05/choose-protocol-buffers/
相關文章
- Protocol Buffers 在 iOS 中的使用ProtocoliOS
- Protocol Buffers 系列 (1) - 什麼是Protocol Buffers?Protocol
- 還在用JSON? Google Protocol Buffers 更快更小 (原理篇)JSONGoProtocol
- 還在用JSON? Google Protocol Buffers 更快更小 (實踐篇)JSONGoProtocol
- Protocol Buffers 3 學習Protocol
- Protocol Buffers學習(1):定義一個訊息Protocol
- Protocol Buffers 學習(5):在 rpc 中使用 protobufProtocolRPC
- 使用流式計算引擎 eKuiper 處理 Protocol Buffers 資料UIProtocol
- Python 在Python中使用Protocol Buffers基礎介紹PythonProtocol
- Protocol Buffers學習(4):更多訊息型別Protocol型別
- 如何在 PHP 中處理 Protocol Buffers 資料PHPProtocol
- Wire:基於安卓的谷歌的Protocol Buffers的開源實現安卓谷歌Protocol
- 谷歌將在 Kotlin 中支援 Protocol Buffers 資料格式谷歌KotlinProtocol
- 第19篇 Protocol Buffers 編譯器生成proto檔案Protocol編譯
- C#語言下使用gRPC、protobuf(Google Protocol Buffers)實現檔案傳輸C#RPCGoProtocol
- 是時候該瞭解一波Protocol Buffers了[Java]ProtocolJava
- Protocol Buffers 學習(6):檔案 | 欄位選項介紹Protocol
- iPhone使用者不願意用安卓手機的五個原因iPhone安卓
- 是時候該瞭解一波Protocol Buffers了[Android]ProtocolAndroid
- [譯] Flutter — 五個你會愛上它的原因Flutter
- 專案管理計劃必不可少的五個原因專案管理
- 網站轉化率不高的五個常見原因網站
- 如何編譯C#版本的Protocol Buffers與gRPC服務端,客戶端程式碼編譯C#ProtocolRPC服務端客戶端
- Protocol Buffer 使用指北Protocol
- 【elasticsearch】bulk api奇特的json格式的原因ElasticsearchAPIJSON
- Google Protocol Buffer 的使用和原理GoProtocol
- 使用 "switch(ture)" 代替大量if
- 使用 "switch(true)" 代替大量if
- iOS中使用Protocol BufferiOSProtocol
- 幽默:使用CSS中!important的原因只有一個CSSImport
- 從五個方面解析多媒體展廳受歡迎的原因
- TP 框架解析 JSON 失敗原因框架JSON
- Vue 使用預渲染代替 SSRVue
- SpringCloud使用Sentinel 代替 HystrixSpringGCCloud
- 使用go指令碼代替makefileGo指令碼
- Laravel 5.4 使用 pluck () 代替 lists ()Laravel
- 使用RxJava代替EventBus類庫RxJava
- protocol buffer 安裝與使用Protocol