2025-01-23 11:17:22
忙忙碌碌又是一年,2024 匆匆结束。回想这一年的成长和收获,除了个人能力的提升,在做人做事做选择等方面也有了更多的认识。可以说,自己并未虚度时光,过得十分充实。
临近除夕,总算抽出时间坚持自己之前的习惯来继续写年终总结。希望今年的总结不仅能继续鞭策自己寻找并实践摩尔定律的成长节奏,也能获得更多反馈来修正自己。
首先依然是自我介绍环节,我叫谭新宇,清华本硕,师从软件学院王建民/黄向东老师。目前在时序数据库 Apache IoTDB 的商业化公司天谋科技系统组担任内核开发工程师。我对分布式系统、性能优化等技术驱动的系统设计感兴趣,2024 年也一直致力于提升 Apache IoTDB 的集群易用性 & 鲁棒性、共识能力和写入性能等,并接手完成了若干具有挑战性的大项目。
接下来介绍一下我司:
天谋科技的物联网时序数据库 IoTDB 是一款低成本、高性能的时序数据库,技术原型发源于清华大学,自研完整的存储引擎、查询计算引擎、流处理引擎、智能分析引擎,并拓展集群管理、系统监控、可视化控制台等多项配套工具,可实现单平台采存算管用的横向一站式解决方案,与跨平台端边云协同的纵向一站式解决方案,可方便地满足用户在工业物联网场景多测点、多副本、多环境,达到灵活、高效的时序数据管理。
天谋科技由全球性开源项目、Apache Top-Level 项目 IoTDB 核心团队创立。公司围绕开源版持续进行产品性能打磨,提供更加全面的企业级服务与行业特色功能,并开发易用性工具,使得 IoTDB 的读写、压缩、处理速度、分布式高可用、部署运维等技术维度领先多家数据库厂商。目前,IoTDB 可达到单节点每秒千万级数据写入、10X 倍无损压缩、TB 数据毫秒级查询响应、两节点高可用、秒级扩容等性能表现,实现单设备万级点位、多设备亿级点位管理。
目前,IoTDB 能够为我国关键行业提供一个国产的、更加安全的、性能更加优异的选择。据不完全统计,IoTDB 已服务超 1000 家以上工业企业,在能源电力、钢铁冶炼、航空航天、石油石化、智慧工厂、车联网等行业均成功部署数十至数百套,并扩展至期货、基金等金融行业。目前已投入使用的企业包括华润电力、中核集团、国家电网、宝武钢铁、中冶赛迪、中航成飞、中国中车、长安汽车等。
值得一提的是,2024 年 IoTDB 的商业公司天谋科技营收同比增长近 300%,正式进入了指数增长的摩尔定律节奏。
介绍完背景后,在这里回顾下 2024 年我们系统组的主要工作,可分为 TPCx-IoT 双版本登顶、共识遥遥领先、性能优化摩尔定律新时代、集群易用性 & 鲁棒性显著提升、海量项目支持和海量技术沉淀 6 个方面。
在 TPCx-IoT 双版本登顶方面,国际事务处理性能委员会(TPC)是全球最权威的数据库性能测评基准组织之一。TPCx-IoT(TPC Express Benchmark IoT)是业界首个能直接对比物联网场景下不同软件和硬件性能的基准,涵盖了性能和性价比两个维度。今年,TimechoDB 1.3.2.2 版本在开启和关闭 WAL 测试的两种配置下,分别在 TPCx-IoT 的性能和性价比两个维度均登顶。值得一提的是,原本性能第一的系统是开启 WAL 的,而性价比第一的系统则关闭了 WAL。做数据库的人都知道,是否开启 WAL 对写入性能和资源消耗有着巨大的影响。尽管如此,IoTDB 最终实现了即使开启 WAL,仍能在性能和性价比两个维度同时登顶。如果关闭 WAL,性能和性价比还能够进一步提升约 20%,这充分彰显了 IoTDB 在应对物联网高吞吐场景中的极致性能。如今回想今年与新豪一起完成的这一工作,个人感触颇深,这对我来说也是四年磨一剑的过程。还记得 2020 年下半年研究生刚入学时,我就第一次尝试用 TPCx-IoT 测试过 0.12 版本的 IoTDB 老分布式集群。当时的分布式架构存在较大问题,性能始终难以提升,那年我的外号也成了 “tpc”,因为我一个学期几乎都在做 TPCx-IoT 测试,遗憾的是最终没有得到理想结果。经过四年的彻底重构与迭代,IoTDB 自 1.0 版本推出了全新的分布式架构,并在分区、共识和写入性能等方面做了诸多创新与改进。这些进展不仅使 IoTDB 能够支撑更多的用户场景,也最终帮助我们在 TPCx-IoT 榜单上登顶,性能达到了老版本的近 6 倍,充分证明了技术创新始终是第一生产力。此外,随着商业化公司成立,本次登顶过程中,我们不再是单打独斗,获得了许多同事的全力支持,特别是在与 TPC 委员会沟通、撰写报告等方面。这里特别感谢鹏程、Chris、昊男和苏总等同事对我们组的支持与帮助。没有团队的默默付出与协作,我们也不可能在今年完成这一目标,让这把磨了四年的剑最终得以出鞘。
在共识遥遥领先方面,IoTDB 的 1.x 分布式版本参照 2020 OSDI 最佳论文 Facebook Delos 的思路抽象了一个支持不同共识算法的统一共识框架,允许用户在一致性、可用性、性能和存储成本等若干维度进行权衡。今年我们不仅将现有共识算法迭代的几乎稳定,更是创新的提出了一个新的性能遥遥领先的共识算法
在性能优化摩尔定律新时代方面,今年我跟旭鑫、昊男、雨峰、湘鹏、荣钊、钰铭、江天学长,田原学长和振宇师兄等团队成员一起进行了多项盲测写入性能优化工作并取得了显著进展。我们不仅在很多特定场景下实现了性能提升数十倍的效果,还在通用场景下实现了写入性能翻倍的成就,这是 IoTDB 写入性能提升最大的一年。通过分布式架构、存储引擎和系统优化的组合拳,我们成功让 IoTDB 在通用场景下的盲测写入性能进入了摩尔定律的成长节奏(每 18 个月性能翻一倍或资源利用率减少一半)。以 2023 年为基准,2024 年我们已经实现了这一目标,2025 和 2026 年现有的技术储备也已经为继续沿着摩尔定律节奏提升奠定好了基础。在具体优化方面,我们做了很多关键工作,仅列举已做的开源部分如下:
在集群易用性 & 鲁棒性显著提升方面,我们也做了非常多的工作
在 IoT-Benchmark 方面,今年我们梳理了其项目结构和 README,使其逐步向更通用的时序基准测试工具演进。过去一年钰铭作为主力带领我们迭代了近 100+ commit,包括 50+ 稳定性修复和易用性提升、以及 10+ 性能优化。
在持续集成与迭代体系方面,今年在王老师的指引下,我们引入了对第三方库的 SBOM 管理,并开始使用 NVD 扫描并持续追踪开源项目中的 CVE 问题,从而逐步提升了对第三方依赖漏洞安全问题的重视。此外,我们还开始统计 IoTDB 的代码量,以评估代码复用效果和项目的复杂度。与此同时,我们也意识到,随着产品功能和复杂度的不断增加,测试用例的指数级增长与产品迭代效率之间存在一定的 trade-off。结合每天晚上和周末 CI 机器几乎都在空闲的现状——每周 168 个小时中,只有大约 1/3 的时间 CI 机器在工作,其余 2/3 的时间处于闲置状态——我与钰铭开始探索将 CI 拆分为不同级别的测试体系,包括 commit、daily 和 weekly 级别的测试。我们在 commit 级别保留最为关键的 CI 测试,在 daily 和 weekly 测试中充分利用闲置的机器资源,补充更多的测试用例。同时,我们也将引入智能化策略,自动识别并追踪有问题的 commit,从而在开发效率与质量保障之间找到更好的平衡点。
在海量项目支持这块,我则个人负责了若干探索性项目并参与了很多实际项目
在海量技术沉淀这块,则基本是我们出于技术 & 业务双驱动完成的很多探索
今年,我在 Apache IoTDB 社区提交并被合并了 84 个 PR(去年 119 个),Review 了 509 个 PR(去年 387 个)。相比去年,今年我的大部分精力都集中在贴近业务和技术管理上,也对个人和团队如何最大化产出有了更多思考和感悟。今年 8 月,我受邀成为 Ratis 社区的 Committer,并成功拥有了 1k Github Follower,这让我更加认可自己在开源领域的专注。回顾过去一年,我觉得我们成功将团队的许多工作通过各种方式沉淀下来,并影响了许多人。希望我们能始终在这段青春年华中保持对技术的热情,专注于我们的工作继续前行。在这里,我特别感谢我的女朋友🍊 始终支持我的工作并帮助我疏解情绪,让我感受到生活的美好与幸福。她还带我见识了许多新事物,让我对人生的很多方面有了新的认识和思考。
介绍完充实的 2024,回顾 2023 年终总结,可以发现今年我们在去年四个维度的展望上都取得了不错的成绩
下面分享一下我今年的很多成长感悟,欢迎大家批评指正。
对于一个稳定性打磨的功能,如何评估其完善时间?在打磨 Region 迁移的稳定性时,我今年思考了很久。如果考虑无数硬件环境(如 4C16G 和 192C768G)、测试负载(实时写入、读写混合),再加上注入各种异常(如节点重启、网络分区、断电等),以及多个模块功能的组合(如多级存储、存储引擎、共识层、流处理引擎等),可以看出它们的组合是指数级扩展的。即使研发进行了完善的设计与实现,但提测后仅测试完善的开销就几乎永无止境。但如果一开始就定下工作周期为半年或一年,也难以做出可靠的过程管理来向上汇报。
在这种困境下,我们必须意识到场景是无限的,在精力有限的情况下,我们的目标是用最小的研发和测试代价解决尽可能多的 bug。最初,我们按照研发视角将功能的稳定性迭代分为 V1、V2、V3,期望逐步打磨到稳定状态。然而在实际测试中,我们发现测试视角与研发视角并不同频,导致测出的 bug 比较分散,尽管测试与研发一同打磨很久,仍难以向上汇报阶段性成果,因为每个模块都有不少 bug 被修复。这使得这个工作看起来像是无底洞,且容易受到质疑。其实,问题的根本在于缺乏多方共识的客观评价标准。
回顾整体流程,我认为可以在以下两个方面做得更好
今年有件让我深受感触的事,那就是发现大家对 IoTV2 共识算法的价值产生了质疑。从纯研发的视角来看,IoTV2 显然在创新性和性能上都显著超越了 IoTV1,是我们组过去几年最具创新性的工作之一,其他共识算法也都花了好几年才稳定,IoTV2 毕竟才诞生一年。但如果想在开发团队中获得更广泛的认可,就需要考虑大家关注的不同方面,包括稳定性、创新性、问题收敛程度、潜在收益与投入的平衡等。可以看出,这些维度之间往往存在矛盾,而且很难得出绝对客观的结论,很多东西也完全看未来的事在人为,因此很难在所有人中达成共识。这让我意识到,当一个软件项目和团队发展到一定阶段后,是否落实创新工作,往往会面临保守和激进的分歧,二者需要不断博弈与制衡,才能走向一个可行的方向。完全激进或者完全保守都会带来不可预知的风险。
回到 IoTV2,我们能够平息质疑的一个重要原因是我们做了共识层的抽象,能在一套接口下支持不同的共识算法,从而使得各个共识算法可以单独迭代。如果没有这个统一的接口,不管 IoTV2 作为业界第一个多副本超越单副本的共识算法有多么创新,仍然会面临无数质疑,甚至可能导致无法迭代。而对于竞品来说,除非照抄 IoTDB 整体共识层的设计,否则也很难平息内部质疑,全力推进这项工作。这为我们未来的扩展性设计提供了指导——良好的接口抽象能够使得系统的关键迭代从“不可能”变为“可能”。当然,软件工程没有银弹,即使我们通过共识层的抽象让 IoTV2 的迭代得以顺利进行,但代价就是翻倍的测试和打磨开销。总体而言,抽象得越好,复杂度封装得越到位,测试和打磨的开销也就越低。
在今年参与更多技术管理工作后,我渐渐关注到个人管理成本 ROI 这一概念,其本质是消耗尽可能低的 +1 管理成本(包括时间和资源等)完成更复杂的工作,并在有风险时及时汇报并提供辅助决策的数据。
总体而言,不同的人有不同的管理风格,同一个人对于不同的事情也会采取不同的管理方式。有时像《大明王朝 1566》中的嘉靖一样,只关注结果,不拘过程;有时又像《大决战》中的 101 一样,会关注每一个细节。其实,不论是哪种管理风格,最终目标都是完成工作,并没有绝对的好坏之分。
对于我们个人而言,我们控制不了别人,唯一能够不断改善的就是提升自己的管理成本 ROI。通过这种方式,我发现能够使得自己与他人的合作变得更加高效和愉快。类似的例子包括但不限于
这些经验很多是在与我们组俊植一起进步的过程中学到的。希望自己能像俊植一样,不断提升自己的管理成本 ROI,进而锻炼出更好的职业素养。
今年年中,我读了润基哥哥的十倍程序员文章,受益良多。对于十倍程序员的成长,本质上有两个方面:
从纯个人能力上来看,可以按照上述思路进行纵向和横向扩展,但今年我也意识到人力始终有限,战略上选择一个正确的方向才是事半功倍的关键。所以今年除了个人业务能力的提升,我还积累了很多做人做事的经验。对于很多事情的可行性,我不用再依赖他人的意见,而是能够自己进行主观判断。希望自己能在这个方向上继续沉淀,用靠谱的战略指引自己不断成长。
其实这个感悟与战略类似,说一个应该做的事情只需要十秒钟,然而将这个事情具体落地可能需要十周甚至十个月的时间。人力始终有限,尤其对于一个软件团队来说,面对无数的输入和决策指引,客观上这些工作不可能面面俱到,必须进行战略性取舍。
决定做什么往往没有太多压力,因为人性中总有一种“即使失败了,没有功劳也有苦劳”的自我安慰。但如果要决定不做什么,则必须对自己的业务和竞争力有深刻理解,出于提高人效的角度思考且愿意承担政治责任,才能最终说服别人。这种决策十分困难且珍贵,但也正是许多高效团队能够成功的关键。
今年,我有幸在博士生组会中跟随王老师龙老师带领的实验室团队学习时序 AI 大模型的落地思路。虽然王老师龙老师一直强调我们现在已经做好了“存数”,接下来要把“用数”做好,但他们也明确通过案例分析告诉我们,哪些 AI 项目是靠谱的能够最终产生实际价值,哪些 AI 项目是不靠谱的做了也只是白白耗费精力不创造实际价值。这种战略定力和担当,让我深受触动。
尽管我一直对历史很感兴趣,很多大道理早已听过,但今年在工作中,我从切身实践中获得了一个深刻的感悟:任何事、任何人都会有正负面的影响和评价,不存在一个完人,也不存在一个能够得到所有人认可的方案。
人性大多数时候是非常真实的,大家常常根据结果来判断过程。如果事情没有做成,就会有人列举一堆负面评价来解释为什么失败;如果事情做成了,又会有人说一堆正面评价来证明“早就看他行”。但实际上,成与不成,除了人的因素,还很大程度上取决于天时地利,而这些天时地利,作为非人为因素,反而会深刻影响最终大家的评价。此外,尽管我们都在强调要客观理智,但根据我的观察,大多数人,包括我自己,也曾在情绪驱动下做出一些非预期的行为,并且不断强调自己并没有被情绪左右。
意识到这些后,我明白了很多事情,要么不做,要做就尽己所能做到最好,不必过多顾虑他人的评价。只有这样,才能避免不必要的内耗和沟通成本,将精力集中在更重要的事情上,这样反而更有可能将事情做成。
在今年的工作中,我逐渐有了一些中庸之道的感悟。每个人都有不同的特点,要凝聚一个多样化的团队,需要更多的包容性和开放性。过于从自己的视角偏重某一维度,反而可能导致适得其反,产生“过刚易折”的效果。在做人做事时,面对大的目标和原则性问题时,我们要坚持“刚”;而对于那些不影响最终目标的小细节,则可以选择“柔”。此外,在与许多跨行业朋友的沟通中,我逐渐意识到,尽管我们都在努力工作,但很多事情还是需要天时地利。有时候,顺势而为、蛰伏等待也许是成功的关键。
因此,保持良好的工作心态,营造融洽的工作氛围,在自驱保证自我成长的基础上,不必过于纠结于远方的目标,而应专注当下刚柔并济,才能实现可持续发展,并与团队一起走得更远。
今年对我个人的时间管理和抗压能力来说是极具挑战的一年。上半年临危受命接管存储组,scope 显著扩大,团队人数相比去年接近翻倍。由于一些原因,无法进一步进行分级管理,这对我个人精力提出了极大挑战。基本上,我每天都在不断地线程切换,盯着十几二十个事项。尽管我已经转变为“没有深入参与时间,只略微沟通过程便要结果”的最低投入策略,但由于我依然是单点瓶颈,很多进展缓慢的事情和无人处理的 bug 需要我来当“救火队员”。我的时间依然远远不够用,一旦我在个人处理的某个问题上阻塞了一两个小时,那基本上会造成四五个问题的连锁阻塞。高压状态下,这种情况对我个人的心态和情绪也产生了一定的影响。幸好,下半年江天学长挺身而出,接过了存储组的压力,帮助我们组的人数恢复到了一个相对合理的规模,让我有更多精力去探索和深度参与我们组的很多工作。
现在回想这段经历,我意识到一个人的合理管理半径不应超过 10 个人。在这个范围内,能够在个人输出和团队输出之间取得一个良好的平衡。此外,只有与团队一起成长、大家自驱地去做事,才能在不线性增加时间和精力投入的情况下,扩展管理半径。
即使是同一个人,在不同的年纪,对于金钱、工作氛围、健康和工作生活平衡等方面的追求都会有所不同。但一直以来,驱动我前进并屏蔽这些外部欲望的动力,始终是如何在单位时间内获得更多的成长。随着时间的推移,我逐渐意识到,能够承担越来越大的责任,并创造更多的价值,才是个人成长的核心所在。
固然我们可以在任何地方按照这个思路去追求自我成长,但只有在一个增量团队中,团队和个人的双指数增长才更容易实现。希望大家可以找到与自己 match 的指数增长团队。
通过这一年,我们为 IoTDB 在技术上构建了摩尔定律的成长节奏。幸运的是,这些技术积累也立即在影响力和营收上得到了体现。希望在新的一年,无论是我个人还是团队,都能继续保持这种摩尔定律般的成长节奏,推动更多的技术创新和业务突破。
最后,在除夕之际,预祝大家新年万事如意,心想事成!愿每个人在新的一年中都能够事业有成,收获满满!
2024-02-07 15:24:52
兜兜转转又是一年,不知不觉 2023 已经结束。回想自己过去一年的成长与感悟,依然觉得是收获满满。今年工作之后闲余时间相比学生时代少了许多,到了除夕才有时间来写今年的年终总结。好在自己还是下定决心将这个习惯坚持下去,希望这些年终总结不仅能够在未来的时光里鞭策自己,也能够获得更多大家的反馈来修正自己。
首先依然是自我介绍环节,我叫谭新宇,清华本硕,师从软件学院王建民/黄向东老师。目前在时序数据库 Apache IoTDB 的商业化公司天谋科技担任内核开发工程师。我对分布式系统、可观测性和性能优化都比较感兴趣,2023 年也一直致力于提升 Apache IoTDB 的分布式能力、可观测性和写入性能。
接下来介绍一下我司:
天谋科技的物联网时序数据库 IoTDB 是一款低成本、高性能的时序数据库,技术原型发源于清华大学,自研完整的存储引擎、查询计算引擎、流处理引擎、智能分析引擎,并拓展集群管理、系统监控、可视化控制台等多项配套工具,可实现单平台采存算管用的横向一站式解决方案,与跨平台端边云协同的纵向一站式解决方案,可方便地满足用户在工业物联网场景多测点、多副本、多环境,达到灵活、高效的时序数据管理。
天谋科技由全球性开源项目、Apache Top-Level 项目 IoTDB 核心团队创立。公司围绕开源版持续进行产品性能打磨,提供更加全面的企业级服务与行业特色功能,并开发易用性工具,使得 IoTDB 的读写、压缩、处理速度、分布式高可用、部署运维等技术维度领先多家数据库厂商。目前,IoTDB 可达到单节点每秒千万级数据写入、10X 倍无损压缩、TB 数据毫秒级查询响应、两节点高可用、秒级扩容等性能表现,实现单设备万级点位、多设备亿级点位管理。
目前,IoTDB 能够为我国关键行业提供一个国产的、更加安全的、性能更加优异的选择。据不完全统计,IoTDB 已服务超 1000 家以上工业企业,在能源电力、钢铁冶炼、航空航天、石油石化、智慧工厂、车联网等行业均成功部署数十至数百套,并扩展至期货、基金等金融行业。目前已投入使用的企业包括华润电力、中核集团、国家电网、宝武钢铁、中冶赛迪、中航成飞、中国中车、长安汽车等。
介绍完背景后,在这里回顾下 2023 年我们系统组的主要工作,可分为高扩展性、高可用性、可观测性、性能优化、技术支持和技术沉淀 6 个方面。
在高扩展性方面,我们主要做了以下工作:
在高可用性方面,我们主要做了以下工作:
在可观测性方面,我们主要做了以下工作:
在性能优化方案,我们主要做了以下工作:
在技术支持方面,我们主要做了以下工作:
在技术沉淀方面,我们主要做了以下工作:
今年我在 Apache IoTDB 社区提交并被合并了 119 个 PR, Review 了 387 个 PR。从 PR 数量上来说相比去年和前年有了显著提升,可能是由于更加专注于工作,并且 scope 也在不断扩大吧。此外我也于今年 9 月受邀成为了 Apache IoTDB 社区的 PMC 成员,感谢社区对我的认可。
因时间所限,我今年在知乎等社交平台的活跃度有所下降。但回顾这一年,我觉得我们团队完成了许多既有趣又深入的工作,并且几乎都有相应的文档沉淀下来。这些宝贵的积累完全可以与业界分享以交流学习。我期待在 2024 年,我们团队能够更频繁地分享我们的技术沉淀,并吸引更多对技术有兴趣的同学加入 IoTDB 社区或我们的实验室进行交流!
在深入研究和优化数据库系统在各种硬件环境及业务负载下的性能过程中,我越发认识到掌握体系结构和操作系统知识是进行性能优化的基础。今年,我在这两方面补充了许多知识,并阅读了《性能之巅》的部分章节。然而,令人感到有些沮丧的是,随着知识的增加,我反而越来越感觉到自己的无知。但我仍然希望,在 2024 年能够跨越这段充满挑战的绝望之谷,登上开悟之坡。
对于有意向学习 CMU 15-418 课程的朋友,我非常期待能够一同学习和进步!如果有经验丰富的大佬愿意指导,我将不胜感激!
今年,我们组深入研究了 JDK 的垃圾回收(GC)算法,包括但不限于 Parallel Scavenge(PS)、Concurrent Mark Sweep(CMS)、Garbage-First(G1)和 Z Garbage Collector(ZGC)。我们还对 IoTDB 在相同业务负载下采用不同 GC 算法的吞吐量和延迟性能进行了比较测试,结果表明在不同的负载条件下,各 GC 算法的性能表现排序也有所不同。
在 GC 算法的选择上,我们面临着内存占用(footprint)、吞吐量(throughput)和延迟(latency)三者之间的取舍,类似于 CAP 定理,这三者不可能同时被完全满足,最多只能满足其中的两项。通常情况下,高吞吐量的 GC 算法会伴随较长的单次 STW 时间;而 STW 时间较短的 GC 算法往往会频繁触发 GC,占用更多的线程资源,导致吞吐量下降。例如,PS GC 虽然只有一次 STW,但可能耗时较长;G1 的 Mixed GC 在三次 STW 中的 Copying 阶段可能造成几百毫秒的延迟;而 ZGC 的三次 STW 时间都与 GC Roots 数量有关,因此 STW 延迟可以控制在毫秒级别。
JDK GC 算法的发展趋势似乎是在尽量减少 GC 对业务延迟的影响,但这种优化的代价是消耗更多的 CPU 资源(JDK 21 引入的分代 ZGC 有望大幅降低 ZGC 的 CPU 开销)。在 CPU 资源本身成为瓶颈的场景下,使用 ZGC 和 G1 等 GC 算法的吞吐量可能会低于 PS。GC 算法目前的演进具有两面性,例如 Go 语言就由于其默认 GC 与 Java 相比 STW 时间较短而被赞扬,但其 CPU 资源消耗大也会被批评,我们需要根据不同的目标选择合适的 GC 算法。
然而,GC 算法朝低延迟方向的不断演进仍具有重要意义,因为吞吐问题可以通过增加机器进行横向扩展来解决,而延迟问题则只能依赖于 GC 算法的改进。因此,在调优时应该有针对性,分别针对吞吐和延迟进行优化,而不是同时追求两者。如果追求吞吐量,可以优先考虑使用 PS;如果追求低延迟,可以考虑使用 G1/ZGC,并为之准备额外的机器资源以支付低延迟的代价。
今年,我参与了许多问题修复和优先级排序的工作,同时深入思考了编程语言对软件开发总成本的影响。
在 PingCAP 实习期间的一次闲聊中,有些同事提出 TiDB 应该用 Rust 或 C++重写,理由是用 Go 语言编写的性能较差。然而,我的 mentor 徐总认为,采用 Go 语言后显著减少了大家的 OnCall 次数,从而节约了大量研发成本。
从纯技术的角度看,C/C++ 在极限优化下确实能比 Java 更好地发挥硬件特性。但工程开发,尤其是内核开发,不仅仅是技术问题,它更多涉及到软件工程的广泛议题。现实中,我们经常面临着无休止的问题修复和需求实现,性能优化往往未能充分利用硬件能力。我认为,尽管开发团队采用的编程语言可能影响理论上的性能上限,但在大多数工程实践中,项目成功的关键并不仅仅在于将性能优化到极致。更重要的是,在有限资源下如何优先追求满足用户需求的产品特性、如何持续保证产品的稳定性和可维护性、如何提升系统的横向扩展能力、以及如何在现有代码基础上持续进行性能优化。我相信,这些因素比起编程语言的选择所带来的潜在收益要重要得多。
因此,除了少数极特别的场景(例如追求超低延迟 or 边缘端等),选择一个团队熟悉且学习成本较低的编程语言就足够了。
今年,我们面对并快速解决了许多棘手的问题,但同时也遇到了一些难以快速找到原因的疑难杂症。这些问题涵盖了多个方面,例如 DataNode 进程在 OOM 后仍能响应心跳但无法处理新的读写请求(这是因为 JVM 在 OOM 后随机终止了一些线程,导致监听线程被终止无法响应新连接而心跳服务线程仍在运行),以及 Ratis consensusGroupID 编码错误导致的 GroupNotFound 错误(使用 Arthas 监控后问题消失,我们怀疑这是 JVM JIT 的 bug)等。
解决这些问题的过程加深了我们对于设计新功能时对各种异常场景的考虑,有效避免了许多未来可能发生的 Oncall 问题。
在面对问题和解决问题的过程中,我深刻体会到人的认知可以分为四个象限:已知的已知、已知的未知、未知的已知以及未知的未知。其中,最难以应对的是“未知的未知”。我一直在思考工程经验这四个字究竟意味着什么?现在我认为,工程经验的积累不仅意味着将更多的“已知的未知”转化为“已知的已知”,还需要将更多的“未知的未知”变成“已知的未知”,这样才能具有可持续性。
今年,我深刻体会到了流程体系在构建一个可持续发展的软件开发团队中的重要性。我认识到只有拥有一流的团队,才能够开发出一流的软件。
在王老师软件工程理念的统筹指导和 Apache 基金会的支持下,我认为我们的产品流程体系已经相对健全,包括但不限于以下几个方面:
通过在这样的团队中工作,我对如何打造一个可持续的软件工程体系有了更深地理解。
随着我们组负责的模块和同学数量的增加,我逐渐发现,仅仅通过飞书文档记录工作内容的做法,虽然实现了工作的“记录”,却缺乏了有效的“管理”。例如,我们组面临的任务琐碎而多样,大家都经常会忘记一些计划中的任务;同时,我们的业务需求变化迅速,虽然大家都在同时推进多项任务,但仍然跟不上需求的变化速度。这就要求我们能够及时调整任务的优先级,以便灵活应对并优先完成 ROI 最高的任务。此外,我们以前的月度总结并没有持续进行,我分析的原因是任务汇总本身就是一种成本,导致月度总结难以持续,从而失去了很多总结沟通的机会。
为了解决这些问题,我开始学习并使用飞书的多维表格来管理团队的任务。通过多维表格,我们不仅可以清晰地看到每位成员当前的工作任务,还可以在团队会议上根据业务需要灵活调整任务优先级,甚至能够一键生成甘特图来明确不同优先级任务的时间线。在进行每周和每月总结时,我们也能够通过筛选日期快速生成任务汇总。
一开始,多维表格似乎完美地解决了我们之前的问题。然而,随着时间的推移,我发现这种方式也存在缺陷。由于总结能够一键生成,我不再每周花费一小时来统计和规划我们的周报和下周计划,甚至我们的月度总结也鲜少举办。这反而导致我们的日常开发缺乏规划,显得有些随波逐流。在东哥的点拨下,我重新开始在飞书文档中记录周报,并且连续三个月组织了月度总结会。通过定时的每周和每月汇总与沟通,团队的工作变得更加有序和明确。现在如果让我去说上半年做了什么主要工作,我可能还需要看多维表格筛选半天,但如果问我后 3 个月做了什么,我只需要看每月的月度总结就可以了。
现在,我们通过多维表格来管理任务的优先级,同时利用飞书文档来汇总周报和月报。通过对我们组流程管理的持续迭代和优化,我意识到有时候追求速度反而会拖慢进度,而适当地放慢脚步思考反而能够使我们更加高效。
在技术方面,我最开始深入了解的就是分布式系统,我一直在学习如何实现系统的高扩展性和高可用性。随着时间的推移,我发现这些分布式系统的理念同样适用于团队协作中。
为了实现高扩展性,关键在于让所有团队成员并行工作,而不是仅依赖于“主节点”或关键个体,这要求每个成员都能独自完成任务并持续提高自己的工作效率,这样才能提升整个团队的整体性能。同时,团队还需要能够支持成员的动态调整,如新成员的加入和旧成员的离开,确保团队结构的灵活性和适应性。
为了满足高可用性,就需要在关键任务或数据上实施冗余策略,以防止暂时的不可用状态对团队工作造成影响。这可能意味着需要在某些区域投入额外的资源,确保信息、知识或工作负载能够在多个成员之间共享,保持一致性。
这一年来,我们团队负责的模块不断增加,但每个模块都至少有 3 位以上的成员熟悉,上半年我的感受是每天从早忙到晚,连半天假都请不了。但到后半年我感觉偶尔请一两天假也不会对外产生可感知的影响了,这代表了我们组的高可用性出现了显著提升。针对我们组负责的模块,我们维护了详尽的功能和技术设计文档,以及改进措施的追踪记录,这不仅加速了新成员的融入,也保持了团队知识的一致性。此外,我们通过引入自动化工具,如飞书激活解密机器人、各类测试脚本、木马清理脚本等,有效提升了团队的工作效率,体现了我们组在高扩展性方面的进步。
希望 24 年我们组能在高扩展性和高可用性方面继续取得显著进步,为实现更加高效和稳定的团队协作模式而不断努力。
今年我们组的主要工作之一便是打造 IoTDB 的可观测性,目前已经显著提升了问题排查和性能调优的效率,成为线上运维 IoTDB 的必备工具。回到时间管理上,我发现可观测性的很多理念也同样适用。
随着组内同学越来越多,scope 越来越大,沟通协调的成本已经不容忽视,我自己的时间越来越不够用,逐渐成为了单点瓶颈。在向东哥请教后,我开始按照半小时为单位记录自己每天的工作内容,并定期反思每半小时的工作是否满足了高效率。
通过整理自己工作日一天 24 小时的时间分配,我发现自己实际可用于工作的时间并不超过 11 小时,因为每天基本要包括睡眠 8 小时、起床和就寝的准备及洗漱时间 1 小时、通勤 1 小时、餐饮和午休 2 小时以及运动 1 小时(有时会被娱乐消遣取代)。11 月份的数据显示,我的平均工作时间约为 10 小时(没有摸鱼时间),已经接近饱和每天都十分充实。这促使我思考如何提升自己和团队单位时间的工作效率,比如在协调任务时明确目标和截止日期,实行更细致的分工以解决我作为单点瓶颈的问题等。通过这些措施,到了 12 月份,我的平均每日工作时间减少到了 9.5 小时,而感觉团队的整体产出反而有所提升。不过,到了 1 月份,由于一些新的工作安排尚未完全理顺,我的平均工作时间又回升到了 10 小时,这需要我持续进行优化。
总的来说,定期统计和评估自己的时间分配及其 ROI,我觉得对于提高工作效率具有重大意义。
在经历了半年学生生活和半年职场生活后,我对职业发展与生活的关系有了新的认识和感悟。之前我是那种职业动机极强以至于生活显得相对单调的人。对我来说,除了那些能带给我快乐的少数娱乐活动外,生活中的许多琐碎事务如做饭洗碗,都被视为时间的浪费,不如将这些时间用于创造更多的价值。在地铁和高铁上不学习,我也会感到是对时间的浪费。我认为既然职业发展对我而言十分重要且能从中获得快乐,那么我应该将所有可用的时间都投入其中。
然而今年我的心态发生了显著的变化。我逐渐意识到,即使职业发展很重要,即使我能从中获得快乐,它也只是生活的一部分。我开始挤出更多的时间来陪伴家人,也开始与各行各业的老朋友新朋友进行交流。我不再认为生活中的全部琐事是对时间的浪费。我更加注重如何在有限的工作时间内提升效率完成超出预期的工作,而不是简单地用更多的时间去完成这些工作。
这种心态的转变对个人来说不一定是坏事。如果我的心态没有这些变化,可能会投入全部可用的时间于职业发展中,但这样的状态不确定能够持续多久。如果我的心态发生了变化,那我可能会更加注重工作效率和生活体验感,也许能达到职业发展和生活的双赢。
总的来说,每个人在不同的年龄阶段对这种平衡的感悟都会有所不同。我目前的想法是,顺应我们不断成熟的心态,选择让我们感到最舒适的状态,这不仅能让我们的心理状态更加健康,也能更好地平衡职业发展和生活的关系。
马克思指出社会分工是生产力发展的结果和需要,这种分工具有历史的必然性。对于创业公司而言,追求指数型增长是生存和发展的关键,因为即使是线性增长,在激烈的市场竞争中也可能面临被淘汰的风险。如何实现这种增长,是一个复杂且多维的问题,我在这里只从任务分配的角度分享一些个人理解。
在创业团队中,自上而下的任务繁多,而自下而上每个成员的兴趣和专长也各不相同。如何最大化团队的价值?关键在于沟通和了解每个成员的兴趣点和擅长点,尽可能让他们大部分时间都在做自己感兴趣和擅长的工作。虽然总有一些额外的任务需要团队共同承担,但是优先保证成员大部分时间能够从事自己感兴趣且擅长的工作是非常重要的。只有这样,每个人才会带着兴趣和专长去挖掘提升效率的可能,从而可能产生指数级的复利效应,并最终影响整个团队的产出。在现有的权力结构体系下,无论是企业还是更广泛的社会,我觉得自上而下的人员任命也基本遵循这一原则。
基于这样的理解,我在分配我们组的任务时,尽可能根据我对团队成员的了解,分配给每个人感兴趣和擅长的任务,并与大家一起探索提升效率和价值的途径。这一年里,我一直在寻求任务分配的全局最优解,并坚信找到合适的人做他们感兴趣的工作,能够产生的复利远远超过随机或平均分配工作所能带来的效益。
在创业团队的初期阶段,各方面的需求和缺口(技术,市场,运行,销售等等)很多。从公司的角度看,这就非常需要大家能够主动承担额外的职责。从个人的角度看,我们不论是承担更多的职责还是在自己所做的工作上做得更突出,都是对公司的贡献,也都能收获成长。然而人的精力总是有限的,一个人不可能完美地做完所有事情,总是要把有限的精力投入到有限的事情上。面对这样的环境,每个人都面临着如何在工作的广度和深度之间做出选择的问题。
对于这个问题,我今年有了一番思考和探索。个人觉得对于职场新人来说,寻找一个自己擅长且能从中获得乐趣和成就感的领域至关重要,并且需要与领导进行积极的沟通,以获得相应的支持和资源。每个人的选择可能不同,领导的任务就是在团队成员之间找到一个平衡点,不仅能够完成所有任务,还要尽量让每个人能在其擅长的领域内发挥最大的复利效应。
就我个人而言,我目前更倾向于追求工作的深度,希望能够深入学习并掌握我目前尚不擅长但团队需要的技术知识。通过专注于深度,我希望能够在专业领域内取得更大的进步,并为团队带来更具影响力的贡献。当然,这也并不意味着就完全抛弃广度,随着时间不断推移,我在广度上投入的精力也会越来越多。
今年,通过阅读《跳出盒子——领导与自欺的管理寓言》和李玉琢老师的《办中国最出色企业:我的职业经理人生涯》,我对管理有了初步的理解和感悟。这两本书分别代表了不同的管理理念,一种强调以人为本,另一种则是以结果为导向的雷厉风行。对于我目前的心态而言,我认同后者的评价体系,但从个人性格上我自己的风格更像前者。
在日常的产品迭代和团队管理中,我始终认为把人放在第一位是非常重要的。通过团结所有可以团结的力量,关注每个成员的工作态度、能力、心理状态以及需求和期望,找到大家适合的方向,往往能比反复推动大家完成不情愿的工作更加高效。
当然,在工作过程中难免会遇到与某些人的争执和冲突。面对这些情况,我常采取的做法是换位思考。我会设身处地地想,如果我是对方,我是否也会做出同样的选择?如果答案是肯定的,那么这往往是角色之间的冲突,而非个人情感的问题,我就不会在情感层面上过多消耗精力。如果答案是否定的,我则会进一步探索解决分歧的方法。我是一个性格相对温和的人,我通常不倾向于与人争执,而是尽可能地通过和平的方式解决问题。今年,我几乎都是这样处理冲突的。
然而,我也逐渐意识到,过分的忍让并不会赢得他人的尊重和理解,反而会被得过且过。有些原则和理念是需要坚持的底线,绝不能妥协。希望在未来的一年里,我能够在保持真诚坦率的同时,也能够坚持自己的原则和底线。
今年在工作之余也读了《新程序员》杂志,深入了解了很多大佬的成长经历,也获得了不少启发。一个很深刻的感悟还是江同志的一句话:一个人的命运啊,当然要靠自我奋斗,但是也要考虑到历史的进程。
自从 ChatGPT 爆火以来,周围已经涌现出许多彻底成功的案例,这些故事不仅激励着我,也让我对未来充满了好奇和期待。尽管对于自己未来的方向,我目前还没有一个清晰的规划,甚至只能对未来 1 到 2 年内的工作做出一些预测,3 年后会做什么我还没有确切的答案。
但在这样的不确定性中,我坚信的一点是,只要相信自己当前的工作富有意义和前景,并且能够在其中找到快乐,那么就值得坚持下去,全力以赴。关于未来命运将我们带往何方,或许可以交给时间和命运去安排。在这个快速变化的时代,保持学习和成长的心态,积极面对每一次机遇和挑战,可能就是我们能做的最好的准备了。
经过一天多的思考,我终于完成了今年的年终总结。回顾这一年,我在技术和管理方面取得了一些进步,但同时也深刻意识到,在让企业成功的方方面面,我还有太多不了解不擅长需要学习的地方。
展望新的一年,我为自己和我们组设定了以下几点期望:
最后,感谢您的阅读。欢迎各位读者批评指正。
在新的一年里,祝愿大家身体健康、家庭幸福、梦想成真。希望我们都能在新的一年中取得更大的进步!
2023-12-07 18:03:00
2023 年 12 月 3 日,IoTDB 一年一度的 用户大会 成功举办。
在本次大会中,我有幸作为讲师之一做了《优其效:如何用 IoTDB 监控工具进行深度系统调优》的分享,系统介绍了 IoTDB 这一年来在可观测性方面的进展,并展示了它如何显著提升我们的性能调优和问题排查效率。
本博客将通过文字和图片的方式展示我的分享内容。
我们在可观测性方面做的工作后续也会有更多的博客输出出来,敬请期待!
大家好,我是来自天谋科技的谭新宇,接下来我为大家分享的主题是”如何用 IoTDB 监控工具进行深度系统调优”。
本次分享分为 5 个方面,首先我们将介绍数据库系统的用户服务和架构演进挑战,这些挑战的本质都是如何去提升效率;接着我们会对 IoTDB 可观测性的发展进行概览,主要包括 Logging,Metrics 和 Tracing 三个方面;然后我们会介绍一下 IoTDB 的监控模块,其构建主要参考了火焰图作者著作《性能之巅》的思路,即从负载视角和资源视角两个维度对系统进行观测;最后我们会概述一下 IoTDB 的 4 个监控面板并着重做一些性能调优和问题排查的典型案例分享。
首先先来分析一下数据库系统的用户服务和架构演进有着怎样的挑战。
对于用户服务,主要存在以下三个挑战:
第一是如何快速找到业务场景的瓶颈点?系统的性能存在木板效应,会受限于系统最慢的模块,比如某节点的 CPU 和磁盘还没有打满,但网卡已经被打满了,此时增加写入负载也不会获得任何性能上的提升。
第二是如何对业务场景进行针对性调优?不同硬件环境和业务负载的排列组合会使得很多默认参数并不是当下最优的值,针对这个问题,一种理想流派是像 ottertune 一样使用机器学习的方式去找到最优的参数组合,另一种更为实际的流派则是能够对系统进行白盒调优。
第三是如何形成可扩展的调优体系?对于性能调优这个工作,其实非常容易形成马太效应,即越会调优的人越容易被分配更多性能调优的工作,虽然他会越来越能调优,但这也容易形成单点瓶颈,导致调优工作横向扩展不起来,这样其实是不利于整个产研团队和实施团队的共同成长的。因此需要针对调优这项工作形成可复制的调优方法论,大家共享互补调优的知识,一起成长。
对于架构演进,也主要存在以下三个挑战:
第一是如何确定典型业务场景?性能优化需要结合场景谈论才有意义,而一个系统往往也会有很多用户场景,这就需要从中抽象出来通用普适的典型场景并总结他们的典型特征。比如硬件环境到底是 4 核 8G 还是 64 核 128G ,业务需求到底是追求低延迟还是高吞吐等等。
第二是如何进一步演进典型业务场景下的性能?任何系统在特定业务场景下都存在进一步性能演进的可能,我们需要在寻找瓶颈的过程中区分出来哪些是工程问题(比如 GC 参数调优,代码写的冗余),哪些是学术问题(比如针对 IoTDB 特定的时序场景,有些数据库原理的 trade-off 发生了变化,这个时候就可以结合场景做一些更针对的设计,IoTDB 近几年在 Fast 和 ICDE 等顶会上发表的论文都是沿着这个思路去设计的),区分出这两个问题之后就可以利用不同的思路去并行协作优化性能了。
第三是如何确保性能优化的 ROI 最大?对于一个系统怎么优化,收集一圈能够得到一大堆思路,到底哪些效果会好,哪些效果会差?我们需要能够精确评估一个优化的正向作用和负面影响,并能够量化排列优先级,这样才可能将有限的资源持续投入到 ROI 最大的性能优化上,坚持做最正确的选择。
分析完了挑战,其实我们也都清楚了可观测性对于解决这些挑战的重要性。那么接下来我们介绍一下 IoTDB 的可观测性发展概览。
随着分布式架构成为主流,可观测性这一名词逐渐被大家频繁提及。学术界一般会将可观测性分为三个更具体的方向进行研究,分别是 Logging,Metrics 和 Tracing。
Logging 的职责是记录离散事件,从而使得事后可以通过这些记录来分析程序的行为。
Metrics 的职责是将不同类型的消息分别进行统计聚合处理,从而能够对系统进行持续的监控和预警。
Tracing 的职责是记录完整的调用轨迹,这就包含了服务间的网络传输信息与各个服务内部的调用堆栈信息。
IoTDB 自诞生时就使用了 Logback 框架来管理日志,随着版本的不断迭代,目前已经将不同级别和模块的日志拆分成了不同的文件便于检索。
虽然这些日志很重要,但它所有的信息都是离散的。如果要对某一类的信息进行一些汇总聚合统计,比如统计一段时间的平均刷盘点数,就需要首先 cat 文件,接着再 grep 过滤出同一类型的日志,然后还要写脚本来计算次数,平均值之类的,这就非常繁琐。
很自然的这就需要引入 Metrics 了。
IoTDB 在 0.12 版本就开始设计开发 Metrics,但从 1.0 版本之后才开始投入大量精力打磨 Metrics,到了 1.3 版本 Metrics 已经基本打磨的差不多了。
我们用了 Micrometer 和 DropWizard 的算法库来作为监控指标的类型支撑,具体的存储可以导出到 Prometheus 或者 IoTDB 中,可视化目前主要是在用 Grafana 工具。
右边贴了一张我们监控面板的图,还是非常漂亮的,后面会进一步介绍。
有了 Metric 之后,我们可以统计同一类请求的聚合信息,例如平均值,P99 值等等。这其实已经能够解决 90% 以上的问题,但对于剩下 10% 的问题,比如海量小查询和一个大查询并发执行时,大查询的执行耗时会被吞并,从而无法体现在 Metrics 中。此时我们就需要具备单独观测一条请求完整调用链路耗时的能力。
为了满足这种需求,今年我们也启动了对 Tracing 工作的研究,我们用 OpenTelemetry,ElasticSearch 和 Grafana 搭建了 Tracing 系统。
比如右图对于 show region 请求的调用链路,我们可以在 Grafana 中展示这个请求跨进程通信时不同进程内部调用栈的详细耗时信息,这对于慢查询等场景的性能排查效率会有显著提升。
总体而言,IoTDB 的可观测性能力在今年发生了质变。我们有信心也非常欢迎我们的用户朋友前来体验。
接下来我会着重介绍一下 IoTDB 的监控模块:
对于监控模块而言,它的灵魂就是他拥有哪些监控指标。
这里我们参照火焰图作者著作《性能之巅》的思路。从负载分析和资源分析这两个相反的角度去互补推进监控指标体系的建设。
对于自顶向下的负载视角:
我们对客户端写入 IoTDB 的流程进行了拆解。对于每个 IoTDB 的连接,当它将请求交给到 IoTDB 执行时,该连接被视为忙碌状态;当它在客户端攒批等待或者向服务端传输时,该连接被视为闲置状态。通过这种区分,我们能够对瓶颈是否在 IoTDB 内部有一个评估。比如每次连接繁忙都是 10ms,之后却要闲置 5 分钟,那基本瓶颈就不在 IoTDB 端了。
如果发现连接繁忙的时间要更大,要如何进一步去寻找瓶颈呢。我们将 IoTDB 的写入请求延迟进行了拆解,将写入流程分成了若干阶段,并对一般情况下更为耗时的阶段进行了更细粒度的拆分,从而能够确保发现瓶颈出现在哪个模块。比如调度执行阶段一直存在远程转发,那就需要去排查客户端的分区缓存是否失效。
总之,通过这种自顶向下的分析,我们能够找到系统当前的瓶颈是在哪些模块。
对于自底向上的资源视角:
我们主要从 4 个维度进行了考虑:
在磁盘方面,我们希望我们要比 Linux 的常用磁盘监控命令 iostat 更为丰富,比如除了磁盘利用率,吞吐 iops 之外,我们还想统计进程级别的磁盘读写情况和 page cache 的使用情况。
在网络方面,我们希望我们要比 Linux 的常用网络监控命令 sar 更为丰富,比如除了网络吞吐和收发包的速度之外,我们还想统计进程级别的连接个数等等。
在 CPU 方面,我们不仅要统计操作系统和进程的 CPU 利用率,还想统计 IoTDB 进程内部不同模块不同线程池的 CPU 利用率,也还想统计进程内部线程池的关键参数。
在 JVM 方面,我们不仅要对堆内堆外的内存大小做观测,对不同状态的线程个数做观测,还想对 GC 做更细致的观测。
总之,通过这种自底向上的分析,我们能为很多模块的瓶颈原因提供思路
那到了 1.3.0 版本,我们前面提到的监控指标都已经实现了,那么监控模块对于性能的影响到底大不大呢,线上敢不敢打开呢?
其实这块我们也在持续的做性能优化,尽管 IoTDB 监控指标的个数已经从 1.0.0 版本的 134 涨到了 1.3.0 版本的 905,增加了接近 8 倍,但监控模块 CPU 的开销反而从 11.34% 降低到了 5.81%,减少了近 50% 。其对于读写性能的影响也从 7% 以内降低到了 3% 以内。
因此,大家可以放心的开启监控模块,它对于系统运维的收益绝对远远大于这一点点性能损耗。
基于这些监控指标,接下来我们简单介绍一下 IoTDB 的监控面板:
主要分为四个监控面板:
分别 Performance Overview,System,ConfigNode 和 DataNode 面板。
下面将给出这些面板的示例:
对于 Performance Overview 面板:
它汇总统计了集群的基本信息,例如集群大小,总时间序列个数,总写入吞吐等等。
它还以延迟拆解的方式展示了客户端写入不同阶段的耗时统计,辅助定位瓶颈存在于哪个模块。
任何一个子面板我们都写了详细的注释,比如左图这个面板就展示了不同接口的耗时统计。
同时我们也可以在一个面板中同时查看多个节点的监控数据,便于定位相同时间不同节点的状态。
对于 System 面板,它提供了 CPU, JVM, 磁盘和网络维度的监控数据,在用于定位系统资源是否为瓶颈时非常管用。
对于 ConfigNode 面板,它也汇总统计了集群的基本信息,还提供了元数据及数据分区 Leader 分布等维度的监控。在用户定位集群扩展性能力时非常有用,比如是否所有的节点上都分配了读写流量,是否有节点宕机等等。
对于 DataNode 面板,它汇总了单节点引擎内部的细致监控,如存储,查询,元数据,共识和流处理引擎等等。在判断模块内部瓶颈原因时非常有用。
现在 IoTDB 有接近上千的监控指标,这些指标很难在今天短短的分享中介绍完,那接下来我就分享 5 个典型案例来展示一下 IoTDB 监控模块的能力:
第一个案例是在某高吞吐量场景下如何去确认瓶颈所在。
当业务链路较为复杂时,如果整体的性能不达标,用户其实是不太好去确认到底瓶颈是在业务上还是在 IoTDB 中。
那现在 IoTDB 的监控模块则是可以帮忙定位瓶颈是否在数据库中。
比如对于一个 Flink 实时消费 Kafka 数据来写入 IoTDB 的用户场景,业务链路上有 128 节点的 Kafka 集群,96 节点的 Flink 和 IoTDB 集群。
由于集群规模较大,部署测试调优运维的成本都较高。当时跑通整个链路后业务给我们的反馈就是 IoTDB 写入性能不够,IoTDB 集群总写入吞吐仅为 15GB/s,扩展性很差等等。
那当我们进行瓶颈排查之后发现锅并不在 IoTDB 而是在业务上层。
比如我们发现每个连接平均控制 4s 才会繁忙执行请求 20ms,每个节点平均每秒才接受 3 个请求且系统资源利用率都非常低。
因此我们推动了业务侧进行排查,他们发现即使把 Flink 的 Sink 侧置为空写整体吞吐也才 20GB/s,最终他们找到了问题所在并对 Flink 侧进行了优化。
在业务调整进行复测,我们发现 IoTDB 集群的整体吞吐可以达到 62.6GB/s,相比之前提升了 4 倍以上的性能,集群的线性比最高也达到了 0.89。
如果没有监控模块指导我们去推动业务侧改造,我们还一门心思的在数据库内部找瓶颈,那最终的结果一定是事倍功半。
第二个案例是某车联网场景的写入性能尖刺调优。
由于 IoTDB 是 Java 写的,很多用户也会询问我们 GC 对 IoTDB 性能的影响。由于我们在内存中也做了不少的池化来自己管理内存,所以大部分场景下用户其实感知不到 GC 对性能的影响。只有极少数个别场景才会观测到,比如这个案例就是 GC 导致了写入性能尖刺。
那现在 IoTDB 的监控模块内嵌了 GC 调优分析器,其实是具备对 GC 深度观测和调优的能力的,接下来让我们一探究竟。
该场景的整体架构是一个 3c 12D 的 IoTDB 集群,也是 Flink 实时消费 Kafka 的数据写入 IoTDB 集群。
在写入压测过程中,我们发现 IoTDB 的写入吞吐能力基本符合预期,但是存在尖刺,有时吞吐会接近 0。进一步排查原因我们发现这是由于 JVM 每 20 分钟会触发一次 Full GC,每次 Full GC 都耗时 1 min 以上,那这样的 GC 其实是非常不健康的。
那对于 GC 应该如何调优呢?常见的流程是启动 JVM 时打开 GC 日志,测试一段时间后上传 GC 日志到特定的网站进行分析,其会将不同原因导致的 GC 进行耗时和次数的汇总,然后我们可以基于这些聚合后的高密度 GC 信息再分析应该如何调整 GC 算法参数。
在建设好可观测性之后,现在的 IoTDB 如何去做 GC 调优分析呢?
我们首先提供了 GC 耗时比例的新手指标,它表示了 GC STW 耗时占整个 JVM RunTime 耗时的比例,如果这个比例小于 5-10%,则说明 GC 对系统整体的吞吐影响不大,如果在延迟上没有额外要求,那一般就不需要再调优了。
如果这个比例大于 10-15%,则一般说明可以对 GC 进行进一步调优。我们这时提供了若干专家指标,比如我们对不同 GC 原因导致的耗时和次数进行了统计,还对于种种 GC 前后的内存申请,内存大小都做了统计,这都能作为我们进行调优 GC 的数据支撑。
在该用户环境下,我们的调优思路首先是将 GC 算法从 PS 换成了对大内存更为友好的 G1,接着又结合负载和 IoTDB 的特点进行了 GC 参数的调优,其核心思路也是延缓并发标记阈值,提升 MixedGC 吞吐,控制单次 GC 耗时软上限等。
那最终调优的结果呢是写入吞吐稳定,不再又 Full GC,同时写入性能也提升了接近 50%,还是比较可观的。
这个案例主要是说明一下 IoTDB 对 GC 的观测能力和调优能力。
第三个案例是某测试场景下的硬件瓶颈原因探究。
在一些 POC 阶段,当系统出现瓶颈时,如果将系统视为黑盒,其实是不知道如何升级硬件的收益最高的。
结合 IoTDB 的监控模块,我们可以量化算出升级硬件带来的潜在性能收益,用以选择收益最高的硬件升级方案。
比如在该测试场景下,我们用 2 个客户端机器去压测高配机器的单节点集群,发现系统地性能仅为 1.2GB/s,不符合我们对如此高配机器的想象。
那接着我们对系统资源进行了分析,发现 CPU 和网络都没有达到瓶颈,但磁盘的繁忙程度达到了 100% 成为了瓶颈,从而限制了整体吞吐,此时就需要升级磁盘才能进一步提升性能了。
这就是一个典型的木桶效应,在理想状况下,所有资源应该同时达到瓶颈,这样硬件资源才没有浪费;然而在实际情况中,往往会有个别资源先到瓶颈,从而限制整体性能。
在升级磁盘之后,我们发现磁盘和网络不再是瓶颈,写入吞吐也提升到了原来的 2.5 倍,此时 CPU 又成为了新的瓶颈。
通过该案例,可以说明 IoTDB 的系统资源监控可以帮助我们快速找到硬件瓶颈,从而用最小的成本达到最大的收益。
案例 4 是某周测场景的写入性能波动变大问题排查。
对于服务器的 CPU 利用率出现波动这类问题,其实是比较难排查的,因为他不一定持续,等到我们去排查的时候可能已经不波动了。
对于这类问题,IoTDB 监控模块内置了操作系统,进程,线程池和模块 CPU 利用率监控,我们可以首先确认该波动是不是 IoTDB 引起的,如果是则可以一更进一步给出调优建议。
比如该问题就是我们在日常的周测场景中发现 1.2.0 rc5 版本的写入吞吐相比之前的一个版本波动更大,这其实属于很细致的观察了,不一定对业务有什么影响。
但我们没有放弃这一次机会进行了原因探究。
首先我们排查了操作系统及进程的 CPU 监控:发现新版本的 CPU 利用率波动更大,它应该是造成写入性能波动更大的原因。
那更进一步我们直接用了我们的大杀器-线程池 CPU 利用率监控,发现新版本中后台执行的合并线程池利用率在 0-18% 进行大幅波动,而老版本则稳定在 8% 左右。
更进一步我们去排查了存储引擎 TsFile 层级监控:发现新版本的存储引擎合并速度更快,文件状态也更健康。
因此我们就检查那段时间合入的代码,发现新版本修复了之前合并模块 IO 大小预估偏大的问题,可能导致之前受 IO 限速不能执行的合并任务受现在能够被执行。
至此我们已经明确了该现象的根因,考虑到改进后文件合并的更为健康,因此我们也没有进一步修改默认的限速参数。
但对于写入性能波动有要求的场景,我们也可以进一步降低合并模块的限速,从而达到与之前版本近似的效果。
该案例主要是说明 IoTDB 对 CPU 利用率的观测和掌控能力。
最后一个案例则是某钢厂场景的写入性能周期性下降 5% 排查。
随着我们可观测性做的不断深入,很多用户也开始对我们的监控面板越来越感兴趣,每天就上来翻一翻。
那在翻的过程中如果发现监控面板中有一些不影响业务的异样,是否有必要继续深挖?我们欢迎并鼓励这样的行为。
该案例就是由于用户的深挖反而促进了我们内核迭代的进一步演进,从而达到了双赢的效果。
该场景的架构是一个 3c3d 的集群,客户端会定期攒批写入 IoTDB,也会定期查询单设备过去 1 天的全量数据。
在用户日常巡检监控面板时,他发现了一个有趣的现象,即每 7 天会出现一次持续一天的 5% 性能下降。
这个问题其实可大可小,如果没有我们的监控面板,业务都不会感知到这件事情的存在,但该用户跟我们进行了反馈,于是我们也进行排查。
我们首先排查了系统及进程 CPU 监控:发现写入性能下降 5% 之后 CPU 占用率增加 5%,那依然还是怀疑 CPU 利用率的升高应该是写入性能下降 5% 的根因。
然后我们排查了写入延迟拆解监控,发现写入性能刚下降时存在跨节点转发,这代表客户端缓存失效,同时也观测到写入性能下降时调度执行阶段 P99 耗时增加。这基本可以辅助确定写入性能下降时 IoTDB 切换了时间分区,导致数据需要被写到新的节点。
接着我们对查询进行了分析,尽管查询的逻辑数据量始终是最近一天的数据,但跨分片查询时,由于涉及到更多的 operator 算子和跨节点序列化反序列化开销,这也会对 CPU 造成更大的消耗。
至此该问题的原因便找到了,它也催生了 IoTDB 内核的两个后续优化,第一个是尽量使得同一设备的数据保留在一个分片中,这样即可以避免该现象出现,第二个则是线程池 CPU 利用率监控,有了它我们则可以更直观的观察到增加的 5% CPU 都是在查询线程池导致的,排查效率就更高了。
该案例主要说明了 IoTDB 对这种很细微的业务感知不到的波动也具有诊断和迭代能力。
最后对以上 5 个案例做一个总结:
IoTDB 的可观测性目标是高效定位遇到的一切性能问题,虽然还有很长的路要走,但大家已经能够看到我们这一年的质变。
据我们的经验而言,针对硬件环境和业务负载调优一般可以获得 50% - 1000% 的性能提升。
所以我们非常欢迎大家来试用我们的商业版 IoTDB,也非常欢迎大家在使用监控模块过程中对想不通的性能问题和我们沟通。
我们期待与用户一起获得业务和技术上的成长。
我的分享就这么多,谢谢大家!
2023-01-19 12:00:33
忙忙碌碌又是一年,终于到了 2022 年底。去年第一次写年终总结受到了不少的关注,我在这一年里也时常会重读自己的 2021 年终总结来鞭策自己。今年由于家里的特殊原因需要在医院过年,时间比较仓促,勉强抽出了一天的时间来简短写写年终总结。一方面是给 2022 年的自己一个交代,另一方面也是给 2023 年的自己一个警醒。希望我的经历和感悟能给大家一些启发。
首先依然是自我介绍环节,我叫谭新宇,清华本硕,现在清华大学软件学院 Apache IoTDB 组就读研三,师从王建民/黄向东老师,我对共识算法,分布式存储系统,时序数据库和分布式事务都比较感兴趣。
接着简单介绍一下我们组的工作:Apache IoTDB(物联网数据库)是一体化收集、存储、管理与分析物联网时序数据的软件系统。Apache IoTDB 采用轻量式架构,具有高性能和丰富的功能,并与 Apache Hadoop、Spark 和 Flink 等进行了深度集成,可以满足工业物联网领域的海量数据存储、高速数据读取和复杂数据分析需求。
介绍完背景之后,在这里回顾下 2022 年的经历。
2 月,Apache IoTDB 社区的新分布式架构设计正在整个社区的努力下如火如荼的进行着,社区针对分布式时序数据库架构的方方面面都进行了广泛的调研和讨论,我也很幸运地参加了若干模块的调研设计,收获良多。对于分区方式,我们结合一致性哈希和查找表的优缺点,选择了一个更符合时序场景 trade-off 的分区方式,既不引入较大的存储成本,又具备一定的负载均衡灵活性,而且还留有足够的扩展性。对于扩展能力,我们将时序元数据与时序数据等同来看都做了多分片,使得集群拥有很强的横向扩展能力。对于查询引擎,我们调研了 Trino/Impala/Doris 等系统的 MPP 框架,又基于我们对时序场景的理解设计出了针对时序场景特殊优化的 MPP 框架和 Pipeline 执行引擎。对于共识算法,我们观察到不同的业务对于共识算法一致性和性能之间的 trade-off 有不一样的倾向,开始思考并着手设计一个能够支持不同共识算法的通用共识框架。
2 月下旬,在为 Talent Plan 社区提交若干代码修复并做了 3 次有关共识算法和分布式事务的公开分享之后,我荣幸的被 Talent Plan 社区接纳为了 mentor,期待以后能够继续和志同道合的小伙伴在 Talent Plan 社区沟通交流。
3 月,需要毕设开题的我结合 Apache IoTDB 新分布式架构对通用共识框架的需求,开始调研学术界和工业界在通用共识框架领域的相关工作。在调研中,我发现了 Facebook 的 Delos 框架不仅支持在一套接口下实现不同的共识算法,还能够支持生产环境动态变更共识算法,他们的工作也得到了学术界的认可,成为了 2020 OSDI 的 Best Paper。沿着他们的思路,在摒弃了当前 ROI 收益较低的生产环境动态变更共识算法后,我便开始着手设计通用共识框架的接口,该框架不仅需要先支持强一致性的 Raft 算法和弱一致性的异步复制共识算法,还需要为未来更好更丰富的共识算法接入留下扩展性(例如 2021 FAST 的 Best Paper 就是基于异步复制的思路在提升写性能的同时又在读时添加了一些约束,从而提供了跨客户端单调读一致性,基于 ZK 实现后相比 ZK 性能能够提升 1.8-3.3 倍)。由于这个思路在学术界和工业界都相对新颖,我的开题便较为顺利的被通过了。
3-4 月,由于毕设开题读了一大堆论文状态比较好,我开始在知乎上回答自己感兴趣领域的很多问题,并幸运的在最开始就得到了很多赞,这些对我的认可又成为了我进一步在知乎上学习和活跃的动力,从而形成了一个正反馈效应。正如去年年终总结的感悟中所提到的,这种正向反馈对于我自己的激励作用是非常大的。现在回过头来看,那段时间尽管我也有一些输出得到了很多赞,但收获最大的还是在此过程中阅读了知乎上分布式系统领域非常多的优秀回答,学到了很多技术知识,了解了很多思考维度。
4 月,忙完毕设开题的我开始面试暑期实习,尽管八股和项目由于日常的积累都没有什么问题,但由于实在提不起兴趣和动力刷题,所以在面试过程中还是多少有些磕磕绊绊。幸运的是最后投的几家公司除了微软之外总体都面的不错,最后思考再三后还是选择去 PingCAP 实习。一方面是 PingCAP 的三轮面试官(赵磊老师,徐锐老师,金鹏老师)给我的面试体验都非常好,另一方面则是我一直对 PingCAP 的很多体系(例如工程服务体系,架构演进体系,开源体系等等)非常敬佩和好奇,想要借此机会去学习感悟。
5-6 月,我专心投入到了 Apache IoTDB 新分布式框架的实现中。最主要的工作便是通用共识框架,这期间一方面抽象了其对上对下的通用接口,另一方面则是为其支持了若干共识算法。对于强一致性共识算法,我调研了 Java 实现的若干 Raft 库的成熟度,并最终得出只有 SofaJRaft 和 Apache Ratis 可以使用的结论。基于此结论,我和子阳探索了 Apache Ratis 的实现并将其集成到了我们的共识框架中,这使得 Apache IoTDB 的新分布式架构具备了强一致性的能力(这半年以来,子阳在 Apache Ratis 的稳定性和性能优化上投入了大量的精力,令人开心的是目前他已经得到了 Apache Ratis 社区的认可,成为了 Committer,可以说是双赢了)。对于弱一致性共识算法,我们结合时序场景写写冲突极少的业务特点,设计并实现了基于异步复制思路的弱一致性共识算法 IoTConsensus。我和乔老师,恺丰,海铭,金瑞,洪胤,厚亮和珍姐都参与了 IoTConsensus 的设计实现与迭代测试。IoTConsensus 做了非常多的工程优化,包括但不限于 Batching,Pipeline,Thrift AsyncClient/AsyncServer 等等,所以流程非常复杂。虽然实现和 debug 的过程非常艰苦,但我们在异步编程,内存控制,可观测性,debug 技巧等方面都有了显著的进步,可以说是既痛苦又有收获吧。此外,为了兼容统一的共识框架,避免单副本时共识框架的额外开销,我们还专门针对单副本的场景(只需要 scale out 而不需要 high availability 的场景)设计了极为轻量的 SimpleConsensus,避免出现 RaftLog 和存储引擎 WAL 双写的现象出现。在未来,我们还计划为 Apache IoTDB 的共识框架加入更多的共识算法实现,例如 SofaJRaft 和我们组今年中的 ICDE NB-Raft 等等。我非常期待 Apache IoTDB 共识框架的文档,功能,性能,稳定性和正确性等等都能够迅速成熟,甚至可以成为大家未来使用通用共识框架的范式,这样如果业务上对共识算法一致性和性能的 trade-off 有不同的需求,便可以直接使用我们已经封装好的共识框架而不用再去造轮子了。这里也非常欢迎对共识算法感兴趣的同学一起参与进来~
7-10 月,我在 PingCAP 进行了全职实习。在 PingCAP 的暑期实习是我个人体验最好的一次实习。在技术上,我不仅可以去学习公司内部海量的技术积累(Rust,分布式数据库,TiKV,调优培训等)和流程规范(如何建立可扩展的工程服务体系和可持续的架构演进体系 -> 可观测性 + 分级 Support && 业务场景持续打磨),也可以系统学习 TiKV 事务引擎演进的历史(乐观事务->悲观事务->大事务->Async Commit/1PC-> 悲观事务内存悲观锁等)来培养自己的产品思维,最后还可以基于这些成长去做一些深入的探索并取得了不错的成果。在生活上,同事们会非常耐心友善地回答我的种种问题,工程经验十分丰富的 mentor 徐锐老师也花了非常多的时间和我 one-one 沟通我的种种疑问来帮助我快速成长(技术问题。如何平衡技术驱动和业务驱动?如何评估架构演进和工程服务的 ROI 等等),金鹏老师和 HRBP 也会和我定期沟通最近的工作进展。PingCAP 是国内开源数据库和开源社区的佼佼者,非常推荐大家有机会前去实习,一定会不虚此行~
8-10 月,我海投了很多感兴趣的数据库团队,并以没有任何职业背景的身份参加了 41 场秋招面试。虽然非常忙碌,但这些面试尤其是终面加面环节对我技术的成长和产品思维的提升有很大的帮助。在面试过程中我也有幸认识了很多大佬,并幸运地拿到了不少 offer,在这里表达对相关面试官和 HR 的真诚感谢。
10 月中旬,我被评选为了 2022 软件学院科研科创年度人物,这令我诚惶诚恐。在我看来,这个奖项更适合论文发到手软的大佬。询问之后发现现在的评审规则中也包含了开源贡献,所以现在做系统做工程的同学也可以得到学院的认可。在这里也真诚感谢学院对我的认可。
10 月下旬,我和祥威洪胤子阳参加了 2022 TiDB Hackathon,并最终拿到了产品组的最佳校园奖。在这次 Hackathon 中,从技术上我们为 TiKV 做了 Parallel Apply 的优化 Demo;从产品上我们在高并发批量写入热点场景会有不错的收益。我们模拟了银行清算结算等跑批业务的极致情况,在 60 并发下,不同 BatchSize 的批量写入性能提升 89.4%~119.0%。TiKV CPU 利用率从 700% 左右提升至 1500% 左右。我们也尝试了通用的批量导入热点场景,对于 TPCC prepare,在 1024 BatchSize 下,不同并发批量写入性能提升 29.8%~36.0%,TiKV CPU 利用率也从 750% 左右提升至 1000% 左右。通过这次 Hackathon,结合 OB 4.0 版本自适应日志流的设计,我们对 Raft 和 Multi-Paxos 的异同有了更深刻的理解。总体而看,一个系统的架构设计就是要在关键模块的各种 trade-off 中做出纠结的选择,并且一旦做出了某个选择,就需要基于这个选择更进一步做非常多的产品化工作和优化打磨来提升这些技术对于用户的实际价值。例如,TiDB 选了 TSO 的时间戳获取方案并不代表就不能服务跨数据中心场景了,其也做了 Local/Global TSO 的产品化工作来满足部分用户场景的跨数据中心需求。CRDB 用了 HLC 之后并不仅仅体现在获取事务时间戳更快,其至少还基于 HLC 在 Strong/Stale Follower Read 这一块做了许多工作来减少跨域流量从而降低成本。对于 OB,其选择了 Multi-Paxos 而不是 Raft,并且更进一步在 4.0 架构中提出了单机分布式一体化架构来解决其他数据库很难彻底解决的写热点缓解,大事务支持和 1PC 比例增大等难点。当然,这些技术和产品化的工作短期内很难形成事实标准,也都能够在各自的用户场景产生价值,至于孰优孰劣就很难客观判断了。
11 月,我手上的秋招 offer 陆陆续续开奖了,这期间涉及到了非常复杂的心理变化。有期待,有失望,有惊喜,有反思,有迷茫,有透彻。对于最终选择去哪里,我纠结了许久,请教了很多朋友,前辈,同学,师兄,父母和导师的意见。其实选择哪条路都不会太差,主要还是需要剖析自己更喜欢怎样的工作方式,并且说服自己一旦做出选择后就不再患得患失。此外王老师东哥乔老师都对我的就业方向和未来发展路径给予了中肯的建议,最终我选择了 Apache IoTDB 的商业化公司天谋科技继续做 IoTDB。我非常感谢研究生期间 IoTDB 这个大平台对我的帮助,也希望自己未来能够继续在这个大平台发光发热。
12 月,Apache IoTDB 的 1.0 版本发布了,这次新版本凝聚了整个社区的智慧和力量,标志着 Apache IoTDB 从此彻底拥有分布式,为后续产品快速发展奠定了良好基础。这次分布式 1.0 架构的发布也是促使我决定留下的重要原因之一,因为我觉得这个架构有太多可以做的工作可以去做,一些积累的技术宅已经还清,我相信未来 Apache IoTDB 一定能够在工业物联网的时序场景大放异彩。想通以后,我也和洪胤子阳湘鹏组成了系统优化小组,不断扩大我们的 scope 去和 IoTDB 一块成长了~
今年我在 Apache IoTDB 社区 Review 了 187 个 PR,提交并被合并了 48 个 PR。今年的工作有很多新颖的东西,希望明年能够继续保持下去。
今年我在知乎上写了几十篇博客和回答,粉丝数和点赞数相比去年同期有了接近 10 倍的增长。Github 上的 Follower 数和个人仓库 Star 数也有了 6 倍多的增长。希望自己明年还能继续坚持输出有价值有意思的知识。
今年我看了权谋剧的巅峰之作《大明王朝 1566》,尽管剧中演绎的是封建社会,但其中一些社会运行的本质规律放到今天也依然适用,我自认为受益良多,非常推荐大家去看。此外我也读了 IT 人的必读书籍《浪潮之巅》,了解了信息革命以来很多著名公司的兴衰更迭及背后的哲学原因。天下大势,浩浩汤汤,顺之者昌,逆之者亡。不论是公司,组织还是个人,自己的努力不可或缺,但只有抓准大势站上浪潮之巅,才有可能干一番大事。
介绍完了 2022 年的经历,在这里谈谈自己这一年的新感悟,这些感悟不一定适用于每个人,但都是我个人在今年得到成长的诀窍。
这一年在日常的开发过程中修复了无数的 bug,一些是陈年老 bug,一些则是自己在开发过程中引入的新 bug。这期间我一直在思考为什么会有这么多的 bug?什么时候能够修复完所有的 bug?现在我有了更明确的感悟:
对于一个 bug,从设计->编码->UT->IT->压力测试->混沌测试->发版测试->用户 POC 环境->用户生产环境这套全链路的流程中,越晚被发现,则修复的成本就越高。世界上没有不写 bug 的人,也不存在没有 bug 的系统,我们需要尊重这一客观规律。出现 bug 不可怕,但不对其进行反思改进就非常可怕了。虽然没有不写 bug 的人,但要成为追求不写 bug 的人,因为只有具备了这个追求,才会在日常的开发过程中注重 bug 产生原因的积累,并通过种种技术手段来规避 bug 的产生。正是因为对 bug 的反思,学术界和工业界才产生了很多对系统稳定性至关重要的工作(形式化验证,确定性模拟器,混沌测试,持续集成等等)。一个工程师的成长必然伴随着对种种异常情况的考虑,知识边界被拓宽后自然写出 bug 的概率就会越来越低。
新的系统,新的模块,新的引擎,新的算法需要一段时间的稳定性打磨,没有用户去用就很难成熟,但如果用户去用了,团队也一定要利用好这次机会,让产品的稳定性和工程师的能力一起成长,进入一个正反馈循环才有可能让产品越来越好。
一般而言,复杂的性能优化往往会导致代码维护成本的上升。例如事件驱动的并发编程模型具有更高的自主性,性能上限相比完全被 Runtime 接管的协程可能会高一点,但带来的回调地狱问题又可能会大幅增大代码复杂度,导致代码维护成本大幅上升。从全局的 ROI 评估来看,这样的工作不一定收益很高。
今年我在开发 IoTConsensus 过程中就有点过于追求性能优化,加了一堆异步逻辑和工程优化,虽然优化完后性能还不错,但这种代码上的复杂度也使得大家在 debug 时非常痛苦,新人也比较难一下子看懂主要逻辑,只能靠进一步完善文档细节并做代码走读才有可能让新人逐渐上手。
在未来的工作中,我也会吸取这次的教训更关注性能优化与代码可维护性之间的平衡。
今年在实习和秋招面试过程中有幸和非常多的技术大佬有过交流,在他们身上技术能力只是一个值得学习的维度,其他维度的能力还包括管理,演讲,分享,社交,营销,商业感知,为人处世等等。
要想进一步实现职场的抱负,综合能力是十分重要的。总之,有太多领域的太多能力可以去提升,技术只是其中比较重要的方面之一,最好不要仅仅把自己拘泥在技术上。
不断扩展自己的 scope,锻炼培养自己的综合能力,便能在单位时间内获得更大的成长拥有更丰富的阅历,从而可能在机遇出现时顶住压力抓住机会。
技术最终是要为业务服务的。没有业务侧的需求,技术最终也难以发挥实际价值走向成熟。
在做日常的功能开发和性能优化时,最好能够带着产品思维去思考问题:自己所做的工作在整个产品中处于怎样的一个位置?做了这个工作之后整个产品会有什么样的不同?一旦能够培养出来这种端到端的产品思维,自己也会更明确工作目标并更有动力去做事成长。
刚入门数据库的时候一直比较好奇,像 Oracle 这样的数据库厂商是如何每年都有那么多新的工作可以做?为什么我就想不到做那些呢?
通过在 Apache IoTDB 实验室的成长和在 PingCAP 的实习,我理解了业务驱动对于产品的意义。只要有用户和业务的支持,就会有源源不断的需求出来。对于数据库系统而言,在不同的硬件环境和业务负载下,有太多的功能和性能优化可以去做,几乎不存在技术上没有事情可做的情况。当然,任何组织任何个人所能调度的资源都是有限的,如何评估当前所有工作的 ROI,如何在有限的资源上持续的做紧急重要且正确的事,也是产品成败存亡的关键。
OceanBase 的杨传辉老师提过一个观点:每个系统设计时都需要考虑架构、稳定性和性能,这三者之间的关系是什么?一个经典的规律是“把稳定的系统做高效,远比把高效的系统做稳定更容易”。最难的是从 0 到 1 把系统做稳定。有了稳定的系统,接下来逐步优化性能往往会比较顺利,直到遇到系统架构的性能天花板。因此,系统架构设计之前,首先要考虑清楚系统的目标和性能天花板,接着基于正确的架构把系统做稳定,最后优化性能。
在 PingCAP 的暑期实习期间我很明显的一个感受就是,TiDB 的可观测性做得非常好,同事们都比较明确特定业务场景下当前 TiDB 的短板在哪里,也明白自己工作的端到端价值,从而能够持续打磨 TiDB 在特定业务场景下的性能。大家的工作并行汇聚起来便能够促使 TiDB 每个版本都能够在很多业务场景下有不错的进步。
在现在的我看来,Oracle 最有价值的东西其实是在当前的市场规模下能够接触到最多最复杂的业务场景,从而能够持续的对系统进行打磨,这是其他任何单机数据库都没法做到的,自然也就无法在单机数据库领域打败 Oracle 了。
在系统初期,调研设计出一个性能天花板高的系统架构非常重要。在系统搭建完成基本稳定之后,在业务场景下进行持续的打磨就更为重要了。比如 Apache IoTDB 1.0 的分布式架构性能天花板我自认为就很高,目前性能也基本打磨到了和 0.13 版本一致的地步,下一步就是在特定业务场景下进行持续打磨做稳定性和性能的进一步提升了。
好奇心是人类进化创新的驱动力。发现当前存在的问题,才有可能去进一步改进解决。爱因斯坦早在《物理学的进化》中就说过:”提出一个问题比解决一个问题更为重要。 因为解决一个问题也许是一个数学上或实验上的技巧,而提出新的问题,新的可能性,从新的方向看旧问题,则需要创造性的想象力,而且标志着科学的真正进步”。
对于数据库系统,在特定硬件环境和业务负载下,性能瓶颈到底在何处?若想优化当前最大的性能瓶颈,它到底是一个工程问题还是学术问题?如果是工程问题,需要投入多少资源去完成?会有多少收益?如果是学术问题,它的 trade-off 到底是什么?有什么更符合当前业务场景的可能性吗?一旦有了这样思考问题的方式,就会发现技术上其实存在很多可能。
在看了《大明王朝 1566》 和《浪潮之巅》后,越发认识到时势造英雄的客观规律。个人的努力能够决定个人的发展下限,但平台和机遇才能够决定个人的发展上限。很多时候,玄而又玄的天下大势和因缘际会反而可能会在若干年后造就一番佳话。
就目前而言,认识到平台的重要性,学会顺势而为,在职责范围内乐于沟通踏实做事,可能是个人职业生涯短期的最优解了吧。
对于个人而言,绝对的成功很难定义,技术和商业也仅仅是很小的一部分。在认识到时势造英雄的客观规律后,我愈发觉得精神上的富足对于一个人一生的幸福最为重要。有一句话叫做”但行好事,莫问前程”,没有必要去和其他人比来比去,任何人都是比上不足比下有余,能够以个人最舒服的姿态和最擅长的方式去活一生就已足够,剩下的交给命运即可。
在日常工作中,很多时候会涉及到任务的分工与合作,这就需要频繁地沟通。
每个人都有完全不同的成长环境,不同的成长环境造就了不同的三观以及思维方式,进而产生出不同的职业动机和职业规划,最终使得对待工作的态度和动力也会有所差别。这些差异无关对错,但有时候过于从自己角度思考问题并进行沟通反而会适得其反。
在与他人沟通时,如果能够站在别人的角度去思考问题,懂得换位思考,则很多矛盾在沟通过程中就可以被缓解甚至解决。当然,有些天然对立的矛盾是没办法彻底解决的,只能选择一个平衡点进行缓解。
今年的年终总结写的比较仓促,但也算是勉强写完了。
新的一年就主要聊聊与 Apache IoTDB 有关的技术展望吧:
最后,感谢您的阅读,希望这篇总结能够对您有所帮助。
在除夕这天,预祝大家新年身体健康,阖家幸福,心想事成~
2022-12-15 10:21:29
在前前后后忙活了接近四个月后,我的秋招终于结束了。
这篇 回答 分享了我几乎所有技术面的面经,本博客将结合本人在今年秋招中的经验和在院系就业分享会中的分享内容介绍一下实习和秋招各个环节的注意事项,希望能够帮助到对分布式数据库内核研发岗感兴趣的同学。
注:本文内容仅代表个人看法。
2022-12-08 20:28:07
2022 年 10 月,2022 TiDB Hackathon Possibility at Scale 成功举办。
作为暑期实习在贵司事务组的 intern,在对 TiKV 的 codebase 有一定了解后,我兴致勃勃地拉了实验室的同学报名参加了此次 Hackathon,并且最终拿到了产品组的最佳校园奖,虽然没有拿到更大的奖项,但已经玩得十分开心了。
非常感谢 Hackathon 期间队友,mentor,组织者和评委对我们组的帮助和认可。
本文将简单介绍我们组的工作和思考以做回顾。
以下是我们项目的一些相关资料,欢迎点击了解:
注:本文仅代表个人看法。
本小节将沿着答辩 PPT 的思路介绍我们的工作。
我们的名字是热点清零队。我们的项目是无畏写热点,我们希望能够解决 TiKV 写热点问题的最后一公里。
我们的团队成员均来自清华大学软件学院。今年 hackathon 的主题是探索 scale 的可能性,我们的主要工作是解决热点 Region 在单机多核上的扩展性问题。在极致场景下我们提升了 TiDB 接近 1.2 倍的吞吐。
从用户视角来看,写热点问题会给他们带来多少困扰呢?比如某用户就提出,批量写场景下 TiKV 的 CPU/IO 都没用满,但写入依然很慢,这些现象给用户带来了不便和困扰。我们统计了 AskTug 论坛上写满 tag 帖子的原因分布,大致如右上图所示,可以看到写热点问题占比第一。
那现在的 TiDB 是如何解决热点问题的呢?其整体思路都是通过划分 region 来均匀承担负载,从而能够扩展。如右图所示,理想情况下随着 region 的分裂,热点会被稀释,进而线性扩展起来。然而,在当前上层数据分片的语义下,对于聚簇索引,唯一自增索引等场景,写热点问题难以避免。
当分裂 region 不能均分负载时,实际情况会如右上图所示,尽管分裂出了多的 region,但写热点始终集中在个别 region 上。在这种场景下,往往会遇到单节点存算资源并没有被充分利用的情况。其实不论上层怎么去分裂 region,单 region 热点始终是写热点问题的最后一公里,无法回避。
那让我们看看在 TiKV 中单 region 的执行路径。总体来说是需要在 StorePool 中进行 commit,在 ApplyPool 中进行 apply。然而在现有的实现中,不论是 StorePool 的持久化还是 ApplyPool 的写 memtable,并行度都是 1,因而不具备在单机上的扩展性。
那如果我们想要在单机上扩展热点 region,那可以从存储资源和计算资源两个方面来入手。对于存储资源,可以利用 IO 并行来提高吞吐,比如将单 region 不同批的日志用异步 IO 并行化处理,去年的 TPC 项目已经做过尝试,取得了不错的效果。对于计算资源,理论上也可以采用多核并行来提高吞吐,这也是我们的尝试,即去做 Parallel Apply
Parallel Apply 的整体思路是将无依赖的日志并行处理,从而提升整体吞吐。2018 年 VLDB 和 2021 年 JOS 已经对 Parallel Apply 的可行性和正确性进行了证明。
那在 TiKV 上落地 Parallel Apply 会有哪些难点呢?我们主要遇到了 4 个问题,比如如何保证依赖顺序的正确性,数据正确性,语义正确性和 index 正确性等等,以下分别进行介绍
我们的整体思路是在 ApplyPool 以外额外引入一个 ParallelApplyPool,并在 StorePool 中判断路由,进而使得单 region 的日志存在并行的可能性。同时在实现过程中,为了避免锁导致的线程切换,我们的共享状态均使用了原子变量。
对于刚刚提到的难点,我们简单介绍一下解决方案。
对于如何保证具有依赖的日志执行顺序正确?在 Leader 侧和在 Follower 侧需要有不同的处理方案。
对于如何保证 leader 切换或重启时数据依然正确?我们则很简单的使用了 Raft 的 term 变量,当且仅当日志的 term 为当前 term 时才考虑路由到 ParallelApplyPool 并行处理。这样的机制保证了 Leader 切换或者节点重启时系统不会将本不能并行处理的日志并行化处理,从而导致数据不一致。
对于如何保证 admin 等特殊日志的执行依然符合串行语义?即在 admin 日志执行之前其前面的所有日志均需要已经执行,在 admin 之后的日志执行前必须保证该 admin 日志已经执行。这个具体实现非常复杂,简单来说,我们在 Parallel Apply Pool 和 ApplyPool 中用原子变量共享了一些状态,对于单 region,StorePool 会将无冲突的普通日志在 Parallel ApplyPool 中并行执行,当出现 admin 日志时,当 StorePool 未感知到其执行完时,所有的日志都会被路由到 ApplyPool 中串行执行,当 admin 日志的 apply 结果返回 StorePool 后,之后的普通日志可以被继续路由到 Parallel Apply Pool 中并行执行。在 ApplyPool 中,我们还用原子变量来保证了只有 Parallel Apply Pool 中有关该 region 的所有普通日志都已执行完才去执行 Admin 日志。这些工作使得 admin 等特殊日志的执行依然符合了串行语义。在实际测试中,大部分普通日志都能够在 Parallel Apply Pool 中并行处理。,这也是我们在写热点场景性能提升的根源。
对于如何保证 applyIndex 的更新,我们发现不需要在磁盘上实时更新 applyState,这主要与底层 KV 引擎的幂等语义有关。我们在内存中维护了可能存在空洞的 applyIndex,当其连续时才推进 StorePool 中的 applyIndex,这也与现有的代码实现了兼容。
我们模拟了银行清算结算等跑批业务的极致情况,在 60 并发下,不同 BatchSize 的批量写入性能提升 89.4%~119.0%。TiKV CPU 利用率从 700% 左右提升至 1500% 左右。
我们也尝试了通用的批量导入热点场景,对于 TPCC prepare,在 1024 BatchSize 下,不同并发批量写入性能提升 29.8%~36.0%,TiKV CPU 利用率也从 750% 左右提升至 1000% 左右
在测试过程中,我们也更深刻地体会到了木桶效应。在 apply 是瓶颈的热点场景下,我们能取得很好的效果。但是对于 apply 不是瓶颈的场景,尽管这个阶段可能会加速,但根据阿姆达尔定律,最终的整体收益也不明显。
展望未来,我们认为我们的工作拼好了 TiKV 解决写热点问题的最后一块拼图,给出了解决写热点问题的终极形态。在多节点上,我们可以用 Split Region 的方式来在多节点上 scale。在单机上,我们可以用 Parallel Redo log 甚至是 Multi-Paxos 来更好地利用磁盘资源,也可以用 Parallel Apply 来更好的利用 CPU 资源,最终也能够在单机上彻底 scale。
同时在引擎演进方面,我们解决了不相关事务的日志回放顺序依赖问题,为 TiKV 更好的 CPU Scheduling 和极致性能做了铺垫。比如未来可以结合乱序确认乱序 commit 和 TPC 策略来对资源进行更精细的控制。
本小节将更随心的介绍一些我们的思考。
在这次 Hackathon 中,从技术上我们为 TiKV 做了 Parallel Apply 的优化;从产品上我们在高并发批量写入热点场景会有不错的收益。
上小节已经介绍了基于 region split 的方式来缓解热点问题的局限性,那么如何解决这种局限性呢?这就要回到一个圣战问题了:Raft 和 Multi-Paxos 有什么区别?
如同我在 RFC 中介绍的一样,相比 Multi-Paxos,Raft 不能乱序 ack,不能乱序 commit,不能乱序 apply,因而有同学认为 Raft 不如 Multi-Paxos。
dragonboat 的作者对此观点进行了 反驳,其主要有两个观点:
对于第一个观点,从 TiKV 的角度来看,目前默认的 region 大小为 128M,尽管理论上 raft 组数拆的越多,单 raft 组内的串行化 apply 对性能的影响就越小。然而,raft 组过多带来的其他问题也会接踵而来,比如在 TiKV 实际测试中观察到过多的 region 和过大的 LSM Tree 都会导致性能的回退,因而未来 TiDB 的 Dynamic Region 工作计划一方面调大 region 大小到 512MB 至 10GB 从而减少 region 个数,另一方面则是拆分 RocksDB 实例。由此可见,影响 region 大小的因素并不只有 raft 串行化的问题。在未来,一方面 TiKV 的 region 会比现在更大,因此单 raft 组内的串行化问题会更加明显从而可能成为瓶颈;另一方面拆分 RocksDB 实例后 split 也不会再像现在这么轻量,因而实时动态的 split 负载均衡策略相比现在也会趋于保守。总体来看,在 TiKV 内实现乱序 apply 在未来是一个非常有可能的性能优化方向。
对于第二个观点,的确从通用的共识库的角度出发,乱序 apply 并无太大意义。但从 TiKV 中内嵌的共识算法来看,由于共识层之上的事务层已经定了一次序,因而共识层的重复定序在有些 case 下是没有意义,此时的乱序并行 apply 更可能提升热点场景的性能。
事实上,如果不支持乱序 apply,那共识算法的乱序 ack 和乱序 commit 可能没太大意义,因为整个共识组的瓶颈受限于最慢的模块。如果只能顺序 apply,那即使乱序 commit 了一批日志,如果这些日志之前存在空洞,那么这批日志也只能在内存中等待而不能被 apply。然而如果支持了乱序 apply,那结合乱序 ack 和乱序 commit 就更可能提高共识组的吞吐上限。比如一旦支持乱序 commit,那可以使用多个 IO depth 来持久化不同批的日志,这样每次 IO 的大小减少了,也可能能够减少每次 IO 的平均时间。此外支持乱序 commit 后也可以将前面存在空洞但确保与空洞日志无依赖关系的一批乱序 commit 日志提前 apply 处理,进而抬高 apply 的瓶颈天花板。
总体来看,Parallel Apply 能够解决 region 写热点在多核上的扩展性问题,Multi-Paxos 能够解决 region 写热点在现代硬盘上的扩展性问题。因此,Multi-Paxos + Parallel Apply 理论上能够解决写入热点在现代硬件上的扩展性问题。预计能够在写热点场景更充分的利用硬件资源,从而提升性能。
在写 Hackathon RFC 的时候我更多的关注了对于写热点场景下 Raft 与 Multi-Paxos 的区别,然而对于其他场景,我意外的发现 Raft 和 Multi-Paxos 也能体现不同的价值。
在 OB 社区 4.0 版本的 介绍 中,专门提到了一个很大的变动:自适应日志流,即将分片与共识解耦。在不考虑 leader 打散情况下,每个租户在一个进程中可以有多个分片但只会有一个共识组。
基于传统 Raft 的方案是很难去做出这样的架构设计的,但 Multi-Paxos 可以做到。
在收益方面,除了完全控制共识组个数和增大 1PC 比例以外,OB 4.0 更是基于自适应日志流架构重构了事务引擎,从而对大事务有了更好的支持,并基于这些工作产品化包装出了单机分布式一体化架构。这个架构的缺点就是灵活扩缩容和实时负载均衡会更难做,但如果考虑云上的部署形态,这些新的问题又可以通过其他方案来缓解。
总体而看,一个系统的架构设计就是要在关键模块的各种 trade-off 中做出纠结的选择,并且一旦做出了某个选择,就需要基于这个选择更进一步做非常多的产品化工作和优化打磨来提升这些技术对于用户的实际价值。例如,TiDB 选了 TSO 的时间戳获取方案并不代表就不能服务跨数据中心场景了,其也做了 Local/Global TSO 的产品化工作来满足部分用户场景的跨数据中心需求。CRDB 用了 HLC 之后并不仅仅体现在获取事务时间戳更快,其至少还基于 HLC 在 Strong/Stale Follower Read 这一块做了许多工作来减少跨域流量从而降低成本。对于 OB,其选择了 Multi-Paxos 而不是 Raft,并且更进一步在 4.0 架构中提出了单机分布式一体化架构来解决其他数据库很难彻底解决的写热点缓解,大事务支持和 1PC 比例增大等难点。当然,这些技术和产品化的工作短期内很难形成事实标准,也都能够在各自的用户场景产生价值,至于孰优孰劣就很难客观判断了。
仅就技术而言,如同我在之前有关 共识算法综述博客 开头中介绍的一样,对于 Raft 和 Multi Paxos 孰优孰劣这一圣战问题,我的主观看法是对于普通 KV,很可能区别不大。对于结合共识和事务模块的 NewSQL 数据库,Multi-Paxos 能够在整体上为一些难点问题提供一点不一样的思路(例如增大 1PC 比例,缓解写热点问题,大事务支持等等),可能有更高的性能天花板。
本文简要总结了 2022 TiDB Hackathon 产品组最佳校园奖热点清零队的工作,并简要分享了本人对 Raft 和 Multi-Paxos 异同的看法,希望能够引起更多的讨论。
感谢您的阅读~