徹底搞懂 etcd 系列文章(六):etcd 核心 API v3

0 專輯概述

etcd 是雲原生架構中重要的基礎組件,由 CNCF 孵化託管。etcd 在微服務和 Kubernates 集羣中不僅可以作爲服務註冊與發現,還可以作爲 key-value 存儲的中間件。

《徹底搞懂 etcd 系列文章》將會從 etcd 的基本功能實踐、API 接口、實現原理、源碼分析,以及實現中的踩坑經驗等幾方面具體展開介紹 etcd。預計會有 20 篇左右的文章,筆者將會每週持續更新,歡迎關注。

1 proto3

etcd v3 的通信基於 gRPC,proto 文件是定義服務端和客戶端通訊接口的標準。即客戶端該傳什麼樣的參數,服務端該返回什麼樣子的參數,客戶端該怎麼調用,是阻塞還是非阻塞,是同步還是異步。在進行核心 API 的學習之前,gRPC 推薦使用 proto3,我們需要對 proto3 的基本語法有初步的瞭解。proto3 是原有 Protocol Buffer 2(被稱爲 proto2)的升級版本,刪除了一部分特性,優化了對移動設備的支持,另外增加了對android和ios的支持,使得 gRPC 可以順利的在移動設備上使用。

2 Protocol Buffer 是什麼

Protocol buffer 是一個靈活、高效、自動化的結構化數據序列化機制--類似於 xml,但是更小、更快並且更簡單。一旦定義好數據如何構造,就可以使用特殊生成的源代碼輕鬆地在各種數據流中使用各種語言編寫和讀取結構化數據。甚至可以更新之前定義的數據結構而不打破已部署的使用"舊有"格式編譯的程序。

2.1 定義消息類型

首先讓我們來看一個非常簡單的例子。假定我們有這樣的需求,我們要定義一個搜索請求消息,每個消息都包含一個查詢字符串,和你感興趣的特定頁面編號,以及每個頁面的命中個數。

syntax = "proto3";

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
  1. 文件的第一行指定了你使用的是 proto3 的語法:如果你不指定,protocol buffer 編譯器就會認爲你使用的是proto2的語法。這個語句必須出現在.proto文件的非空非註釋的第一行。
  2. 我們看到,搜索請求消息結構中定義指定了三個字段(name/value pairs)。每個字段都有一個名稱和類型。

2.2 指定字段類型

在上述例子中,所有的字段都是值類型:兩個整形(page_number and result_per_page) 和一個字符串 (query)。然而,你也可以指定你的字段的組合類型,包括枚舉和其他消息類型。

2.3 分配標識——tag

消息中的每個字段都有一個唯一的數字標識。這些標識用來在消息的二進制格式中識別你的字段,並且,一旦你的消息投入使用,這些標識就不應該再被修改。

注意,標識是由1到15使用一個字節來編碼,包括標識數字和字段類型(你可以在Protocol Buffer 編碼中查看更多詳細)。

標識16到2047佔用兩個字節。所以你應該保留1到15,用作出現最頻繁的消息類型的標識。記得爲將來會繼續增加並可能頻繁出現的元素留一點兒標識區間,也就是說,不要一下子把1—15全部用完,爲將來留一點兒哦。

你可以指定的最小的標識數字是1,最大是228,或者536,870,911。你也不能使用19000 到 19999之間的數字(FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber),因爲它們被Protocol Buffers保留使用——如果你在自己的.proto文件中使用了一個保留數字,protocol buffer 編譯器將會提示。同樣的,你不能使用任何之前保留的標識。

2.4 指定字段規則

消息字段可以是下邊中的一種:

  1. singular(單個):符合語法規則的消息包含零個或者一個這樣的字段(最多一個)。
  2. repeated(重複): 一個字段在合法的消息中可以重複出現一定次數(包括零次)。重複出現的值的次序將被保留。在proto3中,重複出現的值類型字段默認採用壓縮編碼。

2.5 添加更多消息類型

多個消息類型可以定義在一個.proto文件中。這個在你定義多個關聯的消息的時候非常有用,——這樣,舉個例子吧,如果你想定義你的搜索消息類型的響應消息格式,你可以在同一個.proto文件中添加如下的內容:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {
 ...
}

2.6 添加註釋

在你的 .proto 文件中添加註釋, 使用C/C++-風格的 // 語法,像下邊這樣:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;  // Which page number do we want?
  int32 result_per_page = 3;  // Number of results to return per page.
}

2.7 保留字段

如果你通過刪除整個字段更新了消息類型,或者將整個字段其註釋掉,未來用戶在編寫新的類型的時候能夠複用這些註釋掉的標識數字。然而,這會引起一些嚴重的問題,如果他們後來加載了同一個 .proto 的舊版,包括數據損壞,安全隱私 bug 等等。一個確保這種問題不會發生的辦法是,保留你要刪除的字段的標識。Protocol buffer 編譯器將會提示以後用戶使用這些保留的字段標識。

message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

注意不要混淆同一個保留語句中的字段名稱和標識。

2.8 值類型

值類型的消息字段可以是一下類型中的一種——這個表格展示了可以在.proto文件中使用的類型,以及自動生成的相應語言的類型:

3 .proto 編譯之後會生成什麼

一個 .proto 文件的編譯之後,編譯器會爲你選擇的語言生成代碼。你在文件中描述的消息類型,包括獲取和設置字段的值,序列化你的消息到一個輸出流,以及從一個輸入流中轉換出你的消息。

  • 對於 C++,編譯器會爲每個 .proto 文件生成一個 .h 和一個 .cc 的文件,爲每一個給出的消息類型生成一個類。
  • 對於 Java,編譯器會生成一個java文件,其中爲每一個消息類型生成一個類,還有特殊的用來創建這些消息類實例的Builder類,
  • Python編譯器生成一個模塊,其中爲每一個消息類型生成一個靜態的描述器,在運行時,和一個 metaclass 一起使用來創建必要的 Python 數據訪問類。
  • 對於 Go,編譯器爲每個消息類型生成一個 .pb.go 文件。

4 小結

所有 etcd3 API 均在 gRPC 服務中定義,該服務對 etcd 服務器可以理解的遠程過程調用(RPC)進行分類。本篇主要介紹了 proto3 相關的定義概念,爲後面具體學習 gRPC 的接口儲備一些必要的知識。下篇文章我們將具體介紹 etcd3 的 gRPC API
核心接口。

訂閱最新文章,歡迎關注我的公衆號

推薦閱讀

  1. etcd 與 Zookeeper、Consul 等其它 k-v 組件的對比
  2. 徹底搞懂 etcd 系列文章(一):初識 etcd
  3. 徹底搞懂 etcd 系列文章(二):etcd 的多種安裝姿勢
  4. 徹底搞懂 etcd 系列文章(三):etcd 集羣運維部署
  5. 徹底搞懂 etcd 系列文章(四):etcd 安全
  6. 徹底搞懂 etcd 系列文章(五):etcdctl 的使用

參考

etcd docs

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章