Etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现。etcd是由CoreOS开发并维护的,灵感来自于 ZooKeeper 和 Doozer,它使用Go语言编写,并通过Raft一致性算法处理日志复制以保证强一致性。Raft是一个来自Stanford的新的一致性算法,适用于分布式系统的日志复制,Raft通过选举的方式来实现一致性,在Raft中,任何一个节点都可能成为Leader。Google的容器集群管理系统Kubernetes、开源PaaS平台Cloud Foundry和CoreOS的Fleet都广泛使用了etcd。
CoreOS是一个基于Docker的轻量级容器化Linux发行版,专为大型数据中心而设计,旨在通过轻量的系统架构和灵活的应用程序部署能力简化数据中心的维护成本和复杂度,如果说Docker是下一代的虚拟机,那CoreOS就应该是下一代的服务器Linux。
安装:
brew install etdc
单机运行etcd:
./bin/etcd
启动后etcd会监听两个端口:
- 2379: 客户端通信。
- 2380: 服务器通信。
获取etcd版本号:
curl -L http://127.0.0.1:2379/version
curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello world"
{
"action": "set",
"node": {
"createdIndex": 2,
"key": "/message",
"modifiedIndex": 2,
"value": "Hello world"
}
}
- action: 刚才执行的动作,因为是设置值,所以是
set
- node.key: http path将对应为key。
/message
- node.value: key对应的值。
- node.createdIndex: 这个index是一个唯一的,单调递增的数字,由etcd内部维护,你可以注意到这明明使我们第一次操作,但是这个值是2,因为有很多后台命令会使用它,比如增加一个服务器。
- node.modifiedIndex: 每一次修改都会递增这个值,有这些修改行为: set, delete, update, create, compareAndSwap and compareAndDelete。
Response Headers
etcd在http头里面涵盖一些内部信息:
X-Etcd-Index: 35
X-Raft-Index: 5398
X-Raft-Term: 1
- X-Etcd-Index : 当前的etcd_index(上面的node.createdIndex已经解释过)。
- X-Raft-Index : 类似Etcd-Index,具体不详。
- X-Raft-Term : 当发生leader选举时这个值会自增,如果这个值短时间跳动特别大,你也许需要调试这个选举超时参数。
curl http://127.0.0.1:2379/v2/keys/message
{
"action": "get",
"node": {
"createdIndex": 2,
"key": "/message",
"modifiedIndex": 2,
"value": "Hello world"
}
}
curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello etcd"
{
"action": "set",
"node": {
"createdIndex": 3,
"key": "/message",
"modifiedIndex": 3,
"value": "Hello etcd"
},
"prevNode": {
"createdIndex": 2,
"key": "/message",
"value": "Hello world",
"modifiedIndex": 2
}
}
curl http://127.0.0.1:2379/v2/keys/message -XDELETE
{
"action": "delete",
"node": {
"createdIndex": 3,
"key": "/message",
"modifiedIndex": 4
},
"prevNode": {
"key": "/message",
"value": "Hello etcd",
"modifiedIndex": 3,
"createdIndex": 3
}
}
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5
{
"action": "set",
"node": {
"createdIndex": 5,
"expiration": "2013-12-04T12:01:21.874888581-08:00",
"key": "/foo",
"modifiedIndex": 5,
"ttl": 5,
"value": "bar"
}
}
- expiration: 值的超时时间,超过这个时间后会被自动删除。
- TTL: 按秒计算的超时时间。
每一个Key只能被集群Leader超时,所以如果一个节点离开了集群,在它重新加入集群之前,它的key不会超时。
curl http://127.0.0.1:2379/v2/keys/foo
# 如果TTL超时,这个key将被删除,你将获得errorCode 100。
{
"cause": "/foo",
"errorCode": 100,
"index": 6,
"message": "Key not found"
}
TTL也可以通过update操作取消
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl= -d prevExist=true
{
"action": "update",
"node": {
"createdIndex": 5,
"key": "/foo",
"modifiedIndex": 6,
"value": "bar"
},
"prevNode": {
"createdIndex": 5,
"expiration": "2013-12-04T12:01:21.874888581-08:00",
"key": "/foo",
"modifiedIndex": 5,
"ttl": 3,
"value": "bar"
}
}
etcd中的key可以宰不通知当前的观察者的情况下被更新,需要设置refresh为true。
但是当你refresh这个key的时候,你不能更新它的value。
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d ttl=5 -d refresh=true -d prevExist=true
这样会重新更新这个key的ttl时间。
{
"action": "set",
"node": {
"createdIndex": 5,
"expiration": "2013-12-04T12:01:21.874888581-08:00",
"key": "/foo",
"modifiedIndex": 5,
"ttl": 5,
"value": "bar"
}
}
{
"action":"update",
"node":{
"key":"/foo",
"value":"bar",
"expiration": "2013-12-04T12:01:26.874888581-08:00",
"ttl":5,
"modifiedIndex":6,
"createdIndex":5
},
"prevNode":{
"key":"/foo",
"value":"bar",
"expiration":"2013-12-04T12:01:21.874888581-08:00",
"ttl":3,
"modifiedIndex":5,
"createdIndex":5
}
}
我们可以等待一个值的改变,包括该节点的子节点,只需要指定recursive=true
# 发送一个GET请求,加上参数wait=true,这个时候我们在等待这个key的任意修改。
curl http://127.0.0.1:2379/v2/keys/foo?wait=true
# 在另一个终端,我们么修改这个值
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=bar
当修改的时候,GET请求会返回。
{
"action": "set",
"node": {
"createdIndex": 7,
"key": "/foo",
"modifiedIndex": 7,
"value": "bar"
},
"prevNode": {
"createdIndex": 6,
"key": "/foo",
"modifiedIndex": 6,
"value": "bar"
}
}
实际上,watch还可以做更强大的事情,可以通过指定modifiedIndex
来等待:
curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=7'
只要modifiedIndex大于7,这个wait就可以得到返回。
etcd只在所有etcd节点中保存最近1000个事件,所以更推荐读取值后立刻返回而不是等待。