七叶笔记 » golang编程 » etcd系列(etcd入门)

etcd系列(etcd入门)

etcd简介

etcd是一个可靠的分布式KV存储,其底层使用Raft算法保证一致性,主要用于共享配置和服务发现。etcd是CoreOS公司发起的一个开源项目,授权协议为Apache,其源代码地址为。

目前提供配置共享和服务发现功能的组件还是比较多的,其中应用最为广泛、大家最为熟悉的应该就是ZooKeeper了,很多开源项目也都在不同程度上依赖了ZooKeeper,例如,Dubbo、Kafka等。

这里简单介绍一下“服务发现”和“共享配置”两个概念。随着一个系统的不断迭代,功能模块会不断增加,对整个系统进行服务的拆分是必然的,这就会出现多个服务之间的相互调用,而在出现服务发现组件之前,一般是通过读取配置文件中预先设置的IP来获取服务的地址,然后进行调用。这会导致很多问题,例如,某些服务已经不可用时,调用方不能及时感知,负载均衡比较复杂,等等。使用服务发现组件之后,我们可以将服务提供方的信息注册到服务发现组件,例如,注册到ZooKeeper中,然后定期发送心跳等信息,让服务发现组件知晓服务提供方是可用的。当调用方进行服务调用时,会先请求服务发现组件,由服务发现组件来保证返回可用的服务地址及负载均衡等功能。

在一个系统的不同模块中有很多配置信息,例如,数据库地址、连接配置信息等都差不多,如果使用静态配置文件的方式实现,则需要将相同的信息写多份,每次更新配置时也需要更新多次。如果将这些配置信息注册到共享配置组件中,则系统的不同模块在启动时可从共享配置组件中获取配置,同时会监听配置信息的更改,当配置信息发生变更时,可以自动将配置值替换成新值。

在Golang社区中,etcd则是唯一一个可以媲美ZooKeeper的组件,在有些方面,etcd甚至超越了ZooKeeper,给开发者眼前一亮的感觉。下面简单列举一下 etcd 相较于 ZooKeeper的优势。

·一致性协议:一致性协议是配置共享和服务发现组件的核心,etcd底层采用了Raft协议,而ZooKeeper使用ZAB协议,ZAB 协议是一种类 Paxos的一致性协议。目前公认的是Raft比Paxos协议易于理解,工程化也较为容易。

·API接口:etcd v2版本中提供了HTTP+JSON的调用方式,在etcdv3版本的客户端中则使用GRPC与服务端进行交互,而GRPC本身就是跨平台的。

·性能:在官方提供的基准测试数据中,etcd集群可以支持每秒10000+次的写入,性能相当可观,优于ZooKeeper。

·安全性:etcd支持TLS访问,而ZooKeeper在权限控制这方面做得略显粗糙。

etcd也有很多成功的案例,最为大家熟知的就是 Kubernetes,其底层就依赖于etcd实现集群状态和配置的管理。

数据模型

etcd 支持可靠的键值对存储并且提供了可靠的 Watcher 机制,其中的键值对存储支持多版本,并且具备能够“Watch”历史事件的功能。这里简单介绍多版本存储的含义,假设键K1对应的值为V1,当我们将K1对应的值修改成V2时,etcd并不会直接将V1修改成V2,而是同时记录V1和V2两个值,并通过不同的版本号进行区分。另外,Watch历史事件的含义是,我们可以向一个Key添加 Watcher,同时可以指定一个历史版本,从该版本开始的所有事件都会触发该Watcher。

随着应用不断运行,键值对不断修改,每个Key都在etcd中保存了多个版本,数据量也会越来越大。为了缓解压力,etcd会定期进行压缩,清理过旧的数据。

在很多现代数据库系统中,都用了B树索引加速查询,etcd也是如此,其存储中会维护一个字段序的B树索引。在B树索引的每个索引项中,都存储了一个Key值,这样可以快速定位指定的Key或是进行范围查询。而每个Key值对应了多个版本号,etcd中维护了一个全局自增的版本号,为每次事务分配一个全局唯一的版本号(main revision),事务中的每个操作也有唯一的编号(sub revision),通过这两部分可以确定一个唯一的Value值。

每个Key会对应多个generation,当Key首次创建时,会同时创建一个与之关联的generation实例,当该Key被修改时,会将对应的版本记录到generation中,当Key被删除时,会向generation中添加tombstone,并创建新的generation,会向新generation中写入后续的版本信息。

在查询时,先在内存索引中通过用户指定的Key值,查找到该Key值对应的全部版本号,然后根据用户指定的版本号,从底层存储中查找到具体的 Value 值。当然,如果指定的版本号已经被etcd压缩删除,则无法再查询到该版本的Value值。

在etcdv3版本中,底层存储使用的是BoltDB,其中的Key是版本信息(main revision+subrevision)。这样,在查询时先通过上述B树索引查找到对应的版本信息,然后在BoltDB中通过版本信息查找相应的Value值。

相关文章