程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Etcd gRPC API 简介

发表于 2022-11-17 | 分类于 Etcd | 0 | 阅读次数 3523

基础

Etcd 提供了以下几个 gRPC Service 和相关 API,详见 官方文档-etcd3 API。相关的 gRPC Service 定义可见 etcd 源码的 api/etcdserverpb/rpc.proto 文件(源码版本为 v3.5.1)。

  • KV:创建/更新/删除/获取 key-value 对。
  • Watch:监听 keys 的变更。
  • Lease:客户端保持 keep-alive 的消息原语。
  • Auth:认证和鉴权相关,同时包含用户的增删改查等操作。
  • Cluster:提供集群 member 的配置管理功能,member 的增删改查等操作。
  • Maintenance:提供恢复快照、对存储进行碎片整理等操作。

本文只介绍 KV、Watch 两个 Service。

KV Service

KV Service 的定义如下所示。可以看到,KV Service 提供了以下 gRPC API:

  • Range:获取范围内的 key。
  • Put:设置给定 key 对应的 value。Put 请求会增加一次 revision,并且在 Event 历史中为该 key 生成一个 Event。
  • DeleteRange:删除给定范围的 key。DeleteRange 请求会增加一次 revision,并且在 Event 历史中,为每个被删除的 key 生成一个删除事件。
  • Txn(Transaction):在一个 txn 请求中处理多个操作,一个 txn 请求会增加一次 revision,并且请求中的每个操作涉及的 key 会生成相同 revision 的 Event。注意:不容许在一个 txn 中多次修改同一个 key。
  • Compact:对 etcd 中的历史 revision 及其 key-value 进行压缩。该操作会定期进行压缩,否则历史 revision 及其对应的 key-value 会无限制的持续增长。

option (google.api.http) = {} 的作用是在 Protobuf 文件中定义 gRPC API 对应的 HTTP API。在使用 gRPC-Gateway 插件的时候,该插件可以将对应的 HTTP API 自动转换为对应的 gRPC 请求,并将 gRPC 响应转换为 HTTP 响应。

service KV {
  rpc Range(RangeRequest) returns (RangeResponse) {
      option (google.api.http) = {
        post: "/v3/kv/range"
        body: "*"
    };
  }

  rpc Put(PutRequest) returns (PutResponse) {
      option (google.api.http) = {
        post: "/v3/kv/put"
        body: "*"
    };
  }

  rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse) {
      option (google.api.http) = {
        post: "/v3/kv/deleterange"
        body: "*"
    };
  }

  rpc Txn(TxnRequest) returns (TxnResponse) {
      option (google.api.http) = {
        post: "/v3/kv/txn"
        body: "*"
    };
  }

  rpc Compact(CompactionRequest) returns (CompactionResponse) {
      option (google.api.http) = {
        post: "/v3/kv/compaction"
        body: "*"
    };
  }
}

Range API

Range API 中的 RangeRequest 消息体的定义如下所示(其中 1、2、3 这些数字表示的是字段对应的编号),

  • key:如果 range_end 没有给定,则该请求表示仅查找这个 key。

  • range_end:代表请求的上限。

    • 如果 range_end 是 '\0',则查询的范围为大于等于 key 的所有key;
    • 如果 range_end 比给定的 key 长一个 bit,则表示查询的是所有带有以 key 为前缀的 key;
    • 如果 key 和 range_end 都是'\0',则范围查询返回所有key。
  • limit:请求返回的 key 的数量限制,也就是说只返回 range 范围内前 limit 个 key-value,哪怕范围内的 key-value 数量超过了 limit。limit 在分页时会非常有用,一次只返回 range 范围内的部分结果,然后根据需要和返回结果,获取更多数据。limit 的使用可以减少网络带宽的使用,提高查询效率。

    如果不设置 limit,则请求将返回 range 范围内的所有 key-value,没有数量上的限制(除非超过 gRPC 消息的大小限制)。不设置 limit 在 key-value 数量较大时,可能会导致网络负载增大,并可能影响客户端和服务端的性能。

  • revision:如果 revision 未指定或者指定了小于或等于零的值,则返回当前最新的 key-value 数据。如果指定了其他值,则返回在该 revision 时的 key-value 数据,此时如果相应的 revision 已被 compact,则返回 ErrCompacted。

  • sort_order:返回结果的排序顺序。

  • sort_target:返回结果的排序方式,是按照 Key 进行排序,还是按照 version 进行排序。

  • serializable:serializable 表示 range 请求是否使用串行读。range 请求默认是采用线性读的方式,线性读相比串行读会有较高的延迟和较低的吞吐量,但是可以反映集群当前的一致性。

  • keys_only:仅仅返回 keys,不返回 values。

  • count_only:仅仅返回 keys 的数量。

  • min_mod_revision:key mod revision 的下边界,对于比该 mod revision 更小的 key 将会被过滤。

  • max_mod_revision:key mod revision 的上边界,对于比该 mod revision 更大的 key 将会被过滤。

  • min_create_revision:key create revision 的下边界,对于比该 create revision 更小的 key 将会被过滤。

  • max_create_revision:key create revision 的上边界,对于比该 create revision 更大的 key 将会被过滤。

message RangeRequest {
  enum SortOrder {
	NONE = 0; // default, no sorting
	ASCEND = 1; // lowest target value first
	DESCEND = 2; // highest target value first
  }
  enum SortTarget {
	KEY = 0;
	VERSION = 1;
	CREATE = 2;
	MOD = 3;
	VALUE = 4;
  }

  bytes key = 1;
  bytes range_end = 2;
  int64 limit = 3;
  int64 revision = 4;
  SortOrder sort_order = 5;
  SortTarget sort_target = 6;
  bool serializable = 7;
  bool keys_only = 8;
  bool count_only = 9;
  int64 min_mod_revision = 10;
  int64 max_mod_revision = 11;
  int64 min_create_revision = 12;
  int64 max_create_revision = 13;
}

RangeResponse 消息体的定义如下,

  • header:使用 ResponseHeader 消息体,ResponseHeader 是每个 gRPC API Response 中的通用消息体。包含以下字段,
    • cluster_id:产生响应的集群的 ID。
    • member_id:产生响应的 member ID。
    • revision:产生响应时,集群的 revision。
    • raft_term:产生响应时,集群的 raft term。
  • kvs 是 mvccpb.KeyValue 的列表。mvccpb.KeyValue 中包含以下字段,
    • key:key 的内容。
    • value:value 的内容。
    • create_revision:这个 key 创建时的 revision。
    • mod_revision:这个 key 最后一次修改时的 revision。
    • version:这个 key 经过几次修改。删除会将该值设置为 0。
    • lease:lease 是附加给 key 的租约 id。当附加的租约过期时,key 将被删除。如果 lease 为 0,则表示没有租约附加到 key。
  • more:表示在请求的范围内是否还有更多的 key,这个仅在设置了 limit 才有效。
  • count:满足请求范围的 keys 的数量。
message RangeResponse {
  ResponseHeader header = 1;
  repeated mvccpb.KeyValue kvs = 2;
  bool more = 3;
  int64 count = 4;
}

message ResponseHeader {
  uint64 cluster_id = 1;
  uint64 member_id = 2;
  int64 revision = 3;
  uint64 raft_term = 4;
}

message KeyValue {
  bytes key = 1;
  int64 create_revision = 2;
  int64 mod_revision = 3;
  int64 version = 4;
  bytes value = 5;
  int64 lease = 6;
}

Put API

Put 请求的消息体是 PutRequest,如下所示,

  • key/value:要创建/更新的 key-value 内容。
  • lease:和 key 关联的租约 id,如果为 0 表示没有租约。
  • prev_kv:如果 prev_kv 为 true,则 etcd 会在改变该 key 之前先获取到前一个该 key 及其 value 的内容,并在 PutResponse 中返回。
  • ignore_value:如果为 true,则使用它当前的 value 来更新 key。如果 key 不存在则返回 error。
  • ignore_lease:如果为 true,则使用它当前的 lease。如果 key 不存在则返回 error。
message PutRequest {
  bytes key = 1;
  bytes value = 2;
  int64 lease = 3;
  bool prev_kv = 4;
  bool ignore_value = 5;
  bool ignore_lease = 6;
}

Put 请求返回的消息体是 PutResponse:

  • header:通用的 ResponseHeader 消息体。
  • prev_kv:如果 PutRequest 中设置了 prev_kv 为 true,它就是该 key 前一个的 key-value 内容。
message PutResponse {
  ResponseHeader header = 1;
  mvccpb.KeyValue prev_kv = 2;
}

DeleteRange API

DeleteRange 请求的消息体是 DeleteRangeRequest,如下所示,

  • key/range_end:同 Range 请求 key/range_end。
  • prev_kv:同 Put 请求中的 prev_kv。
message DeleteRangeRequest {
  bytes key = 1;
  bytes range_end = 2;
  bool prev_kv = 3;
}

返回的消息体是 DeleteRangeResponse,如下所示,

  • header:通用的 ResponseHeader 消息体。
  • deleted:该请求删除的 key 的数量。
  • prev_kvs:同 Put 请求中的 prev_kv,但是由于 DeleteRange 可能会删除一批 key,因此这些 key 及其 value 都会被返回。
message DeleteRangeResponse {
  ResponseHeader header = 1;
  int64 deleted = 2;
  repeated mvccpb.KeyValue prev_kvs = 3;
}

TXN API

etcd 事务采用 If/Then/Else 这样的原语。在事务请求中可以处理多个操作,etcd 针对事务只增加一次 revision,事务中生成的 event 都具有相同的 revision。txn 请求使用的消息体如下所示,

  • 如果 compare 中的所有比较都为 true 的话,则顺序处理 success 中定义的操作,否则顺序处理 failure 中的操作。
  • 其中 compare 中,可以相同的 key 进行两次不同的比较。
message TxnRequest {
  repeated Compare compare = 1;
  repeated RequestOp success = 2;
  repeated RequestOp failure = 3;
}

其中,Compare 消息体如下所示,主要是检查 key 的 create_version/mod_version/version/value/lease 与指定值的比较,

  • result:比较方式,是大于/等于/小于/不等于。
  • target:对 key 的什么信息进行比较,是 create_version/mod_version/version/value/lease 其中的一种。
  • key:要比较的 key。
  • target_union:根据 target 类型,指定用于比较的实际值。

比如想要对键 /foo 的当前值进行检查,检查它是否等于 bar。此时,result 为 EQUAL,target 是 VALUE,key 为 /foo,target_union 中为 value,内容为 bar。

message Compare {
  enum CompareResult {
    EQUAL = 0;
    GREATER = 1;
    LESS = 2;
    NOT_EQUAL = 3;
  }
  enum CompareTarget {
    VERSION = 0;
    CREATE = 1;
    MOD = 2;
    VALUE = 3;
    LEASE = 4;
  }
  
  CompareResult result = 1;
  CompareTarget target = 2;
  bytes key = 3;
  oneof target_union {
    int64 version = 4;
    int64 create_revision = 5;
    int64 mod_revision = 6;
    bytes value = 7;
    int64 lease = 8;
  }
}

RequestOp 消息中如下所示,

  • request_range/request_put/request_delete_range:依次使用的是RangeRequest/PutRequest/DeleteRangeRequest 消息体,参考上述的介绍。
  • request_txn:使用的是 TxnRequest 消息体,意味着事务可以嵌套使用事务,也就是在 success 或 failure 中可以定义更多的事务。比如在 success 中先进行 PUT,然后再执行一条事务,该条事务先进行检查是否 PUT 成功,然后再决定进一步的操作。
message RequestOp {
  oneof request {
    RangeRequest request_range = 1;
    PutRequest request_put = 2;
    DeleteRangeRequest request_delete_range = 3;
    TxnRequest request_txn = 4;
  }
}

txn 请求返回的消息为 TxnResponse 消息体,TxnResponse 将按顺序包含上述处理操作对应的处理结果,

  • header:通用的 ResponseHeader 消息体。
  • succeeded:如果 TxnRequest 中的 compare 比较为 true 则 succeeded 被设置为 true,否则是 false。
message TxnResponse {
  ResponseHeader header = 1;
  bool succeeded = 2;
  repeated ResponseOp responses = 3;
}

message ResponseOp {
  oneof response {
    RangeResponse response_range = 1;
    PutResponse response_put = 2;
    DeleteRangeResponse response_delete_range = 3;
    TxnResponse response_txn = 4;
  }
}

Compact API

Compact 请求使用的 CompactionRequest 消息体定义如下,该接口的主要作用是压缩 key-value 存储到给定 revision。

  • revision:表示 compact 操作结束的 revision。
  • physical:设置为 true 时 RPC 将会等待该请求,直到被压缩的内容从后端存储中删除。
message CompactionRequest {
  int64 revision = 1;
  bool physical = 2;
}

Compact 请求应答的消息体 CompactionResponse 如下,只包含了一个通用的 ResponseHeader 消息体。

message CompactionResponse {
  ResponseHeader header = 1;
}

Watch Service

Watch Service 的定义如下所示,它只有一个 gRPC API,也就是 Watch。

service Watch {
  rpc Watch(stream WatchRequest) returns (stream WatchResponse) {
      option (google.api.http) = {
        post: "/v3/watch"
        body: "*"
    };
  }
}

Watch API

Watch 请求的消息体是 WatchRequest,如下所示。可以看到,无论是创建一个 watcher,还是取消一个 watcher 使用的都是 WatchRequest 消息体。

  • create_request:使用 WatchCreateRequest 消息体,表示创建一个 watcher。

    • key/range_end:同 Range API。

    • start_revision:表示从 start_revision(包含) 开始监听。如果这个值没有设置则从创建 WatchResponse 时候的 revision 开始监听。监听历史是从最后一个 compact revision 开始

    • progress_notify:如果设置了,即使没有最新 event,还是会定期的发送不带任何 event 的 WatchResponse,但是会带当前最新的 revision。etcd 将基于当前的负载决定发送频率。该字段的主要作用是,

      • 充当心跳,帮助 client 验证其 watch 请求仍然有效,并且 client 与 etcd 之间的连接是健康的。
      • client 可以通过定期的通知来知道 etcd 集群最新的 revision,确保自己没有错过任何更新。
      • 如果 client 与 etcd 之间的连接暂时断开,那么在重新建立连接后,client 可以使用收到的最新 revision 来恢复其 watch 状态,从而继续接收到重要的更新。
    • filters:配置 event 的过滤选项。

    • prev_kv:如果设置了,WatchResponse 则会返回 event 发生时的上一个 key-value 内容。

    • watch_id:如果 watch_id 被设置了且不为 0,则表示使用 id 为 watch_id 的 watcher。由于 etcd 创建 watcher 不是同步的,因此这个可以用于确保在同一个 strem 上顺序创建多个 watcher。在同一个 strem 上创建一个已存在的 watcher 会返回错误。

    • fragment:如果设置了,则允许分成多个 WatchResponse 返回。

  • cancel_request:使用 WatchCancelRequest 消息体,表示取消一个 watcher。

    • watch_id:表示要取消的 watcher id,取消之后就不再有更多 event 发送过来。
  • progress_request:使用 WatchProgressRequest 消息体,类似于 WatchCreateRequest 中的 progress_notify。

message WatchRequest {
	oneof request_union {
    WatchCreateRequest create_request = 1;
    WatchCancelRequest cancel_request = 2;
    WatchProgressRequest progress_request = 3;
  }
}

message WatchCreateRequest {
  bytes key = 1;
  bytes range_end = 2;
  int64 start_revision = 3;
  bool progress_notify = 4;
  
  enum FilterType {
    // filter out put event.
    NOPUT = 0;
    // filter out delete event.
    NODELETE = 1;
  }
  
  repeated FilterType filters = 5;
  bool prev_kv = 6;
  int64 watch_id = 7;
  bool fragment = 8;
}

message WatchCancelRequest {
  int64 watch_id = 1;
}

message WatchProgressRequest {
}

Watch 请求返回的消息体是 WatchResponse,如下所示,

  • header:通用的 ResponseHeader 消息体 。
  • watch_id:和该 response 相关的 watcher 的 id。
  • created:如果该 response 是创建 watcher 请求的回复,则 created 设置为 true。
  • canceled:如果该 response 是取消 watcher 请求的回复,则 canceled 设置为 true。
  • compact_revision:如果 watcher 是从已被 compact 的 revision 开始监听的话,则 compact_revision 被设置为最小未 compact 的 revision。client 在收到这个信息之后,应该根据该信息重新创建 watcher 并设置 start_revision。例如,client 想要 watch 从 revision 100 开始的变更,但是服务器返回了 compact_revision 为 200 的 WatchResponse,这意味着 revision 100 到 199 的数据已经不再存在。client 应该根据这个信息更新其 watch 请求,使用一个大于或等于 200 的 revision 作为新的起点。
  • cancel_reason:表示 watcher 被取消的原因。
  • fragment:表示回复 watch response 是否被分成多个 response 返回。
  • events:返回的 event 列表。
    • type:表示该 event 的类型,是 PUT 还是 DELETE。
    • kv:表示该 event 涉及的 key-value 内容。PUT event 包含当前的 key-value 内容。kv.Version=1 则表示 PUT event 是刚创建了该 key。DELETE event 包含被删除的 key,它的 revision 设置为删除时的 revision。
    • prev_kv:在 event 发生之前的 key-value 内容,需要 WatchCreateRequest 中的 prev_kv 设置为 true。
message WatchResponse {
  ResponseHeader header = 1;
  int64 watch_id = 2;
  bool created = 3;
  bool canceled = 4;
  int64 compact_revision = 5;
  string cancel_reason = 6;
  bool fragment = 7;
  repeated mvccpb.Event events = 11;
}

message Event {
  enum EventType {
    PUT = 0;
    DELETE = 1;
  }
  
  EventType type = 1;
  KeyValue kv = 2;
  KeyValue prev_kv = 3;
}

相关链接

etcd3 API:https://etcd.io/docs/v3.4/learning/api/

彻底搞懂 etcd 系列文章:https://cloud.tencent.com/developer/article/1690342

卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/265
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Kubernetes # Etcd
Etcd 事务介绍
Raft 算法原理
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%