etcd使用详解

本地集群

  • 独立集群 指只有一台服务器的集群。
  • 多成员集群 指有多台台服务器的集群。

相关概念

Response header

从etcd API返回的所有应答都附带有 response header。这个response header包含应答的元数据。

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

Cluster_ID - 生成应答的集群的ID
Member_ID - 生成应答的成员的ID
Revision - 当应答生成时键值存储的修订版本
Raft_Term - 当应答生成时成员的 Raft term

键值对

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


Key - 字节数组形式的key。key不容许空。
Value - 字节数组形式的value
Version - key的版本。删除将重置版本为0而key的任何修改将增加它的版本。
Create_Revision - key最后一次创建的修订版本。
Mod_Revision - key最后一次修改的修订版本。
Lease - 附加到key的租约的ID。如果lease为0,则表示没有租约附加到ke

etcdctl

写入

这是设置键 foo 的值为 bar 的命令:

$ etcdctl put foo bar

这是将键 foo1 的值设置为 bar1 并维持 10s 的命令

$ etcdctl put foo1 bar1 --lease=1234abcd

注意: 上面命令中的租约id 1234abcd 是创建租约时返回的. 这个 id 随即被附加到键。

读取键

这是读取键 foo 的值的命令:

$ etcdctl get foo

foo
bar

这是只读取键 foo 的值的命令:

$ etcdctl get foo --print-value-only

bar

这是范围覆盖从 foo to foo3 的键的命令:


$ etcdctl get foo foo3

foo
bar
foo1
bar1
foo2
bar2

注意 foo3 不在范围之内,因为范围是半开区间 [foo, foo3), 不包含 foo3.

这是范围覆盖以 foo 为前缀的所有键的命令:

$ etcdctl get --prefix foo
foo
bar
foo1
bar1
foo2
bar2
foo3
bar3

这是范围覆盖以 foo 为前缀的所有键的命令,结果数量限制为2:

$ etcdctl get --prefix --limit=2 foo

这里是访问键的过往版本的例子:

$ etcdctl get --prefix foo # 访问键的最新版本

$ etcdctl get --prefix --rev=4 foo # 访问修订版本为 4 时的键的版本

这是读取大于等于键 b 的 byte 值的键的命令

$ etcdctl get --from-key b

删除键

$ etcdctl del foo1
# 删除了一个键
$ etcdctl del foo foo9 
# 删除了两个键
$ etcdctl del --prev-kv zoo
1   # 一个键被删除
zoo # 被删除的键
val # 被删除的键的值

#这是删除键 zoo 并返回被删除的键值对的命令
$ etcdctl del --prefix zoo

#这是删除前缀为 zoo 的键的命令
$ etcdctl del --from-key b$ 

#这是删除大于等于键 b 的 byte 值的键的命令

观察键

$ etcdctl watch foo
# 在另外一个终端: etcdctl put foo bar
foo
bar

#这是在键 foo 上进行观察的命令
$ etcdctl watch foo foo9
# 在另外一个终端: etcdctl put foo bar
PUT
foo
bar
# 在另外一个终端: etcdctl put foo1 bar1
PUT
foo1
bar1
这是观察从 foo to foo9 范围内键的命令
etcdctl watch --prefix foo

这是观察前缀为 foo 的键的命令
$ etcdctl watch -i
$ watch foo
$ watch zoo
#这是观察多个键 foo 和 zoo 的命令
# 从修订版本 3 开始观察键 `foo` 的改动
$ etcdctl watch --rev=3 foo

授予租约

# 授予租约,TTL为10秒
$ etcdctl lease grant 10
lease 32695410dcc0ca06 granted with TTL(10s)

# 附加键 foo 到租约32695410dcc0ca06
$ etcdctl put --lease=32695410dcc0ca06 foo bar
OK

撤销租约

应用通过租约 id 可以撤销租约。撤销租约将删除所有它附带的 key。

$ etcdctl lease revoke 32695410dcc0ca06
lease 32695410dcc0ca06 revoked

$ etcdctl get foo
# 空应答,因为租约撤销导致foo被删除

维持租约

应用可以通过刷新键的 TTL 来维持租约,以便租约不过期。

$ etcdctl lease keep-alive 32695410dcc0ca06
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
lease 32695410dcc0ca06 keepalived with TTL(10)
...

获取租约信息

# 授予租约,TTL为500秒
$ etcdctl lease grant 500
lease 694d5765fc71500b granted with TTL(500s)

# 将键 zoo1 附加到租约 694d5765fc71500b
$ etcdctl put zoo1 val1 --lease=694d5765fc71500b
OK

# 将键 zoo2 附加到租约 694d5765fc71500b
$ etcdctl put zoo2 val2 --lease=694d5765fc71500b
OK

这是获取租约信息的命令:

$ etcdctl lease timetolive 694d5765fc71500b
lease 694d5765fc71500b granted with TTL(500s), remaining(258s

这是获取租约信息和租约附带的键的命令:

$ etcdctl lease timetolive --keys 694d5765fc71500b
lease 694d5765fc71500b granted with TTL(500s), remaining(132s), attached keys([zoo2 zoo1])

# 如果租约已经过期或者不存在,它将给出下面的应答:
Error:  etcdserver: requested lease not found

grpc 网关(grpc-gateway)

  • etcd v3 使用 gRPC 作为它的消息协议。etcd 项目包括基于 gRPC 的 Go client 和 命令行工具 etcdctl,通过 gRPC 和 etcd 集群通讯。对于不支持 gRPC 支持的语言,etcd 提供 JSON 的 grpc-gateway。这个网关提供 RESTful 代理,翻译 HTTP/JSON 请求为 gRPC 消息。

  • keyvalue 字段被定义为 byte 数组,因此必须在 JSON 中以 base64 编码。

查看版本

curl http://172.17.0.2:2380/version

写入和获取键

使用 v3/kv/rangev3/kv/put 服务来读取和写入键:

# https://www.base64encode.org/
# Zm9v 就是foo 经过based64编码得来的
# YmFy 也是bar 经过based64编码得来的


curl http://localhost:2379/v3/kv/put -d '{"key": "Zm9v", "value": "YmFy"}'

返回:{"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"5","raft_term":"8"}}

curl http://localhost:2379/v3/kv/range -d '{"key": "Zm9v"}'

返回:{"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"5","raft_term":"8"},"kvs":[{"key":"Zm9v","create_revision":"3","mod_revision":"5","version":"3","value":"YmFy"}],"count":"1"}

观察键

curl http://localhost:2379/v3/watch -d '{"create_request": {"key":"Zm9v"} }'


返回:{"result":{"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"5","raft_term":"8"},"created":true}}

事务

curl -L http://localhost:2379/v3/kv/txn \
    -X POST \
    -d '{"compare":[{"target":"CREATE","key":"Zm9v","createRevision":"2"}],"success":[{"requestPut":{"key":"Zm9v","value":"YmFy"}}]}'
    
返回:{"header":{"cluster_id":"14841639068965178418","member_id":"10276657743932975437","revision":"5","raft_term":"8"}}

核心API

KV 服务

service KV {  
    // 从键值存储中获取范围内的key.  
    rpc Range(RangeRequest) returns (RangeResponse) {}  
    // 放置给定key到键值存储.  
    // put请求增加键值存储的修订版本并在事件历史中生成一个事件.  
    rpc Put(PutRequest) returns (PutResponse) {}  
    // 从键值存储中删除给定范围。  
    // 删除请求增加键值存储的修订版本并在事件历史中为每个被删除的key生成一个删除事件.  
    rpc DeleteRange(DeleteRangeRequest) returns (DeleteRangeResponse) {}  
    // 在单个事务中处理多个请求。  
    // 一个 txn 请求增加键值存储的修订版本并为每个完成的请求生成带有相同修订版本的事件。  
    // 不容许在一个txn中多次修改同一个key.  
    rpc Txn(TxnRequest) returns (TxnResponse) {}  
    // 压缩在etcd键值存储中的事件历史。  
    // 键值存储应该定期压缩,否则事件历史会无限制的持续增长.  
    rpc Compact(CompactionRequest) returns (CompactionResponse) {}
}

watch 服务

service Watch {   
    // Watch 观察将要发生或者已经发生的事件。   
    // 输入和输出都是流;输入流用于创建和取消观察,而输出流发送事件。   
    // 一个观察 RPC 可以在一次性在多个key范围上观察,并为多个观察流化事件。   
    // 整个事件历史可以从最后压缩修订版本开始观察。  
    rpc Watch(stream WatchRequest) returns (stream WatchResponse) {}
}

Lease 服务

service Lease {  
    // LeaseGrant 创建一个租约,当服务器在给定 time to live 时间内没有接收到 keepAlive 时租约过期。  
    // 如果租约过期则所有附加在租约上的key将过期并被删除。  
    // 每个过期的key在事件历史中生成一个删除事件。  
    rpc LeaseGrant(LeaseGrantRequest) returns (LeaseGrantResponse) {}  
    // LeaseRevoke 撤销一个租约。  
    // 所有附加到租约的key将过期并被删除。  
    rpc LeaseRevoke(LeaseRevokeRequest) returns (LeaseRevokeResponse) {}  
    // LeaseKeepAlive 通过从客户端到服务器端的流化的 keep alive 请求和从服务器端到客户端的流化的 keep alive 应答来维持租约.  
    rpc LeaseKeepAlive(stream LeaseKeepAliveRequest) returns (stream LeaseKeepAliveResponse) {}  
    // LeaseTimeToLive 获取租约信息。  
    rpc LeaseTimeToLive(LeaseTimeToLiveRequest) returns (LeaseTimeToLiveResponse) {}
}

Lock 服务

// Lock service 以 gRPC 接口的方式暴露客户端锁机制。
service Lock {  
    // 在给定命令锁上获得分布式共享锁。  
    // 成功时,将返回一个唯一 key,在调用者持有锁期间会一直存在。  
    // 这个 key 可以和事务一起工作,以安全的确保对 etcd 的更新仅仅发生在持有锁时。  
    // 锁被持有直到在 key 上调用解锁或者和所有者关联的租约过期。  
    rpc Lock(LockRequest) returns (LockResponse) {} 
    // Unloke 使用 Lock 返回的 key 并释放对锁的持有。  
    // 下一个在等待这个锁的 Lock 的调用者将被唤醒并给予锁的所有权。  
    rpc Unlock(UnlockRequest) returns (UnlockResponse) {}
}

Election 服务

// Election service 以 gRPC 接口的方式暴露客户端选举机制。
service Election {  
    // Campaign 等待获得选举的领导地位,如果成功返回 LeaderKey 代表领导地位。  
    // 然后 LeaderKey 可以用来在选举时发起新的值,在依然持有领导地位时事务性的守护 API 请求,  
    // 还有从选举中辞职。  
    rpc Campaign(CampaignRequest) returns (CampaignResponse) {}  
    // Proclaim 用新值更新领导者的旧值  
    rpc Proclaim(ProclaimRequest) returns (ProclaimResponse) {}  
    // Leader 返回当前的选举公告,如果有。  
    rpc Leader(LeaderRequest) returns (LeaderResponse) {}  
    // Observe 以流的方式返回选举公告,和被选举的领导者发布的顺序一致。  
    rpc Observe(LeaderRequest) returns (stream LeaderResponse) {}  
    // Resign 放弃选举领导地位,以便其他参选人可以在选举中获得领导地位。  
    rpc Resign(ResignRequest) returns (ResignResponse) {}
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×