通过etcd v2 API的HTTP+JSON,很方便的用curl来调用etcd v2 API,有如下的内容:
- 集群管理API
一、集群管理API
1、查看版本
[root@localhost etcd-v3.3.10-linux-amd64]# curl -L http://127.0.0.1:2379/version {"etcdserver":"3.3.10","etcdcluster":"3.3.0"}
2、集群状态
# 返回true则是健康的 [root@localhost etcd-v3.3.10-linux-amd64]# curl -L http://127.0.0.1:2379/health {"health":"true"}
3、leader数据
etcd的集群可以获取整个集群的:
- 节点时延信息
- 失败/成功的RPC请求次数
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/stats/leader { "leader": "57bf4d2527966724", "followers": { "4c14bc06668e9505": { "latency": { "current": 0.001479, "average": 0.003306272727272727, "standardDeviation": 0.0017684453414284075, "minimum": 0.000948, "maximum": 0.006036 }, "counts": { "fail": 0, "success": 11 } }, "a11e107c0081dbf8": { "latency": { "current": 0.001337, "average": 0.0033447999999999999, "standardDeviation": 0.0036313811091649415, "minimum": 0.00096, "maximum": 0.011139 }, "counts": { "fail": 0, "success": 10 } } } }
4、节点自身数据
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/stats/self { "name": "etcd2", "id": "57bf4d2527966724", "state": "StateLeader", "startTime": "2021-02-14T08:28:31.154812422+08:00", "leaderInfo": { "leader": "57bf4d2527966724", "uptime": "4h55m26.902989917s", "startTime": "2021-02-14T11:23:54.355889296+08:00" }, "recvAppendRequestCnt": 391, "sendAppendRequestCnt": 21 }
其中:
- name 该节点的name
- id 该节点的唯一标识
- state 该节点是否是leader
- startTime 该etcdServer启动时间
- leaderInfo.leader 集群当前leader的id
- leaderInfo.uptime 集群当前leade的在任时长
- leaderInfo.startTime 集群当前leade的启动时间
- recvAppendRequestCnt 该节点已处理的append请求数
- sendAppendRequestCnt 该节点已发送的append请求数
5、数据统计
etcd集群中全部节点都会记录修改存储的状态,比如,增加、修改、删除等状态,通过以下API可以获取其计数:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/stats/store { "getsSuccess": 27, "getsFail": 33, "setsSuccess": 44, "setsFail": 0, "deleteSuccess": 1, "deleteFail": 0, "updateSuccess": 1, "updateFail": 0, "createSuccess": 6, "createFail": 1, "compareAndSwapSuccess": 0, "compareAndSwapFail": 0, "compareAndDeleteSuccess": 1, "compareAndDeleteFail": 0, "expireCount": 2, "watchers": 0 }
二、写、读、改、删除
etcd v2的键一般位于路径"v2/keys"路径下,例如,message这个键的完整路径是“/v2/keys/message”,那么如何通过API的形式实现呢?
1、写
[root@localhost etcd-v3.3.10-linux-amd64]# curl -L http://127.0.0.1:2379/v2/keys/message -XPUT -d value="hello" {
"action":"set",
"node":{
"key":"/message",
"value":"hello",
"modifiedIndex":19,
"createdIndex":19
}
}
在返回的json数据中,其中action表示请求的动作是set。在v2 API中创建键值或者更新键值使用的都是PUT方法。 在node中,node.key是需要设置的键;node.value是需要设置的值;对etcd来说,每次创建一个键值都会产生一个唯一的createdIndex,第一个key的createdIndex是2而非1;任何更改行为(create、delete、set)都会更该modifiedIndex的值。
2、读
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message { "action": "get", "node": { "key": "/message", "value": "hello", "modifiedIndex": 19, "createdIndex": 19 } }
3、改
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message -XPUT -d value="message1" { "action": "set", "node": { "key": "/message", "value": "message1", "modifiedIndex": 23, "createdIndex": 23 }, "prevNode": { "key": "/message", "value": "hello", "modifiedIndex": 19, "createdIndex": 19 } }
可以看到更改之前的key会多返回一个字段prevNode信息,这是之前存储的key信息。
4、删除
{ "action": "delete", "node": { "key": "/message", "modifiedIndex": 24, "createdIndex": 23 }, "prevNode": { "key": "/message", "value": "message1", "modifiedIndex": 23, "createdIndex": 23 } }
删除键值,它会将之前修改过的记录全部返回。
三、TTL
etcd的键可以通过TTL设置过期时间,一旦过了设置的时间,键就会被自动删掉。
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1 -XPUT -d value="hello" -d ttl=20 { "action": "set", "node": { "key": "/message1", "value": "hello", "expiration": "2021-02-14T02:12:27.005370199Z", "ttl": 20, "modifiedIndex": 25, "createdIndex": 25 } }
上述的返回值中node.expiration表示在该时刻这个键会过期,ttl表示还有多少秒会过期,一旦到期会自动删除该键。如下:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1 { "errorCode": 100, "message": "Key not found", "cause": "/message1", "index": 26 }
当然你可以接着刷新ttl:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1 -XPUT -d value="hello" -d ttl=20 -d prevExit=true { "action": "set", "node": { "key": "/message1", "value": "hello", "expiration": "2021-02-14T02:18:48.300233144Z", "ttl": 20, "modifiedIndex": 28, "createdIndex": 28 }, "prevNode": { "key": "/message1", "value": "hello", "expiration": "2021-02-14T02:18:29.321723784Z", "ttl": 2, "modifiedIndex": 27, "createdIndex": 27 } }
四、观察者(watch)
watch是观察一个key并且等待接收消息,它有以下内容:
- watch一个key
- 带索引的watch
- stream watch
1、watch一个key
在一个终端中发起一个get请求,并且设置参数wait=true:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1?wait=true
此时,会一直阻塞在这里。
接着,再另起一个终端,进行key的更新:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1 -XPUT -d value="hello1" { "action": "set", "node": { "key": "/message1", "value": "hello1", "modifiedIndex": 30, "createdIndex": 30 } }
在第一个终端中就能观察这个key的变化:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1?wait=true { "action": "set", "node": { "key": "/message1", "value": "hello1", "modifiedIndex": 30, "createdIndex": 30 } }
一旦监听到key的变化就会退出,这就是“一次性watch”。
2、带索引的watch
带索引的watch可以观察到历史记录,保证信息的不丢失,上述的watch只是watch当前及以后的发生事件。其步骤如下:
- 获取key当前的状态
- 从key当前的modiifiedIndex+1开始watch
获取key当前状态:
[root@localhost ~]# curl -i http://127.0.0.1:2379/v2/keys/message1 HTTP/1.1 200 OK Content-Type: application/json X-Etcd-Cluster-Id: 735c420e06827765 X-Etcd-Index: 30 X-Raft-Index: 216 X-Raft-Term: 59 Date: Sun, 14 Feb 2021 02:51:36 GMT Content-Length: 98 { "action": "get", "node": { "key": "/message1", "value": "hello1", "modifiedIndex": 30, "createdIndex": 30 } }
此时可以从31及以后的位置开始watch,比如33:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/message1?wait=true &waitIndex=33
此时,只要等到这个key的modifiedIndex的值等于33是才会有响应。
3、stream watch
也被称为持久化watch,也就是客户端保持长链接,中途不会因为监控到变化有返回值而中断链接。只需要在请求参数中添加stream=true即可:
[root@localhost ~]# curl http://127.0.0.1:2379/v2/keys/message1?wait=true&stream=true
stream watch即使收到事件也不会退出;“一次性watch”只要收到事件就会退出,然后再重新发起watch。不过stream watch它是持续watch当前及以后的事件,历史事件也是无能为力。
五、原子操作
原子操作包括:
- CAS
- CAD
1、CAS(Compare And Swap)
先比较客户端与所提供的条件是否一样,如果不一样就进行交换,CAS的比较条件包括:
- prevValue 检查key之前的value
- prevIndex 检查key之前的modifiedIndex
- prevExist 检查key是否存在,如果存在是一个更新操作,如果不存在是一个新建操作
新建一个键值对:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/msg -XPUT -d value="val" { "action": "set", "node": { "key": "/msg", "value": "val", "modifiedIndex": 53, "createdIndex": 53 } }
prevExist的使用:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/msg?prevExist=false -XPUT -d value="val1" { "errorCode": 105, "message": "Key already exists", "cause": "/msg", "index": 53 }
显然这个key已经存在了,现在参数是false,所以会报错。正确的是参数传递true:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/msg?prevExist=true -XPUT -d value="val1" { "action": "update", "node": { "key": "/msg", "value": "val1", "modifiedIndex": 54, "createdIndex": 53 }, "prevNode": { "key": "/msg", "value": "val", "modifiedIndex": 53, "createdIndex": 53 } }
prevValue与prevIndex的用法相似。
2、CAD(Compare And Delete)
先比较客户端与所提供的条件是否一样,如果一样就删除对应的key,CAD的比较条件包括:
- prevValue 检查key之前的value
- prevIndex 检查key之前的modifiedIndex
使用之前的msg键值:
[root@localhost ~]# curl -L http://127.0.0.1:2379/v2/keys/msg?prevValue=val1 -XDELETE { "action": "compareAndDelete", "node": { "key": "/msg", "modifiedIndex": 55, "createdIndex": 53 }, "prevNode": { "key": "/msg", "value": "val1", "modifiedIndex": 54, "createdIndex": 53 } }
prevIndex用法与之类似。