万级K8s集群背后etcd稳定性及性能优化实践

背景与挑战

随着腾讯自研上云及公有云用户的迅速增加,一方面,腾讯云容器服务TKE服务数量和核数大幅增加, 另外一方面咱们提供的容器服务类型(TKE托管及独立集群、EKS弹性集群、edge边缘计算集群、mesh服务网格、serverless knative)也愈来愈丰富。各种容器服务类型背后的核心都是K8s,K8s核心的存储etcd又统一由咱们基于K8s构建的etcd平台进行管理。基于它咱们目前管理了千级etcd集群,背后支撑了万级K8s集群。git

在万级K8s集群规模下的咱们如何高效保障etcd集群的稳定性? github

etcd集群的稳定性风险又来自哪里?golang

咱们经过基于业务场景、历史遗留问题、现网运营经验等进行稳定性风险模型分析,风险主要来自旧TKE etcd架构设计不合理、etcd稳定性、etcd性能部分场景没法知足业务、测试用例覆盖不足、变动管理不严谨、监控是否全面覆盖、隐患点是否能自动巡检发现、极端灾难故障数据安全是否能保障。web

前面所描述的etcd平台已经从架构设计上、变动管理上、监控及巡检、数据迁移、备份几个方面程度解决了咱们管理的各种容器服务的etcd可扩展性、可运维性、可观测性以及数据安全性,所以本文将重点描述咱们在万级K8s场景下面临的etcd内核稳定性及性能挑战,好比:算法

  • 数据不一致
  • 内存泄露
  • 死锁
  • 进程Crash
  • 大包请求致使etcd OOM及丢包
  • 较大数据量场景下启动慢
  • 鉴权及查询key数量、查询指定数量记录接口性能较差

img

本文将简易描述咱们是如何发现、分析、复现、解决以上问题及挑战,以及从以上过程当中咱们得到了哪些经验及教训,并将之应用到咱们的各种容器服务存储稳定性保障中。数据库

同时,咱们将解决方案所有贡献、回馈给etcd开源社区, 截止目前咱们贡献的30+ pr已所有合并到社区。腾讯云TKE etcd团队是etcd社区2020年上半年最活跃的贡献团队之一, 为etcd的发展贡献咱们的一点力量, 在这过程当中特别感谢社区AWS、Google、Ali等maintainer的支持与帮助。后端

稳定性优化案例剖析

从GitLab误删主库丢失部分数据到GitHub数据不一致致使中断24小时,再到号称"不沉航母"的AWS S3故障数小时等,无一例外都是存储服务。稳定性对于一个存储服务、乃至一个公司的口碑而言相当重要,它决定着一个产品生与死。稳定性优化案例咱们将从数据不一致的严重性、两个etcd数据不一致的bug、lease内存泄露、mvcc 死锁、wal crash方面阐述,咱们是如何发现、分析、复现、解决以上case,并分享咱们从每一个case中的得到的收获和反思,从中汲取经验,防患于未然。api

数据不一致(Data Inconsistency)

谈到数据不一致致使的大故障,就不得不详细提下GitHub在18年一次因网络设备的例行维护工做致使的美国东海岸网络中心与东海岸主要数据中心之间的链接断开。虽然网络的连通性在43秒内得以恢复,可是短暂的中断引起了一系列事件,最终致使GitHub 24小时11分钟的服务降级,部分功能不可用。数组

GitHub使用了大量的MySQL集群存储GitHub的meta data,如issue、pr、page等等,同时作了东西海岸跨城级别的容灾。故障核心缘由是网络异常时GitHub的MySQL仲裁服务Orchestrator进行了故障转移,将写入数据定向到美国西海岸的MySQL集群(故障前primary在东海岸),然而美国东海岸的MySQL包含一小段写入,还没有复制到美国西海岸集群,同时故障转移后因为两个数据中心的集群如今都包含另外一个数据中心中不存在的写入,所以又没法安全地将主数据库故障转移回美国东海岸。安全

最终, 为了保证保证用户数据不丢失,GitHub不得不以24小时的服务降级为代价来修复数据一致性。

数据不一致的故障严重性不言而喻,然而etcd是基于raft协议实现的分布式高可靠存储系统,咱们也并未作跨城容灾,按理数据不一致这种看起来高大上bug咱们是很难遇到的。然而梦想是美好的,现实是残酷的,咱们不只遇到了难以想象的数据不一致bug, 还一踩就是两个,一个是重启etcd有较低的几率触发,一个是升级etcd版本时若是开启了鉴权,在K8s场景下较大几率触发。在详细讨论这两个bug前,咱们先看看在K8s场景下etcd数据不一致会致使哪些问题呢?

  • 数据不一致最恐怖之处在于client写入是成功的,但可能在部分节点读取到空或者是旧数据,client没法感知到写入在部分节点是失败的和可能读到旧数据
  • 读到空可能会致使业务Node消失、Pod消失、Node上Service路由规则消失,通常场景下,只会影响用户变动的服务
  • 读到老数据会致使业务变动不生效,如服务扩缩容、Service rs替换、变动镜像异常等待,通常场景下,只会影响用户变动的服务
  • 在etcd平台迁移场景下,client没法感知到写入失败,若校验数据一致性也无异常时(校验时链接到了正常节点),会致使迁移后整个集群全面故障(apiserver链接到了异常节点),用户的Node、部署的服务、lb等会被所有删除,严重影响用户业务

首先第一个不一致bug是重启etcd过程当中遇到的,人工尝试复现屡次皆失败,分析、定位、复现、解决这个bug之路几经波折,过程颇有趣并充满挑战,最终经过我对关键点增长debug日志,编写chaos monkey模拟各类异常场景、边界条件,实现复现成功。最后的真凶居然是一个受权接口在重启后重放致使鉴权版本号不一致,而后放大致使多版本数据库不一致, 部分节点没法写入新数据, 影响全部v3版本的3年之久bug。

随后咱们提交若干个相关pr到社区, 并所有合并了, 最新的etcd v3.4.9[1],v3.3.22[2]已修复此问题, 同时google的jingyih也已经提K8s issue和pr[3]将K8s 1.19的etcd client及server版本升级到最新的v3.4.9。此bug详细可参考超凡同窗写的文章三年之久的 etcd3 数据不一致 bug 分析

img

第二个不一致bug是在升级etcd过程当中遇到的,因etcd缺乏关键的错误日志,故障现场有效信息很少,定位较困难,只能经过分析代码和复现解决。然而人工尝试复现屡次皆失败,因而咱们经过chaos monkey模拟client行为场景,将测试环境全部K8s集群的etcd分配请求调度到咱们复现集群,以及对比3.2与3.3版本差别,在可疑点如lease和txn模块增长大量的关键日志,并对etcd apply request失败场景打印错误日志。

经过以上措施,咱们比较快就复现成功了, 最终经过代码和日志发现是3.2版本与3.3版本在revoke lease权限上出现了差别,3.2无权限,3.3须要写权限。当lease过时的时候,若是leader是3.2,那么请求在3.3节点就会因无权限致使失败,进而致使key数量不一致,mvcc版本号不一致,致使txn事务部分场景执行失败等。最新的3.2分支也已合并咱们提交的修复方案,同时咱们增长了etcd核心过程失败的错误日志以提升数据不一致问题定位效率,完善了升级文档,详细说明了lease会在此场景下引发数据不一致性,避免你们再次采坑。

img

  • 从这两个数据不一致bug中咱们得到了如下收获和最佳实践:

    • 算法理论数据一致性,不表明总体服务实现能保证数据一致性,目前业界对于这种基于日志复制状态机实现的分布式存储系统,没有一个核心的机制能保证raft、wal、mvcc、snapshot等模块协做不出问题,raft只能保证日志状态机的一致性,不能保证应用层去执行这些日志对应的command都会成功
    • etcd版本升级存在必定的风险,须要仔细review代码评估是否存在不兼容的特性,如若存在是否影响鉴权版本号及mvcc版本号,若影响则升级过程当中可能会致使数据不一致性,同时必定要灰度变动现网集群
    • 对全部etcd集群增长了一致性巡检告警,如revision差别监控、key数量差别监控等
    • 定时对etcd集群数据进行备份,再小几率的故障,根据墨菲定律均可能会发生,即使etcd自己虽具有完备的自动化测试(单元测试、集成测试、e2e测试、故障注入测试等),但测试用例仍有很多场景没法覆盖,咱们须要为最坏的场景作准备(如3个节点wal、snap、db文件同时损坏),下降极端状况下的损失, 作到可用备份数据快速恢复
    • etcd v3.4.4后的集群灰度开启data corruption检测功能,当集群出现不一致时,拒绝集群写入、读取,及时止损,控制不一致的数据范围
    • 继续完善咱们的chaos monkey和使用etcd自己的故障注入测试框架functional,以协助咱们验证、压测新版本稳定性(长时间持续跑),复现隐藏极深的bug, 下降线上采坑的几率

内存泄露(OOM)

众所周知etcd是golang写的,而golang自带垃圾回收机制也会内存泄露吗?首先咱们得搞清楚golang垃圾回收的原理,它是经过后台运行一个守护线程,监控各个对象的状态,识别而且丢弃再也不使用的对象来释放和重用资源,若你迟迟未释放对象,golang垃圾回收不是万能的,不泄露才怪。好比如下场景会致使内存泄露:

  • goroutine泄露
  • deferring function calls(如for循环里面未使用匿名函数及时调用defer释放资源,而是整个for循环结束才调用)
  • 获取string/slice中的一段致使长string/slice未释放(会共享相同的底层内存块)
  • 应用内存数据结构管理不周致使内存泄露(如为及时清理过时、无效的数据)

接下来看看咱们遇到的这个etcd内存泄露属于哪一种状况呢?事情起源于3月末的一个周末起床后收到现网3.4集群大量内存超过安全阈值告警,马上排查了下发现如下现象:

  • QPS及流量监控显示都较低,所以排除高负载及慢查询因素
  • 一个集群3个节点只有两个follower节点出现异常,leader 4g,follower节点高达23G
  • goroutine、fd等资源未出现泄漏
  • go runtime memstats指标显示各个节点申请的内存是一致的,可是follower节点go_memstats_heap_release_bytes远低于leader节点,说明某数据结构可能长期未释放
  • 生产集群默认关闭了pprof,开启pprof,等待复现, 并在社区上搜索释放有相似案例, 结果发现有多个用户1月份就报了,没引发社区重视,使用场景和现象跟咱们同样
  • 经过社区的heap堆栈快速定位到了是因为etcd经过一个heap堆来管理lease的状态,当lease过时时须要从堆中删除,可是follower节点却无此操做,所以致使follower内存泄露, 影响全部3.4版本。
  • 问题分析清楚后,我提交的修复方案是follower节点不须要维护lease heap,当leader发生选举时确保新的follower节点能重建lease heap,老的leader节点则清空lease heap.

此内存泄露bug属于内存数据结构管理不周致使的,问题修复后,etcd社区当即发布了新的版本(v3.4.6+)以及K8s都当即进行了etcd版本更新。

img

img

从这个内存泄露bug中咱们得到了如下收获和最佳实践:

  • 持续关注社区issue和pr, 别人今天的问题极可能咱们明天就会遇到
  • etcd自己测试没法覆盖此类须要必定时间运行的才能触发的资源泄露bug,咱们内部须要增强此类场景的测试与压测
  • 持续完善、丰富etcd平台的各种监控告警,机器留足足够的内存buffer以扛各类意外的因素。

存储层死锁(Mvcc Deadlock)

  • 死锁是指两个或两个以上的goroutine的执行过程当中,因为竞争资源相互等待(通常是锁)或因为彼此通讯(chan引发)而形成的一种程序卡死现象,没法对外提供服务。deadlock问题由于每每是在并发状态下资源竞争致使的, 通常比较难定位和复现, 死锁的性质决定着咱们必须保留好分析现场,不然分析、复现及其困难。

    那么咱们是如何发现解决这个deadlock bug呢?问题起源于内部团队在压测etcd集群时,发现一个节点忽然故障了,并且一直没法恢复,没法正常获取key数等信息。收到反馈后,我经过分析卡住的etcd进程和查看监控,获得如下结论:

    • 不通过raft及mvcc模块的rpc请求如member list能够正常返回结果,而通过的rpc请求所有context timeout
    • etcd health健康监测返回503,503的报错逻辑也是通过了raft及mvcc
    • 经过tcpdump和netstat排除raft网络模块异常,可疑目标缩小到mvcc
    • 分析日志发现卡住的时候因数据落后leader较多,接收了一个数据快照,而后执行更新快照的时候卡住了,没有输出快照加载完毕的日志,同时确认日志未丢失
    • 排查快照加载的代码,锁定几个可疑的锁和相关goroutine,准备获取卡住的goroutine堆栈
    • 经过kill或pprof获取goroutine堆栈,根据goroutine卡住的时间和相关可疑点的代码逻辑,成功找到两个相互竞争资源的goroutine,其中一个正是执行快照加载,重建db的主goroutine,它获取了一把mvcc锁等待全部异步任务结束,而另一个goroutine则是执行历史key压缩任务,当它收到stop的信号后,马上退出,调用一个compactBarrier逻辑,而这个逻辑又偏偏须要获取mvcc锁,所以出现死锁,堆栈以下。

img

这个bug也隐藏了好久,影响全部etcd3版本,在集群中写入量较大,某落后的较多的节点执行了快照重建,同时此时又偏偏在作历史版本压缩,那就会触发。我提交的修复PR目前也已经合并到3.3和3.4分支中,新的版本已经发布(v3.3.21+/v3.4.8+)。

img

从这个死锁bug中咱们得到了如下收获和最佳实践:

  • 多并发场景的组合的etcd自动化测试用例覆盖不到,也较难构建,所以也容易出bug, 是否还有其余相似场景存在一样的问题?须要参与社区一块儿继续提升etcd测试覆盖率(etcd以前官方博客介绍一大半代码已是测试代码),才能避免此类问题。
  • 监控虽然能及时发现异常节点宕机,可是死锁这种场景以前咱们不会自动重启etcd,所以须要完善咱们的健康探测机制(好比curl /health来判断服务是否正常),出现死锁时可以保留堆栈、自动重启恢复服务。
  • 对于读请求较高的场景,需评估3节点集群在一节点宕机后,剩余两节点提供的QPS容量是否可以支持业务,若不够则考虑5节点集群。

Wal crash(Panic)

panic是指出现严重运行时和业务逻辑错误,致使整个进程退出。panic对于咱们而言并不陌生,咱们在现网遇到过几回,最先遭遇的不稳定性因素就是集群运行过程当中panic了。

虽然说咱们3节点的etcd集群是能够容忍一个节点故障,可是crash瞬间对用户依然有影响,甚至出现集群拨测链接失败。

咱们遇到的第一个crash bug,是发现集群连接数较多的时候有必定的几率出现crash, 而后根据堆栈查看社区已有人报grpc crash(issue)[4], 缘由是etcd依赖的组件grpc-go出现了grpc crash(pr)[5],而最近咱们遇到的crash bug[6]是v3.4.8/v3.3.21新版本发布引发的,这个版本跟咱们有很大关系,咱们贡献了3个PR到这个版本,占了一大半以上, 那么这个crash bug是如何产生以及复现呢?会不会是咱们本身的锅呢?

  • 首先crash报错是walpb: crc mismatch, 而咱们并未提交代码修改wal相关逻辑,排除本身的锅。
  • 其次经过review新版本pr, 目标锁定到google一位大佬在修复一个wal在写入成功后,而snapshot写入失败致使的crash bug的时候引入的.
  • 可是具体是怎么引入的?pr中包含多个测试用例验证新加逻辑,本地建立空集群和使用存量集群(数据比较小)也没法复现.
  • 错误日志信息太少,致使没法肯定是哪一个函数报的错,所以首先仍是加日志,对各个可疑点增长错误日志后,在咱们测试集群随便找了个老节点替换版本,而后很容易就复现了,并肯定是新加的验证快照文件合法性的锅,那么它为何会出现crc mismatch呢? 首先咱们来简单了解下wal文件。
  • etcd任何通过raft的模块的请求在写入etcd mvcc db前都会经过wal文件持久化,若进程在apply command过程当中出现被杀等异常,重启时可经过wal文件重放将数据补齐,避免数据丢失。wal文件包含各类请求命令如成员变化信息、涉及key的各个操做等,为了保证数据完整性、未损坏,wal每条记录都会计算其的crc32,写入wal文件。重启后解析wal文件过程当中,会校验记录的完整性,若是数据出现损坏或crc32计算算法出现变化则会出现crc32 mismatch.
  • 硬盘及文件系统并未出现异常,排除了数据损坏,通过深刻排查crc32算法的计算,发现是新增逻辑未处理crc32类型的数据记录,它会影响crc32算法的值,致使出现差别,并且只有在当etcd集群建立产生后的第一个wal文件被回收才会触发,所以对存量运行一段时间的集群,100%复现。
  • 解决方案就是经过增长crc32算法的处理逻辑以及增长单元测试覆盖wal文件被回收的场景,社区已合并并发布了新的3.4和3.3版本(v3.4.9/v3.3.22).

img

虽然这个bug是社区用户反馈的,但从这个crash bug中咱们得到了如下收获和最佳实践:

  • 单元测试用例很是有价值,然而编写完备的单元测试用例并不容易,须要考虑各种场景。
  • etcd社区对存量集群升级、各版本之间兼容性测试用例几乎是0,须要你们一块儿来为其舔砖加瓦,让测试用例覆盖更多场景。
  • 新版本上线内部流程标准化、自动化, 如测试环境压测、混沌测试、不一样版本性能对比、优先在非核心场景使用(如event)、灰度上线等流程必不可少。

配额及限速(Quota&QoS)

etcd面对一些大数据量的查询(expensive read)和写入操做时(expensive write),如全key遍历(full keyspace fetch)、大量event查询, list all Pod, configmap写入等会消耗大量的cpu、内存、带宽资源,极其容易致使过载,乃至雪崩。

然而,etcd目前只有一个极其简单的限速保护,当etcd的commited index大于applied index的阈值大于5000时,会拒绝一切请求,返回Too Many Request,其缺陷很明显,没法精确的对expensive read/write进行限速,没法有效防止集群过载不可用。

为了解决以上挑战,避免集群过载目前咱们经过如下方案来保障集群稳定性:

  • 基于K8s apiserver上层限速能力,如apiserver默认写100/s,读200/s
  • 基于K8s resource quota控制不合理的Pod/configmap/crd数
  • 基于K8s controller-manager的-terminated-Pod-gc-threshold参数控制无效Pod数量(此参数默认值高达12500,有很大优化空间)
  • 基于K8s的apiserver各种资源可独立的存储的特性, 将event/configmap以及其余核心数据分别使用不一样的etcd集群,在提升存储性能的同时,减小核心主etcd故障因素
  • 基于event admission webhook对读写event的apiserver请求进行速率控制
  • 基于不一样业务状况,灵活调整event-ttl时间,尽可能减小event数
  • 基于etcd开发QoS特性,目前也已经向社区提交了初步设计方案,支持基于多种对象类型设置QoS规则(如按grpcMethod、grpcMethod+请求key前缀路径、traffic、cpu-intensive、latency)
  • 经过多维度的集群告警(etcd集群lb及节点自己出入流量告警、内存告警、精细化到每一个K8s集群的资源容量异常增加告警、集群资源读写QPS异常增加告警)来提早防范、规避可能出现的集群稳定性问题

多维度的集群告警在咱们的etcd稳定性保障中发挥了重要做用,屡次帮助咱们发现用户和咱们自身集群组件问题。用户问题如内部某K8s平台以前出现bug, 写入大量的集群CRD资源和client读写CRD QPS明显偏高。咱们自身组件问题如某旧日志组件,当集群规模增大后,因日志组件不合理的频繁调用list Pod,致使etcd集群流量高达3Gbps, 同时apiserver自己也出现5XX错误。

虽然经过以上措施,咱们能极大的减小因expensive read致使的稳定性问题,然而从线上实践效果看,目前咱们仍然比较依赖集群告警帮助咱们定位一些异常client调用行为,没法自动化的对异常client的进行精准智能限速,。etcd层因没法区分是哪一个client调用,若是在etcd侧限速会误杀正常client的请求, 所以依赖apiserver精细化的限速功能实现。社区目前已在1.18中引入了一个API Priority and Fairness[7],目前是alpha版本,期待此特性早日稳定。

性能优化案例剖析

etcd读写性能决定着咱们能支撑多大规模的集群、多少client并发调用,启动耗时决定着咱们当重启一个节点或因落后leader太多,收到leader的快照重建时,它从新提供服务须要多久?性能优化案例剖析咱们将从启动耗时减小一半、密码鉴权性能提高12倍、查询key数量性能提高3倍等来简单介绍下如何对etcd进行性能优化。

启动耗时及查询key数量、查询指定记录数性能优化

当db size达到4g时,key数量百万级别时,发现重启一个集群耗时居然高达5分钟, key数量查询也是超时,调整超时时间后,发现高达21秒,内存暴涨6G。同时查询只返回有限的记录数的场景(如业务使用etcd grpc-proxy来减小watch数,etcd grpc proxy在默认建立watch的时候,会发起对watch路径的一次limit读查询),依然耗时很高且有巨大的内存开销。因而周末空闲的时候我对这几个问题进行了深刻调查分析,启动耗时到底花在了哪里?是否有优化空间?查询key数量为什么如何耗时,内存开销如此之大?

带着这些问题对源码进行了深刻分析和定位,首先来看查询key数和查询只返回指定记录数的耗时和内存开销极大的问题,分析结论以下:

  • 查询key数量时etcd以前实现是遍历整个内存btree,把key对应的revision存放在slice数组里面
  • 问题就在于key数量较多时,slice扩容涉及到数据拷贝,以及slice也须要大量的内存开销
  • 所以优化方案是新增一个CountRevision来统计key的数量便可,不须要使用slice,此方案优化后性能从21s下降到了7s,同时无任何内存开销
  • 对于查询指定记录数据耗时和内存开销很是大的问题,经过分析发现是limit记录数并未下推到索引层,经过将查询limit参数下推到索引层,大数据场景下limit查询性能提高百倍,同时无额外的内存开销。

img

img

再看启动耗时问题太高的问题,经过对启动耗时各阶段增长日志,获得如下结论:

  • 启动的时候机器上的cpu资源etcd进程未能充分利用
  • 9%耗时在打开后端db时,如将整个db文件mmap到内存
  • 91%耗时在重建内存索引btree上。当etcd收到一个请求Get Key时,请求被层层传递到了mvcc层后,它首先须要从内存索引btree中查找key对应的版本号,随后从boltdb里面根据版本号查出对应的value, 而后返回给client. 重建内存索引btree数的时候,偏偏是相反的流程,遍历boltdb,从版本号0到最大版本号不断遍历,从value里面解析出对应的key、revision等信息,重建btree,由于这个是个串行操做,因此操做及其耗时
  • 尝试将串行构建btree优化成高并发构建,尽可能把全部核计算力利用起来,编译新版本测试后发现效果甚微,因而编译新版本打印重建内存索引各阶段的详细耗时分析,结果发现瓶颈在内存btree的插入上,而这个插入拥有一个全局锁,所以几乎无优化空间
  • 继续分析91%耗时发现重建内存索引居然被调用了两次,第一处是为了获取一个mvcc的关键的consistent index变量,它是用来保证etcd命令不会被重复执行的关键数据结构,而咱们前面提到的一个数据不一致bug刚好也是跟consistent index有密切关系。
  • consistent index实现不合理,封装在mvcc层,所以我前面提了一个pr将此特性重构,作为了一个独立的包,提供各种方法给etcdserver、mvcc、auth、lease等模块调用。
  • 特性重构后的consistent index在启动的时候就再也不须要经过重建内存索引数等逻辑来获取了,优化成调用cindex包的方法快速获取到consistent index,就将整个耗时从5min从缩短到2分30秒左右。所以优化同时依赖的consistent index特性重构,改动较大暂未backport到3.4/3.3分支,在将来3.5版本中、数据量较大时能够享受到启动耗时的显著提高。

img

img

密码鉴权性能提高12倍

某内部业务服务一直跑的好好的,某天client略微增多后,忽然现网etcd集群出现大量超时,各类折腾,切换云盘类型、切换部署环境、调整参数都不发挥做用,收到求助后,索要metrics和日志后,通过一番排查后,获得如下结论:

  • 现象的确很诡异,db延时相关指标显示没任何异常,日志无任何有效信息
  • 业务反馈大量读请求超时,甚至能够经过etcdctl客户端工具简单复现,但是metric对应的读请求相关指标数居然是0
  • 引导用户开启trace日志和metrics开启extensive模式,开启后发现无任何trace日志,然而开启extensive后,我发现耗时居然所有花在了Authenticate接口,业务反馈是经过密码鉴权,而不是基于证书的鉴权
  • 尝试让业务同窗短暂关闭鉴权测试业务是否恢复,业务同窗找了一个节点关闭鉴权后,此节点马上恢复了正常,因而选择临时经过关闭鉴权来恢复现网业务
  • 那鉴权为何耗时这么慢?咱们对可疑之处增长了日志,打印了鉴权各个步骤的耗时,结果发现是在等待锁的过程当中出现了超时,而这个锁为何耗时这么久呢?排查发现是由于加锁过程当中会调用bcrpt加密函数计算密码hash值,每次耗费60ms左右,数百并发下等待此锁的最高耗时高达5s+。
  • 因而咱们编写新版本将锁的范围减小,下降持锁阻塞时间,用户使用新版本后,开启鉴权后,业务再也不超时,恢复正常。
  • 随后咱们将修复方案提交给了社区,并编写了压测工具,测试提高后的性能高达近12倍(8核32G机器,从18/s提高到202/s),可是依然是比较慢,主要是鉴权过程当中涉及密码校验计算, 社区上也有用户反馈密码鉴权慢问题, 目前最新的v3.4.9版本已经包含此优化, 同时能够经过调整bcrpt-cost参数来进一步提高性能。

img

本文简单描述了咱们在管理万级K8s集群和其余业务过程当中遇到的etcd稳定性和性能挑战,以及咱们是如何定位、分析、复现、解决这些挑战,并将解决方案贡献给社区。

同时,详细描述了咱们从这些挑战中收获了哪些宝贵的经验和教训,并将之应用到后续的etcd稳定性保障中,以支持更大规模的单集群和总集群数。

最后咱们面对万级K8s集群数, 千级的etcd集群数, 10几个版本分布,其中很多低版本包含重要的潜在可能触发的严重bug, 咱们还须要投入大量工做不断优化咱们的etcd平台,使其更智能、变动更加高效、安全、可控(如支持自动化、可控的集群升级等), 同时数据安全也相当重要,目前腾讯云TKE托管集群咱们已经全面备份,独立集群的用户后续将引导经过应用市场的etcd备份插件开启定时备份到腾讯云对象存储COS上。

将来咱们将继续紧密融入etcd的社区,为etcd社区的发展贡献咱们的力量,与社区一块提高etcd的各个功能。

参考资料

[1]v3.4.9: https://github.com/etcd-io/et...

[2]v3.3.22: https://github.com/etcd-io/et...

[3]K8s issue和pr: https://github.com/kubernetes...

[4]grpc crash(issue): https://github.com/etcd-io/et...

[5]grpc crash(pr): https://github.com/grpc/grpc-...

[6]crash bug : https://github.com/etcd-io/et...

[7]API Priority and Fairness: https://github.com/kubernetes...

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!
相关文章
相关标签/搜索