首页 >> 大全

Java 运行时监控,第 3 部分: 监控应用程序生态系统的性能与可用性

2023-12-28 大全 36 作者:考证青年

另外 JMS 代理发挥功能的方式也不同。本例中解释的模式展示的是目标主机上的一个请求监听代理,因为这些代理在启动后不会执行任何操作,直到它们从中央监控系统接收到一个请求才执行。然而,这些代理可以按照自己的计划自主地收集数据并将它发布到相同的 JMS 服务器。监听代理的优势有两个:第一,可以配置收集参数并保存在一个中央位置,而不用发送到每一个目标主机。第二(虽然在本例中没有实现),由于中央请求监听器发出请求,所以监听器可以在特定的已知服务器没有响应的情况下触发一个报警条件。图 8 显示了组合服务器的 APM 树:

图 8. 和 Linux 服务器的 APM 树

实现

和 使用几乎相同的套接字协议来从 服务器请求数据。(参见参考资料)是一个 Java API,它包装了这个协议并使 WPM 指标对于任何带有 JVM 的系统可用。本文的示例代码中有一个 收集器的例子,它位于 /conf/-/.xml 目录中。

是一个简单的、早期的原型,它有几个缺点,包括:

最后,就像我在前面提到的,应用程序用一个参数引导,它是一个含有配置 XML 文件的目录。这个目录为 /conf/-,它位于示例代码包的根目录中。前面的例子中使用的具体文件为:

我对 OS 监控的论述就到此为止了。接下来,我将介绍数据库系统的监控。

回页首

用 JDBC 监控数据库系统

我经常遇到这种情况,就是认为 DBA 以及他们的工具和应用程序的职责仅仅是监控数据库。然而,要为性能和可用性数据实现非孤立的、集中式 APM 储存库,需要在 DBA 的工作中再补充一些监视整合的 APM 的工作。我将展示一些用名为的 收集器来收集数据(这些数据在某种情况下很可能没有受到监控,而且是非常有用的指标)的技术。

您应该考虑的数据收集的广义范畴为:

非常简单。基本上,它由一个查询和一串映射语句组成,它定义了将查询的结果映射到跟踪名称空间的方式。思考一下清单 12 中的 SQL:

清单 12. 一个简单的 SQL 查询

SELECT schemaname, relname, 
SUM(seq_scan) as seq_scan, 
SUM(seq_tup_read) as seq_tup_read
FROM pg_stat_all_tables
where schemaname = 'public'
and seq_scan > 0
group by schemaname, relname
order by seq_tup_read desc

该查询选择一个表格中的四个列。我想将每一个从查询返回的行映射到一个跟踪名称空间,这个名称空间由每行的一部分数据组成。切记名称空间是由片断名称加上指标名称组成的。使用字母值和/或行标记来指定这些值也就定义了映射。行标记代表编号列中的值,如{2}。处理片断和指标名称时,字母值保持原样不变,而标记在查询结果中使用当前行的各个列值动态替换,如图 9 所示:

图 9.映射

在图 9 中,我呈现的是对查询的一行响应,但每为每一个返回的行定义一次映射,映射过程就会发生一次。片断的值是{1}、{2},所以跟踪名称空间的片段的部分是{"", ""}。指标名是字母值,因而保持不变,指标值在第一次映射时被定义为1,在第二次映射时被定义为2,它们分别代表着3459和。具体的实现该过程便可以进一步澄清它。

回页首

使用 JDBC 的上下文跟踪

运行的数据库中的应用程序数据也许包含有用的且有趣的上下文数据。应用程序数据本身并不一定是与性能相关的,但如果抽样这些数据,把它与表示 Java 类的性能、JVM 的健康状况和服务器性能统计信息的历史指标联系起来的话,就可以清楚地了解系统在某一具体的时间段内到底在做些什么。假想您现在正在监控一个极其繁忙的电子商务 Web 站点。您的客户所发出的订单被记录在一个名为的表中,该表还记录了一个惟一的 ID 和发出订单的时间戳。你可以通过抽样在最后n分钟内输入的记录数来得出提交订单的速率。

这里是的增量(delta)功能的又一个用武之地,因为我可以设置来从某个特定时间点开始查询行数,并将这个值作为一个增量而跟踪它。结果会得到一个可以描述您的网站有多繁忙的指标(或许还有很多其他指标)。这个指标也会成为一个颇有价值的历史参考。例如,如果知道输入的订单数达到每个周期 50 个时数据库的速度就会减慢的话,那么将会很有用。硬性的、特定的经验数据可以简化容量和增长情况的规划。

接下来我将要实现这个例子。使用与前面的例子相同的调度器 bean,它还有一个与我在第 2 部分中涉及到的完全相同的 JDBC 。这些数据库收集器是在 /conf/-/jdbc-.xml 文件中定义的。清单 13 展示了第一个收集器:

清单 13. 订单执行速率收集器

 ? and order_date < ?]]>12


这个例子中的收集器 bean 名为ast5s,类为org....jdbc.。标准收集器被注入,它被当作 JDBC 的一个引用,。query定义要执行的 SQL。SQL 查询既可以把字母值用作参数也可以使用绑定变量(就像在这个例子中一样)。这个例子是人为构造的,因为的两个值很容易用 SQL 语法来表示,但是通常情况下,只有需要提供某些外部值时才会用到绑定变量。

为了提供绑定外部值的能力,我需要先实现org....jdbc.r接口,然后再将该类作为一个 管理的 bean 来实现。在这个例子中,我使用了org....jdbc.vider的两个实例,还有一个通过被传递的属性来提供当前时间戳偏移量的 bean。这些 bean 是,它返回当前时间减去 5 秒得出的值,还有,它返回 “现在” 时间加上 10 毫秒的值。这些 bean 的引用通过binds属性(一个映射)注入到收集器 bean。映射中的每一个入口值都要与要使用该映射的 SQL 语句中的绑定变量相匹配,这一点至关重要,如若不然就会发生错误或意外的结果。

实际上,我利用了这些绑定变量来获取在大约最后 5 秒钟输入系统的销售订单数。这需要对生产表格执行大量查询,因此要适当调节收集的频率和时间窗口(即,的时间段)以避免在数据库上实现不恰当的负载。为了帮助正确地调节这些设置,收集器跟踪收集时间一直到 APM 系统,所以运行时间可以用来度量查询开销。更高级的收集器实现会减缓收集的频率,因为监控查询的运行时间增加了。

上面所呈现的映射是通过属性定义的,该定义使用了一个org....jdbc.类型的内部 bean。它有四个简单的属性:

如果想从每一个执行的查询跟踪多个值,收集器允许为每一个收集器定义多个。接下来我将向您展示的例子会使用把返回数据的值注入跟踪名称空间,但是现在的例子使用的是字母值。但是,要设计一个使用相同查询的例子的话,我会将查询改为 count(*), 'Sales Order ', 'Order Rate' from where > ? and < ?。这使得我所期望的片断和指标名称返回于查询中。要想映射它们,我可以将配置为{1},将设置为{2}。在某些扩展的情况中,甚至可能来源于数据库,而且值也可以用来表示。 图 10 显示了这些收集的指标的 APM 树:

图 10. 销售订单速率监控

数据库性能监控

可以使用相同的进程来从数据库性能视图中获取和跟踪性能数据。在这个使用了 的例子中,这些表 — 称为统计视图— 的名称的前缀为。很多其他的数据库也都拥有类似的视图,并可以使用 JDBC 来访问。在这个例子中,我将使用同一个繁忙的电子商务网站并设置一个来监控最为繁忙的 5 个表上的表格和索引活动。具体的 SQL 展示在清单 14 中:

清单 14. 表格与索引活动监控器

 0group by schemaname, relname, idx_tup_fetch,seq_tup_read, seq_scan, idx_scanorder by total descLIMIT 5 ]]>

查询每隔 20 分钟为最繁忙的 5 个表检索如下的值:

后四列是持续增长的值,所以我使用的是类型的指标,它是一个 增量long。注意,在清单 14中,我配置了四个来将四列值映射到跟踪名称空间。

在这个场景中,我构造了一个有用的例子,而没有在表上创建索引。因此,监控将会揭示更多的顺序扫描(按照数据库用语来说为表扫描),它是一个低效的检索数据的机制,这是因为它要读取表中的每一行。顺序元组读取— 主要指使用顺序扫描读取的行的数量 — 也一样。行和元组之间有一个很大的差别,但是在这里没有关系。要弄清楚这个差异,您可以查看 文档网站(参见参考资料)。看一看 APM 显示的这些统计信息,很明显我的数据库遗漏了一个索引。如图 11 所示:

图 11. 顺序读取

注意到了这一点后,我赶紧触发了两个 SQL 语句来索引表格。随后的结果是两个顺序操作都降到了零,而本来为零的索引操作现在却运行起来。如图 12 所示:

图 12. 索引后

这个索引的创建在整个系统中发生了连锁反应。另一个明显稳定下来的指标是数据库主机上的 User CPU %。如图 13 所示:

图 13. 索引后的 CPU

数据库可用性

我要介绍的有关 JDBC 的最后一个方面是数据库可用性。数据库可用性的最简单的形式是选择标准。如果收集器被配置了一个e值,那么收集器将两个指标跟踪到配置的名称空间:

当用数据源或连接池来获取连接时,连接时间通常都是很快的。但大多数 JDBC 连接池系统都能在分发连接前执行一个可配置的 SQL 语句,所以测试是合法的。在重负载的情况下,连接的获取会有一个非零的运行时间。此外,可以为用于测试可用性的设置单独的数据源。这个单独的数据源可以配置为不共享连接,所以每一个轮询周期都会启动一个新的连接。图 14 显示了我的 运行时数据库的可用性检查 APM 树。请参考清单 14,查看使用e属性的例子。

图 14. 运行时数据库可用性检查

我见过需要多个连锁查询来决定一个特定状态的情况。例如,一个最终的状态需要对 A 进行查询,但它所需的参数只有对 B 进行查询才可以确定。这种情况可以用两个来解决,但要特殊考虑如下几点:

我对数据库监控的论述就到此为止了。我必须补充说明一下,这一节重点介绍的是数据库监控,尤其是通过 JDBC 接口的数据库监控。完成一个典型的数据库监控还要监控数据库所在的 OS、单个数据库进程或数据库进程组、还有一些有必要访问数据库服务的相关的网络资源。

监控 JMS 和消息传递系统

本节将描述监控消息传递服务的健康状况和性能的技巧。消息传递服务,如实现 JMS — 同样指面向消息的中间件(- ,MOM)— 的服务,在很多应用程序中都起着至关重要的作用。它们和其他应用程序依赖项一样也需要监控。通常,消息传递服务提供同步的或者说是 “即发即弃(fire-and-)” 调用点。监控这些点的难度要大一些,因为从很多角度来看,该服务看起来都运行得很好,服务的调用被频繁地分配,并且运行的时间也很短。仍然保持神秘的是上游瓶颈,消息要经过这里被转发到下一个目标,但消息在这里的传输速度很慢或者根本无法通过。

由于大多数消息传递服务都存在于 JVM 中,抑或是作为一个或多个本机进程而存在于一个主机(或一组主机)上,监控点包括一些与目标服务有关的相同的点。这些目标服务可能包括标准 JVM JMX 属性、支持主机上的监控资源、网络响应,以及诸如内存大小和 CPU 使用这样的服务进程特征。

我将概述消息传递服务监控的四个范畴,它们当中的三个都是专用于 JMS 的,另一个则涉及到专有的 API:

通过综合测试消息来监控消息传递服务

综合消息的前提是将测试消息的发送和接收安排到目标消息传递服务并度量消息的发送、接收和整个往返过程的运行时间。为了设计消息的返回并准确地度量从远程位置发送消息的响应时间,最佳的解决方案就是部署远程代理,它的任务是:

监听中央监控器的测试信息 检索它们 给每一个收到的消息添加一个时间戳 重新将它们发送回消息传递服务,目的是返回到中央监控器

然后中央监控器可以分析返回的消息,得出进程中的每一个跳跃点(hop)的运行时间并跟踪到 APM 系统。如图 15 所示:

图 15. 综合消息

虽然这个方法涉及到了监控的大多方面,但它还是有一些缺点:

这里介绍的另一个专用于 JMS(但可能在其他消息传递系统中有等效体)的选择是使用临时队列或主题。临时队列可以由标准 JMS API 自动创建,所以不需要介入任何管理。这些临时构造有很多额外的优势,但只有最初的创建者可以看到,其他所有 JMS 参与者都无法看到。

在这个场景中,我将使用,它可以在启动时自动创建一个临时队列。当调度器提示时,它会将很多测试消息发送给目标 JMS 服务上的临时队列,然后再收回它们。这就有效地测试了 JMS 服务器的吞吐量,而无需创建具体队列或部署远程代理。如图 16 所示:

图 16. 带有临时队列的综合消息

这个场景的 收集器类为org....jms.。配置依赖项相当的简单明了,而且大多数依赖项已经在前面的例子中设置过了。JMS 连通性需要一个 .jms.。我用来获取它的 bean 与在 WPM 收集的例子中用来获取 JMS 连接工厂的 bean 相同。在这里重新修改一下,它需要org..jndi.类型的 bean 的一个实例,该类型的 bean 可以给我的目标 JMS 服务提供一个 JNDI 连接;它还需要org..jndi.n类型的 bean 的一个实例,该类型的 bean 可以使用 JNDI 连接来查找 JMS 连接工厂。

为了使综合消息负载的组成灵活一些,被配置了名为org....jms.tory的接口的一组实现。实现这个接口的对象提供了一组测试消息。收集器会调用每一个配置的工厂,并使用所提供的消息来执行往返测试。用这种方式,我就能够测试我的 JMS 服务器上的吞吐量,因为负载会随着消息大小和消息计数的变化而变化。

每一个tory都有一个可配置的、任意的名称,把它添加到跟踪名称空间。清单 15 展示了完全的配置:

清单 15. 综合消息

org.jnp.interfaces.NamingContextFactorylocalhost:1099org.jboss.naming:org.jnp.interfaces






清单 15 实现了两个消息工厂,它们是:

图 17 显示了综合消息监控的 APM 树。注意字节负载大小被附加到javax.jms.消息工厂名称的末尾。

图 17. 带有临时队列的综合消息的 APM 树

监控应用可用生态性能性程序吗__应用性能监控系统

通过 JMX 监控消息传递服务

诸如 和 这样的消息传递服务通过 JMX 公开了一个管理接口。我曾在第 1 部分中介绍过基于 JMX 的监控。下面我将简短地回顾一下这种监控,然后我将介绍基于org....jmx.类的 收集器以及使用它来监控 实例的方法。由于 JMX 是一个恒定的标准,所以可以使用同一过程来监控任何公开 JMX 的指标,而且它的应用范围很广。

有两个依赖项:

类展示了一些常见于 JMX 监控器的属性。基本的配置属性有:

通配符功能非常强大,因为它可以有效地发现监控目标,而无需为每一个目标配置监控器。对于 JMS 对列, 为每一个队列创建了一个单独的 MBean,所以如果我想监控每一个队列中的消息数(称为队列长度),我只需要指定诸如jboss.mq.:=Queue,*这样的通用通配符,JMS 队列 MBean 的所有实例都是从其中收集到的。但是,由于这些对象是自动发现的,所以如何动态确定队列名就成了另一个难题。在本例中,我知道被发现的 MBean 的 name属性值就是队列的名称。例如,一个被发现的 MBean 的对象名可能是jboss.mq.:=Queue,name=。因此,我需要一种将被发现的对象的属性映射到跟踪名称空间的方式,这样就可以从每一个源中划分出被跟踪的指标。方法就是以与中的相类似的形式来使用标记。支持的标记有:

清单 16 展示了经过删减的 ML 配置:

清单 16. 本地






图 18 显示了用监控的 服务器的 JMS 队列的 APM 树:

图 18. 队列的 JMX 监控的 APM 树

用队列浏览器监控 JMS 队列

如果缺少足够用于监控 JMS 队列的管理 API 的话,可以使用javax.jms.。队列浏览器的行为与javax.jms.的行为类似,不同的是获取的信息不会从队列中移除,而且在被浏览器检索之后仍然可以发送。队列深度通常都是一种重要的指标。据观察在很多消息传递系统中,消息生产者要多于消息消费者。这种严重的不平衡从代理队列中消息的数量可以看出来。因此,如果无法用其他的方式访问队列深度的话,那么最后一招就是使用队列浏览器了。该技巧有很多的缺点。为了计数队列中的消息数,队列浏览器一定要检索队列中的每一条信息(然后删除它们)。这样做的效率是很低的,而且要耗费比使用管理 API 多得多的收集时间 — 而且可能在 JMS 服务器的资源上开销更高。队列浏览的另一个问题是,对于繁忙的系统来说,计数在浏览完成的时候很可能就已经是错误的了。虽说如此,要是为了监控的话,近似值还是可以接受的;更何况在高负载的系统中,即便是对队列深度在给定瞬间的高精确度的度量在下一个瞬间也会是无用的了。

队列浏览有一个好处:在浏览队列的信息的过程中,可以确定最老的消息的年龄。这是一个很难获取的指标,即便是使用最好的 JMS 管理 API 也很难获取,而且在某些情况下,它可能是一个至关重要的监控点。思考一下用于传输重要信息的 JMS 队列。消息生产者和消息消费者有着明显的区别,而流量的模式是这样的:对队列深度执行一次标准的轮询通常显示一到两条信息。通常情况下,导致这个问题的原因是存在一定的延迟,而轮询的频率却是一分钟,队列中的消息不同于轮询到轮询间的消息。它们相同么?它们可能不是相同的消息,在这种情况下,上述的情况就是很正常的。但也可能是消息生产者和消息消费者同时遭遇失败,因此队列中被观察的这对消息在每个轮询中是相同的消息。在这种场景中,在监控队列深度的同时监控最老的消息的年龄就会使情况变得很清晰了:正常情况下,消息的年龄要少于几秒,但如果生产者和消费者同时失败的话,从 APM 出现明显的数据只会占用两个轮询周期间的时间。

这个功能在 收集器的org....jmx.中有所展示。它的另外两个配置属性有javax.jms.,它与类似,还有要浏览的队列的集合。清单 17 展示了该收集器的配置:

清单 17. 本地




图 19 展示了该收集器的 APM 树:

图 19.的 APM 树

作为一个测试机制,一个载入脚本开始循环,在循环中向每一个队列发送了几百条消息。在每一个循环中,被清除的队列是随机选取的。因此,每一个队列中的消息年龄的上限都会随着时间的推移而随意变化。

使用私有 API 监控消息传递系统

有些消息传递系统拥有实现诸如监控这样的管理功能的私有 API。一些消息传递系统使用请求/响应的模式来用它们自己的消息传递系统提交管理请求。(参见参考资料)提供了一个 JMS 通信管理 API 以及一个 JMX 管理 API。实现一个私有的管理 API 需要一个自定义的收集器。在这个小节中,我将呈现 ® MQ(原来称为 MQ )的收集器。该收集器结合使用了两种 API:

其实使用两个 API 是多余的,但是毕竟展示了两种不同的私有 API 的使用方法。

收集器实现是一个名为org....mq.的类。它监控 MQ 服务器上的所有队列,收集每一个队列的队列深度以及当前打开的输入/输出处理的数量。清单 18 展示了org....mq.的配置:

清单 18. MQ 收集器


这里独特的配置属性有:

注意这个例子不包含任何的验证方面。

图 20 展示了为org....mq.生成的 APM 树:

图 20.的 APM 树

我对消息传递服务监控的论述就到此为止。正如我在前面提到的,接下来我将介绍如何用 SNMP 进行监控。

回页首

使用 SNMP 进行监控

SNMP 原本是作为应用层协议而创建的,该协议用来在诸如路由器、防火墙和交换机这样的网络设备间交换信息。这也许仍然是它最常用的功能,但是它也可以充当监控性能和可用性的灵活的标准化协议。SNMP 的整个主题以及它作为一个监控工具的实现超出了本文的讨论范围。但是,SNMP 在监控领域已经非常普及,因此难免会有所遗漏。

SNMP 中的核心结构之一就是代理,它负责代理针对某一个设备的 SNMP 请求。SNMP 相对简单且较低级,所以 SNMP 代理可以简单且快捷地嵌套到多种硬件设备和软件服务中。因此 SNMP 就是一个在应用程序生态系统中监控大量服务的标准化协议。另外,SNMP 被广泛用于通过扫描一系列的 IP 地址和端口来执行发现。从监控的角度看,SNMP 的这个应用可以节省一些管理时间,因为它能够自动填充和更新一个监控目标的集中式清单。SNMP 在很多方面都与 JMX 极其相似。虽然两者之间还是有一些明显的差别,但还是可以在两者间找出一些相同的内容,而且 JMX 和 SNMP 间的互操作性被广泛地支持与实现。表 1 总结了一些两者之间的等价内容:

表 1. SNMP 和 JMX 对比 SNMP 结构 等效 JMX 结构

代理

代理或者

管理程序

客户机、n、协议适配器

MIB

MBean、、

OID

和+名

陷阱

GET、SET

单从监控角度考虑,发布一个 SNMP 查询时,我需要了解的重要因素有:

除了社区以外,有些代理还可以定义其他层面的验证。

在我深入论述 SNMP API 之前,要注意 SNMP 指标可以使用两个普通的命令行实用程序来检索,它们是:,它检索一个 OID 的值;,它检索 OID 值的子集。记住了这点,我就能够经常扩展我的 来跟踪 SNMP OID 值了。清单 19 示范了一个的例子,它带有在 Linux 主机上检索 1、5 和 15 分钟载入的原始的输出。我使用的是该协议的 2c 版本和公共社区。

清单 19.示例

$> snmpwalk -v 2c -c public 127.0.0.1 .1.3.6.1.4.1.2021.10.1.3
UCD-SNMP-MIB::laLoad.1 = STRING: 0.22
UCD-SNMP-MIB::laLoad.2 = STRING: 0.27
UCD-SNMP-MIB::laLoad.3 = STRING: 0.26$> snmpwalk -v 2c -c public 127.0.0.1 .1.3.6.1.4.1.2021.10.1.3 \| awk '{ split($1, name, "::"); print name[2] " " $4}'
laLoad.1 0.32
laLoad.2 0.23
laLoad.3 0.22

第二条命令可以轻松地在我的 Linux 命令集中表现出来,如清单 20 所示:

清单 20. 处理命令的

\n

商用的、开源 SNMP Java API 有好多个。我实现了一个基本的 收集器,它的名称为org....snmp.,该收集器的实现使用到了一个名为 的开源 API(参见参考资料)。该收集器拥有如下的重要配置属性:

:SNMP 协议,0表示 v1,1表示 v2(默认为 v1)。 :SNMP 社区(默认为)。 :尝试操作的次数(默认为1)。 :以 ms 为单位的 SNMP 调用的超时时间(默认为5000)。

清单 21 展示了设置的示例配置,该配置的目的是监控本地 JBoss 应用服务器:

清单 21.的配置




该收集器的确是有些缺点,毕竟配置有些长,而且由于它要为每一个 OID 做出一个调用而非批量收集,导致运行时效率低下。示例代码中的 snmp-.xml 文件(参见下载)也包含了一个监控 Linux 服务器的 SNMP 收集器的配置示例。图 21 显示了 APM 系统指标树:

图 21.的 APM 树

此时,您可能了解到如何创建收集器了。要覆盖整个环境,可能需要集中不同类型的收集器,如果您对此感兴趣的话,您可以参见本文的示例代码,那里包含有其他监控目标的收集器示例。它们都位于org...包中。表 2 是这些收集器的一个概述:

表 2. 其他收集器示例 收集目标 类

Web 服务:检查安全 Web 服务的响应时间和可用性

.

Web 服务和 URL 检查

.

Web 、性能和可用性

.ctor

Ping

.

NTop:一个收集详细网络统计信息的实用程序

.ctor

回页首

数据管理

收集繁忙的可用性和性能数据的系统所面临的一个最复杂的难题就是:如何有效地将收集到的数据持久化到普通指标数据库中。对于要使用的数据库和持久化机制要考虑的问题有:

鉴于这些考虑,您需要:

显然,要以一种最佳的方式来解决上述的每一个问题是很难的,所以必须要考虑折衷的办法。图 22 展示了一个数据收集器在概念上的数据持久化流程:

图 22. 数据管理流程

图 22 表示概念数据收集器(像本文中呈现的 收集器)的数据流。目的是通过一些层推动单个指标跟踪度量,直到它们被持久化。具体的过程为:

数据收集器是随意配置的,为了实现带有如下属性的指标持久化: 收集器缓存就是很多的离散指标读数,该读数与收集器生成的各种指标的数量相等。缓存遵循先入先出(first in, first out,FIFO)原则,所以当历史缓存变满时,最老的指标会被清除,为最新的指标腾出空间。缓存支持注册缓存事件监听器,它们可以被告知有哪些指标被从缓存中移除,又有哪些被存入。 收集器总计是一系列由收集器生成的指标实例的两个或更多循环缓存。由于循环缓冲器中的每一个缓存实例变为活动状态,它就会为历史缓存注册新的跟踪事件并聚合每一个输入的新值,有效地合并给定时间段内的数据流。该总计包含: 中央计时器会在每个时间段末尾触发一个刷新事件。当计时器触发后,收集器总计循环缓冲器索引是递增的,而历史缓存事件被传递给缓冲器中的下一个缓存。然后 “关闭的” 缓冲器中的每一个聚合的总计都会有一个公用的时间戳应用于该总计,并被写入待存入数据库的持久化队列。

注意当循环缓冲器递增时,下一个缓冲元素的最小的、最大的和平均值将会是零,除了指标类型。

持久化线程池中的一池线程从持久化队列中读取总计项并将它们写入数据库。

相同收集器总计被合并的总计时间段的长度要取决于中央刷新计时器的频率。该时间段越长,写入数据库的数据就越少,代价是数据粒度将会丢失。

标准化数据库结构与扁平数据库结构

:集全部监视功能为一体的工具

(Round Robin Tool)是一个强大的工具,它在一个单独的可执行文件中提供了大量功能(参见参考资料)。 不会为您收集任何实际数据,但是它通常被与、和其他命令行工具结合使用来创建一种综合监控解决方案。 使您能够创建循环(round-robin)的时间序列数据库文件(循环特性使文件大小保持不变,避免文件不受控制地增长),以及针对多个聚合调度的一些选项。然后,它可以从文件查询并导出数据,生成丰富的图表以实现数据可视化和动态报告。添加一个简单的 Web 服务器来持续刷新包含图表和交叉表格数据的页面,从而得到一个功能强大的监控解决方案。

一些专用数据库(比如)可以用于指标存储,但是通常使用的是关系数据库。在关系数据库中执行指标存储时,需要考虑两个一般选项:标准化数据或保持一种更加扁平的结构。这主要关系到如何存储复合指标名称;根据数据建模最佳实践,应该对所有其他引用数据进行标准化。

完全标准化的数据库结构的好处在于,通过将指标复合名称分解为独立的片段,实际上任何数据库都可以利用索引功能来加速查询。它们存储的冗余数据更少,从而使数据库更小,数据密度更高,性能也更好。其缺点在于复杂性和查询的大小:即使相对简单的复合指标名称或指标名称的模式(例如主机 11 到 93 之间的 % User CPU)都要求 SQL 包含一些连接和大量谓词。这个缺点可以通过使用数据库视图和硬存储常用指标名解码来减轻。每个单独指标的存储需要分解复合名称来定位指标引用数据项(或创建一个新的引用数据项),但是这种性能开销可以通过在持久过程中缓存所有引用数据来减轻。

图 23 展示一种用于在标准化结构中存储复合指标的模型:

图 23. 一种用于指标存储的标准化模型

在图 23 中,为每个惟一的复合指标分配了一个惟一的,为每个惟一的片段分配了一个。然后在一个包含、和片段出现顺序的关联实体中构建复合名称。指标类型存储在引用表中,而指标值本身存储在中(包含值、时间戳的开始和结束属性,以及对指标类型和惟一的引用)。

另一方面,扁平模型结构非常简单,如图 24 所示:

图 24. 用于指标存储的扁平模型

在本例中,我将指标名称从复合名称中分离开来,剩余的片段仍然保持其在列中的原有模式。同样,如果实现的数据库引擎能够使用基于模式的谓词(比如正则表达式)执行适合较宽的文本列的查询,那么这种模型非常易于查询。这种优点应当重视。使用简化的查询结构,能够显著地简化数据分析、可视化和报告工具,而且在紧急的分类会话期间,加快查询的编写速度可能是最重要的方面!

如果需要持久化数据存储,挑选正确的数据库是非常关键的一步。使用关系数据库是一种可行的方法,因为关系数据库能够很好地执行,并且可以从中提取数据并针对您的需要进行格式化。时间序列驱动的数据的生成比较复杂,但是通过正确地分组和聚合 —— 以及使用其他工具,比如 (参见参考资料)—— 可以生成出色的典型报告和图表。如果想要实现一种更加专门化的数据库(比如 ),那么请做好心理准备,因为这种数据库的提取和报告需要很长时间。如果数据库不支持 ODBC、JDBC 等标准,那么将不能使用常用的标准化报告工具。

对数据管理的讨论到此为止。本文最后一节将提供一些用于实时可视化数据的技术。

可视化和报告

在某些情况下,将实现插装和性能数据收集器,数据将会流入您的 APM 系统中。那么下一个逻辑步骤就是实时地查看数据的可视化表示。我在这里宽泛地使用实时这个词,其含义是可视化地表示最近收集的数据。

常用的数据可视化术语是指示板。指示板能够可视化地呈现您所考虑的数据模式或活动的所有方面,它们惟一的限制就是数据的质量和数量。本质上,指示板告诉您生态系统中正在发生什么。指示板在 APM 系统中的一个强大之处是,它能够通过一种统一的显示形式表示各种各样的数据(即从不同来源收集的数据)。例如,一种显示形式可以在指示板上同时显示数据库中 CPU 的最近使用情况和当前趋势、应用服务器之间的网络活动,以及当前登录到您的应用程序的用户数量。在本节中,我将提供一些不同的数据可视化样式,以及我在本文前面提供的 收集器的一个可视化层实现示例。

收集器可视化层的前提条件包括:

图 25 列出了这一过程:

图 25. 缓存和呈现

本例中的缓存实现是org....cache.。可以将其他对象注册为缓存事件监听器,这样,在其他事件中,呈现器可以监听表示新值被添加到缓存的新缓存项事件。通过这种方式,呈现器能够实际地缓存它们生成的内容,并在新数据可用时使缓存无效。来自呈现器的内容通过一个称为org....的 传递到客户机指示板。该 解析它接收到的请求,定位呈现器,并请求内容(所有内容都以一个字节数组的形式呈现和传递)和内容的 MIME 类型。字节数组和 MIME 类型然后流动到客户机,以供客户机解释。处理来自基于 URL 的服务的图形内容是最理想的,因为它们可以被 Web 浏览器、富客户机及它们之间的所有内容使用。当呈现器从媒体服务器接收到一个内容请求时,内容将从缓存传递,除非该缓存被一个缓存事件标记为 dirty。通过这种方式,呈现器不需要对每个请求重新生成它们的内容。

以字节数组格式生成、缓存和传递可视化的媒体非常有用,因为这种格式占用的空间最小,并且大多数客户机都可以在提供了 MIME 类型的情况下重新建立内容。由于这种实现在内存中缓存生成的内容,所以我使用了一种压缩方案。总体内存消耗随着缓存内容的增多而显著增加;同样,如果内容附带提供了压缩算法标记,那么大多数客户机都能够解压缩。例如,时下流行的大多数浏览器都支持gzip解压缩。然而,合理的压缩级别不一定要非常高(对于较大的图像来说,30-40% 的压缩率就不错了),因此,呈现实现可以缓存到磁盘,或者如果磁盘访问开销更高,动态地重新生成内容可能会需要更少的资源。

在这里,使用一个具体示例将有助于理解。我设置了两个 Web 收集器来监控大量繁忙的 线程。每个收集器都分配有一个缓存,而且我设置了少量的呈现器,用以提供图表来显示每个服务器上繁忙的 线程。在本例中,呈现器生成一个 PNG 文件来显示两个服务器的时间序列线图及其序列。一个服务器的收集器和缓存设置如清单 22 所示:

清单 22. 一个 Web 收集器和缓存




注意收集器中的属性,以及它如何引用称为-AP02-Cache的缓存对象。

我还设置了一个呈现器,它是org....的一个实例。这个呈现器将所有呈现任务委派给文件系统的一个底层 脚本。这是最理想的方法,因为我能够在运行时对其进行调整,从而调整生成的图的细节。这个呈现器的一般属性包括:

缓存设置如清单 23 所示:

清单 23. 用于 Web 繁忙 线程监控的图形呈现器

xSize=700ySize=300title=Apache Servers Busy WorkersxAxisName=TimeyAxisName=# of Workers Busy

呈现器非常容易实现,但是我发现,我经常需要对它们进行调整,因此这里列出的 方法非常适用于对新的图表类型或者新的图形包进行快速原型化。编译 代码时,性能非常好,实现出色的内容缓存也不是问题。动态热更新功能和功能强大的 语法使动态更新变得非常轻松。随后,当我确定了呈现器要做的工作以及它应该支持哪些选项时,我将它们移植到 Java 代码。

指标名称由org...Trace类生成。这个类的每个实例表示一个读操作,所以它封装了跟踪的值、时间戳和完整的名称空间。指标的名称就是完整的名称空间。在本例中,我所显示的指标是//-AP01/Busy ,因此,在清单 23 的呈现器中定义的过滤器使用该指标来呈现。生成的 JPG 如图 26 所示:

图 26. 呈现的 繁忙 线程

不同的客户机可能需要不同的呈现图。例如,一个客户机可能需要一个更小的图像。能够动态调整大小的图像通常比较合适。另一个客户机可能也需要一个更小的图像,但不想要标题(在其自己的 UI 中提供标题)。允许在内容请求期间实现其他选项。这些选项被附加到内容请求的 URL 之后,并以 REST 格式进行处理。基本格式是媒体 路径(可以进行配置)后接缓存名称,或/media/-All--Line。每个呈现器能够支持不同的选项。对于我们上面使用的呈现器,以下选项就是一个很好的示例:

图 27 展示了两个没有标题的缩小的饼图,使用了 URI -AP02--Pie/150/150/ /:

图 27. 缩小的 线程池图像

呈现器可以生成请求内容的客户机能够显示的几乎任何格式的内容。图像格式可以是 JPG、PNG 或 GIF。也支持其他图像格式,但是对于定位于 Web 浏览器客户机的静态图像,PNG 和 GIF 可能最适合。其他格式选择包括基于文本的标记,比如 HTML。浏览器和富客户机都能够呈现 HTML 片段,HTML 是显示独立数据字段和交叉表格的理想选择。纯文本也非常有用。例如,一个 Web 浏览器客户机可以从呈现器检索表示系统生成的事件消息的文本,并将其插入到文本框和列表框中。其他类型的标记也非常实用。许多呈现适用于浏览器的数据包的富客户机和客户端读入定义图形的 XML 文档,然后这些图形可以在客户端生成,这样可以优化性能。

客户端呈现能够提供额外的优化。如果客户机能够呈现自己的可视化,那么它就可以将缓存更新直接传递到客户机,绕过呈现器,除非需要使用呈现器来添加标记。通过这种方式,客户机可以订阅缓存更新事件,并接受这些事件,更新其自己的可视化。可以通过多种方式将数据传递到客户机。在浏览器客户机中,一种简单的 Ajax 风格的轮询程序能够周期性地检查服务器的更新,并实现一个能够将任何更新插入到数据结构中的处理程序来处理浏览器中的呈现。其他选项稍微复杂,涉及到使用 Comet 模式的实际数据流,要求一个到服务器的连接始终保持打开,而且当服务器写入数据时,这些数据就会被客户机读取(参见参考资料)。对于富客户机,使用一个消息传递系统是最理想的方法,客户机可以在其中订阅数据更新提要。 既能够与 Jetty Web 服务器结合使用,又具有其 Comet 功能,因此可以创建一个基于浏览器的 JMS 客户机并订阅队列和主题。

客户端上丰富的呈现选择还提供了扁平图像不具有的功能,比如单击元素以向下钻取的功能 — APM 指示板的一种常见需求,向下钻取用于导航或更详细地查看图表中的特定项。一个示例就是 ,它是一种开源绘图工具,与 (参见参考资料)结合使用。清单 24 展示一个 XML 片段,该片段生成一个显示各个数据库服务器的 CPU 使用情况的条形图:

清单 24. 数据库平均 CPU 使用情况的图形呈现器


这段 XML 非常普通,所以很容易为其创建一个呈现器,并且外观非常不错。客户端呈现器也可以为可视化添加动画效果,这对 APM 系统显示没什么价值,但是在一些情况下可能非常有帮助。图 28 展示了在启用了 客户机的浏览器中生成的图形:

图 28. 一个 呈现的图表

APM 指示板中包含所有标准图标类型。最常见的是折线图、多线图、条形图和饼图。一些图表通常是组合而成的,比如将条形图和折线图组合以显示两种不同类型数据的重叠情况。在另外一些情形中,一个折线图具有两条y轴,以便在同一个图表中表示数量差距较大的数据序列。绘制一个百分比值和一个标量值时通常属于这种情况,比如路由器上的 % CPU 利用率与传递的字节数。

在一些场景下,可以创建专门的小部件来以一种自定义方式表示数据,或者以一种直观的方式显示数据。例如,枚举的符号显示一个与监控目标状态一致的特定图标。因为状态通常由有限的值表示,使用图形表示有些大材小用了,所以可以采用一些类似交通灯的显示方式来表示,比如红色表示下降、黄色表示警告、绿色表示良好。另一个流行的小部件是刻度盘(通常表示为一种速度计)。我认为使用刻度盘浪费了屏幕空间,因为它们仅显示一个数据矢量,不包含历史记录。折线图既能显示相同的数据,还能够显示历史趋势。一个例外是,多指针的刻度盘能够显示高/低/当前状态等范围。但是在很大程度上,它们只能提供一种视觉上的吸引力,比如图 29 中的刻度盘,通过 “high/low/” 显示了在过去一小时内每秒获得的数据库块缓冲区情况:

图 29. 示例刻度盘小部件

依我看来,可视化的好处在于信息密度高。屏幕空间是有限的,但我想要查看尽可能多的数据。可以通过多种方式来提高数据密度,但自定义图形表示是一种有趣的方式,它将多种维度的数据组合到一个小的图片之中。图 30 展示了一种不错的示例,该示例来自一个已经退役的数据库监控产品:

图 30. 缓存命中率显示

图 30 显示了与数据库缓冲命中率相关的一些数据矢量:

提高数据密度的第二种方法是 ,这是一种要求更低的方法。这个词是由数据可视化专家(参见参考资料)根据 “嵌入到文字、数字和图像中的小型、高分辨率图形” 得出的。它通常用于显示大量的财务统计信息。尽管缺乏上下文,但它们的用途是显示跨许多指标的相对趋势。 呈现器由org....类实现,它为 Java 库实现开源的 (参见参考资料)。图 31 中演示了两个 ,展示了基于条和线的显示效果:

图 31. 显示 2 繁忙 线程的

此处和附加的代码中列出的示例都非常简单,但一个 APM 系统显然需要更高级和详细的指示板。而且,大多数用户都不希望从头创建指示板。APM 系统通常拥有某种指示板生成器,允许用户查看或搜索可用指标的存储库,并挑选要嵌入到指示板中的指标以及应该显示的格式。图 32 显示了我使用 APM 系统创建的指示板的一部分:

图 32. 指示板示例

结束语

现在,本系列已经全部结束了。我提供了一些指导、一些常见的性能监控技术,以及您能够实现的特定开发模式,可以使用这些模式增强或构建您自己的监控系统。收集和分析好的数据可以显著提高应用程序的正常运行时间和性能。我鼓励开发人员参与到监控生产应用程序的过程中来:要确定您编写的软件在负荷状态下运行时实际发生了什么,这是最好的信息来源。作为改进的一部分,这种反馈的价值不可估量。希望您的监控过程充满乐趣!

致谢

非常感谢 在 Web 服务收集器方面提供的帮助。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了