增压的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,一经查实,立即删除!

相关文章

(网页)css和js的版本号问题

HTML页面自动清理js、css文件的缓存,之前用的是?v11每次都要找寻到网页进行更改,非常的麻烦. <script type"text/javascript"> document.write("<script typetext/javascript srcjs/xxxx?v" new Date().getTime() ">"); </s…

wchar_t 的输出问题

wchar_t 定义的变量之所以不能输出呢&#xff1f;我查了一下资料&#xff0c;就是说宽字符类型要本地化&#xff0c;否则输不出想要结果。本地化有三条语句可以使用&#xff0c;任取其一。最后一句是全局函数&#xff0c;前两个是wcout的一个成员函数的两种表达方式。std::wcou…

Apache Cassandra和Java入门(第二部分)

要求 要遵循本教程&#xff0c;您应该已经有一个正在运行的Cassandra实例&#xff08; 一个小型集群会很好 &#xff0c;但不是必需的&#xff09;&#xff0c;已安装Datastax Java驱动程序&#xff08; 请参阅第I部分 &#xff09;&#xff0c;并且已经在这里进行了10分钟的演…

Zabbix监控多个JVM进程

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

(网页)swiper.js轮播图插件

Swiper4.x使用方法 1.首先加载插件&#xff0c;需要用到的文件有swiper.min.js和swiper.min.css文件。可下载Swiper文件或使用CDN。 <!DOCTYPE html> <html> <head>...<link rel"stylesheet" href"path/to/swiper.min.css"> <…

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…

架构设计

好的架构是进化出来的 &#xff0c;不是设计出来的&#xff1b; 不同时期和不同环境有着不同的最佳架构&#xff1b; 存在即合理&#xff0c;合适的才是最好的&#xff1b; 转载于:https://www.cnblogs.com/sky-jyq/p/11527254.html

(网页)js每隔5分钟执行一次ajax请求的实现方法(转)

转自脚本之家: 一个页面好像只能有一个 window.οnlοadfunction(){}&#xff0c;所以要有多个事件&#xff0c;这样写就好了 window.onloadfunction(){ //假设这里每个五分钟执行一次test函数 publicBusi(); personBusi(); } function publicBusi(){ setTimeout(perso…

Flash网站流量统计的方法

在我印象中&#xff0c;一般的免费流量统计代码是不允许嵌套在Flash中使用的&#xff0c;而且也不允许在内置IFrame中嵌套使用&#xff0c;网上检索了一下&#xff0c;找到了Flash网站的流量统计办法&#xff0c;其实就是使用内置IFrame的办法&#xff0c;使用的是51啦&#xf…

从浏览器端JavaScript代码进行服务器端日志记录

应用程序日志记录是我们在部署到应用程序服务器上的应用程序中都要做的事情&#xff0c;对吗&#xff1f; 对于大多数Java开发人员而言&#xff0c;使用Log4J或Logback之类的框架似乎都是理所当然的。 但是&#xff0c;我们编写的在那些讨厌的浏览器中运行的代码又如何呢&#…

Oracle连接字符串记录

<?xml version"1.0" encoding"utf-8"?> <!--有关如何配置 ASP.NET 应用程序的详细信息&#xff0c;请访问https://go.microsoft.com/fwlink/?LinkId301879--> <configuration><configSections><!-- For more information on…

(网页)JS编程中,有时需要在一个方法返回两个个或两个以上的数据

转自脚本之家: 1 使用数组的方式&#xff0c;如下&#xff1a; <html> <head><title>JS函数返回多个值</title> </head> <body><input type"button" onclick"getNames()" value"test" /><script …

(网页)AngularJS 参考手册

指令描述ng-app定义应用程序的根元素。ng-bind绑定 HTML 元素到应用程序数据ng-bind-html绑定 HTML 元素的 innerHTML 到应用程序数据&#xff0c;并移除 HTML 字符串中危险字符ng-bind-template规定要使用模板替换的文本内容ng-blur规定 blur 事件的行为ng-change规定在内容改…

Apache Cassandra和Java入门(第一部分)

在此页面上&#xff0c;您将学到足够的知识来开始使用NoSQL Apache Cassandra和Java&#xff0c;包括如何安装&#xff0c;尝试一些基本命令以及下一步做什么。 要求 要遵循本教程&#xff0c;您应该已经有一个正在运行的Cassandra实例&#xff0c;并且已经在这里进行了10分钟…

vagrant网站中box下载方法

假设需要下载Laravel/homestead这个包。 首先定位到地址&#xff1a;https://app.vagrantup.com/laravel/boxes/homestead/versions/8.0.0 然后直接在后面加上 “providers/virtualbox.box”就可以下载了 (注意virtualbox.box是指供应商的名字&#xff0c;不同供应商提供不同名…

响应式Web设计——最佳指南

2012年被称为智能手机年。根据最近一份调查显示&#xff0c;美国的智能手机覆盖率已达50%。现在确实是提升移动终端用户体验的大好时机。如果你正运营一个网站&#xff0c;那就必须有一个响应式的Web设计&#xff0c;以便可以从移动终端上很好地访问你的网站。如果你还没意识到…

Eclipse扩展的轻量级集成测试

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

原生js实现简单的焦点图效果

用到一些封装好的运动函数&#xff0c;主要是定时器 效果为图片和图片的描述定时自动更换 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><style type"text/css">ul,li,p,h3 {padding: 0;…

二:熟悉 TCP/IP 协议

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