问题描述
2013 年,CoreOS 团队需要一个协调服务来存储服务配置信息、提供分布式锁等能力;
需求概述:
该服务需要满足五个目标:可用性角度:高可用;数据一致性角度:提供读取“最新”数据的机制;容量角度:低容量、仅存储关键元数据配置;功能:增删改查,监听数据变化的机制(数据同步);运维复杂度:可维护性;
现有方案:
高可用性、数据一致性、功能:从这三个角度来说,ZooKeeper 是满足 CoreOS 诉求的;
配置繁琐:但是,当时的 ZooKeeper 不支持通过 API 安全地变更成员,需要人工修改一个个节点的配置,并重启进程;
容易故障:如果操作错误,则 ZooKeeper 有可能出现脑裂等严重故障;
维护成本:适配云环境、可平滑调整集群规模、在线变更运行时配置是 CoreOS 的期望目标,而 ZooKeeper 在这块的可维护成本相对较高;
资源占用:ZooKeeper 是用 Java 编写的,占用较多的内存资源;
部署繁琐:
专有接口:同时 ZooKeeper RPC 的序列化机制用的是 Jute,自己实现的 RPC API,其无法使用 curl 等常用工具来操作,CoreOS 期望使用比较简单的 HTTP + JSON;
解决方案
CoreOS 决定开始开发协调服务(具体原因我们不得而知,总之 CoreOS 开始着手 etcd 开发);
原理简述
概览架构
详细架构
Client Layer
该层层包括:
1)Client API v2 和 Client API v3 两个版本,提供简洁易用的 API,
2)同时支持负载均衡、节点间故障自动转移,可极大降低业务使用 etcd 复杂度,提升开发效率、服务可用性;
API Layer
该层包括 client 访问 server 和 server 节点之间的通信协议;
1)Client 访问 etcd 的 API v2 和 API v3 两个版本:API v2 使用 HTTP/1.x 协议;API v3 使用 gRPC 协议,且 API v3 通过 etcd grpc-gateway 组件也支持 HTTP/1.x 协议,便于各种语言的服务调用;
2)Server 间通信协议(是指节点间通过 Raft 算法实现数据复制和 Leader 选举等功能时使用的协议),其为 HTTP 协议;
Raft Layer
Raft 算法层实现 Leader 选举、日志复制、ReadIndex 等核心算法特性,用于保障 etcd 多个节点间的数据一致性、提升服务可用性等;
功能逻辑层
etcd 核心特性实现层:
1)典型的 KV-Server 模块、Auth-Server 模块、Lease 租约模块、Compactor 压缩模块等,
2)MVCC 模块:主要由 treeIndex 模块和 boltdb 模块组成;
Storage Layer(存储层)
存储层包含:
1)快照 (Snapshot) 模块、
2)boltdb 模块:boltdb 则保存集群元数据和用户写入的数据;
3)预写日志 (WAL) 模块:其中 WAL 可保障 etcd crash 后数据不丢失;
特性特征
etcd 协调服务使用 Go 语言编写,无依赖,部署简单
2013-08, etcd v0.1, API v1
简单的 HTTP Get/Set/Delete/Watch API,但读数据一致性无法保证;
2013-12, etcd v0.2, API v2
支持通过指定 consistent 模式,从 Leader 读取数据(保证数据强一致性)
发布新的 API v2,这就是大家熟悉的 etcd v2 版本,第一个非 stable 版本;
2014-06,Kubernetes v0.4 发布,使用使用 etcd v0.2 版本
2014-02, etcd v0.3, API v2
Discovery API
并将 Test And Set 机制修正为 CAS(Compare And Swap),解决原子更新的问题
2015-01, etcd v2.0, API v2
Raft 网络、存储抽象、插件化、支持 Quorum Read(等到大多数节点返回数据,则成功读取)
2015/07,Kubernetes v1.0.1 发布,使用 etcd v2.0 版本;
2015-07, etcd v2.1, API v2
实现鉴权和授权 Auth API
2015-09, etcd v2.2, API v2
改进 Client 库,提升错误处理能力;
2016-06, etcd v3
随着 Kubernetes 项目不断发展,v2 版本的瓶颈和缺陷逐渐暴露,遇到若干性能和稳定性问题;
首先是功能局限性问题。它主要是指 etcd v2 不支持范围和分页查询、不支持多 key 事务;
然后是 Watch 机制可靠性问题。Kubernetes 项目严重依赖 etcd Watch 机制,然而 etcd v2 是内存型、不支持保存 key 历史版本的数据库,只在内存中使用滑动窗口保存最近的 1000 条变更事件,当 etcd server 写请求较多、网络波动时等场景,很容易出现事件丢失问题,进而又触发 client 数据全量拉取,产生大量 expensive request,甚至导致 etcd 雪崩;
其次是性能瓶颈问题。etcd v2 早期使用简单、易调试的 HTTP/1.x API,但是随着 Kubernetes 支撑的集群规模越来越大,HTTP/1.x 协议的瓶颈逐渐暴露出来。比如集群规模大时,由于 HTTP/1.x 协议没有压缩机制,批量拉取较多 Pod 时容易导致 APIServer 和 etcd 出现 CPU 高负载、OOM、丢包等问题;
最后是内存开销问题。etcd v2 在内存维护一颗树来保存所有节点 key 及 value。在数据量场景略大的场景,如配置项较多、存储大量 Kubernetes Events, 它会导致较大的内存开销,同时 etcd 需要定时把全量内存树持久化到磁盘。这会消耗大量的 CPU 和磁盘 I/O 资源,对系统的稳定性造成一定影响;
etcd 聆听社区的声音并积极改进,解决社区的痛点。etcd v3 就是为解决以上稳定性、扩展性、性能问题而诞生的;
2017-01, etcd v3.1
提升线性读性能
2017-03 Kubernetes 1.6 发布,使用 etcd v3,支撑 5000 个节点;
2017-06, etcd v3.2
提升 etcd 并发读取性能;
2018-02, etcd v3.3
boltdb 等稳定性提升,增加数据毁坏检测功能;
2019-08, etcd v3.4
支持全并发读、Learner
2021-06, etcd v3.5
支持集群降级特性;
应用场景
WIP
参考文献
极客时间 /etcd 实战课(唐聪,腾讯云资深工程师,etcd 活跃贡献者)
《etcd 工作笔记:架构分析、优化与最佳实践》
etcd/Documentation versions