摘要
在2023年夏季,网上国网APP经历了前所未有的用户活跃高峰。面对网上国网APP的集中式架构和错综复杂的微服务调用,技术团队面临重大挑战:如何在无法1:1搭建测试环境的情况下,保证系统能够顺畅处理数百万的日订单量,确保千万的日活用户体验顺畅,同时大幅降低因性能缺陷而致的用户咨询。
本文深入探讨了网上国网确保系统性能的5大关键策略。最终,经过精心的部署和优化,网上国网APP在“迎峰度夏”的高峰期表现出色,不仅稳健处理了每日高达270万的订单量,还为超千万用户提供了无缝稳定的服务体验,且未曾因系统性能不足遭遇任何大的故障。详细的解决策略和方法,请参阅文章正文。
背景
在过去,居民们倾向于使用支付宝或微信缴纳电费,但近来,我们见证了用户群体逐渐向国网自己的应用平台转移的趋势。自2020年网上国网APP用户突破一亿以来,用户量持续攀升,至2023年达到3亿。特别是在2023年8月,也就是夏季用电高峰期,“迎峰度夏”的时候,网上国网APP的日活跃用户数首次冲破千万门槛,居民因使用空调等电器导致的用电量和缴费需求急剧上升。
在应对“迎峰度夏”期间的性能挑战时,我们首先碰到的难题是网上国网业务量庞大、组件繁多、系统复杂。该系统基于阿里云搭建,采取了与淘宝相似的集中式架构,因此它要处理大量的服务间调用和复杂的系统操作性问题。此外,一个巨大的挑战是,我们无法构建一个与生产环境完全相同的测试环境来进行全面的压力测试。
因此,关于在“迎峰度夏”高峰期前,服务器到底要扩容多少机器?系统性能到底能否承受巨大的负载?这些问题谁也无法给出确定答案。
一、“迎峰度夏”最终达成了怎样的性能效果?
1.1 整体目标
在回顾“迎峰度夏”期间取得的成效前,这里先分享一下我们的总体目标,这些目标在业务和技术两个维度上进行定义。业务目标是指确立每分钟或者每秒钟必须处理的业务量;技术目标则涉及到API接口——其响应时间或者事务处理速率(TPS)的具体数值。值得注意的是,响应时间不应直接等同于处理能力——一个单独的请求可能需要200毫秒来处理,但随着整体处理能力,即TPS的提高,这两者将表现出密切的相关性。
为了支撑业务更好的发展,网上国网需能支撑数百万日订单量、超千万的日活用户请求,确保在这些压力测试下依然平稳运作。而且在国家关键时期,如大型体育盛会——大运会、亚运会等,系统必须持续稳定运作。同时,致力于提升用户的满意度也是我们的目标之一,特别是通过减少夏季高峰期间由性能问题引起的用户咨询量,从而提高服务品质。
技术目标分为两方面。第一是提升系统的性能和容量,确保在用电高峰期间,系统不仅能够承受单日百万级的订单处理的压力,而且能在核心业务场景下显著缩短平均响应时长,并提高每秒处理量(TPS)。第二是有效提升系统的稳定性,预防因性能不足而引发的重大故障,确保用户在任何情况下都能享受到流畅的使用体验。
1.2 最终效果
二、如何确保达成性能目标?
实际上,无论是讨论项目背景、面临的挑战,还是最终的目标设定,所有这些都可以归结为一系列成熟的管理理念和方法论,包括但不限于:PDCA(计划-执行-检查-行动)的持续改进循环、DMAIC(定义-测量-分析-改进-控制)流程改进方法,以及OKR(目标与关键结果)目标设定框架。这些方法的核心思想是一致的,即:明确目标、辨识差距、策划解决方案、执行方案并最终验证效果。
基于此,我们的行动计划可以概括为以下五个关键步骤,这构成了我们实现性能目标的行动框架。
2.1 确定容量和性能目标
2.1.1 目标推导过程
在确定我们的容量和性能目标时,我们选择了一种直接而有效的方法。这种做法与那些可能遭遇5到10倍增长冲击的互联网公司(如淘宝)的策略不同。我们的方法是:将某个业务接口的日常高峰TPS(每秒事务数)乘以3,即以3倍的高峰TPS作为我们的压力测试目标。
(网上国网APP“迎峰度夏”性能和容量的整体目标)
2.1.2 踩坑经验分享
经验一:RT指标不可控,应重点聚焦TPS指标
最初,我们也设定了响应时间(RT)指标,希望将其控制在200-300毫秒之内。然而,很快我们便认识到,这一目标可能过于乐观。因为数据需要经过从总部到外网,再到内网,最后传达到各个省级公司的长链路,这一过程不可避免地涉及到一定的网络传输延时。具体来说,网上国网架构中包含了多个层级和分支,当我们请求网上国网服务时,部分数据需要从省级公司获得,这涉及账户信息或者缴费信息等敏感数据。网上国网作为一个集中的平台,虽然能在总部处理部分信息,但最终某些数据处理是在省级完成的。这就意味着,点击网上国网的某些服务可能需要访问不同的省级公司系统。
在压测初期,我们设定了一个标准,即每个链路和接口的响应时间应控制在200毫秒内。然而,实际测试中,这个标准被现实所挑战。我们发现,尽管许多接口能够在200毫秒内响应,但对于那些需要访问省级公司数据的接口来说,这一目标并不现实。特别是对于那些涉及到省级公司数据处理的服务,响应时间会相对较长。
因此,我们决定将重点聚焦于TPS,以日常高峰期的三倍为基准,执行生产级别的压力测试,并据此设定性能优化目标。
经验二:性能优化不完全依赖于全链路压测,可考虑从组件入手
在设定了这些容量和性能目标以后,我们遇到了一个主要挑战:受各类行政规定影响,每月都进行一次全链路压力测试并不是一件容易的事。
为了应对这一挑战,我们采取了一种替代策略。考虑到压力测试机会的有限性,我们如何能够继续优化性能呢?我们决定不完全依赖于压力测试,转而利用实际的生产流量来进行性能分析。例如,我们原本设定响应时间不超过200毫秒的目标可能并不切实际,于是我们将它调整到了300-400毫秒的范围。对于那些不可变的网络延迟因素,我们集中精力优化每个组件的性能目标,例如从应用程序到数据库、从应用程序到缓存的响应时间等。这样的目标调整,既基于现实情况,也保证了目标的达成性和可执行性。
2.2 设定性能标准
2.2.1 微服务响应标准
我们对各个微服务组件制定了严格的性能标准。比如,我们要求微服务自身处理时间不得超过10毫秒,数据库调用的延迟必须控制在5毫秒以内,而对缓存的操作则要求单个命令处理在2毫秒以下。设立这些具体的性能门槛后,我们能够迅速识别出那些超出预期响应时间的请求,并将其作为优化的重点。
(参考:银联和银行对接的接口RT标准要求为200ms。如超过该响应时间会被要求做整改优化)
在这个基础上,我们进一步分析并确定哪些接口最有改善的潜力。这不仅基于我们设立的性能门槛,还结合了请求的频率和批量。例如,对于SQL查询,如果我们发现在关键路径上的查询时间超过了10毫秒,这就明显指向了优化的需求。
2.2.2 经验分享
经验一:指标超预定阈值,应关注背后的潜在优化机会
在我们设定的性能标准中,一旦观察到某项指标超出了既定的阈值,比如响应时间超过了10毫秒,我们便会深入挖掘潜在的根本原因。以数据库响应时间为例,标准设定为5毫秒,任何超额现象都引起我们的警觉。这些额外的毫秒可能揭示了多种问题,例如,数据库连接池可能配置不当——太小则导致连接争夺,太大则浪费资源。或者,可能是某些性能调优参数未正确配置。我们会细致研究这些优化细节,逐一排查和识别关键链路的优化点。
经验二:响应时间延迟的问题要重点关注
微服务间的响应时间延迟也是我们密切关注的问题。例如,服务A调用服务B时,可能由于网络延迟或其他因素导致响应时间不理想。云服务环境中的延迟尤其值得关注。在不同云服务提供商的环境下,如腾讯云、京东云、华为云等,我们都发现了类似的问题:应用程序请求Redis等资源时,尽管处于同一可用区,但由于云服务提供商的内部变更,网络连接的延迟可能会从0.1毫秒激增至2毫秒。
我们的应用对于中间件如Redis、数据库或消息队列等极为依赖,一次业务操作可能需要调用它们十几次甚至几十次。一旦云服务提供商做了改动,比如将网络连接时间从0.1毫秒调整到2毫秒,这种小小的变化都可能导致我们的服务响应时间大幅度增加。
在这种情况下,我们发现响应速度的影响因素往往不在于应用本身,而在于云服务的基础设施变更。通过设定精细化的性能标准,我们能够迅速发现并定位到这些问题。虽然大数据分析和智能运维工具可助力解决类似问题,但关键仍然在于我们的标准设定,它使得问题的发现和解决变得更为直接和高效。
2.3 计算优化收益与识别优化潜力
优化收益的计算过程始于业务请求的Trace数据采集,这一数据集提供了一个窗口,透视出各个组件的响应时间及其分布情况。以此为基础,我们对Trace路径上的每个节点进行风险评估,按照设定的性能框架对数据库访问时间进行打分:响应时间在0-5毫秒内的视为正常性能范畴,5-10毫秒内的标记为低风险区间,而一旦响应时间超过10毫秒,即划入高风险领域。
(风险评分结果 — 各风险项及其潜在原因分析)
进一步地,我们量化优化潜力,即通过实际组件耗时与低风险标准耗时之差来评估。例如,数据库响应时间若实际记录为20毫秒,与低风险阈值5毫秒相比,有15毫秒的优化空间。将此方法应用于所有追踪的业务请求,我们能够累积每个组件的潜在优化收益,最终合计得到全面的优化收益总量。
2.4 给出优化方案,开发团队进行修改
背景:
尽管我们制定了一系列严格的性能标准,并成功识别出多个需要改进的问题点,但在实践中,我们发现,即使将这些优化点明确提交给研发团队,他们也可能不会立刻采取行动进行必要的调整。
原因分析:
经过反思我们认识到,对于研发团队而言,这些建议性的优化可能与他们当前的任务优先级不同,或是他们认为从这些调整中获得的潜在增益不足以促使他们行动起来。这种情况往往是“利益驱动”的表现:如果这些改动对研发团队没有直接的、明显的好处,他们自然缺乏执行这些改动的积极性。
解决方案:
我们需要提出一个收益明显、优化成效最大化的解决方案,并确保研发团队充分认识到这些改进的价值。只有当他们看到确切的好处,才会有足够的动力去执行这些优化调整。
场景案例:
我们曾遇到一个案例,用户在交电费时可以获得积分奖励。原本的实现中,为了确保积分扣减的准确性,研发团队使用了阿里云的分布式事务组件GTS,这不可避免地带来了对全局分布式锁的依赖。在评估整个流程时,我们注意到多数相关请求的处理时间远超过了60秒的预期。
面对这一挑战,研发团队并不确定应如何进行优化。我们向他们提出了一个方案:借鉴互联网公司常用的乐观锁策略,这不仅可以有效提升性能,还能确保积分扣减操作的一致性。我们认为这将带来显著收益,研发团队对此也表示认同。尽管如此,他们对于实施此变更仍持保留态度,迟迟不肯进行改动。
为了推动他们采取行动,我们开始跟踪并记录所有因积分扣减操作超时而失败的事件,并将这些数据定期呈现给研发团队,明确展示这些问题影响了多少用户。通过这些直观、有力的数据,研发团队最终意识到这些优化的紧迫性和潜在价值了,成功促使他们执行必要的改动。
成效:
采用这一策略,我们不仅提供了切实可行的解决方案,还运用数据来驱动决策和行动,最终有效地激励研发团队实施了这些关键的优化措施。
2.5 生产环境压力测试及目标验收
为了验证我们所做的优化是否真正有效,我们需要一种方法来验收工作成果。在这里,我们采用了全链路压力测试,这是一个在生产环境中进行的关键测试过程。
2.5.1 技术方案
在我们的技术方案中,生产压力测试不仅充当了验证系统稳定性的角色,它也是一个极为有效的问题探测手段。面对分布式系统的复杂性,我们采用了多倍负荷进行压力测试,通过这一过程暴露出了众多平时难以察觉的配置漏洞。由于测试环境的局限性,模拟生产环境中庞大的服务器集群和海量的数据变得几乎不可能。为了解决这一难题,我们采用了流量分流策略。
具体而言,当压力测试的流量涌入系统时,我们在JVM层利用字节码的修改技术进行流量识别,并将其智能地重定向到“影子”表或数据库。这一策略的核心价值在于,它能在不干扰实际业务数据的前提下,对整个网上国网的读写能力进行隔离压力测试。通过这种方法,我们不仅完成了全链路的生产环境压力测试,更实现了对系统性能和承载能力的全面验证。
在技术细节层面,这个方案的关键在于为HTTP请求头部添加特定压测标识。结合Java Agent技术和JVM字节码操作功能,我们开发出了一种无需修改任何业务代码便可以实现自动分流的机制。这种方法确保了压测流量被有效隔离,同时被正确引导到影子库和表中,确保了真实业务数据的不受影响。利用这种创新技术,我们可以模拟出高峰时段的流量模式,并确保在真实的流量高峰到来之前,系统已经做好了充分的准备工作。
2.5.2 主要步骤
在进行网上国网生产环境的全链路压测时,我们遵循了以下4个阶段的步骤,以确保测试的有效性和安全性。
-
明确压测目标:与利益相关者协商,确立压测的具体目的和预期成果,包括性能指标和容量目标。
-
非生产环境准备:
-
在非生产环境部署监测探针,这是为了不影响生产系统的正常运行。
-
创建和配置影子库表,这些是与生产环境相隔绝的数据库,用于承载压测数据。
-
对压测流量进行梳理和调试,确保读写操作正确无误地重定向到影子环境。
-
-
生产环境部署和压测:
-
在生产环境中部署探针,并建立影子库表。
-
逐步增加压测强度,从初始的小流量(1倍标准流量),逐渐增加到中等(100倍)和最高目标流量(1000倍或更多),以验证系统在各级负载下的表现。
-
在每个压测阶段,仔细检查压测数据的准确性,确保影子环境中的数据与预期一致。
-
-
压测结果总结:
-
完成压测后,对测试结果进行汇总和评估。
-
分析性能数据,验证是否达到预定目标。
-
根据压测的结果,提出改进建议或采取必要的优化措施。
-
通过这些详尽的步骤,我们能够确保全链路压测不仅能够揭示潜在的性能瓶颈,还能够在不影响真实用户体验的前提下,全面评估系统的承载能力和稳定性。
2.5.3 生产环境压测发现的部分问题列表
前面提到,全链路压测不仅为了验证性能标准,也希望暴露出系统的隐藏性能问题,这些问题只有在实际生产环境中才能暴露出来。例如,在将系统负载增加至三倍标准压力时,我们发现了若干问题。
下面是我们总结的一些核心问题:
-
核心与非核心服务混合部署:非核心服务的性能问题影响了核心服务的稳定性,导致整体系统性能下降。
-
数据库连接池配置问题:一些Java应用程序的数据库连接池配置不当,或者日志记录采用的是同步而非异步,增加了系统的响应时间。
-
下游服务超时:某些下游服务响应时间过长,反过来影响了上游服务的性能。
-
数据库索引未能有效使用:由于某些查询设计不当,如包含函数调用,导致数据库索引无法被有效利用,从而降低查询效率。
此外,我们还发现了一些编码实践上的问题,比如:
-
处理方式选择不当:在一些情况下,本可采用批量处理的场景,却选择了单条处理,这显著降低了效率。
这些发现是我们在全链路压测过程中的迭代步骤的一部分,它们帮助我们识别并解决了系统中存在的各种问题。通过这些反馈,我们可以持续改进系统架构和代码实践,以提高生产环境的稳定性和性能。
三、总结与展望
经过前文所述的五个关键步骤,我们在2023年网上国网APP的“迎峰度夏”活动中取得了显著成效。我们确保了在高订单量和活跃用户数快速增长的情况下,APP依然能够保持稳定运行,每日处理数百万订单,服务超过千万活跃用户。
我们了解到性能基准的重要性——即确立细致的性能指标,并监控系统是否超出这些预设的标准。我们不仅设置了三倍、五倍的负载压力测试,以考验系统的承受力,而且在高峰期系统表现尚可的情况下,也暴露出在变更环境后可能出现的性能瓶颈。
最后,我希望能够传达一种乐观的观点。我们都在为了共同的目标(系统稳定性)而努力。虽然在这一路上我们不可避免地会遇到挑战,但只要问题被识别,我们就能够诊断它们,找到解决方案,并将其付诸实施。之所以提出这个观点,是因为虽然我们此次成功地应对了高峰期的性能挑战,但在持续的运维过程中,性能问题依然是我们需要不断面对和解决的难题。正如瑞达利欧在《原则》中所阐述的,“拥抱现实和应对现实”,是实现更大成功的必由之路。我们期待着这一旅程,不断优化,不断进步,以期在未来遇到更多挑战时,能够更加从容应对。
本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。