ETCD——性能优化

"A distributed, reliable key-value store for the most critical data of a distributed system."

一个分布式、可靠 key-value 存储分布式系统。

理解ETCD性能

etcd性能影响.png

从架构上来看,影响etcd性能的几个方面:

  • Raft层:

    • 同步数据:网络IO节点之间的RTT/带宽;
    • Wal收到磁盘IO写入的影响;
  • Storage层:

    • 磁盘IOfdatasync延迟;
    • 索引层锁的block;
    • boltdb tx的锁;
    • boltdb本身的性能;
  • 其他:

    • 内核参数;
    • grpc api层延迟;

性能优化

硬件部署

  • 升级CPU、Memory;
  • SSD;
  • 网络带宽优先级;
  • 独占部署,减少其他程序运行的干扰。

软件优化

  • 内存索引层:提升etcd内存索引性能,优化内部锁的使用和减少等待时间;https://github.com/etcd-io/etcd/pull/9511

  • lease规模使用:优化lease revoke和过期失效的算法,解决了lease规模性的问题;https://github.com/etcd-io/etcd/pull/9418

  • 后端boltdb优化:后端batch size limit/interval,可根据不同的硬件和工作负载配置(以前是固定的保守值),https://github.com/etcd-io/etcd/commit/3faed211e535729a9dc36198a8aab8799099d0f3

    完全并发读,优化调用boltdb tx读写锁的使用,提升读性能;https://github.com/etcd-io/etcd/pull/10523

  • 基于segregated hashmap的etcd内部存储freelist分配回收算法(阿里),https://www.cncf.io/blog/2019/05/09/performance-optimization-of-etcd-in-web-scale-data-scenario/

    将etcd内部存储空间分配算法时间复杂度从O(n)优化到O(1),回收从O(nlogn)优化到O(1),极大的提高了单个etcd集群的能力,真是场景,存储容量2GB->100GB/读写性能24x

freelist算法.png

上图中为 etcd 内部存储分配回收的一个核心算法,这里先介绍一下背景知识。首先,etcd 内部使用默认为 4KB 的页面大小来存储数据。如图中数字表示页面 ID,黄色的表示该页面正在使用,白色的表示未使用。

当用户想要删除数据的时候,etcd 并不会把这个存储空间立即还给系统,而是内部先留存起来,维护一个页面的池子,以提升下次使用的性能。这个页面池子叫做 freelist,如图所示,freelist 页面 ID 为 43、45、 46、50、53 正在被使用,页面 ID 为 42、44、47、48、49、51、52 处于空闲状态。

当新的数据存储需要一个连续页面为 3 的配置时,旧的算法需要从 freelist 头开始扫描,最后返回页面起始 ID 为 47,以此可以看到普通的 etcd 线性扫描内部 freelist 的算法,在数据量较大或者是内部碎片严重的情况下,性能就会急速的下降。

针对这一问题,阿里设计并实现了一个基于 segregated hashmap 新的 freelist 分配回收算法。该算法将连续的页面大小作为 hashmap 的 key,value 是起始 ID 的配置集合。当需要新的页面存储时,我们只需要 O(1) 的时间复杂度来查询这个 hashmap 值,快速得到页面的起始 ID。

再去看上面例子,当需要 size 为 3 的连续页面的时候,通过查询这个 hashmap 很快就能找到起始页面 ID 为 47。

同样在释放页面时,我们也用了 hashmap 做优化。例如上图当页面 ID 为 45、46 释放的时候,它可以通过向前向后做合并,形成一个大的连续页面,也就是形成一个起始页面 ID 为 44、大小为 6 的连续页面。

综上所述:新的算法将分配的时间复杂度从 O(n) 优化到了 O(1),回收从 O(nlogn) 优化到了 O(1),etcd 内部存储不再限制其读写的性能,在真实的场景下,它的性能优化了几十倍。从单集群推荐存储 2GB 可以扩大到 100GB。该优化目前在阿里内部使用,并输出到了开源社区。

etcd client性能优化实践

  • Put时避免大Value,精简再精简,例如k8s下crd的使用;
  • 避免创建频繁变化的key/value,例如k8s下node数据上传;
  • 避免创建大量的lease,尽量选择复用,例如k8s下event数据管理。

保持客户端的使用的最佳实践,将保证你的etcd集群高效稳定运行。

你可能感兴趣的:(ETCD——性能优化)