編碼與模式------《Designing Data-Intensive Applications》讀書筆記5

来源:https://www.cnblogs.com/happenlee/archive/2018/01/13/8280374.html
-Advertisement-
Play Games

進入到第四章了,本篇主要聊的點是編碼(也就是 序列化 )與代碼升級的一些場景,來梳理存儲之中涉及到的編解碼的流程。目前主流的編解碼便是來自Apache的 Avro ,來自Facebook的 Thrift 與Google的 Protocolbuf ,在本篇之中,我們也會一一梳理各種編碼的優點與痛點。 ...


進入到第四章了,本篇主要聊的點是編碼(也就是序列化)與代碼升級的一些場景,來梳理存儲之中涉及到的編解碼的流程。目前主流的編解碼便是來自Apache的Avro,來自Facebook的Thrift與Google的Protocolbuf,在本篇之中,我們也會一一梳理各種編碼的優點與痛點。

1.非二進位的編碼格式

程式通常以至少兩種不同的表示方式處理數據:

1、在記憶體中,數據是保存在對象、結構、列表、數組、哈希表、樹、等等。這些數據結構在記憶體之中被優化為CPU可以高效訪問和操作的結構(通常這是操作系統的任務,並不需要程式員操心)。

2、而當你想把數據寫入一個文件或者通過網路發送它時,你必須把它編碼成某種形式的位元組序列(例如,一個JSON文檔)。

因此,我們需要兩種形式之間的某種轉換。(記憶體與其他位置)翻譯從記憶體中表示的數據稱之為編碼(也稱為序列化),反之稱為解碼(反序列化)。

通常編碼有如下幾種格式:

  • 特定的語言格式
    許多編程語言都對編碼有內置的支持,用於將記憶體對象編碼成位元組序列。例如:Java的java.io.Serializable , Ruby的Marshal, Python的pickle。但是這些編程語言內置的庫存在一些深層次的問題。
  • 編碼通常與特定的編程語言捆綁在一起,用另一種語言讀取數據是非常困難的
  • 為了在同一對象類型中恢複數據,解碼過程需要能夠實例化任意類,如果攻擊者可以讓您的應用程式解碼任意位元組序列,則它們可以實例化任意類。這常常是安全問題的來源。
  • 效率(用於編碼或解碼的CPU時間,以及編碼結構的大小),java內置編碼庫臭名昭著的就是其糟糕的表現和臃腫的編碼

  • JSON、XML與CSV
    上面這幾種格式,也是我們在編碼之中常見到的。
  • XML的描述十分精準,但是因過於冗長。
  • JSON的流行主要歸功於它在Web瀏覽器中的內置支持(由於它是JavaScript的一個子集)和相對於XML的簡單性。
  • CSV是另一種流行的與語言無關的格式,儘管功能不強。

JSON、XML和CSV都是文本格式,因此都具有一定的可讀性。但他們也有如下一些微妙的問題:

  • 關於數字的編碼有很多歧義。在XML和CSV中,不能區分恰好由數字組成的數字和字元串(除了引用外部模式)。JSON區分字元串和數字,但它不區分整數和浮點數,也不能確認精度。
  • JSON與XML為Unicode字元串的支持,但他們不支持二進位字元串(位元組序列沒有字元編碼)。
  • 對於XML和JSON,都有可選的模式支持。這些模式語言非常強大,因此學習和實現起來相當複雜。而CSV沒有任何模式,因此需要應用程式定義每個行和列的含義。如果應用程式添加了新行或列,則必須手動處理該更新。CSV是一個相當模糊的格式(出於是分隔符的原因)

2.二進位的編碼格式

二進位的編碼格式通常是最緊湊的編碼格式,對於一個小的數據集,編碼大小的收益是微不足道的,但一旦進入百萬兆位元組的數據集,數據格式的選擇就會有很大的影響了。接下來我們來看一個通過JSON描述的數據結構:
使用JSON描述的數據結構

  • MessagPack
    我們來看看通過MessagePack進行二進位編碼之後的JSON格式:
    通過MessagePack進行編碼後的二進位格式
    二進位編碼長度為66個位元組,這僅比81位元組的文本JSON編碼小了一點。通過這樣的空間減少便喪失了可讀性的保障,我們來看看有木有更優秀的解決方式。
  • Thrift
    在Thrift中的數據進行編碼,需要預先在Thrift介面定義語言(IDL)中描述這樣的模式:
    通過IDL描述Thrift的數據格式
    在Thrift之中存在兩種不同的二進位編碼格式,一種是直接使用二進位編碼的Binary格式,另一種則是使用壓縮之後的Compact格式,我們來一一看兩者的區別。

Binary格式
Binary格式編碼之後為59個位元組大小,並且每個欄位都有一個類型註釋(用於指示它是字元串、整數、列表等),併在需要時指定長度指示(字元串的長度、列表中項的數量)。但是和MessagePack相比就省去了欄位名等信息,取而代之的是欄位標記(1,2和3),這些是出現在模式定義中的數字。欄位標記類似於欄位別名,它們是一種簡潔的方式來描述我們所談論的欄位,而不必拼寫欄位名稱。從而減少了二進位編碼的大小。

Compact格式
Compact格式它包含相同的信息只有34個位元組。它通過將欄位類型和標記號打包成一個位元組,並使用可變長度整數來實現這一點。它不是為1337號使用八個完整的位元組,而是用兩個位元組編碼,每個位元組的最高位用來指示是否還有更多的位元組要來。這意味著64到63之間的數字用一個位元組編碼,8192到8191之間的數字用兩個位元組編碼,較大的數字使用更多位元組。

  • ProtocolBuf
    Protocolbuf(只有一個二進位編碼格式)相同的數據編碼如下圖所示。它位包裝略有不同,但Thrift的Compact格式大同小異。Protobuf以33位元組匹配相同的記錄。
    ProtocolBuf的編碼格式

  • Avro
    Avro是一個二進位編碼格式,它是發源於開源項目Hadoop,來作為Thrift的替換方案存在的,我們來看看通過Avro編碼之後的記錄,又是怎麼樣的呢?
    Avro的編碼格式
    在Avro模式之中沒有標記號。將同樣的數據進行編碼,Avro二進位編碼是32個位元組長,是上述編碼之中最緊湊的。檢查上述的位元組序列,並沒有標識欄位或數據類型。編碼簡單地由連接在一起的值組成。在解析二進位數據時,通過使用模式來確定每個欄位的數據類型。這意味著如果讀取數據的代碼與寫入數據的代碼使用完全相同的模式,二進位數據才能被正確地解碼。

3.模式升級與演化

隨著應用程式的開發,模式不可避免地需要隨著時間而改變。而在這個過程之中,二進位編碼同時保持向後和向前相容性呢?

  • 欄位標記
  • 從示例中可以看到,編碼的記錄只是編碼欄位的串聯。每個欄位由標簽號碼和註釋的數據類型識別(如字元串或整數)。如果沒有設置欄位值,則只需從已編碼的記錄中省略該欄位值。因此欄位標記對編碼數據的含義至關重要。我們可以更改模式中欄位的名稱,因為編碼的數據從不引用欄位名稱,但不能更改欄位的標記,因為這將使所有現有編碼數據無效。
  • 可以通過添加一個新的標記號的方式向模式添加新欄位。如果舊代碼(不知道您添加的新標記號)試圖讀取由新代碼編寫的數據,包括一個新欄位,該欄位的標記號不識別,它可以簡單地忽略該欄位。數據類型註釋允許分析器來確定需要跳過多少位元組。因為每個欄位都有唯一的標記號,新代碼可以無縫連接舊的數據,因為標記號仍然具有相同的含義。但是,如果是添加了一個新欄位,則不能使它成為必需欄位。如果要添加一個欄位並使其成為必需的欄位,那麼如果新代碼讀取舊代碼編寫的數據,則該檢查將失敗,因為舊代碼將不會寫入您添加的新欄位。因此,為了保持向後相容性,在初始部署模式之後添加的每個欄位必須是可選的或具有預設值。
  • 刪除欄位就像添加欄位一樣,這意味著只能刪除一個可選的欄位(必填欄位不能被刪除),而且您不能再次使用相同的標記號(因為您可能還有一個包含舊標記號的數據,該欄位必須被新代碼忽略)。

  • 數據類型
    如何改變欄位的數據類型?例如,將32位整數轉換為64位整數。新代碼可以很容易地讀取舊代碼編寫的數據,因為解析器可以用零填充任何丟失的位。但是,如果舊代碼讀取由新代碼編寫的數據,舊代碼仍然使用32位變數來保存值。如果解碼的64位值不適合32位,會被截斷。
    Protocolbuf並沒有一個列表或數組的數據類型,而是有一個重覆的標記欄位。可以將可選的(單值)欄位轉換為重覆的(多值)欄位。讀取舊數據的新代碼看到一個具有零個或一個元素的列表(取決於欄位是否存在);讀取新數據的舊代碼只看到列表的最後一個元素。而Thrift有一個專門的列表數據類型,這是參數列表中的數據類型。這不允許像Protocolbuf那樣從單值到多值的升級,但它具有支持嵌套列表的優點。

  • 動態生成模式
    Avro最大的特點是支持了動態生成模式,它的核心思想是編碼者與解碼者的模式可以不同,事實上他們只需要相容就可以了。相比於Protocolbuf和Thrift,它並不包含任何標簽數字。每當資料庫模式發生變化時,管理員必須手動更新從資料庫列名到欄位標記的映射。而Avro是每次運行時簡單地進行模式轉換。任何讀取新數據文件的程式都會感知到記錄的欄位發生了變化。

4.小結

編碼的細節不僅影響到工作效率,更重要的是會影響到應用程式和軟體的架構。Prorotocol Buf,Thrift 與 Avro,都使用一個模式來描述一個二進位編碼格式。它們的模式語言比XML模式或JSON模式要簡單得多,它支持更詳細的驗證規則,並且能夠更好的進行模式的演化升級,在性能上也有了更好的提升。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JavaScript加法運算符用加號(+)表示。 代碼實例如下: 在處理特殊值時,加法也有一些特殊行為: (1).某個運算數是NaN,那麼結果為NaN。 (2).-Infinity加-Infinity,結果為-Infinity。 (3).Infinity加-Infinity,結果為NaN。 (4). ...
  • 此選擇器能夠匹配緊跟在E元素之後的元素F。 語法結構: 瀏覽器支持: (1).IE瀏覽器支持此選擇符。 (2).edge瀏覽器支持此選擇符。 (3).谷歌瀏覽器支持此選擇符。 (4).火狐瀏覽器支持此選擇符。 (5).opera瀏覽器支持此選擇符。 (6).safria瀏覽器支持此選擇符。 註意:I ...
  • 居中是我們在css中經常遇到的問題,一般有水平居中、垂直居中、垂直水平居中這3種情況,那麼今天首先就來對學習到的水平居中的方法做個總結筆記。 css水平居中 text-align:center 為了看得更清楚,我們舉一個例子,如圖,我們將div2放入div1中,現在,如果我們想讓文字在div2中水平 ...
  • HTTP首部解析 轉載請註明出處: "HTTP首部解析" 文章目錄 1.與HTTP協議相關的Web伺服器 2.HTTP首部 與HTTP協議相關的Web伺服器 在說明HTTP首部相關知識之前,有必要先瞭解一下與HTTP協作的Web伺服器。 用一臺主機實現多個功能變數名稱 HTTP/1.1規範明確提出,允許一臺 ...
  • 舉個例子,我想在項目中引用Iconfont裡面的圖標,怎麼辦 首先第一步,註冊賬號登入官網, 到如下界面 第二步,新建一個項目 第三步 上面記住,font-family這個改成你自己想要定義字體規則名稱 然後,你會有像下麵一樣的空項目 接著你在右上角搜索你要的圖標並且加到‘暫存車’ 看到上面,圖標就 ...
  • 13、語句 概念:就是分號(;) 代表一條語句的結束 習慣:一行只編寫一條語句;一行編寫多條語句(代碼可讀性較差) 語句塊:可以包含多條語句 "{ }"將多條語句包裹 u 條件語句 * if 語句 * if...else 語句 * else if 語句 * switch...case 語句 if 語 ...
  • 9、數據類型 概念:表示當前存儲的數據的分類(表示數字 - 整數和小數) u 原始類型(原始值) 【typeof運算符:判斷變數的原始類型】 *number(數字):表示數字 var num1 = 10.123; console.log(num1); * NaN(不是一個數字): 全稱為 Not a ...
  • table元素 table元素 table元素 table元素 table元素 table元素 table元素 table元素 table用來創建表格,表格也可以用來佈局,但是嵌套過於複雜,不利於靈活佈局,已經幾乎沒人用它來佈局了。 表格基本上有如下幾個標簽構成: (1)<table>標簽用來創建表 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...