导致系统性能失败的十个原因
很多软件系统由于性能问题导致了失败,在开发生命周期和性能测试生命周期的每个阶段都存在导致性能失败的原因。有时候,性能问题是无法控制的,它不在项目经理、技术架构师或性能工程师的控制范围之内。从业务和个人层面来看,大多数的系统性能失败仅仅是因为性能工程师、开发人员、 DBA、业务团队和利益相关者之间从一开始就缺乏沟通,这导致了许多其他问题,这些问题将直接影响应用程序的性能和 ROI。对任何应用/产品进行有效性能测试的唯一目标是实现令人满意的投资回报。性能测试和软件工程是有风险的,并且总是需要从开发的早期阶段开始,进行大量的反复试验。
系统性能的失败必须与其他业务问题进行类似的处理。了解问题出在哪里,为什么会出问题,以及如何预防。在大多数场景中,需要每个人都了解/理解端到端全生命周期实现中的性能挑战。他山之石,根据老码农的经验,总结了一个导致系统性能失败的原因列表。
1. 对最终用户反馈的置若罔闻
作为最终用户,才会意识到的现有潜在性能问题。为了理解生产系统中现有的性能问题,需要从最终用户那里获得关于应用程序在不同的预期负载条件下如何运行的持续反馈。总是有很多用户在生产环境中使用某个功能,即使这一功能不能满足他们期望的性能,他们也不会质疑它,而且会假设它是正确的,当用户可以同时从多个位置访问时,这可能是一个大问题。因此,如果想提高应用程序的性能,就必须让最终用户参与进来,以获得关于应用程序或系统在生产环境中性能的持续反馈。当然,与最终用户的交互需要时间和精力,尽管如此,为了使产品/应用提供最佳性能,这绝对是值得的。
2. 不关注性能目标
设定目标是确定系统性能的最重要方面之一。许多团队经常无法实现他们的性能目标以求改进,于是花费了大量时间修复系统中现有的和隐藏的性能问题。性能测试的完美目标应该在最现实的条件下定义、设计和执行,比如真实的浏览器、设备和多个地理位置。确定正确的指标来监控,定义每个指标的最小阈值,执行性能测试来得到基线结果,所有这些数字对于确定什么样的变化可以创造性能改进是必要的。在软件开发生命周期中尽早开始性能测试是一种很好的做法,可以首先消除瓶颈,并确保在用户负载很重的情况下不断检查应用程序的性能。
3. 不清晰及不完整的非功能性需求
收集完整的非功能性需求比功能性需求更复杂,因为它们被视为第二类甚至第三类需求。因此,它们经常被误解和忽视,只有少数组织将非功能性需求作为一等公民。这会在系统架构/设计中导致严重的问题,经常导致项目崩溃和网站崩溃,使系统无法使用。在大多数情况下,非功能性需求文档不完整、不一致,或者在大多数不成功的项目中不存在。性能测试第一步是对应用程序/系统进行可行性分析,并创建一组明确的非功能性需求。一个可靠的非功能性需求文档将确定产品/应用具有最佳性能的所有标准。此外,还需要:
- 为产品/应用和系统建立明确的性能目标和期望
- 必须让所有人(开发团队、QA、管理团队、 DBA、涉众和业务团队)达成一致。
- 在技术团队、项目团队和业务团队之间建立沟通,以了解生产环境中最终用户的实际性能问题
- 使用分析工具,获取生产流量统计数据,以创建合适的工作负载模型
- 在收集非功能性需求时,了解应用程序/产品的体系结构、设计、问题和现有的性能问题
- 非功能性需求应该从软件开发过程的开始并在整个生命周期中进行讨论; 如果应用程序是全新的,基线和基准测试对于性能测试是必要的。
- 获取所有涉及的内部和外部组件的完整信息,并了解它们如何通信(CDN、防火墙、 DNS、负载均衡器、服务器、网络和系统、缓存等)
- 了解应用程序内存占用和第三方体系结构限制
- 与涉众和业务团队交谈,以了解目标并确定什么是基本的、现有的遗留系统性能问题、平台约束和竞争对手。
- 有必要记录所有内容,并让业务和其他涉众一起参加会议,以确定现有的非功能性需求是否合适,并就定义的 SLA 达成一致。
4. 糟糕的架构设计
最初,糟糕的架构设计只会导致一些小问题,这些问题在开始时会比较少,但是会逐渐累积起来。简单维护是一个挑战,在一个区域中的任何更改都会破坏应用程序的其他部分。如果在架构设计阶段作出了不恰当的决定,应用/系统可能会出现严重的性能下降,导致过多的网络延迟和其他问题。由于不了解明确定义的系统架构,在负载测试执行阶段会存在太多不确定性和复杂性的高风险,这可能会给性能测试和工程团队带来意想不到的性能问题。在软件开发生命周期的应用程序设计和开发阶段,由于性能方面的挑战,软件发布可能会推迟。
5. 对技术依赖缺乏预见
依赖关系是允许更多应用和功能组件之间的连接。特定的操作系统版本、应用服务器、数据库服务器或 Java 虚拟机、通用语言运行库和框架都是依赖关系的例子。然而,有些依赖关系更为复杂,比如由 Linux、 Java 中的各种包组成的依赖关系,以及 Python 和 Ruby 等脚本语言组成的依赖关系。理解每个技术在设计和基础设施方面对每个组件的依赖性,使用哪些技术,以及使用哪些框架和工具来开发应用程序,对于系统性能来说,以期望的结果完成性能测试是至关重要的。
6.新功能的过度扩展
过度的新功能扩展是软件开发人员经常遇到的一个主要障碍。处理这种情况的有效方法是定期举行面向用户体验的会议和讨论,每个团队成员都参与其中,以验证每个功能,并确保它有意义地解决了设定的问题。性能测试团队必须从规划发布的时间表开始,并且应该主动地公布需要的时间,以防在发布前的最后一分钟添加任何新功能。如果项目有一个固定的最后期限,就需要提前计划环境需求,以确保意外的环境延迟不会影响性能测试的进度。如果在最后一刻继续添加了新功能,交付的质量大概率会受到影响。最终,客户可能会拒绝最终的可交付成果,从而产生返工和额外资源短缺的情况。
7. 推崇好大喜功
在性能测试执行的最初版本中,直接关注目标 SLA 以达到可接受的限制可能是不现实的。性能测试是一个迭代过程,需要大量持续的性能测试来识别和消除所有的性能瓶颈。需要花费额外的时间优化每一行代码和组件,以提高系统/应用程序的性能。在性能测试中,每个 SLA 和 KPI 都是必要的,并且只有通过持续的性能测试、代码分析、内存分析、性能工程、监控以及客户端和服务器端的调优才能获得所需的响应时间、吞吐量、网络延迟和资源利用率,这有时需要花费很长的时间。分析所有的性能结果和降低,并从用户级、操作系统级、系统级、网络级和服务器级使用适当的指标收集数据,对所有导致性能问题根本原因的分析是至关重要的。
8. 容量规划的匮乏
许多基础设施未能实施有效的规划,简单地说,容量规划过程并不简单直接。我们可以创建一个场景、添加流量、评估结果、解决性能问题,然后重复,直到满意为止,但是实际的问题往往伴随着糟糕的容量规划。糟糕的容量计划增加了性能缺失的可能性,风险会完全暴露,最终导致失败。所有这些都可以通过仔细的容量规划来适当解决。来自基础设施领域的系统工程师、来自数据库领域的DBA和来自应用程序开发领域的程序员是最需要参与有效容量规划过程的三类人。许多人有时会将容量管理与容量计划混淆,不能准确地预测和错误预测未来的工作负载。需要确保识别准确的资源需求(CPU、内存、磁盘空间和网络带宽) ,以支持当前和未来增加的工作负载,以满足业务需求并避免容量规划失败。使用正确的度量标准进行持续监控将帮助我们进行有效的容量规划,并且还有助于处理流量增加后未预料到的工作负载。
9. 性能问题没有完全解决
当应用的用户量增加时,往往会看到更多的性能问题。随着时间的推移,系统中隐藏的性能问题和已知的性能问题是导致性能持续下降的主要原因。必须与项目中的每个团队成员讨论确定的每个瓶颈,以成功地确保客户 SLA 的性能。当涉及到性能问题时,每一秒都很重要,如果忽略现有的性能问题,系统将会变慢,甚至更糟。例如,某些服务可能会停止在严重超载的服务器上运行,从而使应用程序无法访问。找出监控数据,检查服务的健康状态,一般就能找出性能问题的常见原因。
10. 方法论的缺失
缺乏合适的方法来建立性能测试策略及其覆盖范围的话,会很难获得有效的性能测试结果。理解性能测试方法和过程将帮助团队中的每个工程师,特别是当性能问题出现时,为每个发生问题的瓶颈提供正确的修复。性能测试过程应该有良好的计划和定义,并且文档化。好的文档可以在开发人员、 DBA和QA之间建立有效的沟通。随着软件变得更加复杂和多元化,并且有越来越多的平台和位置需要测试,需要有一个强有力的性能测试方法,以确保正在开发的软件系统经过充分的性能测试,以确保它们满足特定的业务要求,并且能够在所有预期的负载条件和环境中高性能地运行。