ETCD API V3

news/2025/3/5 5:40:54/

ETCD API V3

  • ETCD V3 vs V2
    • gRPC
    • 序列化与反序列化
    • 减少TCP连接
    • 租约机制
    • 观察者模式
    • 数据存储模型
    • mini事务
    • 快照
    • 大规模watch
  • gRPC服务
  • KV API
    • Range
    • Put
    • DeleteRange
    • Txn
    • Compact
  • watch API
  • Lease API
    • 获取租约
    • 撤销租约
    • KeepAlives

ETCD V3 vs V2

etcd V3做出的改进和优化。

  • 使用gRPC+protobuf取代HTTP+JSON通信,提高通信效率;另外通过gRPC gateway来继续保持对HTTPJSON接口的支持
  • 使用更加轻量级的基于租约的key自动过期机制,取代了基于TTL的 key的自动过期时间
  • 观察者(watcher)机制进行了重新设计。etcd v2的观察者机制是基于HTTP长连接的时间驱动机制;而etcd v3是基于HTTP/2 的server push,并且对事件进行了多路复用(multiplexing)优化
  • 数据模型发生了较大的改变。v2是一个简单的key-value的内存数据库,而v3是支持事务和多版本并发控制的磁盘数据库。v2数据不直接落盘,落盘的日志和快照文件只是数据的中间格式而非最终格式,系统通过回放日志文件来构建数据的最终形式。v3罗盘的是数据的最终形态,日志和快照的主要作用是进行分布式的复制。

gRPC

gRPC是Google开源的一个高性能,跨语言的RPC框架,基于HTTP/2协议实现。使用protobuf作为序列化和反序列化协议,基于protobuf来声明数据模型和RPC接口服务

序列化与反序列化

protobuf的效率远高于JSON。v3的gRPC序列化和反序列化速度是v2的两倍多

减少TCP连接

v2通信协议使用HTTP1.1,gRPC支持HTTP/2,HTTP/2对HTTP通信进行了多路复用,可共享一个TCP连接。因此v3大大减少了客户端和服务端的连接数,一个客户端只需要与服务端建立一个TCP连接即可。v2,一个客户端需要与服务端建立多个TCP连接,每个HTTP请求都需要建立一个连接

租约机制

v2 是在每个key上设置TTL,v3是租约机制,然后key绑定租约,如果需要更新key的过期时间,可以直接更新租约(lease),多个key绑定到一个租约上,需要更新每个key的过期时间时,v3减少了客户端请求数量。

观察者模式

v2通过索引的方式支持连续的watch,客户端每次watch都可以带上之前的key的索引,然后服务端会返回比上一次watch更新的数据。然而v2的服务端对于每个客户端的每个watch请求都维护一个HTTP长连接,如果数钱个客户端watch了数千个key,那么v2服务端的socket和内存等资源会很快耗尽。
v3改进方法是对于同一个客户端的watch请求进行了多路复用,同一个客户端只需要与服务端维护一个TCP连接,减轻了服务端的压力。

数据存储模型

v2是一个key-value数据库,只保存key的最新的value,之前的value直接覆盖,但是会维护1000个所有key的变更记录,如果在短时间频繁写操作,那么变更记录会很快超过1000,如果watch过慢就会无法得到之前的变更,带来后果就是watch丢失事件。
v3为了支持多记录,抛弃不稳定的“滑动窗口”的设计,通过引入MVCC,采用了从历史记录为主索引的存储接口,保存了key的所有历史记录。
由于v3实现了MVCC,保存了每个key-value pair的历史版本,数据大了很多,不能将整个数据库放内存了,因此v3摒弃了内存数据库,转为磁盘数据库,整个数据库都存储在磁盘上,底层的存储引擎使用的是BoltDB

mini事务

v2只支持对单个key的CAS(Compare-And-Swap)操作,会对key的版本号或值比较,然后进行操作。
v3引入迷你事务,可以包含一系列的条件语句,只有在满足条件时事务才会执行成功

快照

v2与其他类似的开源一致性系统一样,最多只能存储十万级别的key,主要原因是一致性系统都采用了基于log的复制,log不能无限增长,所以某一时刻系统需要做一个完整的快照,并且将快照存储到磁盘。在存储快照后将之前的log丢弃。
v3通过Raft和存储系统的重构,支持增量快照和传输相对较大的快照,v3可以存储百万到千万级别的key

大规模watch

v2中每一个watcher都会占用一个TCP资源和一个goroutine资源,大概小号30~40KB。
v3利用TCP多路复用,只需要一个TCP连接,不同的watcher只消耗一个goroutine,减轻了etcd服务器的资源消耗。

gRPC服务

etcd v3的每个API请求均为gRPC远程调用,gRPC的proto文件包含了service,method,message三个部分,例如:

service KV {rpc Range(RangeRequest) returns (RangeResponse) {option (google.api.http) = {post: "/v3/kv/range"body: "*"};}}message RangeRequest {enum SortOrder {NONE = 0; // default, no sortingASCEND = 1; // lowest target value firstDESCEND = 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;
}

etcd v3所一定不同服务,包含了键值(KV),集群(Cluster),维护(Maintenance),认证/鉴权(Auth),观察(Watch)与租约(Lease)六大类。(具体可见源码:https://github.com/etcd-io/etcd/blob/main/api/etcdserverpb/rpc.proto)

  • KV:创建,更新,获取,删除键值对
  • Cluster:集群中增加或删除成员,更新成员配置,得到集群包含所有成员的列表
  • Maintenance:启动或停止警报,查询警报,查询成员状态,为成员后端的数据库整理碎片,在client的流中发送某成员的完整后端快照等
  • Auth:增删用户,更改用户密码,查询用户信息,获取用户列表,授予撤销用户角色,增删查角色,角色授予撤销某个特定的key
  • Watch:监听key的变化
  • Lease:消耗客户端keep-alive消息的原语

从proto的响应中,可见都包含了

message ResponseHeader {uint64 cluster_id = 1; // 生成该响应的cluster IDuint64 member_id = 2;// 生成该响应的memberIDint64 revision = 3;// 生成该响应的键值存储的版本uint64 raft_term = 4;// 生成该响应的member所处的Raft协议任期(term)
}

客户端通过检查cluster_id或member_id字段的值来确认是否正在与目标集群或节点通信。

KV API

Range

请求参数:

message RangeRequest {enum SortOrder {NONE = 0; // 默认。不排序ASCEND = 1; // 从小打到DESCEND = 2; // 从从到小}enum SortTarget {KEY = 0;VERSION = 1;CREATE = 2;MOD = 3;VALUE = 4;}bytes key = 1;// 表示bytes类型,不允许为空,如果range_end没有,则表示只是为了查询keybytes range_end = 2;// [key,range_end) ,当range_end为'\0'表示大于key的所有键,如果key和range_end都是'\0',请求返回所有的键,如果range_end是键加1(例如:key=“aa”,range_end=“ab”),则表示以这个key为前缀的所有keyint64 limit = 3;// 限制返回的key的数量,如果limit=0,则表示不限制int64 revision = 4;// 如果小于等于0,表示最新的键值存储,如果被压缩,则响应ErrCompactedSortOrder sort_order = 5;// 表示排序顺序SortTarget sort_target = 6;// 排序方式bool serializable = 7;// 设置使用可序列化的成员本地读取,默认是可线性化的,可线性化更高延迟更低吞吐量,但是反应的是整个集群的共识,为了更好的性能,以换取可能陈旧的读取,可串行化的范围请求在本地提供服务,不需要与其他节点达成共识bool keys_only = 8;// 被设置时,只返回键不返回值bool count_only = 9;// 被设置时,只返回键的数量int64 min_mod_revision = 10;// 返回key的mod_revision的下界,小于这个的会被过滤掉int64 max_mod_revision = 11;// 返回key的mod_revision的上界,大于这个的会被过滤掉int64 min_create_revision = 12;// 返回key的create_revision的下界,小于这个的会被过滤掉int64 max_create_revision = 13;// 返回key的create_revision的上界,大于这个的会被过滤掉
}

响应参数:

message RangeResponse {ResponseHeader header = 1;repeated mvccpb.KeyValue kvs = 2;// 表示符合range请求的key-value对列表,如果count_only设置为true,则kvs就为空bool more = 3;//表明是否还有更多的key没有在响应结果中返回int64 count = 4;// 满足reamge reqiest的key的总数
}message KeyValue {bytes key = 1;int64 create_revision = 2;int64 mod_revision = 3;int64 version = 4;bytes value = 5;int64 lease = 6;
}

Put

请求参数:

message PutRequest {bytes key = 1;// 表示写入的keybytes value = 2;// 表示写入的valueint64 lease = 3;// 表示关联在key上的租约ID,如果lease的值为0,代表没有租约bool prev_kv = 4;// 设置后,会返回该PUT请求修改前的key=value对数据bool ignore_value = 5;// 设置后,值更新key,但不修改当前的value,如果key不存在,则返回一个错误bool ignore_lease = 6;// 设置后,PUT操作更新key时不改变当前的租约,如果key不存在,则返回一个错误
}

响应参数:

message PutResponse {ResponseHeader header = 1;mvccpb.KeyValue prev_kv = 2;
}

DeleteRange

请求参数

message DeleteRangeRequest {bytes key = 1;// 表示删除范围的左端bytes range_end = 2;// 表示删除范围的右端, [key,range_end) ,当range_end没有,则表示只是删除这个key;如果为'\0'表示删除大于这个key的所有键;如果range_end是键加1(例如:key=“aa”,range_end=“ab”),则表示以这个key为前缀的所有keybool prev_kv = 3;// 如果被设置成true,则会在response中返回所有被删除的键值对。
}

响应参数

message DeleteRangeResponse {ResponseHeader header = 1;int64 deleted = 2;// 被删除的key的数目repeated mvccpb.KeyValue prev_kvs = 3;// 所有被删除的键值对列表
}

Txn

事务就是一个原子的,针对key-value存储操作的If/Then/Else结构。事务可以用来保护key不受其他并发更新操作的修改,也可以构造CAS(Compare And Swap)操作,并以此作为更高层次并发控制的基础。
一次事务,后台存储的revision只增长一次,而且该事务所有操作产生的事件都拥有同样的revision。
在一个事务中多次修改同一个key是被禁止的。
请求参数

message TxnRequest {repeated Compare compare = 1;// 比较repeated RequestOp success = 2; // 待处理的请求列表,如果所有的比较测试的结果均为真,则执行repeated RequestOp failure = 3;//  待处理的请求列表,只要任意一个比较测试的结果返回为假,则执行
}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; // 带比较的key-value字段。可以是key的version,create revision,mod revision,value。bytes key = 3; // 待比较的keyoneof target_union { // 用户比较的用户相关的数据int64 version = 4;int64 create_revision = 5;int64 mod_revision = 6;bytes value = 7;int64 lease = 8;}bytes range_end = 64; // 给定目标与[key,range_end)中的所有键进行比较
}message RequestOp {oneof request {RangeRequest request_range = 1;PutRequest request_put = 2;DeleteRangeRequest request_delete_range = 3;TxnRequest request_txn = 4;}
}

响应参数

message TxnResponse {ResponseHeader header = 1;bool succeeded = 2; // 表明Compare的结果是否为真repeated ResponseOp responses = 3;// 表示一个响应体列表,对应于success模块或failure模块的结果
}
message ResponseOp {oneof response {RangeResponse response_range = 1;PutResponse response_put = 2;DeleteRangeResponse response_delete_range = 3;TxnResponse response_txn = 4;}
}

Compact

请求参数

message CompactionRequest {int64 revision = 1;// 用于比较操作的键值存储的修订版本bool physical = 2;// 设置为true时,RPC会等待知道压缩物理性地应用到本地数据库,之后被压缩的项将完全从后端数据库中移除
}

响应参数

message CompactionResponse {ResponseHeader header = 1;
}

watch API

watch API提供基于事件的接口,用于异步检测key的变化。etcd v3的watch机制会针对某一给定的revision进行连续检测,等待key的变化出现,并最终将key的更新信息返回client。这里的revision既可以采用当前的revision,也可以采用历史的revision

请求参数:

message WatchRequest {oneof request_union {WatchCreateRequest create_request = 1;WatchCancelRequest cancel_request = 2;WatchProgressRequest progress_request = 3;}
}message WatchCreateRequest {bytes key = 1;// 与range_end组成watch的key的范围[key,range_end)bytes range_end = 2;int64 start_revision = 3;//指定从该revision起开始连续watch,如果不指定,就从watch流中建立响应头revision开始watch,//如果最后一次压缩后的版本开始,则能watch所有Event历史bool progress_notify = 4;//设置后,如果近期无Event,则watch将周期性的接收到无Event的WatchResponse消息// 这在客户端希望从最后一个已知revision出恢复断开的watcher的时候非常有用。// 至于多久发送一次通知,则取决于etcd Server的当前负载enum FilterType {NOPUT = 0;NODELETE = 1;}repeated FilterType filters = 5;//过滤Event类型的列表bool prev_kv = 6;//设置后,watch可接受到Event发生前的key-value数据int64 watch_id = 7;// 如果watch_id非零,它将被分配给这个监视器。// 由于在etcd中创建一个watcher不是同步操作,当在同一个流上创建多个watchers时,可以使用该命令确保顺序正确// 创建一个ID在stream已经存在的监视器会导致返回错误bool fragment = 8;//设置后拆分大的revision为多个watch响应
}message WatchCancelRequest {int64 watch_id = 1; // client对watch停止接收Event
}message WatchProgressRequest {
}

响应参数:

message WatchResponse {ResponseHeader header = 1;int64 watch_id = 2; // 对应watch response的IDbool created = 3;// 若reponse对应于一个创建watch的请求,则设为true。客户端应该记录watch id并且期望在流上接受该watch的Event。所有发给新创建的watcher客户端的event都是同一个watch_idbool canceled = 4;// 若response对应于取消watch请求,则设置为true。以后不再有Event发送到一个已经取消的watcher上int64 compact_revision = 5;// 如果watcher尝试watch一个已经被压缩的历史版本,那么compact_revision就会被设置成一个当前etcd可用的最小历史版本,并且watcher会被取消。当watcher无法跟上etcd键值存储的处理速度时,会发生以上情况。两个相同的start_revision的watch最多只会成功一个string cancel_reason = 6;// 表示取消watcher的原因bool fragment = 7;// 如果监听到响应被拆分为多个响应,则为truerepeated mvccpb.Event events = 11;
}message Event {enum EventType {/PUT = 0;// PUT类型表明新的数据已经存储到相应的keyDELETE = 1;// DELETE类型表明key已经被删除了。}EventType type = 1;/ Event的类型,分为PUT类型和DELETE类型。KeyValue kv = 2;// 与Event关联的key-value//一个PUT Event包含当前的KV,一个Version=1的PUT Event表明这个key是新建的。//一个DELETE Event包含被删除的key和该key被删除时的modification revisionKeyValue prev_kv = 3;// 该key在发生此Event之前最近一刻revision的key-value对,//为了节约带宽,只有在watch请求中显式地启用该选项时才会相应返回该值
}

watch操作是长期持续存在的请求,它使用gRPC流来传输Event数据,这里的watch流是双向流。
client通过写入流来创建watch;client通过读取流接受watch到的Event。
单个watch流可以通过使用pre-watch标识符来标记Event,已达到在一个watch流中多路传输多个不同的watch Event的目的。多路复用watch流能帮助减少etcd集群内存占用与连接开销。

etcd的watch机制确保了检测到Event具有有序,可靠与原子性的特点:

  • 有序:Event按照revision排序,后发生的Event不会在前面的Event之前出现在watch流中
  • 可靠:某个事件序列不会遗漏其中任意的子序列,例如,发生事件a,b,c,而如果watch接受到a和c,那么就能保证b也已经被接收了
  • 原子性:Event列表确保包含完整的revision,在相同revision的多个key上,更新不会分裂为几个事件列表。

Lease API

租约是一种检测客户端活跃度(liveness)的机制,租约是有生存时间的,集群为租约授予一个TTL(time-to-live)。Lease的实际TTL不低于最小TTL,该最小TTL由etcd集群选择。当Lease的TTL到期时,所有与之相关联的key都将被删除。如果etcd集群在一个给定TTL周期没有收到一个keepAlive消息来维持租约,那么该租约将过期。

获取租约

请求参数:

message LeaseGrantRequest {int64 TTL = 1;// TTL值,单位sint64 ID = 2;// 默认是0,如果置空,那么etcd均为该Lease选择一个ID
}

响应参数

message LeaseGrantResponse {ResponseHeader header = 1;int64 ID = 2;int64 TTL = 3;string error = 4;
}

撤销租约

当撤销该Lease时,所有关联的key都会自动删除

请求参数:

message LeaseRevokeRequest {int64 ID = 1;
}

响应参数:

message LeaseRevokeResponse {ResponseHeader header = 1;
}

KeepAlives

请求参数:

message LeaseKeepAliveRequest{int64 ID = 1;
}

响应参数:

message LeaseKeepAliveResponse {ResponseHeader header = 1;int64 ID = 2;int64 TTL = 3; // 表示一个新的TTL值,单位是s,表示该Lease继续存在的时间
}

http://www.ppmy.cn/news/546463.html

相关文章

内存卡打不开需要格式化怎么恢复数据

内存卡是我们常用的存储数据的工具,在我们频繁的使用过程中,难免会出现一些意向不到的问题。 比如:内存卡打不开,提示需要格式化才能继续使用。但是,我有很多重要的文件在内存卡里面,怎么办? …

怎么在计算机修复flash,win10系统怎么用flash修复器?教你用flash修复器修复视频的方法...

flash修复器可以解决看网页视频异常,网页flash空白等flash问题,是一款非常不错的工具。win10正式版系统安装上flash修复器,好多新手小白不知道怎么用flash修复器修复视频。其实操作步骤简单,接下来小编教你用flash修复器修复视频。 具体方法如…

内存卡坏了怎么修复?内存卡恢复也不难

内存卡坏了怎么修复?内存卡又名SD卡,是一种轻便小巧的便携式存储设备,但因为长期大量读写数据,很容易从内部发生损坏,这时候最令人担心的就是里面的数据,其实内存卡损坏一般都是来源于内部,这是…

关于修复mp4文件损坏的过程小记

最近项目中遇到设备异常断电,导致mp4文件损坏的问题,最近花了点时间,深入分析原因,并进行了相关修复尝试工作,最后,虽然文件中的音视频数据大部分可以修复,但因为原始文件中视频的帧率是动态变化…

sdhc卡文件丢失常见原因和两种恢复方法

sdhc卡作为sd卡的继任者,主要有容量/速度等级高、支持文件格式和兼容的机器多等特征,通常被用于存储大量文件的设备中,比如松下照相机。但是sdhc卡跟其他存储设备相似,也会因各种原因导致重要数据丢失,那么sdhc卡文件丢…

解决视频播放器找不到解码器问题

打开视频播放器,我经常使用的qq影音精简版居然什么格式的视频都不能播放了(提示文件无法渲染),这时候我怀疑快播不能播放也是因为系统缺少dll文件了(提示文件格式不正确);设置了好长时间还是不行网上给出的资料大多数是视频文件损坏&#xff…

记一次bandicom录制的mp4文件损坏修复

最近使用bandicom录制视频文件的时候中途不小心断电了,留下了一个mp4文件,播放器无法恢复,使用010editor打开这个mp4文件,发现仅有两个头的box, 和正常的mp4文件比对,缺少了moov数据块 经过查询得知mdat主…

ps安装找不到vcruntime140.dll怎么修复呢?

vcruntime140.dll是Windows系统中非常重要的组件,缺失vcruntime140.dll会导致电脑很多软件无法打开运行,报如下错误。由于找不到VCRUNTIME140_1.dll,无法继续执行代码。重新安装程序可能会解决此问题。小编今天就把修复教程分享给大家&#x…