如何定位服务性能_定位常见的微服务性能反模式

如何定位服务性能

在上一篇文章中,我们介绍了如何在Java代码中诊断常见的数据库性能热点 。 在当前的文章中,我们重点介绍在分布式“面向微服务”的面向服务的体系结构(SOA)中导致性能和可伸缩性问题的模式,例如通过低延迟连接传输大量数据,或由于服务接口不良而进行过多的服务调用设计或线程/连接池耗尽。

这是我最近帮助分析的一个应用程序示例。 该公司不得不将其旧的单片应用程序迁移到面向服务的体系结构,以应对对其受欢迎的网站不断增长的需求。 该应用程序的标志性功能是其搜索功能。 以前在前端Web渲染代码中实现的搜索逻辑已移至新的后端Search REST API 。 当我们进行架构审查时,我们执行了几个不同的搜索查询,结果令许多人大开眼界。 每个搜索关键字导致对新的后端Search REST API的调用数量不同。 事实证明,对搜索结果中的每个项目都调用了内部Search REST API,这是一种经典的N + 1查询问题模式。 以下是提供33个搜索结果的单个搜索的Dynatrace事务流的屏幕截图。 很容易发现几种不良的服务访问模式,我将在本文稍后详细说明。 我一直在寻找关键的架构指标,在这种情况下,这告诉我该应用程序很可能永远不会像他们所设想的那样扩展和运行:

通过查看对服务的关键传入和传出呼叫,可以很容易地发现我的服务呼叫问题模式。 查看这些数据将使体系结构和代码审查也变得更加容易!

我知道:这不会发生在您身上!

我已经在世界各地的用户组和聚会中多次提出了搜索功能的这种特殊用例。 我总是看到“这不适用于我们,因为我们知道如何正确地进行服务”。 继续阅读,您会发现实时生产代码中有无数类似违规的例子! 没有人故意这样做。 它只是发生了,这是我观察到的三个原因:

#1:没有看到或了解更大的图片!

服务团队如此专注于自己的服务,并投入大量精力使其规模和绩效得以提高,以至于他们常常忘记了全局。 我的服务将如何使用? 我们是否为服务使用者提供正确的接口方法?

在上面的示例中,Search REST API团队提供了服务GetProductDetails(int productId) 。 他们应该提供的是GetAllProductDetails(string searchQuery)GetAllProductDetails(int [] productIds) 。 我建议每个服务团队不断与您的客户/消费者交谈,不要只听他们认为他们需要什么,而是要确保在实施过程中也要监视服务使用情况,并从生产环境中了解每项服务的频率被谁使用!

#2:不了解您框架的内部

大多数团队并不实现自己的框架,而是依靠现有的流行框架,例如MVC和REST。 这是一件好事,因为我们每次构建新应用程序时都不应重新发明轮子。 但是,当新项目从基于GitHub等公共代码存储库下载的样本的小型原型开始时,就会出现常见的综合症。 原型会演变并变形为一个完整的应用程序,并且团队忽略了进行必要的回顾以评估所选框架是否最适合该工作并进行了适当调整。 我的技巧是花时间了解所选框架的内部以及如何最佳配置和优化它们以提高吞吐量和性能。 如果您不这样做,那么请准备好解决上述情况。 我每天都看到!

#3:迁移与重新架构

当您不得不拆分您的整体应用程序时,不要仅仅假设您可以“精简”提供某些功能并将其投入服务的类。 这样做可能导致本地线程内和进程内调用变为跨服务/服务器/网络/云调用,这可能不会引起注意,因为调用这些服务与调用本地方法一样容易。

从整体式迁移到微服务时,请确保首先了解您的服务真正需要提供的API。 在大多数情况下,这意味着需要重新架构和重新定义接口,而不是将代码从一个整体项目复制/粘贴到多个服务项目中!

可用的诊断工具和选项

如上面的示例所示,我一直在寻找关键的体系结构指标,例如呼叫频率,服务器之间的呼叫计数,传输的数据,以及简单地了解哪些服务相互通信。 通常,您可以通过用于构建应用的服务框架来收集这些指标,例如:Spring,Netflix等; 大多数框架都提供诊断和监视功能。 您还可以依靠自己的代码分析器,或选择完全免费或至少免费/免费试用版中可用的任何应用程序性能监视(APM)工具。 我选择的工具是Dynatrace Application Monitoring&UEM,它可以通过Dynatrace Personal License作为完全免费的版本供开发人员,架构师和测试人员使用。 这种工具的关键标准是其能够显示整个服务基础架构中的数据以及所有服务如何交互的能力。 探查器仅评估单个JVM,因此对于本练习来说太受限制了!

诊断不良服务访问模式

现在,让我们进入我要注意的服务访问模式的主列表。 如果要使用面向服务的体系结构构建高度可扩展的高性能应用程序,请确保在自己的应用程序中检查这些模式。 我们将首先陈述该列表,然后研究一些利用这些模式来定位和修复特定性能问题的示例:

  • 过多的服务呼叫 :每个单个端到端用例的服务呼叫太多。 多少太多? 当然,这取决于您的特定应用程序和要求,以及您如何分离服务。 但是根据经验,五个服务电话应该向您发出信号,要求您开始调查。
  • N + 1服务调用模式 :在端到端用例中多次执行同一服务。 这很好地表明您可能必须重新定义服务端点并提供该服务的更特定版本。 简而言之,请使用“向我提供用于搜索查询的产品详细信息”,而不是“向我提供产品X然后是产品Y的产品详细信息”。
  • 高服务网络有效负载 :带宽便宜–但前提是端点非常接近; 将服务移至云后,您将需要考虑更高的延迟,新的带宽限制以及云提供商的额外费用,以增加往返于云实例的网络流量。 当我看到内部服务调用之间传输的数据多于发送回最终用户的数据时,我会仔细研究如何优化传输的数据。
  • 连接和线程池大小调整 :服务通过连接进行通信,这就是为什么我们必须适当调整大小并监视传出和传入连接以及线程池的原因。 一旦了解了哪些服务通过哪些渠道进行通信,就可以根据负载预测进行适当的调整。
  • 过多地使用异步线程 :实现事件驱动的服务调用模式并不容易,这些服务调用模式会进行异步调用并在工作完成时接收通知。 通过产生并阻止多个后台线程,直到所有服务调用的所有结果到达之前,注意那些“伪造”异步行为的框架。
  • 违反体系结构 :您的服务是否与预期的其他服务交互,或者访问反模式意外进入了您的体系结构(例如,直接访问后端数据存储,而不是通过数据访问服务API)。
  • 缺乏缓存 :将工作转移到服务上很不错,但是如果现在这项工作的执行效率较低,则可能会遇到资源问题。 一个很好的例子是进行冗余数据库访问,而不是在多个服务调用之间缓存数据,以避免额外的数据库往返。

如所承诺的,让我们看看这些技术的作用:

例1:过多的服务呼叫和N + 1查询模式

这个例子来自一个著名的求职网站。 对于最终用户执行的每个搜索请求,前端服务将查询与提供的搜索关键字匹配的潜在职位列表。 对于返回的每个单独的职位,然后将调用外部“搜索” REST服务。 通过提供可以接受职位列表的粗粒度搜索REST调用,可以轻松地优化此过程,从而显着减少REST往返次数:

对前端服务的职位搜索请求导致对外部服务的38个REST调用,以检索各个职位名称结果的详细信息。 可以通过提供更好的REST接口来优化此效果,该接口可以提供职位列表的结果!

仅查看呼叫数量并不能立即表明这实际上是一个不好的设计,还是对前端和后端之间的REST接口使用效率不高。 要了解全部情况,您需要查看实际执行的REST查询-通过端点URL和查询字符串进行组织。 现在,此策略公开了实际存在问题的N + 1查询问题,并且每个重复的REST调用都重用了完全相同的查询字符串:

通过查看端点+查询字符串的调用次数,发现对REST端点的无效调用。 如果您有这些模式,请考虑提供更好的接口,以通过单个服务调用来处理这些查询。

如果您在上面的示例中看到您的服务正在使用中,对于每个工作搜索,同一服务针对不同的工作标题执行了多次,那么考虑提供一个更好地支持端到端用例的REST接口是很有意义的。 。 也可能是您的服务已经提供了此接口,但是前端开发人员(或您的服务的使用者)并不知道它。 因此,通过执行这种使用情况分析,您还可以教育您的消费者更好地利用您的服务!

提示 :在Dynatrace中,您可以使用Web Requests Dashlet向您显示由单个端到端事务完成的所有调用。 确保通过上下文菜单将小仪表盘置于“显示->全部”和“分组依据-> URL +查询”模式。

示例2:过多使用异步线程

在同一求职示例中,对/ getResult URL的所有调用都是通过为每个服务调用生成一个新的后台线程来执行的。 主HTTP线程产生了总共35个线程,以并行执行这些REST调用。 最后,HTTP Worker线程将阻塞,直到所有这些线程都已完成执行为止:

分析执行REST调用时涉及的线程数。 如果您有N + 1个服务调用模式,那么前端上的每个传入请求也会消耗N个额外的线程!

N + 1服务访问模式显然影响了35个线程的问题。 如果解决了该模式,它还将解决为每个服务调用占用一个新线程的问题。

Example#3:线程比率和线程池

还可以通过查看传入请求/事务与执行中涉及的活动线程总数之间的比率来分析示例#2。 您可以通过轻按JVM公开的JMX指标来轻松访问这两个指标。 您甚至可以通过按线程组细分线程数来扩展它–如果您的应用程序像上面的示例一样提供线程名,则此方法很好用,这是一个很好的开发模式。 同时观察您的CPU; 如果您遇到速度慢但没有观察到CPU使用率过高的情况,则表明您的线程正在等待I / O或彼此等待:

良好的做法是将传入请求的数量与活动线程的总数和CPU利用率相关联。 如果看到26:1的比率,我知道我们的应用程序在每个请求中绑定了许多后台线程。 观察较长时间的线程数,还可以查看它是否达到“上限”。 像上面的情况一样,最大工作线程数为1300。如果有更多请求进入,则由于线程饥饿而无法为它们服务!

在整个管道中监控服务指标

上一篇文章中,我们讨论了数据库指标以及如何将它们集成到您的持续集成版本中。 对于服务指标,我们也可以这样做。 如果您有针对服务的自动化测试,测试搜索或某些新闻警报功能,则应在每次测试执行时自动监视这些指标。 但是,在CI中执行测试后,您不应停止监视软件。 为什么? 因为您刚刚测试的软件将被部署到暂存和生产环境中,所以保持监视这些相同指标同样重要。 对我而言,“圣杯”是一旦在生产中部署了该服务,您就会观察到类似的指标。 此外,您还希望监视服务的功能使用情况,以帮助您更好地决定消费者实际使用了哪些新服务/功能。 有了这些数据,您就可以决定要改进哪些功能以增加使用率,以及在功能不如您所想的情况下删除哪些功能。 这有助于减少代码库,减少代码复杂性,并最终减少行业所谓的“技术债务”

在我的介绍性示例中,这是一个快速的演练,其中产品搜索功能导致了33个服务呼叫。 我的故事从那时开始,那时应用程序仍然是软件的“整体”版本。 我们可以从CI的测试中捕获新闻警报和搜索功能的指标,从而为我们提供有关代码如何与数据库交互,进行了多少次服务调用,传输了多少数据以及在其中使用了哪些功能的指标。生产:

版本17显示新闻警报和搜索在生产中运行缓慢。 新闻警报的使用率非常低,这可能是由于响应时间过长导致用户不愿使用该功能所致。 搜索采用率不错,但可能会更好。

通过评估这些指标,我们现在可以了解代码的当前运行方式,并且可以通过将整体式搜索功能分解为面向服务的方法来决定优化性能。 我们已经完成了一些新的面向服务的实施。 但是,运行相同的测试会产生一些意外的指标,从而迫使我们推迟产品发布; 查看下面的图表,我们发现我们对搜索所做的更改明显违反了我们的一些体系结构规则(数字全部取自我在开头段落中的初始示例):

Build 25显然是一个非常糟糕的版本,因为向微服务方法的迁移显示出我们的服务调用模式中的性能指标非常差。 我们不要部署它,而是要解决它!

N + 1查询问题模式还导致许多其他SQL查询以及通过网络传输的更多数据。 此实现的修补程序是对新的后端搜索服务接口进行更干净,更高效的设计和实现。 引入了新的“批量”服务,而不是为每个单独的搜索结果调用后端服务,该服务返回了完整搜索的所有详细信息。 有了该修复程序,我们终于有了可以部署的构建。 在持续集成服务器上,所有数字看起来都很不错。 通过查看部署后生产中的使用量数字,可以看出Search实际上现在可以在多个服务容器上运行,提供了更好的性能,并且显示了更高的使用率。 但是,新闻警报功能仅显示少量增加; 可能是在以后的版本中删除此功能的指标,因为它显然没有什么价值:

版本26是可靠的技术版本,显示了搜索使用方面的改进。 但是,新闻警报的使用并没有真正改善-让我们决定在Build 35中将其删除!

在我们的数据库文章中,我们显示了Dynatrace在您的测试自动化/连续集成中的体系结构指标的可视化选项。 将其与以下仪表板进行比较,该仪表板显示了我们生产中的搜索服务的关键体系结构指标。 例如,黄色,橙色和绿色的不同阴影告诉我们在一个和五个内部REST调用(黄色)或五个或更多(明亮的黄色)之间执行了多少搜索请求。 对于执行SQL调用数量(橙色阴影)和每次搜索发送的有效负载(绿色),执行相同的操作。 这种可视化方式有助于识别服务使用情况随时间的变化(Y轴上的总和),还可以识别行为的变化(如果某些颜色代码的部分变大或变小)。

生产中的服务监视:了解代码部署后的使用情况和内部行为

在为时已晚之前先处理好服务

如果您还没有基于指标的体系结构审查,建议您开始做。 查看我描述的模式,让我们知道是否还有其他模式值得我们注意。 但是,不要只是在编码阶段手动进行操作。 从Dev(to)Ops自动化监控这些指标,并就部署什么以及要推广或淘汰的服务做出更好的决策。

翻译自: https://www.infoq.com/articles/Diagnose-Microservice-Performance-Anti-Patterns/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

如何定位服务性能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值