Mode of Dataflow 和 Encoding and Evolution 結論

本文為 Design Data Intensive Applications 的書摘 + 個人心得。

聊聊資料有哪幾種方式能讓它從某個 process 流到另一個 process (data flow),是誰 encoding 或 decoding 資料的?先來列一下常見的幾種方式:

  • 通過資料庫 (database)
  • 通過服務呼叫 (service call)
  • 通過非同步訊息傳遞 (asynchronous message passing)

通過資料庫的 dataflow

在資料庫中,有個 process 可能負責寫入資料 (encoding),另個 process 可能負責讀取資料 (decoding),也有可能是在同一個 process 作業,所以讀取者 (reader) 可以很輕易的用最後版本的 schema 來讀取資料,這裡可以想像成 寄一封訊息給未來的你,所以向後兼容在這裡是必要的,否則未來的你不認識你在寫什麼東西,

至於向前兼容呢?通常資料庫同時會有多個 process 在存取,某個 process 可能來自不同的應用程式或服務,而應用程式會改變,這就代表有些 process 是被取新版本的程式存取,有些 process 是被舊版本的程式存取,也就是會有舊版本的程式會讀取到新版本程式寫的資料,所以向前兼容也是必要。

另外還有一個要留意的點是,在 應用程式這個等級下 (application level) ,舊程式可能會回寫整筆資料,導致新程式寫的資料缺失,如下圖說明,理想狀態是新程式寫的新欄位,舊程式在回寫資料時不會動到新欄位,解決這個問題不難,但你要知道你的程式可能會發生這種情況。

figure_4-7

通過服務呼叫的 Data Flow: Rest and RPC

當你需要讓資料在網路上傳遞時,通常會把角色分為 clientserver ,server 揭露 API,而 client 向這些 API 發 request,這些 server 也可稱為 service (服務) ;client 有很多種,瀏覽器、原生 app、AJAX、server 都可視為 client,server 做為 client 端可以是向資料庫發送需求,或者向另一個 service 發送 request,這種建置系統的方式也被稱 microservice architecture (微服務架構)

微服務架構的關鍵想法讓整個應用系統更易於改變和維運,因為每個 service 都能獨立給一個團隊負責,而每個 service 都能自己部署和更有進化性。

Web services

當你是用 HTTP 當做 service 的協定,我們稱為 web services,web 不只能讓網站使用,舉例來說:

  1. 在 user 的裝置裡執行的 client 應用程式 (原生 app 或 AJAX),透過 HTTP 發 request 給 services。
  2. 組織內部的 microservice。
  3. 不同組織間的 service 溝通,通常用在資料交換或者後端程式 (信用卡授權 service、OAuth service 等等)

這裡有 2 種流行的方法來做 web services,REST 和 SOAP,

REST 不是一個協定,而是一個基於 HTTP 原則的設計哲學,它強調簡單的資料格式,使用 URLs 來識別資源和使用 HTTP 有的功能來做 cache 控制、授權和內容類型協商 (GET, POST, UPDATE etc..), REST 原則來設計的 API 稱為 RESTful API。

SOAP 是一個以 XML-based 協定來產生網路用的 API request,雖然它是用在 HTTP 上,但它的目標是獨立於 HTTP (不用 HTTP 有的功能),然後用一堆協定、功能來讓 web services 變的更複雜。

RPC (remote procedure calls)

RPC 一個最大的賣點是讓你在程式中當 local function 呼叫的方式來使用,但這本質上就是有缺陷的,因為最終還是透過網路來 call service,古老的 RPC 有 Enterprise JavaBeans (EJB)、 Java 用的 Remote Method Invocation (RMI)、Microsoft 用的 The Distributed Component Object Model (DCOM) 和很複雜的 The Common Object Request Broker Architecture (CORBA) ,這些都很難做到向前與向後兼容。

所幸現在我們有許多好用的新選擇,這些 RPC 框架知道遠端 request 跟 local function 呼叫是不一樣的,它們會用我們前幾天講的那些 encoding 方式,例如 Thrift 和 Avro 都支援 RPC、gRPC 是使用 Protocl Buffers、Finagle 也用 Thrift、Rest.li 透過 HTTP 使用 JSON。

這些框架提供 service discovery (服務發現) 來讓 client 知道哪些 IP 跟 PORT 是可呼叫的;雖然 RPC + binary encoding 的效能會比 JSON + REST 好,但 RESTful API 有個很大的優勢是比較好做實驗和 debug,但想怎麼用還是看個人啦!

我們公司就把內部所有 microservices 間的溝通都改成 gRPC。

通過非同步訊息傳遞的 Data Flow

最後要來介紹 asynchronous message-passing (非同步訊息傳遞) 系統,它的特性介於 RPC 和資料庫之間,client 的 request (通常稱為 message ) 會低延遲的傳遞給另一個 process ,然後會透過一個 message broker (訊息代理) 的角色來暫時儲存 message,message broker 也被稱為 message queuemessage-oriented middleware

使用 message broker 跟 RPC 比起來有幾個好處:

  • 它能在接受者 (recipient) 掛掉或重啟時當 buffer,所以能提高系統的可靠性 (reliability)。
  • 它能自動重送 message 給接受者,所以能避免 message 遺失。
  • 它能避免讓寄送者 (sender) 知道接受者的 IP 或 PORT。
  • 它能允許 message 能被傳給多個接受者。
  • 它能讓寄送者和接受者做到邏輯上的 decouples (解耦合),意為寄送者不會在意是誰接受了它的 message。

asynchronous message-passing (非同步訊息傳遞) 系統跟 RPC 有個最大的不同是 寄送者通常不會期望接收 message 的回應,如果要接收回應的話會用分開的頻道來處理,這種溝通模式稱為 asynchronous:寄送者不會等待 message 被交付,且會送了就忘 (send it and then forgets about it)。

Message broker (訊息代理)

基於此概念下的 open source 工具有 RabbitMQ、ActiveMQ、HornetMQ、NATS 和最多人使用的 Apache Kafka

message broker 的主要用法是:一個 process 寄送 message 給 queue 或 topic,然後 broker (代理) 會確保這個 message 能被交付於另一個 consumers (消費者) 或 subscribers (訂閱者),我們能有許多 producer (生產者) 和 consumers ;

一個 topic 是一個單向的資料流,consumer 也能當 producer 發佈一個 message 給 topic,所以你能把它們連起來或者當處理完 message 的回覆 (就能做到類似 RPC 的 request/response);

message broker 通常不會指定如何做資料的 encoding,一個 message 就是用連續的位元組傳遞,所以你能自由選擇用哪種 binary encoding 格式,相對的就有很大的彈性做到向前和向後兼容。

Distributed actor frameworks (分散式角色框架)

actor 模型是一種為了在同一個 process 做並發 (concurrency) 的程式模型,而不是直接用 執行緒 來做,執行緒的相關問題有:競爭條件 (race condition)、鎖定 (locking) 跟死鎖 (deadlock)。

actor 的特性有:

  • 每一個 actor 代表一個 client 或 entity,它能有 local 的狀態 (不與其他 actor 分享),與其他 actor 的溝通也是透過寄送或接受非同步 message。
  • message 不保證交付,在某些情況下 message 會遺失。
  • 每一個 actor 一次只處理一個 message,所以不用特別擔心執行緒的問題。
  • 每個 actor 都能設定排程做事情。

在 Distributed actor frameworks (分散式角色框架) 中通常會在多個節點執行,所以寄送者和接受者是否在同一個節點不重要,最終都會 encoding 成連續的位元組用網路來傳遞 message;它實質上整合了 Message broker 和 actor 程式模型在單一個框架上,所以當你在 rolling 部署你的 actor-base 應用程式時,得多留意向前和向後兼容的問題。

常用的框架為 Akka、Orleans 和 Erlang OTP。

總結

Encoding and Evolution 主要就是介紹如何把記憶體的資料結構轉成透過網路傳遞或存在硬碟裡的位元組和兼容性;

Rolling upgrades (滾動式升級) 允許你的程式在釋出時不會有 downtime (頻繁的小更新好過一次大更新),也能降低部署時的風險 (能做 canary 觀察新程式上線時情況),因此系統的兼容性就代表了系統的進化能力。

兼容性分 2 種:

  • Backward compatibility (向前兼容) 新程式要能讀舊程式寫入的資料。
  • Forward compatibility (向後兼容) 舊程式要能讀新程式寫入的資料。

我們也討論了 binary encoding 的格式:

  • Programming language–specific encoding
  • 文字格式如 JSON, XML, and CSV
  • Binary schema–driven 格式如 Thrift, Protocol Buffers, and Avro

最後則討論了 3 種 dataflow 方式:

  • 資料庫
  • RPC and REST APIs
  • Asynchronous message passing (非同步訊息傳遞)
tshine73
tshine73
文章: 50

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *