这两天抽了点时间研究了下现在比较火辣的etcd,网上很多的文章都是写etcd和docker的结合使用。 不说docker,咱们单独就etcd这个高可用键值来聊聊吧。
etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现。etcd是由CoreOS开发并维护的,灵感来自于 ZooKeeper 和 Doozer,它使用Go语言编写,并通过Raft一致性算法处理日志复制以保证强一致性。Raft是一个来自Stanford的新的一致性算法,适用于分布式系统的日志复制,Raft通过选举的方式来实现一致性,在Raft中,任何一个节点都可能成为Leader。
Google的容器集群管理系统Kubernetes、开源PaaS平台Cloud Foundry和CoreOS的Fleet都广泛使用了etcd。
在分布式系统中,如何管理节点间的状态一直是一个难题,etcd像是专门为集群环境的服务发现和注册而设计,它提供了数据TTL失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能,可以方便的跟踪并管理集群节点的状态。etcd目前的版本是0.4.5,虽然未发布1.0版本(今年会发布),但其已经使用在多个生产系统中,可见其火热程度。etcd的特性如下:
简单: curl可访问的用户的API(HTTP+JSON)
安全: 可选的SSL客户端证书认证
快速: 单实例每秒 1000 次写操作
可靠: 使用Raft保证一致性
目前有很多支持etcd的库和工具,比如命令行客户端工具etcdctl、Go客户端go-etcd、Java客户端jetcd。
那么zookeeper和etcd的区别有什么方面 ?
在原生接口和提供服务方式方面,etcd更适合作为集群配置服务器,用来存储集群中的大量数据。方便的REST接口也可以让集群中的任意一个节点在使用Key/Value服务时获取方便。ZooKeeper则更加的适合于提供分布式协调服务,他在实现分布式锁模型方面较etcd要简单的多。所以在实际使用中应该根据自身使用情况来选择相应的服务。
我这里照着官网的例子揍一遍, 怎么用都感觉在用zookeeper的kazoo似的。
In [1]: import etcd In [2]: client = etcd.Client(host='127.0.0.1', port=4001) In [3]: client.write('/nodes/n1', 1) Out[3]: <class 'etcd.EtcdResult'>({'newKey': False, '_prev_node': <class 'etcd.EtcdResult'>({'newKey': False, '_children': [], 'createdIndex': 3, 'modifiedIndex': 3, 'value': u'1', 'expiration': None, 'key': u'/nodes/n1', 'ttl': None, 'action': None, 'dir': False}), 'raft_index': 168, '_children': [], 'createdIndex': 4, 'modifiedIndex': 4, 'value': u'1', 'etcd_index': 4, 'expiration': None, 'key': u'/nodes/n1', 'ttl': None, 'action': u'set', 'dir': False}) In [4]: result = client.read('/nodes/n1') In [5]: result. result.action result.createdIndex result.etcd_index result.get_subtree result.leaves result.newKey result.raft_index result.value result.children result.dir result.expiration result.key result.modifiedIndex result.parse_headers result.ttl In [5]: result.value Out[5]: u'1'
既然我们说etcd 和 ZooKeeper很像,那也是完全可以做成全局网络锁的。
client = etcd.Client() lock = client.get_lock('/customer1', ttl=60) # Use the lock object: lock.acquire() lock.is_locked() # True lock.renew(60) lock.release() lock.is_locked() # False # The lock object may also be used as a context manager: client = etcd.Client() lock = client.get_lock('/customer1', ttl=60) with lock as my_lock: do_stuff() lock.is_locked() # True lock.renew(60) lock.is_locked() # False
这里再把etcd的python api再来详细的描述下
创建etcd的连接对象 client = etcd.Client(host=’127.0.0.1′, port=4001) 啥端口,啥主机,你自己搞定。
需要注意的时,allow_redirect=True 这个参数是当断链的时候,etcd会再次复用connect创建可用的连接
[root@slave1 etcd-v0.4.6-linux-amd64]# ./etcd [etcd] Jan 23 14:34:00.703 WARNING | Using the directory slave1.etcd as the etcd curation directory because a directory was not specified. [etcd] Jan 23 14:34:00.703 INFO | slave1 is starting a new cluster [etcd] Jan 23 14:34:00.707 INFO | etcd server [name slave1, listen on :4001, advertised url http://127.0.0.1:4001] [etcd] Jan 23 14:34:00.707 INFO | peer server [name slave1, listen on :7001, advertised url http://127.0.0.1:7001] client = etcd.Client( host='127.0.0.1', port=4003, allow_reconnect=True, protocol='https',)
下面的东西和zookeeper很像了,但是那种目录结构体。
client.write('/nodes/n1', 1) # with ttl 设置几秒,几秒后这数据就没了 client.write('/nodes/n2', 2, ttl=4) # sets the ttl to 4 seconds # create only client.write('/nodes/n3', 'test', prevExist=False) prevExist 如果数据有的话,就不再插入了。 client.write('/nodes/n3', 'test2', prevValue='test1') 保证value以前是test1 # mkdir client.write('/nodes/queue', dir=True) 新版本不用这个也行,最少我不用指明dir 也是可以创建mkdir的 # Append a value to a queue dir client.write('/nodes/queue', 'test', append=True) #will write i.e. /nodes/queue/11 client.write('/nodes/queue', 'test2', append=True) #will write i.e. /nodes/queue/12
对于数据的修改也可以用 update
result = client.read('/foo') print(result.value) # bar result.value += u'bar' updated = client.update(result) print(updated.value)
用read()方法 从etcd获取节点数据
client.read('/nodes/n2').value #recursive递归的目录 #sorted 排序 r = client.read('/nodes', recursive=True, sorted=True) for child in r.children: print("%s: %s" % (child.key,child.value)) #相当于zookeeper的watch监听 client.read('/nodes/n2', wait=True) #Waits for a change in value in the key before returning. client.read('/nodes/n2', wait=True, waitIndex=10)
过两天再写一篇,关于etcd 和 docker组合在一起的应用方案
对我有用