前面四篇文章也算是差不过针对etcd的store涉及到的核心内容作了说明,今天主要是对前面提供的剖析源码进行一个总结
1 架构

etcd
从etcd的架构图中我们可以看到,etcd主要分为四个部分。
HTTP Server: 用于处理用户发送的API请求以及其它etcd节点的同步与心跳信息请求。
Store:用于处理etcd支持的各类功能的事务,包括数据索引、节点状态变更、监控与反馈、事件处理与执行等等,是etcd对用户提供的大多数API功能的具体实现。
Raft:Raft强一致性算法的具体实现,是etcd的核心。
WAL:Write Ahead Log(预写式日志),是etcd的数据存储方式。除了在内存中存有所有数据的状态以及节点的索引以外,etcd就通过WAL进行持久化存储。WAL中,所有的数据提交前都会事先记录日志。Snapshot是为了防止数据过多而进行的状态快照;Entry表示存储的具体日志内容。
通常,一个用户的请求发送过来,会经由HTTP Server转发给Store进行具体的事务处理
如果涉及到节点的修改,则交给Raft模块进行状态的变更、日志的记录,然后再同步给别的etcd节点以确认数据提交
最后进行数据的提交,再次同步。
2 etcd概念词汇表
Raft:etcd所采用的保证分布式系统强一致性的算法。
Node:一个Raft状态机实例。
Member: 一个etcd实例。它管理着一个Node,并且可以为客户端请求提供服务。
Cluster:由多个Member构成可以协同工作的etcd集群。
Peer:对同一个etcd集群中另外一个Member的称呼。
Client: 向etcd集群发送HTTP请求的客户端。
WAL:预写式日志,etcd用于持久化存储的日志格式。
snapshot:etcd防止WAL文件过多而设置的快照,存储etcd数据状态。
Proxy:etcd的一种模式,为etcd集群提供反向代理服务。
Leader:Raft算法中通过竞选而产生的处理所有数据提交的节点。
Follower:竞选失败的节点作为Raft中的从属节点,为算法提供强一致性保证。
Candidate:当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始竞选。
Term:某个节点成为Leader到下一次竞选时间,称为一个Term。
Index:数据项编号。Raft中通过Term和Index来定位数据。
3 Store
Store这个模块顾名思义,就像一个商店把etcd已经准备好的各项底层支持加工起来,为用户提供五花八门的API支持,处理用户的各项请求。
要理解Store,只需要从etcd的API入手,接下来我们能够看到有如下API是对etcd存储的键值进行的操作,亦即Store提供的内容。
API中提到的目录(Directory)和键(Key),上文中也可能称为etcd节点(Node)。
为etcd存储的键赋值
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: 进行的动作名称。
node.key: 请求的HTTP路径。etcd使用一个类似文件系统的方式来反映键值存储的内容。
node.value: 请求的键所存储的内容。
node.createdIndex: etcd节点每次有变化时都会自增的一个值,除了用户请求外,etcd内部运行(如启动、集群信息变化等)也会对节点有变动而引起这个值的变化。
node.modifiedIndex: 类似node.createdIndex,能引起modifiedIndex变化的操作包括set, delete, update, create, compareAndSwap and compareAndDelete。
查询etcd某个键存储的值
curl http://127.0.0.1:2379/v2/keys/message
修改键值:与创建新值几乎相同,但是反馈时会有一个
prevNode
值反应了修改前存储的内容。
curl http://127.0.0.1:2379/v2/keys/message -XPUT -d value="Hello etcd"
删除一个值
curl http://127.0.0.1:2379/v2/keys/message -XDELETE
对一个键进行定时删除:etcd中对键进行定时删除,设定一个TTL值,当这个值到期时键就会被删除。反馈的内容会给出expiration项告知超时时间,ttl项告知设定的时长。
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 value=bar -d ttl= -d prevExist=true
对键值修改进行监控:etcd提供的这个API让用户可以监控一个值或者递归式的监控一个目录及其子目录的值,当目录或值发生变化时,etcd会主动通知。
curl http://127.0.0.1:2379/v2/keys/foo?wait=true
对过去的键值操作进行查询:类似上面提到的监控,只不过监控时加上了过去某次修改的索引编号,就可以查询历史操作。默认可查询的历史记录为1000条。
curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=7'
自动在目录下创建有序键。在对创建的目录使用
POST
参数,会自动在该目录下创建一个以createdIndex值为键的值,这样就相当于以创建时间先后严格排序了。这个API对分布式队列这类场景非常有用。
curl http://127.0.0.1:2379/v2/keys/queue -XPOST -d value=Job1{ "action": "create", "node": { "createdIndex": 6, "key": "/queue/6", "modifiedIndex": 6, "value": "Job1" } }
按顺序列出所有创建的有序键。
curl -s 'http://127.0.0.1:2379/v2/keys/queue?recursive=true&sorted=true'
创建定时删除的目录:就跟定时删除某个键类似。如果目录因为超时被删除了,其下的所有内容也自动超时删除。
curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d ttl=30 -d dir=true
刷新超时时间
curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d ttl=30 -d dir=true -d prevExist=true
自动化CAS(Compare-and-Swap)操作:etcd强一致性最直观的表现就是这个API,通过设定条件,阻止节点二次创建或修改。即用户的指令被执行当且仅当CAS的条件成立。条件有以下几个。
curl http://127.0.0.1:2379/v2/keys/foo -XPUT -d value=one然后再进行操作:
curl http://127.0.0.1:2379/v2/keys/foo?prevExist=false -XPUT -d value=threeprevValue 先前节点的值,如果值与提供的值相同才允许操作。
prevIndex 先前节点的编号,编号与提供的校验编号相同才允许操作。
prevExist 先前节点是否存在。如果存在则不允许操作。这个常常被用于分布式锁的唯一获取。
假设先进行了如下操作:设定了foo的值。条件删除(Compare-and-Delete):与CAS类似,条件成立后才能删除。
就会返回创建失败的错误。
curl http://127.0.0.1:2379/v2/keys/dir -XPUT -d dir=true
创建目录
curl http://127.0.0.1:2379/v2/keys/
列出目录下所有的节点信息,最后以
/
结尾。还可以通过recursive参数递归列出所有子目录信息。
curl http://127.0.0.1:2379/v2/keys/
删除目录:默认情况下只允许删除空目录,如果要删除有内容的目录需要加上
recursive=true
参数。
curl 'http://127.0.0.1:2379/v2/keys/foo_dir?dir=true' -XDELETE
创建一个隐藏节点:命名时名字以下划线
_
开头默认就是隐藏键。
curl http://127.0.0.1:2379/v2/keys/_message -XPUT -d value="Hello hidden world"
基本上述这些API的使用,基本上对Store的工作内容基本了解了。
它对etcd下存储的数据进行加工,创建出如文件系统般的树状结构供用户快速查询。
它有一个Watcher
用于节点变更的实时反馈,还需要维护一个WatcherHub
对所有Watcher
订阅者进行通知的推送。
同时,它还维护了一个由定时键构成的小顶堆,快速返回下一个要超时的键。
最后,所有这些API的请求都以事件的形式存储在事件队列中等待处理。
关于watch【关于这部分先简单介绍下,后面会有专门的文章介绍】
先上个简单的watch流程吧

watch
etcd会保存每个客户端发来的watch请求,watch请求可以关注一个key(单key),或者一个key前缀(区间)。
etcd会有一个协程持续不断的遍历所有的watch请求,每个watch对象都维护了其watch的key事件推送到了哪个revision。




