以etcd作为持久化服务的开发与传统基于关系型数据库的开发有所区别,与基于Nosql数据库和redis的开发也不同,以下作记录:
-
etcd 主要用于非频繁更新的数据,如
meta data等。 且提供订阅watch的API, redis也有类似功能 -
etcd本质上是一个有序的k-v存储,key值用btree存储在内存,value存在磁盘。 -
etcd采用raft算法作为一致性算法, 因此其瓶颈在于单个Leader的问题,不能支撑较大的访问流量(QPS)。分布式一致性问题是计算机科学的重要议题, 关于raft算法的基础原理见此 -
etcd的性能benckmark官方测试见此, 可见其在可接受的延时下(假定位50ms)的, 合理客户端数(1 ~ 200 +)下,其读写QPS约在2000 - 16000范围内。 -
由于
etcd侧重于元数据的一致性存储及访问, 常用于服务发现或支撑元数据服务的存储层, 如其get接口会返回除k-v外的额外信息, e.g."revision":xxx, 用于显示该k-v被修改过的次数,在开发中, 可将其应用在业务逻辑中, kubernetes的典型例子见此, 其对etcd的使用和理解是etcd使用的最佳实践之一。 -
etcd支持事务,每次事务完成只形成一次revision, 关于etcd事务的详细描述见此, transaction本质上与redis 的pipeline不同,pipeling内的命令不一定满足事务原子性。 -
关于
etcd的更多介绍和原理见此, 其中这里将etcd与ZooKeeper和Consul等作比较。这里也有一篇不错的中文参考。 -
etcd暴露的api有v2和v3, 其区别见此, 推荐使用v3 -
关于
etcd的选举机制, 数据一致性机制和集群容错能力等的相关注意项, 如etcd集群节点的增加注意点, 详见etcd FAQ 。文中有关于etcd集群的节点数推荐为奇数的理由叙述,在这里概括一下:- 同一
etcd集群内,数据一致性以大多数节点(majority)为依据实施仲裁机制(quorum),majority = (n/2)+1。 如3节点的集群,majority为2, 4节点的集群,majority为3。若集群的majority不能达到要求,则会失去仲裁quorum, 引起数据丢失 。这一点容易引起误解, 这里以一个例子来阐述。如3节点集群在启动时,etcd-1,etcd-2和etcd-3均状态正常,此时majority已设定为2, 但在一段时间后,etcd-3节点故障, 失去通信,但其仍登记在集群, 只是状态为不可用。etcd-1和etcd-2仍正常运作, 仍满足majority为2的要求,quorum正常。 若此后etcd-2节点故障,则会导致不满足majority为2的要求,quorum丢失。 Failure Tolerance为集群能容忍的最大故障节点数。Failure Tolerance = n - majroity。承接上一点的例子, 可得奇数节点集群和偶数节点集群的Failure Tolerance均为1。在Failure Tolerance相同的情况下, 节点数越多,其故障的期望值越高。因此推荐奇数节点数集群。- 对于故障节点数已经达到
Failure Tolerance的集群,直接增加新的etcd节点的做法风险很高。举例,3节点集群, 故障节点为etcd-3, 此时新增etcd-4, 使得集群节点数变为4,majority变为3。若此时etcd-4配置错误, 则故障节点为etcd-3和etcd-4,quorum丢失。因此正确做法应该是先剔除etcd-3,再增加etcd-4。 - 集群节点数越多,
Failure Tolerance越高, 但节点间数据同步开销越大。虽然理论上etcd集群节点数无限制,在最佳实践中推荐5个或7个节点。
- 同一
-
用
docker搭建实验环境的etcd很简单, 参见, 也可对docker-compose.yml稍作修改, 使其暴露端口, 方便调试
version: '2'
services:
etcd:
image: bitnami/etcd:3
environment:
- ALLOW_NONE_AUTHENTICATION=yes
volumes:
- etcd_data:/bitnami
ports:
- "2379:2379"
- "2380:2380"
...
- 使用
etcdctl可以与远程或本地的etcd,etcdctl在etcd的安装包内, 详见。使用举例如下:
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key get / --prefix --keys-only
以上etcdctl列出kubernentes中在etcd中存储的所有key/value.例子运行机器是k8s的master节点。
etcd几乎没有任何数据结构, 类似redis的set和 hashMap 等, 但一般使用时, 可以通过对key值的设计实现key之间的关联。如kubernetes中要获取所有namespaces, 其设计思路是将所有namespace的key以/foo/bar/..的形式来表达集合包含关系, 如:
ETCDCTL_API=3 etcdctl ... get /registry/namespace --prefix --keys-only
/registry/namespaces/cattle-system
/registry/namespaces/default
/registry/namespaces/kube-node-lease
/registry/namespaces/kube-public
/registry/namespaces/kube-system
/registry/namespaces/label-system
/registry/namespaces/nginx-ingress
这里/registry/namespace --prefix 获取了所有以/registry/namespace为前缀的key。
-
key-value中的value一般为字节数组, 业务实现中可以对于重要的元数据, 在put的时候用加密算法加密,get用加密算法解密。 -
对删除和更新
key-value等操作, 应符合事务操作规范, e.g. :
for {
txnResp, err := s.client.KV.Txn(ctx).If(
clientv3.Compare(clientv3.ModRevision(key), "=", origState.rev),
).Then(
clientv3.OpDelete(key),
).Else(
clientv3.OpGet(key),
).Commit()
if err != nil {
return err
}
if !txnResp.Succeeded {
getResp = (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange())
continue
}
return. ..
}
这里使用了事务和循环去确保所删除的对象为最后一次更新的对象。
-
相关议题:
kubernetes使用etcd作为存储层,实现各种Object的CRUD操作, 涉及到一致性的例子是, 当多客户端在同一时刻对相同对象(相同namespace)进行更新等操作时,kubernetes的应对和实现逻辑。 从更新资源的Restful API的handler实现, 源码见此, 到update 逻辑实现见此, 及此, 最后到持久化实现, 见此。可见k8s对于重要资源的更新,作了很多保证更新有效性的操作。 -
相关议题:
kubernetes的namespace与etcd 3.2版本推出的namespace不是同一个概念。
Reference
https://yq.aliyun.com/articles/738055?spm=a2c4e.11155472.0.0.560075355p5Gc7
最后
以上就是风趣酸奶最近收集整理的关于关于基于etcd服务的开发记录的全部内容,更多相关关于基于etcd服务内容请搜索靠谱客的其他文章。
发表评论 取消回复