增压的jstack:如何以100mph的速度调试服务器

霹雳舞

使用jstack调试实时Java生产服务器的指南

jstack就像U2一样-从时间的黎明就一直在我们身边,我们似乎无法摆脱它 。 除了笑话,到目前为止,jstack是您调试军用生产服务器中最方便的工具之一。 即便如此,我仍然认为它在情况恶化时能够将您从火中扑灭的能力仍未得到充分利用,因此我想分享一些方法,您可以在对抗生产错误的战争中将其增压为更强大的武器。

jstack的核心是一个超级简单的工具,它向您显示在目标JVM中运行的所有Java线程的堆栈跟踪。 只需通过一个pid将其指向JVM进程即可获得该时间点所有线程堆栈跟踪的打印输出。 这使您能够回答“这个服务器在做什么?”这个古老的问题,并使您更进一步地了解它为什么真正在做它。 关于jstack的最大优点是它轻巧–它不会给JVM增加任何性能开销,也不会更改其执行状态(与调试器或探查器不同)。

由于没有什么是完美的 ,因此jstack有两个明显的缺点。 第一个是jstack除了调用堆栈外没有为您提供任何变量状态,这意味着尽管您可能正在查看堆栈,但您不知道将其置于何处的状态。 一个很好的例子是查看挂起的JVM,其中jstack会向您显示大量线程正在执行数据库查询或等待获得连接。

这可能意味着某些查询执行时间太长,导致其他线程要么等待连接,要么被拒绝。 在这里,您真的想知道正在执行的查询(或查询的参数是什么)会导致速度下降以及何时开始。 当然,这只是一个例子,在很多情况下,其中某些线程被阻塞并降低了应用程序的吞吐量。 但是不幸的是,使用jstack时,因为您没有获得任何变量状态,所以您无法真正确定应归咎于哪个线程。 还是可以吗?

jstack的第二个缺点是它不是永远在线的工具。 这意味着,当问题发生时,您必须在那里-在生产中这是罕见的事件。 在不断重启VM的弹性环境中,这一点更为真实。

好的部分到了–让我们看一下两种技术,它们可以帮助我们克服这两个缺点,并使一个好的工具真正变得很棒。

创建有状态线程数据

第一个问题是如何向jstack打印输出添加状态? 答案简单而强大-线程名称。 尽管许多人错误地认为线程名称是不可变的,或者是操作系统确定的属性,但实际上,每个线程都具有可变的且非常重要的特征。 这也是进入您的jstack流的关键所在。

实际的应用程序就像日志记录一样,一旦它通过诸如servlet,actor或Scheduler之类的入口点输入代码,就应该控制线程名。 此时,您需要将其名称设置为一个有意义的值,该值可以帮助您了解执行上下文和相关参数,从而可以帮助您隔离事务及其内容。

这很可能包括–

  1. 线程的用途(例如,处理消息,响应用户请求等)。
  2. 使用事务ID,您可以识别跨不同机器和应用程序各部分的此特定数据流。
  3. 参数值,例如servlet参数或要出队的消息的ID。
  4. 获得线程控制的时间。 对于使用jstack观察它们时,确切地知道代码中的哪些线程被卡住,最后一项至关重要。
Thread.currentThread().setName(Context + TID + Params + current Time,..);

这些数据将意味着查看打印输出(例如下面的打印输出实际上并不能告诉我们任何线程在做什么或为什么)与提供信息的输出之间的区别:

“ pool-1-thread-1”#17 prio = 5 os_prio = 31 tid = 0x00007f9d620c9800 nid = 0x6d03 in Object.wait()[0x000000013ebcc000]

将此与以下线程打印输出进行比较:

“队列处理线程,MessageID:AB5CAD,类型:AnalyzeGraph,队列:ACTIVE_PROD,Transaction_ID:5678956,开始时间:2014/10/8 18:34”

#17 prio = 5 os_prio = 31 tid = 0x00007f9d620c9800 nid = 0x6d03 in Object.wait()[0x000000013ebcc000]

您在这里看到的是对该线程实际作用的更全面的解释。 您可以轻松地从AWS队列中查看其出队消息,它正在分析该消息,其类型,ID和事务ID。 最后,但并非最不重要–线程何时开始对其进行处理。 这可以帮助您非常快速地将注意力集中在那些被卡住的线程上,并查看它们所处的状态。从那以后,在本地进行优化和复制将变得更加容易。

这里的替代方案是要么希望日志文件中有数据,而且能够将日志中的数据关联到该确切线程。 另一个选择是在生产环境中本地或远程连接调试器。 既不是很愉快又很费时间。

在线程名称中写入此信息也有助于传统日志记录。 即使大多数日志记录框架都提供了可以添加到日志中的基于线程的上下文,您也必须确保正确配置它。 使用线程名称还可以确保您将在日志中拥有所需的所有数据。

注意:有些人可能会说不要修改或更改线程名称。 根据我多年的个人经验以及许多同事的经验,我对此非常信奉。

使jstack始终在线

使用jstack时,我们面临的第二个挑战是,就像调试器一样,它是您必须在发生问题时立即手动捕获损坏状态的工具。 但是,当服务器挂起或低于或低于某个特定阈值时,有一种更活跃的方法可以使用jstack自动生成打印输出。 关键是要以编程方式调用jstack,就像在满足特定应用程序条件时从JVM中的任何日志记录功能一样。
这里的两个主要挑战是何时以及如何实现。

如何以编程方式激活jstack?

由于jstack是一个普通的OS进程,因此调用它非常简单。 您要做的就是激活jstack进程并将其指向您自己。 这里的关键是如何从JVM中获取进程的pid。 实际上,没有标准的Java API可以做到这一点( 至少要等到Java 9才可以 )。 这是完成工作的一小段代码(尽管它不是已记录的api的一部分):

String mxName = ManagementFactory.getRuntimeMXBean().getName();int index = mxName.indexOf(PID_SEPERATOR);String result;if (index != -1) {result = mxName.substring(0, index);
} else {throw new IllegalStateException("Could not acquire pid using " + mxName);
}

另一个小挑战是将jstack输出定向到您的日志中。 使用输出流检流器也很容易设置。 在此处查看有关如何将您调用的进程输出的输出数据定向到日志文件或输出流中的示例。

尽管可以使用getAllStackTraces在内部捕获正在运行的线程的堆栈跟踪,但出于多种原因,我更喜欢通过运行jstack来执行此操作。 首先,这是我通常希望在正在运行的应用程序外部进行的操作(即使JVM正在参与提供信息),以确保我不会通过内省调用来影响应用程序的稳定性。 另一个原因是,jstack在功能方面更为强大,例如向您显示本机框架和锁定状态,而这在JVM中是不可用的。

什么时候激活jstack?

您需要做出的第二个决定是在什么条件下您希望JVM记录jstack。 当服务器低于或高于特定处理(即请求或消息处理)阈值时,可能会在预热期之后执行此操作。 您可能还需要确保每次激活之间都花费足够的时间。 只是为了确保您不会在低负载或高负载下泛滥日志。

您将在此处使用的模式是从JVM内加载看门狗线程,该线程可以定期查看应用程序的吞吐量状态(例如,最近两分钟内处理的消息数),并确定是否对屏幕进行“截屏”。线程状态将很有帮助,在这种情况下,它将激活jstack并将其记录到文件中。

设置该线程的名称以包含目标吞吐量和实际吞吐量状态,因此当您执行自动jstack快照时,您可以确切地看到看门狗线程决定这样做的原因。 由于这只会每隔几分钟发生一次,因此该过程没有实际的性能开销,尤其是与所提供数据的质量相比。

下面的代码片段显示了这种模式的实际效果。 startScheduleTask加载看门狗线程以定期检查吞吐量值,该吞吐量值在处理消息时使用Java 8 并发加法器递增。

public void startScheduleTask() {scheduler.scheduleAtFixedRate(new Runnable() {public void run() {checkThroughput();}}, APP_WARMUP, POLLING_CYCLE, TimeUnit.SECONDS);
}private void checkThroughput()
{int throughput = adder.intValue(); //the adder in inc’d when a message is processedif (throughput < MIN_THROUGHPUT) {Thread.currentThread().setName("Throughput jstack thread: " + throughput);System.err.println("Minimal throughput failed: exexuting jstack");executeJstack(); //see the code on github to see how this is done}adder.reset();
}
  • 在此处可以找到从代码中抢占调用jstack的完整源代码。

翻译自: https://www.javacodegeeks.com/2014/10/supercharged-jstack-how-to-debug-your-servers-at-100mph.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361405.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zabbix监控多个JVM进程

一、场景说明&#xff1a; 我们这边的环境用的是微服务&#xff0c;每个程序都是有单独的进程及单独的端口号&#xff0c;但用jps查询出来的结果有些还会有重名的情况&#xff0c;所以某些脚本不太适用本场景&#xff1b; 二、需求说明&#xff1a; 需使用Zabbix-server监控每个…

Android 4.0 Launcher源码分析系列(二)

原文&#xff1a;http://mobile.51cto.com/hot-314700.htm 上一节我们研究了Launcher的整体结构&#xff0c;这一节我们看看整个Laucher的入口点&#xff0c;同时Laucher在加载了它的布局文件Laucher.xml时都干了些什么。 我们在源代码中可以找到LauncherApplication&#xff0…

使用JFace Viewer延迟获取模型元素

Eclipse JFace Viewers显示的模型元素有时需要花费大量时间来加载。 因此&#xff0c; 工作台提供了IDeferredWorkbenchAdapter类型以在后台获取此类模型元素。 不幸的是&#xff0c;似乎仅通过DeferredTreeContentManager派生的AbstractTreeViewer支持此机制。 因此&#xff…

Eclipse扩展的轻量级集成测试

最近&#xff0c;我为Eclipse扩展点评估引入了一个小助手。 辅助程序努力减少通用编程步骤的样板代码&#xff0c;同时增加开发指导和可读性。 这篇文章是希望的后续文章&#xff0c;展示了如何将实用程序与AssertJ定制断言结合使用&#xff0c;以编写针对Eclipse扩展的轻量级…

二:熟悉 TCP/IP 协议

一篇文章带你熟悉 TCP/IP 协议&#xff08;网络协议篇二&#xff09; 同样的&#xff0c;本文篇幅也比较长&#xff0c;先来一张思维导图&#xff0c;带大家过一遍。 一图看完本文 一、 计算机网络体系结构分层 计算机网络体系结构分层计算机网络体系结构分层不难看出&…

DOM操作案例之--全选与反选

全选与反选在表单类的项目中还是很常见的&#xff0c;电商项目中的购物车一定少不了这个功能。 下面我只就用一个简单的案例做个演示吧。 <div class"wrap"><table><thead><tr><th><input type"checkbox" id"j_cbA…

带有Swagger的Spring Rest API –公开文档

创建API文档后&#xff0c;将其提供给涉众非常重要。 在理想情况下&#xff0c;此发布的文档将具有足够的灵活性以解决任何最新更改&#xff0c;并且易于分发&#xff08;就成本以及完成此操作所需的时间而言&#xff09;。 为了使这成为可能&#xff0c;我们将利用我在上一篇文…

hinkphp项目部署到Linux服务器上报错“模板不存在”如何解决

检查了服务器上的文件&#xff0c;并没有缺少文件&#xff0c;再次上传文件到服务器&#xff0c;还是报错。莫名其妙&#xff0c;怀疑是代码问题。 仔细检查后&#xff0c;发现是模板的文件名问题&#xff1a; 用过TP的都知道&#xff1a;thinkphp会在$this->display()的时候…

Elements in iteration expect to have v-bind:key directives错误的解决办法

一、错误如下[eslint-plugin-vue][vue/require-v-for-key]Elements in iteration expect to have v-bind:key directives.Renders the element or template block multiple times based on the source data. 使用VS Code 出现如下问题&#xff0c;如图 二、解决 在用vscode编写…

无法使用JDK 8卸载JavaFX SceneBuilder 1.0

我最近从旧的基于Vista的笔记本电脑中删除了一些我曾经使用过的软件开发应用程序&#xff0c;工具和文件&#xff0c;因为主要使用该笔记本电脑的人们现在对软件开发不再感兴趣。 作为该工作的一部分&#xff0c;我尝试删除了几年前在该笔记本电脑上安装的JavaFX Scene Builder…

分享一个不错的表格样式

先贴个HTML生成的源码出来&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"> <head>…

如何将SQL GROUP BY和聚合转换为Java 8

我无法抗拒。 我已经阅读了Hugo Prudente在Stack Overflow上提出的问题 。 而且我知道必须有比JDK提供的更好的方法。 问题如下&#xff1a; 我正在寻找一个lambda来优化已检索的数据。 我有一个原始的结果集&#xff0c;如果用户不更改我想要的日期&#xff0c;则使用Java的…

zabbix监控docker容器

1、环境说明 由于最近zabbix进行过一次迁移&#xff0c;所以zabbix-server系列采用docker方式安装&#xff0c;参考zabbix官网&#xff1a;https://github.com/zabbix/zabbix-docker。为适应本地环境和需求&#xff0c;docker-compose.yml文件有改动&#xff0c;具体内容如下&a…

Hibernate应用程序级可重复读取

介绍 在我以前的文章中&#xff0c;我描述了应用程序级事务如何为长时间的对话提供合适的并发控制机制。 所有实体都在Hibernate会话的上下文中加载&#xff0c;充当事务后写式缓存 。 Hibernate持久性上下文可以包含给定实体的一个引用和一个引用。 一级缓存可确保会话级可重…

canvas动画简单操作

canvas动画 小球滚动效果 关键api&#xff1a; window.requestAnimationFrame(draw) 会递归调用draw函数&#xff0c;替代setIntervalvar x 20; var speed 4; //电脑的帧率是1秒钟60Hz&#xff0c; 就相当于一秒钟可以播放60张图片&#xff0c;就相当于播放一张图片使用16.…

使用PrimeFaces开发数据导出实用程序

我的日常工作涉及大量使用数据。 我们使用关系数据库来存储所有内容&#xff0c;因为我们依赖于企业级的数据管理。 有时&#xff0c;具有将数据提取为简单格式&#xff08;例如电子表格&#xff09;的功能很有用&#xff0c;以便我们可以按需进行操作。 这篇文章概述了我使用P…

Tomcat到Wildfly:配置数据库连接

此摘录摘自《 从Tomcat到WildFly 》一书&#xff0c;您将在其中学习如何将现有的Tomcat体系结构移植到WildFly&#xff0c;包括服务器配置和在其顶部运行的应用程序。 WildFly是完全兼容的Java Enterprise Edition 7容器&#xff0c;与Tomcat相比&#xff0c;它具有更多的可用…

在jOOQ之上构建的RESTful JDBC HTTP服务器

jOOQ生态系统和社区正在持续增长。 我们个人总是很高兴看到基于jOOQ构建的其他开源项目。 今天&#xff0c;我们非常高兴为您介绍BjrnHarrtell结合REST和RDBMS的一种非常有趣的方法。 BjrnHarrtell从小就是瑞典的程序员。 他通常在Sweco Position AB上忙于编写GIS系统和集成&a…

node.js 搭建http调取 mysql数据库中的值

首先&#xff0c;我们先在数据库中创建两个表t_news,t_news_type;插入数据&#xff1a; 然后我们再写代码&#xff1a; //加载模块express var express require("express"); var fs require("fs"); //加载路径 var url require("url"); //加…

NHibernate.3.0.Cookbook第三章第9节的翻译

Using stateless sessions 使用无状态会话 当进行大量数据处理的时候,可能会放弃使用一些高级特性,而使用更接近底层的API来提高性能.在NHibernate中,这种高性能的底层API就是无状态的会话.本节介绍如何使用无状态会话来更新movie对象的价格. 准备 使用第一章的Eg.Core和第二章…