Etcd的使用

在正常运行的状态下,集群中会有一个leader,其余的member都是followers。leader向 followers 同步日志,保证数据在各个member都有副本。leader还会定时向所有的 member 发送心跳报文,如果在规定的时间里 follower 没有收到心跳,就会重新进行选举

客户端所有的请求都会先发送给leader,leader 向所有的 followers 同步日志,等收到超过半数的确认后就把该日志存储到磁盘,并返回响应客户端。

每个 etcd 服务有三大主要部分组成:raft 实现、WAL 日志存储、数据的存储和索引。WAL 会在本地磁盘(就是之前提到的 —data-dir)上存储日志内容(wal file)和快照(snapshot)。 etcdctl是一个客户端,它能提供一些简洁的命令,供用户直接跟etcd服务打交道,而无需基于 HTTP API方式。可以方便我们在对服务进行测试或者手动修改数据库内容。

命令选项详细:

  1. --debug 输出CURL命令,显示执行命令的时候发起的请求
  2. --no-sync 发出请求之前不同步集群信息
  3. --output, -o 'simple' 输出内容的格式(simple 为原始信息,json 为进行json格式解码,易读性好一些)
  4. --peers, -C 指定集群中的同伴信息,用逗号隔开(默认为: "127.0.0.1:4001")
  5. --cert-file HTTPS下客户端使用的SSL证书文件
  6. --key-file HTTPS下客户端使用的SSL密钥文件
  7. --ca-file 服务端使用HTTPS时,使用CA文件进行验证
  8. --help, -h 显示帮助命令信息
  9. --version, -v 打印版本信息
  • etcdctl 命令行工具 ```bash

    设置一个 key 的值

获取 key 的值

./etcdctl get /message use, etcd

获取 key 的值,包含更详细的元数据

./etcdctl -o extended get /message Key: /message Created-Index: 1073 Modified-Index: 1073 TTL: 0 Index: 1073

use, etcd

获取不存在 key 的值,会报错

./etcdctl get /notexist Error: 100: Key not found (/notexist) [1048]

设置 key 的 ttl,过期后会被自动删除

./etcdctl set /tempkey “fly with wind” —ttl 5 gone with wind ./etcdctl get /tempkey gone with wind ./etcdctl get /tempkey Error: 100: Key not found (/tempkey) [1050]

如果 key 的值是 “use, etcd”,就把它替换为 “goodbye, etcd”

./etcdctl set —swap-with-value “use, world” /message “goodbye, etcd” Error: 101: Compare failed ([use, world != use, etcd]) [48]

./etcdctl set —swap-with-value “use, etcd” /message “goodbye, etcd” goodbye, etcd

仅当 key 不存在的时候创建

./etcdctl mk /foo bar bar ./etcdctl mk /foo bar Error: 105: Key already exists (/foo) [1052]

自动创建排序的 key

更新 key 的值或者 ttl,只有当 key 已经存在的时候才会生效,否则报错

./etcdctl update /message “etcd changed” etcd changed

./etcdctl get /message etcd changed

./etcdctl update /notexist “etcd changed” Error: 100: Key not found (/notexist) [1055]

./etcdctl update —ttl 3 /message “etcd changed” etcd changed

./etcdctl get /message Error: 100: Key not found (/message) [1057]

删除某个 key

./etcdctl mk /foo bar bar

./etcdctl rm /foo PrevNode.Value: bar

./etcdctl get /foo Error: 100: Key not found (/foo) [1062]

只有当 key 的值匹配的时候,才进行删除

./etcdctl mk /foo bar bar ./etcdctl rm —with-value wrong /foo Error: 101: Compare failed ([wrong != bar]) [1063] ./etcdctl rm —with-value bar /foo

创建一个目录

删除空目录

./etcdctl mkdir /dir/subdir/ ./etcdctl rmdir /dir/subdir/

删除非空目录

./etcdctl rmdir /dir Error: 108: Directory not empty (/dir) [1071] ./etcdctl rm —recursive /dir

列出目录的内容

递归列出目录的内容

./etcdctl ls —recursive / /anotherdir /message /queue /queue/00000000000000001053 /queue/00000000000000001054

监听某个 key,当 key 改变的时候会打印出变化

./etcdctl watch /message changed

监听某个目录,当目录中任何 node 改变的时候,都会打印出来

./etcdctl watch —recursive / [set] /message changed

一直监听,除非 CTL + C 导致退出监听

./etcdctl watch —forever /message new value chaned again Wola

监听目录,并在发生变化的时候执行一个命令

./etcdctl exec-watch —recursive / — sh -c “echo change detected.” change detected. change detected. ```

etcd过HTTP API对外提供服务,这种方式非常方便测试(通过 curl 或者其他工具能实现etcd 交互),也很容易集成到各种语言中(每个语言封装 HTTP API 实现自己的 client 就行)。

HTTP/1.1 200 OK Content-Length: 44 Content-Type: application/json Date: Tue, 26 Jun 2018 05:43:30 GMT { “etcdcluster”: “3.1.0”, “etcdserver”: “3.1.0” }

  1. * key的增删查改
  2. etcd 的数据按照树形的结构组织,类似于 linux 的文件系统,也有目录和文件的区别,不过一般被称为 nodes。数据的 endpoint 都是以 /v2/keys 开头(v2 表示当前 API 的版本),比如 /v2/keys/names/elegance。如果要创建一个值,只要使用 PUT 方法在对应的 url endpoint设置就可以了。如果对应的 key 已经存在,PUT也会对key进行更新。
  3. ```bash
  4. > http PUT http://127.0.0.1:2379/v2/keys/message value=="Etcd"
  5. HTTP/1.1 201 Created
  6. Content-Length: 100
  7. Content-Type: application/json
  8. Date: Tue, 26 Jun 2018 05:45:28 GMT
  9. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  10. X-Etcd-Index: 27
  11. X-Raft-Index: 50
  12. X-Raft-Term: 24
  13. {
  14. "action": "set",
  15. "node": {
  16. "createdIndex": 27,
  17. "key": "/message",
  18. "modifiedIndex": 27,
  19. "value": "Etcd"
  20. }
  21. }

通过 PUT 方法把 /message 设置为use etcd。返回的格式中,其中的字段:

  • action:请求出发的动作,这里因为是新建一个 key 并设置它的值,所以是set。
  • node.key:key 的 HTTP 路。
  • node.value:请求处理之后,key 的值。
  • node.createdIndex: createdIndex 是一个递增的值,每次有 key 被创建的时候会增加。
  • node.modifiedIndex:同上,只不过每次有 key 被修改的时候增加。

除返回的 json 体外,上面的情况还包含了一些特殊的 HTTP 头部信息,这些信息说明了 etcd cluster 的一些情况。它们的具体含义如下:

  • X-Etcd-Index:当前 etcd 集群的 index.
  • X-Raft-Index:raft 集群的 index.
  • X-Raft-Term:raft 集群的任期,每次有 leader 选举的时候,这个值就会增加.

查看信息比较简单,使用 GET 方法,url 指向要查看的值就行:

  1. > http GET http://127.0.0.1:2379/v2/keys/message
  2. HTTP/1.1 200 OK
  3. Content-Length: 100
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 05:50:28 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 29
  8. X-Raft-Index: 52
  9. X-Raft-Term: 24
  10. {
  11. "action": "get",
  12. "node": {
  13. "createdIndex": 29,
  14. "key": "/message",
  15. "modifiedIndex": 29,
  16. "value": "use etcd"
  17. }
  18. }

这里的 action 变成了get,其他返回的值和上面的含义一样,略过不提。

使用PUT可用来更新key的值:

  1. > http PUT http://127.0.0.1:2379/v2/keys/message value=="changed etcd value"
  2. HTTP/1.1 200 OK
  3. Content-Length: 196
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 05:52:28 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 30
  8. X-Raft-Index: 53
  9. X-Raft-Term: 24
  10. {
  11. "action": "set",
  12. "node": {
  13. "createdIndex": 30,
  14. "key": "/message",
  15. "modifiedIndex": 30,
  16. "value": "changed etcd value"
  17. },
  18. "prevNode": {
  19. "createdIndex": 29,
  20. "key": "/message",
  21. "modifiedIndex": 29,
  22. "value": "use etcd"
  23. }
  24. }

这次和第一次执行PUT命令不同的是,返回中多了一个字段 prevNode,它保存着更新之前该key的信息。它的格式和node是一样的,如果之前没有这个信息,这个字段会被省略。

我们如果需要删除key可以通过DELETE方法,比如我们要删除上面创建的字段:

  1. > http DELETE http://127.0.0.1:2379/v2/keys/message
  2. HTTP/1.1 200 OK
  3. Content-Length: 179
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 05:54:36 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 31
  8. X-Raft-Index: 54
  9. X-Raft-Term: 24
  10. {
  11. "action": "delete",
  12. "node": {
  13. "createdIndex": 30,
  14. "key": "/message",
  15. "modifiedIndex": 31
  16. },
  17. "prevNode": {
  18. "createdIndex": 30,
  19. "key": "/message",
  20. "modifiedIndex": 30,
  21. "value": "changed etcd value"
  22. }
  23. }

注意:这里的 action是delete,并且modifiedIndex增加了,但是createdIndex没有变化,因为这里是一个修改操作,而不是新建操作。

  • Time To Live(生存时间值)

在etcd中,key可以有TTL属性,超过这个时间会被自动删除。

  1. > http PUT http://127.0.0.1:2379/v2/keys/tempkey value=="Traveling Light" ttl==5
  2. HTTP/1.1 201 Created
  3. Content-Length: 160
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 05:59:00 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 32
  8. X-Raft-Index: 55
  9. X-Raft-Term: 24
  10. {
  11. "action": "set",
  12. "node": {
  13. "createdIndex": 32,
  14. "expiration": "2018-06-26T05:59:05.682833507Z",
  15. "key": "/tempkey",
  16. "modifiedIndex": 32,
  17. "value": "Traveling Light"
  18. }
  19. }

除了key返回的信息之外,上面多了两个字段:

  • expiration:代表 key 过期被删除的时间.
  • ttl:表示 key 还要多少秒可以存活(这个值是动态的,会根据你请求的时候和过期时间进行计算).

如果我们在 5s 之后再去请求查看该 key,会发现报错信息:

http 返回为 404,并且返回体中给出了 errorCode 和错误信息。TTL也可通过 PUT 方法进行取消,只要设置空值 ttl= 就行,这样key就不会过期被删除。比如:

  1. > http PUT http://127.0.0.1:2379/v2/keys/foo value==bar ttl== prevExist==true

注意:需要设置 value==bar,不然 key 会变成空值。

  • 监听变化

监听动作只需要 GET 方法,添加上 wait=true 参数就行.使用 recursive=true 参数,也能监听某个目录。

  1. http http://127.0.0.1:2379/v2/keys/foo wait==true
  2. HTTP/1.1 200 OK
  3. Content-Type: application/json
  4. Date: Tue, 26 Jun 2018 06:06:06 GMT
  5. Transfer-Encoding: chunked
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 34
  8. X-Raft-Index: 68
  9. X-Raft-Term: 24

这个时候,客户端会阻塞在这里,如果在另外的 terminal 修改 key 的值,监听的客户端会接收到消息,打印出更新的值:

  1. {
  2. "node": {
  3. "createdIndex": 35,
  4. "key": "/tempkey",
  5. "modifiedIndex": 35,
  6. "value": "Traveling Light"
  7. },
  8. "prevNode": {
  9. "createdIndex": 34,
  10. "key": "/tempkey",
  11. "modifiedIndex": 34,
  12. "value": ""
  13. }
  14. }

除了这种最简单的监听之外,还可以提供基于index的监听。如果通过 waitIndex 指定了index,那么会返回从 index 开始出现的第一个事件,这包含了两种情况:

  • 当给出的 index 小于等于当前 index ,即事件已经发生,那么监听会立即返回该事件.
  • 当给出的 index 大于当前 index,等待 index 之后的事件发生并返回.

目前 etcd 只会保存最近 1000 个事件(整个集群范围内),再早之前的事件会被清理,如果监听被清理的事件会报错。如果出现漏过太多事件(超过 1000)的情况,需要重新获取当然的 index 值(X-Etcd-Index),然后从 X-Etcd-Index+1 开始监听。

监听的时候出现事件就会直接返回,因此需要客户端编写循环逻辑保持监听状态。在两次监听的间隔中出现的事件,很可能被漏过。所以最好把事件处逻辑做成异步的,不要阻塞监听逻辑。

注意:监听 key 时会出现因为长时间没有返回导致连接被 close 的情况,客户端需要处理这种错误并自动重试

  • 自动创建有序的 keys

通常情况下我们需要的key是有序的,etcd 提供了这个功能。对某个目录使用 POST 方法,能自动生成有序的 key,这种模式可以用于队列处理等场景。

  1. > http POST http://127.0.0.1:2379/v2/keys/queue value==enterprise
  2. HTTP/1.1 201 Created
  3. Content-Length: 123
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 06:22:23 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 36
  8. X-Raft-Index: 70
  9. X-Raft-Term: 24
  10. {
  11. "action": "create",
  12. "node": {
  13. "createdIndex": 36,
  14. "key": "/queue/00000000000000000036",
  15. "modifiedIndex": 36,
  16. "value": "enterprise"
  17. }
  18. }

创建的 key 会使用 etcd index,只能保证递增,无法保证是连续的(因为两次创建之间可能会有其他发生)。然后用相同的命令创建多个值,在获取值的时候使用 sorted=true参数就会返回已经排序的值:

  1. > http http://127.0.0.1:2379/v2/keys/queue sorted==true
  2. HTTP/1.1 200 OK
  3. Content-Length: 389
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 06:25:14 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 38
  8. X-Raft-Index: 72
  9. X-Raft-Term: 24
  10. {
  11. "action": "get",
  12. "node": {
  13. "createdIndex": 36,
  14. "dir": true,
  15. "key": "/queue",
  16. "modifiedIndex": 36,
  17. "nodes": [
  18. {
  19. "createdIndex": 36,
  20. "key": "/queue/00000000000000000036",
  21. "modifiedIndex": 36,
  22. "value": "enterprise"
  23. },
  24. {
  25. "createdIndex": 37,
  26. "key": "/queue/00000000000000000037",
  27. "modifiedIndex": 37,
  28. "value": "enterprise1"
  29. },
  30. {
  31. "createdIndex": 38,
  32. "key": "/queue/00000000000000000038",
  33. "modifiedIndex": 38,
  34. "value": "enterprise2"
  35. }
  36. ]
  37. }
  38. }
  • 设置目录的 TTL 和key类似,目录(dir)也可以有过期时间。设置的方法也一样,用dir=true 参数来说明这是一个目录。 ```bash

{ “action”: “update”, “node”: { “createdIndex”: 36, “dir”: true, “expiration”: “2018-06-26T06:28:08.835276191Z”, “key”: “/queue”, “modifiedIndex”: 39, “ttl”: 5 }, “prevNode”: { “createdIndex”: 36, “dir”: true, “key”: “/queue”, “modifiedIndex”: 36 } }

  1. 目录过期的时候会被自动删除,包括它里面所有的子目录和 key,所有监听这个目录中内容的客户端都会收到对应的事件.
  2. * 比较更新的原子操作
  3. 在分布式环境中,我们需要解决多个客户端的竞争问题,etcd 提供了原子操作 CompareAndSwapCAS),通过这个操作可以很容易实现分布式锁。
  4. 这个命令只有在客户端提供的条件成立的情况下才会更新对应的值。目前支持的条件包括:
  5. * preValue:检查 key 之前的值是否和客户端提供的一致.
  6. * prevIndex:检查 key 之前的 modifiedIndex 是否和客户端提供的一致.
  7. * prevExist:检查 key 是否已经存在。如果存在就执行更新操作,如果不存在,执行 create 操作.
  8. 比如目前/queue的值为 bar,要把它更新成 changed,可以使用:
  9. ```bash
  10. http PUT http://127.0.0.1:2379/v2/keys/foo prevValue==bar value==changed

注意:匹配条件是 prevIndex=0 的话,也会通过检查。这些条件也可以组合起来使用,只有当都满足的时候,才会执行对应的操作

  • 比较删除的原子操作

和条件更新类似,etcd 也支持条件删除操作:只有在客户端提供的条件成立的情况下,才会执行删除操作。支持 prevValue 和 prevIndex 两种条件检查,没有 prevExist,因为删除不存在的值本身就会报错。

  • 操作目录

在创建 key 的时候,如果它所在路径的目录不存在,会自动被创建,所以在多数情况下我们不需要关心目录的创建。目录的操作和 key 的操作基本一致,唯一的区别是需要加上 dir=true 参数指明操作的对象是目录。

比如,如果想要显示地创建目录,可以使用PUT方法,并设置dir=true:

创建目录的操作不能重复执行,再次执行上面的命令会报 HTTP 403 错误。 如果 GET 方法对应的 url 是目录的话,etcd 会列出该目录所有节点的信息(不需要指定 dir=true)。比如要列出根目录下所有的节点:

  1. > http http://127.0.0.1:2379/v2/keys/
  2. HTTP/1.1 200 OK
  3. Content-Length: 408
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 06:54:19 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 46
  8. X-Raft-Index: 116
  9. X-Raft-Term: 24
  10. {
  11. "action": "get",
  12. "node": {
  13. "dir": true,
  14. "nodes": [
  15. {
  16. "createdIndex": 35,
  17. "key": "/tempkey",
  18. "modifiedIndex": 35,
  19. "value": "Traveling Light"
  20. },
  21. {
  22. "createdIndex": 41,
  23. "dir": true,
  24. "key": "/queue",
  25. "modifiedIndex": 41
  26. },
  27. {
  28. "createdIndex": 44,
  29. "dir": true,
  30. "key": "/foo",
  31. "modifiedIndex": 44
  32. },
  33. {
  34. "createdIndex": 46,
  35. "dir": true,
  36. "key": "/anotherdir",
  37. "modifiedIndex": 46
  38. },
  39. {
  40. "createdIndex": 26,
  41. "key": "/testkey",
  42. "modifiedIndex": 26,
  43. "value": "first use etcd"
  44. ]
  45. }
  46. }

如果添加上 recursive=true 参数,就会递归地列出所有的值:

  1. > http http://127.0.0.1:2379/v2/keys/\?recursive\=true
  2. HTTP/1.1 200 OK
  3. Content-Length: 891
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 06:55:03 GMT
  6. X-Etcd-Index: 46
  7. X-Raft-Index: 116
  8. X-Raft-Term: 24
  9. {
  10. "action": "get",
  11. "node": {
  12. "dir": true,
  13. "nodes": [
  14. {
  15. "createdIndex": 26,
  16. "key": "/testkey",
  17. "modifiedIndex": 26,
  18. "value": "first use etcd"
  19. },
  20. {
  21. "createdIndex": 35,
  22. "key": "/tempkey",
  23. "modifiedIndex": 35,
  24. "value": "Traveling Light"
  25. },
  26. {
  27. "createdIndex": 41,
  28. "dir": true,
  29. "key": "/queue",
  30. "modifiedIndex": 41,
  31. "nodes": [
  32. {
  33. "createdIndex": 42,
  34. "key": "/queue/00000000000000000042",
  35. "modifiedIndex": 42,
  36. "value": "enterprise"
  37. },
  38. {
  39. "createdIndex": 43,
  40. "key": "/queue/00000000000000000043",
  41. "modifiedIndex": 43,
  42. "value": "enterprise1"
  43. },
  44. {
  45. "createdIndex": 41,
  46. "key": "/queue/00000000000000000041",
  47. "modifiedIndex": 41,
  48. "value": "enterprise"
  49. }
  50. ]
  51. },
  52. {
  53. "createdIndex": 44,
  54. "dir": true,
  55. "key": "/foo",
  56. "modifiedIndex": 44,
  57. "nodes": [
  58. {
  59. "createdIndex": 44,
  60. "key": "/foo/00000000000000000044",
  61. "modifiedIndex": 44,
  62. "value": "bar"
  63. },
  64. {
  65. "createdIndex": 45,
  66. "key": "/foo/00000000000000000045",
  67. "modifiedIndex": 45,
  68. "value": "new"
  69. }
  70. ]
  71. },
  72. {
  73. "createdIndex": 46,
  74. "dir": true,
  75. "key": "/anotherdir",
  76. "modifiedIndex": 46
  77. }
  78. ]
  79. }
  80. }

和linux删除目录的设计一样,要区别空目录和非空目录。删除空目录很简单,使用DELETE方法,并添加上 dir=true 参数,类似于 rmdir;而对于非空目录,需要添加上 recursive=true,类似于 rm -rf。

  1. > http DELETE http://127.0.0.1:2379/v2/keys/queue dir==true
  2. HTTP/1.1 403 Forbidden
  3. Content-Length: 78
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 06:55:52 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. X-Etcd-Index: 46
  8. {
  9. "cause": "/queue",
  10. "errorCode": 108,
  11. "index": 46,
  12. "message": "Directory not empty"
  13. }
  14. > http DELETE http://127.0.0.1:2379/v2/keys/queue dir==true recursive==true
  15. HTTP/1.1 200 OK
  16. Content-Length: 168
  17. Content-Type: application/json
  18. Date: Tue, 26 Jun 2018 06:56:29 GMT
  19. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  20. X-Etcd-Index: 47
  21. X-Raft-Index: 118
  22. X-Raft-Term: 24
  23. {
  24. "action": "delete",
  25. "node": {
  26. "createdIndex": 41,
  27. "dir": true,
  28. "key": "/queue",
  29. "modifiedIndex": 47
  30. },
  31. "prevNode": {
  32. "createdIndex": 41,
  33. "dir": true,
  34. "key": "/queue",
  35. "modifiedIndex": 41
  36. }
  37. }
  • 隐藏的节点

etcd 中节点也可以是默认隐藏的,类似于 linux 中以 . 开头的文件或者文件夹,以 _ 开头的节点也是默认隐藏的,不会在列出目录的时候显示。只有知道隐藏节点的完整路径,才能够访问它的信息.

  • 查看集群数据信息 etcd 还保存了集群的数据信息,包括节点之间的网络信息,操作的统计信息。
  1. /v2/stats/leader会返回集群中 leader 的信息,以及 followers 的基本信息。

  2. /v2/stats/self 会返回当前节点的信息。

  3. /v2/state/store:会返回各种命令的统计信息。

  • 成员管理

etcd 在 /v2/members 下保存着集群中各个成员的信息

  1. > http http://127.0.0.1:2379/v2/members
  2. HTTP/1.1 200 OK
  3. Content-Length: 133
  4. Content-Type: application/json
  5. Date: Tue, 26 Jun 2018 07:01:08 GMT
  6. X-Etcd-Cluster-Id: 9bfa9b14e11989b1
  7. {
  8. "members": [
  9. {
  10. "clientURLs": [
  11. "http://localhost:2379"
  12. ],
  13. "id": "65388a54a71622c7",
  14. "name": "keke",
  15. "peerURLs": [
  16. "http://172.16.2.201:2380"
  17. ]
  18. }
  19. ]
  20. }

可以通过 POST 方法添加成员:

  1. curl http://10.0.0.10:2379/v2/members -XPOST \
  2. -H "Content-Type: application/json" -d '{"jame":["http://10.0.0.10:2380"]}

也可以通过 DELETE 方法删除成员: