赢得自定义新的遗物弹球机!只需将数据书呆子提交以注册Futureestack。 现在注册

在比例下的操作应用程序意味着我们必须对我们的监测策略进行深思熟虑的警惕,因此我们始终如一地监控一切。随着应用程序的规模,它变得越来越重要 - 越来越复杂 - 有效地监控整个软件生命周期,从代码部署通过构建和部署到警报。那么快速增长的组织是如何做到的?

在New Relic,一切都是自动化。随着我们在全球范围内发展到超过50个工程团队,定期将新代码投入生产,我们从基础架构作为代码到“作为代码的监控”,包括四个关键的最佳实践:

  1. 在应用程序构建中安装监视代理
  2. 在部署系统中添加标记和标记
  3. Bootstrap应用程序和监控
  4. 使用API​​和DSL用于仪表板和警报

让我们仔细看看每个人。

自动执行#1:在应用程序构建中安装监视代理

让我们从构建系统开始。

现代构建工具,如Gradle,几乎可以做任何事情,你应该利用这种力量。在新的遗物中,我们使用我们编写应用程序的编程语言的完整电源和表现力自动化我们的构建流程。我们在建立系统中使用API​​和代码对抗它们。

例如,要将New Relic代理安装到Java应用程序中,您必须下载代理,将New Relic API作为依赖项添加,生成YAML配置文件,修改我们的运行命令,并将所有这些包含在一个可部署的工件中。我们如何实现自动化呢?

我们可以编写构建脚本,捕获所有依赖项和任务以完成代理安装,但我们必须为我们部署的每个应用程序复制/粘贴此样板脚本。我们永远不会写这样的实际应用程序代码,所以为什么要使用构建脚本?

这是构建插件发挥的地方。考虑此示例build.gradle文件:

apply plugin: ‘application’ apply plugin: ‘newrelic-agent-plugin’ apply plugin: … application { name 'my_app' mainClass 'com.example.MyAppMain' } newrelic { version ‘4.10.0’ includeAgentApi true distribution { configFilePath 'config/newrelic.yml' agentJarPath 'agent/newrelic.jar' } } …

这是可行的,但仍然不理想。我们仍然需要在所有的应用程序中使用这个样板文件,如果我们想要更改监视配置的某些内容,我们就必须更新数百个构建文件中的配置块。

那么为什么不朝向“零配置构建”的Nirvana?

Apply plugin: ' company-java-service ' dependencies{…}

在这里,我们已经写了一个“Mega-Plugin”,它在我们要使用的所有其他插件中提取,并为它们提供明智的默认配置。从这里,单独的服务可以应用此插件及其构建依赖项,并且它的IT - 包括监视现在是应用程序构建中的零精力默认值。

自动化#2:在部署系统中添加标记和标记

大多数现代软件团队都有一个通用的自动化部署系统。不一定是一个持续的部署系统,而是将代码投入生产的一种标准的、集中的方式。

但你必须知道你已经部署了代码。当监视数据发生变化时,人们会问的第一个问题是:“这与部署有关吗?”有两种方法可以跟踪此信息:部署标记和版本标记。两者都很有用,所以这不是非此即彼的选择,而是两者兼有的情况。标记和标记提供了扩展和自动化部署监视所需的关键信息

部署标记是在主监控遥测系统的某个地方记录的事件日志。它们提供了所有系统中所有变化的时间顺序记录。如果您想记录部署标记,通常只需在部署过程中调用REST API即可。从那里,你可以使用图表库或New Relic自动显示在仪表板上的标记。

但部署标记确实有一些缺点。

随着金丝雀部署、阶段性推出和蓝绿色部署等技术的普及,越来越难以确切地知道部署标记在标记什么。它是标志着一个部署的开始,还是一个部署的结束?如果您在部署过程中发现了一个问题,需要中止并回滚该怎么办?在这种情况下,版本标记更有用。

在新的遗物中,我们的部署系统将版本号注入应用程序作为环境变量。这是仪表板的一个例子,我们的所有遥测数据都标记了应用程序的版本号。

版本标记监视应用程序。
版本标记监视应用程序。

通过跟踪报告每个版本(在路由器数图表)我们可以看到这是90分钟的阶段逐步的推出。

当这种情况发生时,我们可以比较版本之间的性能(在查询第95个百分位图表)看到,在第一条大公中的一点点Java虚拟机(JVM)预热之外,这两个版本轨道非常接近彼此,即使从分钟到分钟的事情,基于改变工作负载跳过一点。

我们使用标签跟踪其他类型的信息。当我们响应事件或支持请求时,我们经常需要知道如何范围问题 - 是限于单个实例的问题,还是普遍存在的问题?我们通常需要基于群集或单元格或按区域和可用性区域进行比较或限制数据,或者由哪些团队拥有应用程序 - 所有这些都可以使用标签完成。

此外,在集装箱内的世界中,应用程序通常不知道他们正在运行的主机,如果我们需要关闭不行动实例,这可能是一个问题。出于这个原因,我们有部署系统告诉容器在推出时运行的情况,所以我们确切地知道我们应该在哪里遇到问题。

您的部署系统是一个功能强大的工具,它为您提供了所有您所需的所有信息,您可以确切地知道您的监视数据来自的位置:哪个版本在哪个机器上运行哪些区域,依此类推。

自动执行它#3:引导应用程序和监控

我们研究了如何自动安装应用程序中的监控代理版本构建并监控我们的部署,因此我们可以查看我们如何自动监控我们的应用程序本身。

前面,我说过尽可能多地删除样板代码是很重要的,但事实是,您永远无法完全删除它们。如果你必须复制/粘贴样板代码来创建一个新的服务,至少让一台机器使用统一的基于模板的构建系统来为你做这件事,比如Apache Maven Archetype.。当您在组织范围内定义使用模板引导新服务的最佳实践时,您正在采取积极的步骤来确保微服务体系结构中的一致性。

如上所述,新的遗物部署系统将环境变量注入我们的应用程序,该应用程序确切地描述了应用程序以及它们正在运行的位置。但除非我们实际与它做点什么,否则此信息的价值有限。为此,我们编写了简单的包装器库,允许我们将属性(如我们的应用程序的名称,版本,版本和主机名)附加到我们在监控它们时收集的所有数据:

public void RecordEvent(String EventType,Map 属性){//添加标准属性映射<字符串,字符串> envvars = system.getenv();attributes.put(“appname”,envvars.getordefault(“new_relic_app_name”,“未知”));attributes.put(“版本”,envvars.getordefault(“gc_version”,“未知”));attributes.put(“jvmid”,managementfactory.getruntimemxbean()。getName());attributes.put(“ipport”,envvars.getordefault(“cf_primary_ip_port”,“未知”));attributes.put(“hostname”,envvars.getordefault(“cf_fqdn”,“未知”));attributes.put(“区域”,envvars.getordefault(“cf_region”,“未知”));attributes.put(“zone”,envvars.getordefault(“cf_zone”,“未知”));attributes.put(“子网”,envvars.getordefault(“cf_subnet_id”,“未知”));newrelic.recordcustomevent(EventType,属性); }

有了这一点,我们就能够按照一致的维度集对所有应用程序的监控数据进行分割,即使它们继续扩展。

自动化#4:为仪表板和警报使用api和dsl

所以现在你正在建造和部署监控所有服务 - 但如果没有人关注,那么你就没有很好。

对于整体应用程序体系结构,只需开始创建仪表板和设置警报就足够了。但是大型微服务体系结构是大规模运行的,手动gui驱动的仪表板和警报配置太重复、太容易出错,而且太容易放弃。这就是为什么现代软件开发团队将api作为gui的首选。

New Relic给你用于创建仪表板的apiapi来定义合成监视器API设置警报条件等等。但您需要决定如何与这些api交互——显然,您不希望人们手动输入JSON有效负载和cURL命令;比起在GUI上做一些改变,这几乎算不上什么改进。不过,好消息是,您可以选择如何处理这一问题。

最近,例如,IBM开源的命令行工具它用于自动化其新的遗物任务和资源(例如,创建,编辑和删除警报策略)。这是您想要构建更复杂的工作流程的工具;例如,您可以使用它来下载所有现有的仪表板配置并以编程方式管理这些配置,基本上为模板。

事实上,这就是我们如何在新遗物中管理我们的合成监测脚本。新的遗物合成纤维监视器只是JavaScript程序,但如果您正在监视多个提供单个服务的集群,则需要更新这些脚本如果群集具有不同的URL。考虑到这些问题,我们将综合脚本转化为嵌入式Ruby(ERB)模板因此,我们可以循环所有群集,并为每个群集生成脚本的唯一版本。

对于其他任务,我们拥抱域特定语言(DSL)。术语“DSL”可以有很多含义,但我谈论的是一种能够以自动化方式驱动API的模板或配置语言。例如,在New Relic,我们通过基于ruby的DSL来管理我们的警告策略:

1 .策略“统一数据流CF警报”do rollup 'condition ' team_low_priority_channels condition "WARNING Service(s) OOMing" do type 'nrql ' query "SELECT count(*) FROM cf_docker_event where action = 'oom ' " since 2。Minutes value 'single_value ' critical above: 0, for: 1。分钟结束结束

因为这是所有Ruby代码,我们可以添加循环和函数调用 - 这使得事情变得更加有趣。在下面的示例中,我们循环循环并以几种不同的方式使用群集标识:我们将群集名称注入警报策略,并选择每个群集的通知通道。生产群集群的通知转到PageRduty.,但从生产中的群集中的通知转到电子邮件。这确保了合适的人获得了正确的原因,并且没有必要在夜间中间醒来。

群集。处理|集群|policy "#{cluster} MyApp Lag" do rollup 'condition' team_alert_channels(cluster) condition "#{sev_and_cluster('SEV3’, cluster)} MyApp" do entities [config[cluster][‘lag_monitor_app_name']] metric 'Custom/ConsumerLag/appendSecondsLag/my_topic/my_app' value 'max' critical above: 60, for: 5.minutes end end end

这些配置选择的关键部分是让正确的事情变得易于易做。您的工程师将要配置警报策略数百或数千次,这为他们创造了很多机会,以便采取捷径或犯错误。将这些机会限制在您的警报配置中自动管理 - 有无数方法可以做到这一点,因此找到最适合您组织的方法。没有什么能让你的Dev和Ops队伍在晚上努力,就像想知道某些东西可能是默默地打破并没有警报来看出来。

监测应该减少辛劳

在新的遗物上,我们显然有很多意见现代软件监控。但我们还知道,微服务架构具有增加劳动力和运营不确定性的风险。您的监测策略不必为此辛劳做出贡献。使用这样的技术将有助于您在您的应用程序和基础架构继续增长时,您可以帮助您提前和继续进行游戏。