KubeBrain 是字节跳动针对 Kubernetes 元信息存储的运用需求,依据分布式 KV 存储引擎规划并完结的取代 etcd 的元信息存储体系,支撑线上超越 20,000 节点的超大规划 Kubernetes 集群的安稳运转。

项目地址:github.com/kubewharf/kubebrain

1. 布景

分布式运用编列调度体系 Kubernetes 现已成为云原生运用基座的事实标准,可是其官方的安稳运转规划只是局限在 5,000 节点。这关于大部分的运用场景现已满足,可是关于百万规划机器节点的超大规划运用场景, Kubernetes 难以供给安稳的支撑。

特别跟着“数字化””云原生化”的发展,全球全体 IT 根底设施规划仍在加快添加,关于分布式运用编列调度体系,有两种方法来适应这种趋势:

  • 水平扩展 即构建办理多个集群的才能,在集群毛病阻隔、混合云等方面更具优势,首要经过集群联邦(Cluster Federation)来完结;
  • 垂直扩展 即进步单个集群的规划,在下降集群运维办理成本、减少资源碎片、进步全体资源利用率方面更具优势。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

K8s 选用的是一种中心化的架构,一切组件都与 APIServer 交互,而 APIServer 则需求将集群元数据耐久化到元信息存储体系中。当时,etcd 是 APIServer 仅有支撑的元信息存储体系,跟着单个集群规划的逐渐增大,存储体系的读写吞吐以及总数据量都会不断攀升,etcd 不可防止地会成为整个分布式体系的瓶颈。

1.1 Kubernetes元信息存储需求

APIServer 并不能直接运用一般的强共同 KV 数据库作为元信息存储体系,它与元信息存储体系的交互首要包含数据全量和增量同步的 List/Watch,以及单个 KV 读写。更近一步来说,它首要包含以下方面:

  • 在版别操控方面,存储体系需求对 APIServer 露出数据的版别信息,APIServer 侧依赖于数据的版别生成对应的 ResourceVersion;
  • 在写操作方面,存储体系需求支撑 Create/Update/Delete 三种语义的操作,更为重要的是,存储体系需求支撑在写入或许删去数据时对数据的版别信息进行 CAS;
  • 在读操作方面,存储体系需求支撑指定版别进行快照 List 以此从存储中获取全量的数据,填充APIServer 中的 WatchCache 或供查询运用,此外也需求支撑读取数据的一起获取对应的数据版别信息;
  • 在事情监听方面,存储体系需求支撑获取特定版别之后的有序改变,这样 APIServer 经过 List 从元信息存储中获取了全量的数据之后,能够监听快照版别之后的一切改变事情,然后以增量的方法来更新 Watch Cache 以及向其他组件进行改变的分发,然后确保 K8s 各个组件中数据的终究共同性。

1.2 etcd 的完结方法与瓶颈

etcd 本质上是一种主从架构的强共同、高可用分布式 KV 存储体系:

  • 节点之间,经过 Raft 协议进行选举,将操作抽象为 log 依据 Raft 的日志同步机制在多个状况机上同步;
  • 单节点上,按次序将 log 运用到状况机,依据 boltdb 进行状况耐久化 。

关于 APIServer 元信息存储需求,etcd 大致经过以下方法来完结:

  • 在版别操控方面,etcd 运用 Revision 作为逻辑时钟,对每一个修正操作,会分配递加的版别号Revision,以此进行版别操控,而且在内存中经过 TreeIndex 办理 Key 到 Revision 的索引;
  • 在写操作方面,etcd 以串行 Apply Raft Log 的方法完结,以 Revision 为键,Key/Value/Lease 等数据作为值存入 BoltDB 中,在此根底上完结了支撑对 Revision 进行 CAS 的写业务;
  • 在读操作方面,etcd 则是经过办理 Key 到 Revision 的 TreeIndex 来查询 Revision 然后查询 Value,并在此根底上完结快照读;
  • 在事情监听方面,历史事情能够从 BoltDB 中指定 Revision 获取 KV 数据转化得到,而新事情则由写操作同步 Notify 得到。

etcd 并不是一个专门为 K8s 规划的元信息存储体系,其供给的才能是 K8s 所需的才能的超集。在运用过程中,其露出出来的首要问题有:

  • etcd 的网络接口层限流才能较弱,雪崩时自愈才能差;
  • etcd 所选用的是单 raft group,存在单点瓶颈,单个 raft group 添加节点数只能进步容错才能,并不能进步写功能;
  • etcd 的 ExpensiveRead 简单导致 OOM,如果选用分页读取的话,延迟相对会进步;
  • boltdb 的串行写入,约束了写功能,高负载下写延迟会明显进步;
  • 长期运转简单因为碎片问题导致写功能产生必定劣化,线上集群定期经过 defrag 整理碎片,一方面会比较复杂,另一方面也或许会影响可用性。

2. 新的元数据存储

曩昔面临出产环境中 etcd 的功能问题,只能经过按 Resource 拆分存储、etcd 参数调优等手法来进行必定的缓解。可是面临 K8s 更大规模的运用之后带来的应战,咱们火急的需求一个更高功能的元数据存储体系作为 etcd 的替代计划,然后能对上层业务有更有力的支撑。

在调研了 K8s 集群的需求以及相关开源项目之后,咱们借鉴了 k3s 的开源项目 kine 的思维,规划并完结了依据分布式 KV 存储引擎的高功能 K8s 元数据存储项目—— KubeBrain 。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

KubeBrain 体系完结了 APIServer 所运用的元信息存储 API ,全体选用主从架构,主节点担任处理写操作和事情分发,从节点担任处理读操作,主节点和从节点之间同享一个分布式强共同 KV 存储,在此根底上进行数据读写。下面介绍 KubeBrain 的核心模块。

2.1 存储引擎

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

KubeBrain 统一抽象了逻辑层所运用的 KeyValue 存储引擎接口,以此为根底,项目完结了核心逻辑与底层存储引擎的解耦:

  • 逻辑层依据存储引擎接口来操作底层数据,不关心底层完结;
  • 对接新的存储引擎只需求完结对应的适配层,以完结存储接口。

目前项目现已完结了对 ByteKV 和 TiKV 的适配,此外还完结了用于测验的适配单机存储 Badger 的版别。需求留意的是,并非一切 KV 存储都能作为 KubeBrain 的存储引擎。当时 KubeBrain 关于存储引擎有着以下特性要求:

  • 支撑快照读
  • 支撑双向遍历
  • 支撑读写业务或许带有CAS功能的写业务
  • 对外露出逻辑时钟

此外,因为 KubeBrain 关于上层供给的共同性确保依赖于存储引擎的共同性确保, KubeBrain 要求存储引擎的业务需求到达以下级别 (界说参考 HATs :www.vldb.org/pvldb/vol7/… ):

  • Isolation Guarantee: Snapshot Isolation
  • Session Guarantee: Linearizable

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

在内部出产环境中, KubeBrain 均以 ByteKV 为存储引擎供给元信息存储服务。ByteKV 是一种强共同的分布式 KV 存储。在 ByteKV 中,数据依照 key 的字典序有序存储。当单个 Partition 数据巨细超越阈值时, Partition 主动地割裂,然后能够经过 multi-raft group 进行水平扩展,还支撑配置割裂的阈值以及割裂鸿沟选择的规矩的定制。此外, ByteKV 还对外露出了大局的时钟,一起支撑写业务和快照读,而且供给了极高的读写功能以及强共同的确保。

2.2 选主机制

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

KubeBrain 依据底层强共同的分布式 KV 存储引擎,封装完结了一种 ResourceLock,在存储引擎中指向一组特定的 KeyValue。ResourceLock 中包含主节点的地址以及租约的时长等信息。

KubeBrain 进程启动后均以从节点的身份对自己进行初始化,而且会主动在后台进行竞选。竞选时,首要测验读取当时的 ResourceLock。如果发现当时 ResourceLock 为空,或许 ResourceLock 中的租约现已过期,节点会测验将自己的地址以及租约时长以 CAS 的方法写入 ResourceLock,如果写入成功,则晋升为主节点。

从节点能够经过 ResourceLock 读取主节点的地址,然后和主节点树立连接,并进行必要的通信,可是主节点并不感知从节点的存在。即使没有从节点,单个 KubeBrain 主节点也能够供给完结的 APIServer 所需的 API,可是主节点宕机后可用性会受损。

2.3 逻辑时钟

KubeBrain 与 etcd 相似,都引入了 Revision 的概念进行版别操控。KubeBrain 集群的发号器仅在主节点上启动。当从节点晋升为主节点时,会依据存储引擎供给的逻辑时钟接口来进行初始化,发号器的Revision 初始值会被赋值成存储引擎中获取到的逻辑时刻戳。

单个 Leader 的任期内,发号器宣布的整数号码是单调接连递加的。主节点产生毛病时,从节点抢到主,就会再次重复一个初始化的流程。因为主节点的发号是接连递加的,而存储引擎的逻辑时刻戳或许对错接连的,其添加速度是远快于接连发号的发号器,因而能够确保切主之后, Revision 依然是递加的一个趋势,旧主节点上发号器所分配的最大的 Revision 会小于新主节点上发号器所分配的最小的Revision。

KubeBrain 主节点上的发号是一个纯内存操作,具有极高的功能。因为 KubeBrain 的写操作在主节点上完结,为写操作分配 Revision 时并不需求进行网络传输,因而这种高功能的发号器关于优化写操作功能也有很大的协助。

2.4 数据模型

KubeBrain 关于 API Server 读写恳求参数中的 Raw Key,会进行编码出两类 Internal Key写入存储引擎索引和数据。关于每个 Raw Key,索引 Revision Key 记载只有一条,记载当时 Raw Key 的最新版别号, Revision Key 一起也是一把锁,每次对 Raw Key 的更新操作需求对索引进行 CAS。数据记载Object Key 有一到多条,每条数据记载了 Raw Key 的历史版别与版别对应的 Value。Object Key 的编码方法为magic+raw_key+split_key+revision,其间:

  • magic\x57\xfb\x80\x8b
  • raw_key为实践 API Server 输入到存储体系中的 Key ;
  • split_key$
  • revision为逻辑时钟对写操作分配的逻辑操作序号经过 BigEndian 编码成的 Bytes 。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

依据 Kubernetes 的校验规矩,raw_key 只能包含小写字母、数字,以及’-‘ 和 ‘.’,所以目前选择 split_key 为 $ 符号。

特别的,Revision Key 的编码方法和 Object Key 相同,revision取长度为 8 的空 Bytes 。这种编码计划确保编码前和编码后的比较联系不变。

在存储引擎中,同一个 Raw Key 生成的一切 Internal Key 落在一个接连区间内 。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

这种编码方法有以下长处:
  • 编码可逆,即能够经过Encode(RawKey,Revision)得到InternalKey,相对应的能够经过Decode(InternalKey)得到RawkeyRevision
  • 将 Kubernetes 的对象数据都转化为存储引擎内部的 Key-Value 数据,且每个对象数据都是有仅有的索引记载最新的版别号,经过索引完结锁操作;
  • 能够很简单地结构出某行、某条索引所对应的 Key,或许是某一块相邻的行、相邻的索引值所对应的 Key 规模;
  • 因为 Key 的格局非单调递加,能够防止存储引擎中的递加 Key 带来的热点写问题。

2.5 数据写入

每一个写操作都会由发号器分配一个仅有的写入 revision ,然后并发地对存储引擎进行写入。在 创立、更新 和 删去 Kubernetes 对象数据的时分,需求一起操作对象对应的索引和数据。因为索引和数据在底层存储引擎中是不同的 Key-Value 对,需求运用写业务确保更新过程的原子性,而且要求至少到达 Snapshot Isolation 。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

一起 KubeBrain 依赖索引完结了达观锁进行并发操控。KubeBrain 写入时,会先依据 APIServer 输入的 RawKey 以及被发号器分配的 Revision 结构出实践需求到存储引擎中的 Revision Key 和 Object Key,以及希望写入到 Revision Key 中的 Revision Bytes。在写业务过程中,先进行索引 Revision Key 的查看,查看成功后更新索引 Revision Key,在操作成功后进行数据 Object Key 的插入操作。

  • 履行 Create 恳求时,当 Revision Key 不存在时,才将 Revision Bytes 写入 Revision Key 中,随后将 API Server 写入的 Value 写到 Object Key 中;
  • 履行 Update 恳求时,当 Revision Key 中寄存的旧 Revision Bytes 契合预期时,才将新 Revision Bytes 写入,随后将 API Server 写入的 Value 写到 Object Key 中;
  • 履行 Delete 恳求时,当 Revision Key 中寄存的旧 Revision Bytes 契合预期时,才将新 Revision Bytes 附带上删去符号写入,随后将 tombstone 写到 Object Key 中。

因为写入数据时依据递加的 Revision 不断写入新的 KeyValue , KubeBrain 会进行后台的垃圾回收操作,将 Revision 过旧的数据进行删去,防止数据量无限添加。

2.6 数据读取

数据读取分红点读和规模查询查询操作,分别对应 API Server 的 Get 和 List 操作。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

Get 需求指定读操作的ReadRevision,需求读最新值时则将 ReadRevision 置为最大值MaxUint64, 结构 Iterator ,开始点为Encode(RawKey, ReadRevision),向Encode( RawKey, 0)遍历,取第一个。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

规模查询需求指定读操作的`ReadRevision`。关于规模查找的 RawKey 鸿沟`[RawKeyStart, RawKeyEnd)`区间, KubeBrain 结构存储引擎的 Iterator 快照读,经过编码将 RawKey 的区间映射到存储引擎中 InternalKey 的数据区间
  • InternalKey 上界InternalKeyStartEncode(RawKeyStart, 0)
  • InternalKey 的下界为InternalKeyEndEncode(RawKeyEnd, MaxRevision)

关于存储引擎中[InternalKeyStart, InternalKeyEnd)内的一切数据按序遍历,经过Decode(InternalKey)得到RawKeyRevision,关于一个RawKey相同的一切ObjectKey,在满足条件Revision<=ReadRevision的子集中取Revision最大的,对外返回。

2.7 事情机制

关于一切改变操作,会由 TSO 分配一个接连且仅有的 revision ,然后并发地写入存储引擎中。改变操作写入存储引擎之后,不管写入成功或失败,都会依照 revision 从小到大的次序,将改变结果提交到滑动窗口中,改变结果包含改变的类型、版别、键、值、写入成功与否 。在记载改变结果的滑动窗口中,从起点到终点,一切改变数据中的 revision 严厉递加,相邻 revision 差为 1。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

记载改变结果的滑动窗口由事情生成器统一从起点开始消费,取出的改变结果后会依据改变的 revision更新发号器的 commit index ,如果改变履行成功,则还会结构出对应的修正事情,将并行地写入事情缓存和分发到一切监听所创立出的告诉行列。

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

在元数据存储体系中,需求监听指定逻辑时钟即指定 revision 之后产生的一切修正事情,用于下游的缓存更新等操作,然后确保分布式体系的数据终究共同性。注册监听时,需求传入开始 revision 和过滤参数,过滤参数包含 key 前缀等等。

当客户端发起监听时,服务端在树立事情流之后的处理,分红以下几个首要步骤:

  1. 处理监听注册恳求时首要创立告诉行列,将告诉行列注册到事情生成组件中,获取下发的新增事情;
  1. 从事情缓存中拉取事情的 revision 大于等于给定要求 revision 一切事情到事情行列中,并放到输出行列中,以此获取历史事情;
  1. 将告诉行列中的事情取出,添加到输出行列中, revision 去重之后添加到输出行列;
  1. 依照 revision 从小到大的次序,依次运用过滤器进行过滤;
  1. 将过滤后契合客户端要求的事情,经过事情流推送到元数据存储体系外部的客户端。

3. 落地效果

突破 etcd 限制!字节自研 K8s 存储 KubeBrain

  • 在 Benchmark 环境下,依据 ByteKV 的 KubeBrain 对比于 etcd 纯写场景吞吐提升 10 倍左右,延迟大幅度下降, PCT 50 下降至 1/6 ,PCT 90 下降至 1/20 ,PCT 99下降至 1/4 ;读写混合场景吞吐提升 4 倍左右;事情吞吐大约提升5倍;
  • 在模拟 K8s Workload 的压测环境中,合作 APIServer 侧的优化和调优,支撑 K8s 集群规划到达 5w Node 和 200w Pod;
  • 在出产环境中,安稳上量至 2.1w Node ,高峰期写入超越 1.2w QPS,读写负载合计超越 1.8w QPS。

4. 未来演进

项目未来的演进计划首要包含四个方面的作业:

  • 探究完结多点写入的计划以支撑水平扩展现在 KubeBrain 本质上还是一个单主写入的体系,KubeBrain 后续会在水平扩展方面做进一步的探究,后续也会在社区中讨论;
  • 提升切主的康复速度当时切主会触发 API Server 侧的 Re-list ,数据同步的开销较大,咱们会在这方面进一步做优化;
  • 完结内置存储引擎完结两层存储融合,因为现在在存储引擎、KubeBrain 中存在两层 MVCC 规划,全体读写扩大较多,完结融合有助于下降读写扩大,更进一步进步功能;
  • 完善周边组件包含数据迁移工具、备份工具等等,协助用户更好地运用 KubeBrain 。

5. 关于咱们

字节根底架构编列调度团队,担任构建字节跳动内部的容器云渠道,为产品线供给运转柱石;以超大容器集群规划全体支撑了字节内产品线,包括今日头条、抖音、西瓜视频等。

团队支撑业务一起掩盖在线、离线机器学习,引荐/广告/搜索等多种运用场景;在继续多年的超高速添加中,积累了丰富的 Kubernetes/容器超大规划运用经验,旨在打造掩盖多场景,多地域的千万级容器的大渠道。欢迎情投意合的同学们加入咱们。

简历投递:lijiazhuo@bytedance.com