QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

Salesforce 如何连续分析数以万计的生产服务器

  • 2020-03-17
  • 本文字数:3791 字

    阅读完需:约 12 分钟

Salesforce如何连续分析数以万计的生产服务器

本文最初发布于 Salesforce 工程博客,经原作者授权由 InfoQ 中文站翻译并分享。


Salesforce CRM 应用程序是一个运行在 JVM 上的多租户单体应用,整个生产环境运行在数万台服务器上。这些主机每天处理数十亿个请求,为不同的租户处理报告查询和各种同步或异步任务。每天都有成千上万的工程师对单库源代码进行修改。此外,对底层数据以及 Salesforce CRM 之上的用户自定义扩展进行的大量更改,可能会导致我们在生产环境中观察不同服务器/集群时看到不一致的行为。

挑战和解决方案

当功能中断或性能退化时,准确确定在那天的关键点上发生了什么,对于调试非最佳行为至关重要。单个单体应用程序负责处理这么多不同租户的多样化要求,每个工作线程都会有丰富的上下文数据(例如,租户 ID、用户、URL),为了能够迅速查明生产环境的问题,必须维护好这些数据。


我们的团队在 Salesforce 主要职责是,确保在任何时候都可以从每个生产服务器获得正确的诊断数据。我们开发了一个完全自主的应用程序性能管理系统,不断地从所有生产服务器捕获性能分析和诊断数据。


我们遇到了一些 Salesforce 应用程序特有的问题,但是,我们相信这些问题的解决方案可能对构建类似系统的工程师有用。这篇文章简要地描述了一些主要的挑战和我们采用的解决方案。

扩展性

挑战

代理在数万个 JVM 上运行。每个数据中心都有很多主机,从每个主机都会捕获大量的数据,再加上跨数据中心的网络延迟,这意味着我们无法有效地将所有数据持久存储到一个集中化的存储解决方案。在所有服务器上,每秒写次数达 300 多万次,每一次有几 KB 的数据,总计超过每秒 1GB。这种速率对于单个网络或存储解决方案来说太高了(在合理的成本下)。

解决方案

将负载分布到多个数据中心,然后从一个可以访问所有数据中心并知道如何将请求路由到特定数据中心的中心站点协调检索。用户请求指定需要哪些主机集群的性能分析数据,中心站点将请求路由到正确数据中心内的相应服务器。这为调查工程师提供了良好的体验,依靠一个中心站点查看整个站点的所有性能分析数据。我们在存储中维护一个路由查找表(可以由系统管理员在运行时修改),将集群映射到相应的数据中心。

容错

挑战

对于 JVM 性能分析来说,许多最重要或最有趣的时间段都是在极端状况下,要么是故障原因,要么是故障征兆。当慢速请求堆积、客户工作负载模式改变或贪婪作业分配太多大对象时,内存和 CPU 会急剧增加。在紧急关头,JVM 可能会宕机或终止,或丢失网络连接;因此,如果只是将性能分析数据缓冲到内存中,而不是立即将其持久化到某种形式的永久存储中,那么性能分析数据可能会丢失。

解决方案

为了避免丢失最重要的数据,同时保持批量保存数据的能力,需要以弹性的方式缓存数据。当应用程序受到威胁时,将缓冲区保存在内存中可能容易丢失数据,因此,我们实现了一个磁盘上的循环缓冲区。从 JVM 捕获样本(线程转储和相关上下文)后,立即将它们保存在本地磁盘上。这样,在服务器或网络故障时,可以防止在将数据转发到集中存储之前丢失缓存数据。为了防止在长时间停机时对磁盘空间产生负面影响,缓冲区的循环特性是必须的,因此,缓冲区会根据配置的时间间隔覆盖。

多语言运行时支持

挑战

Salesforce 为 Apex 编程语言提供了一个定制的解释器,客户可以使用该解释器来添加特定于其组织的自定义业务逻辑。在处理生产环境的问题时,能够分析用户定义的扩展很有价值,这可以减少服务成本或响应时间。我们的解决方案必须能够捕获和表示性能分析和可观测数据,而不用管底层的语言是什么。此外,Salesforce 运行着各种基于 JVM 的服务,其中许多都是很好的性能分析候选对象。因此,我们的解决方案必须能够适应各种各样的 JVM,而不能仅仅适用于 CRM 的单体应用。

解决方案

我们的系统设计没有对所使用的编程语言做任何假设。底层实现语言作为另一个元数据附加到所有性能分析数据点,允许用户基于该语言进行查询。此外,为了能够支持不同的语言和环境,实现多语言支持,用于抽象堆栈跟踪和元数据的数据结构是以一种通用且足够灵活的方式表示的。

上下文元数据

挑战

通常情况下,领域专属上下文会触发调查和调试:报告花费的时间比它应该花费的时间长、请求失败或花费的时间太长、特定于租户的性能问题或加载了畸形数据的页面。允许调试工程师使用这个领域专属上下文来驱动他们的调查,可以极大地加快得出结论的过程。


如果工程师已经知道花费很长时间才能加载的 URL,那么搜索与该 URL 相关的堆栈跟踪信息可以让他们快速地将视野缩小到相关数据。这样就省去了许多常见的起始步骤,比如根据线程 ID 搜索日志和交叉引用 URL。

解决方案

我们的实现会针对每个线程收集领域专属上下文和它收集的堆栈跟踪信息。我们将流程设计得足够通用,以便每个经过性能分析的服务都可以确定将哪些相关信息映射到每个线程抽样:一个 JVM 处理请求,这些请求可能附加了 URL、HTTP 方法和请求参数;一个 JVM 运行批处理作业,这些作业可能附加了作业名称、ID 和作业类型。领域专属上下文与标准性能分析元数据一起存储,完全索引,并允许在查询时添加适当的过滤器,以避免额外的干扰。


此外,我们还允许对堆栈跟踪信息进行深度搜索,用户可以在其中通过正则表达式查找包含特定栈帧的抽样数据。这是最有用和最受欢迎的查询参数之一,因为在许多情况下,开发人员只对某些代码路径感兴趣,而不是对应用程序中执行的所有代码的抽样数据感兴趣。特性团队知道其模块的入口点(接口/API),因此,他们可以使用这些知识验证其特性在生产环境中的行为,从而提供一个反馈循环来识别潜在的进一步优化机会。

高线程数

挑战

为了及时处理请求或活动的激增,Salesforce 应用程序维护着大量的活动线程池。这将导致一定百分比的活动线程始终处于空闲状态,不做任何重要的工作。各个服务器上各种类似的情况会使这种影响成倍地增加,因此,任何给定的线程转储都至少包含 1500 个单独的线程。来自这些线程的数据将很快淹没我们的存储基础设施。

解决方案

抛弃捕获的那些空闲线程的数据!我们的目标不是在给定时刻完美地表示每个线程,而是表示在给定时刻正在进行的工作。过滤掉那些无所事事地等待工作的线程,或者是在检查一个值时休眠的线程,可以让我们更频繁地分析数据并更长时间地保存数据。在给定的 JVM 中,我们能够过滤掉 99%的初始线程转储。供参考:在整个生产环境中,我们平均每分钟丢弃数亿的堆栈跟踪信息,每分钟仅保留 500 万跟踪信息供以后使用。

压缩和去重

挑战

代码库经常变化,但是整体来看,它们的变化并不大。此外,在特定的时期内,最常执行的代码基本上没有变化。因此,线程转储包含大量的重复数据。这就提出了一个挑战,将性能分析数据直接捕获并存储会导致巨大但合理的存储需求。

解决方案

将数据分割成离散的部分,并跟踪数据的关系,使我们能够尽可能减少存储线程转储时的重复。选择正确的存储解决方案和正确的存储模式至关重要,这样构建的系统可以减少重复,从而使存储这些数据成为可能。我们在HBase上使用Apache Phoenix构建了相关的表。每个数据中心只存储每个堆栈跟踪信息帧一次,并且为了实现快速查找建立了索引。堆栈跟踪信息也只存储一次。堆栈跟踪信息以栈帧 ID 列表的形式存储,并根据它们的散列 ID 值建立索引。在给定的线程转储中,各个线程抽样被存储为时间序列事件,堆栈跟踪信息记录为对散列 ID 值的引用。所有这些结合起来,使我们减少了堆栈跟踪信息(任何给定线程转储的最大部分)存储的空间占用。


为了减少 HBase 集群上的写入负载,我们保留了可配置的堆栈跟踪信息和栈帧缓存。我们可以检查这些缓存,看看堆栈跟踪信息是否已经写入,而不是写入每条堆栈跟踪信息或栈帧。这些缓存消除了 99%的栈帧写入和 75%的堆栈跟踪信息写入。

回归识别

挑战

对应用程序(例如新版本)进行更改后的回归检测和识别是我们希望解决的主要问题之一。回归可能是由于对特定代码路径的调用频率增加,或者是由于子系统的运行时性能下降。

解决方案

通过将性能分析数据保存较长的时间(我们目前的 TTL 为 90 天),我们的系统支持在不同的版本、库和平台升级以及对软件的其他(较长时间有效)更改之间进行比较分析。


可以在运行时进行短时间(少于一小时)的比较分析。这些数据被表示为火焰图和树形差异图。这种可视化使得工程师可以很容易地识别代码路径的差异,在他们调查的时间段内找出罪魁祸首。


此外,对于时间跨度较大的查询,因为通过如此大量的数据在运行时确定回归是不可行的,所以我们开发了一种通用的作业和报表框架,用户可以定义和调度在所有数据集上执行的作业,作业结果会被持久化,并且可以从 UI 上查看。作业框架内置支持与 Salesforce 其他内部工具的交互,使我们能够将性能分析数据与日志、系统级和应用级监控数据、站点可靠性工具等关联起来。

未来工作

我们正在寻求集成Java Flight Recorder,以添加 CPU 性能分析以及提供更高的采样率支持。这将使我们可以准确地度量在不同代码路径上花费的 CPU 周期的数量,帮助我们关联成本与系统中单个组件的服务价值。此外,我们正在考虑与Async Profiler集成,以便为非 JVM 应用程序提供更好的支持。


我们的下一篇博文将介绍使用诊断数据收集代理捕获可观测数据的方法。该文将详细介绍我们如何设计一个低开销、可配置的代理来从生产服务器收集系统和应用程序诊断数据。


原文链接:


How to Continuously Profile Tens of Thousands of Production Servers


2020-03-17 09:441563

评论

发布
暂无评论
发现更多内容

做正确的事情,而不是把事情做正确

非著名程序员

个人成长 提升认知 认知提升 8月日更

英特尔CEO帕特·基辛格:面向未来的数字化需求,推进未来计算创新、探索与颠覆

科技新消息

跨团队项目的集成测试实践分享

PingCode研发中心

软件测试 测试

Go- 函数返回值

HelloBug

函数 返回值 Go 语言

手把手教你15分钟搭建人脸戴口罩识别软硬件系统

百度大脑

人工智能 EasyDL

搭建太阳系3D可视化平台,科普宇宙的未知奥秘

一只数据鲸鱼

科普 数据可视化 智慧宇宙 太空

python通过Matplotlib绘制常见的几种图形

Python研究者

8月日更

Tron波场链智能合约系统开发案例|波场链源码搭建

Geek_23f0c3

TRONex波场智能合约 DAPP智能合约交易系统开发 波场DAPP

火爆 GitHub!这个图像分割神器开源了

百度开发者中心

人工智能 开源 最佳实践 图像

迅雷不及掩耳盗铃

escray

生活记录 8月日更 搜房记

spring-boot 2.5.4,nacos 作为配置、服务发现中心,Cloud Native Buildpacks 打包镜像,GitLab CI/CD

Zhang

gitlab nacos CI/CD spring-boot 2.5.4 CNB

中国法定数字货币(DCEP)全面启航!全国普及势在必行

CECBC

模块五:微博评论模块高性能高可用计算架构设计

kk

架构实战营

量化策略APP系统开发,马丁策略交易平台

13530558032

Python代码阅读(第16篇):列表求差集

Felix

Python 编程 Code Programing 阅读代码

InnoDB 表空间

leonsh

MySQL innodb 表空间

ipfs投资者靠什么赚钱?投资ipfs要多少钱?

投资ipfs要多少钱 ipfs投资者靠什么赚钱

ipfs矿机公司哪家好?ipfs矿机公司实力排行?

分布式存储 Filecoin ipfs挖矿 ipfs矿机 ipfs矿商排名

快手基于 Flink 构建实时数仓场景化实践

阿里云大数据AI技术

微信架构图设计&“学生管理系统”毕设架构

Imaginary

BuildPacks 打包

Zhang

Docker image CNB OCI

干货!DataPipeline2021数据管理与创新大会全篇划重点

DataPipeline数见科技

大数据 数据融合 数据管理

亚信数据库AIDB通过统信UOS认证,国产自主可控项目新选择

亚信AntDB数据库

国产化 国产数据库 亚信数据库AIDB

Linux内核源码分析方法—程序员进阶必备

Linux服务器开发

操作系统 Linux内核 内核源码 底层原理 内核开发

LVS 学习: netfilter 与 ipvs 无秘密

绅鱼片

Linux 负载均衡 LVS Netfilter IPVS

探索技术与应用融合的区块链 实现产业良性发展

CECBC

BI软件漫谈

格林海文

BI Tableau 帆软

最好用的 Angular 甘特图组件 ngx-gantt

PingCode研发中心

软件 工具 甘特图 ngx-gantt

上游思维:凭一己之力能做些什么?

石云升

读书笔记 8月日更 上游思维

项目进度经常超时怎么办?项目经理如何有效管理项目进度?

优秀

项目管理工具

Vue进阶(五十九):ES数组操作:splice() 实现数组删除、替换、增加指定元素

No Silver Bullet

Vue 8月日更 splice

Salesforce如何连续分析数以万计的生产服务器_软件工程_Paul Howden_InfoQ精选文章