使用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

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

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

    jstack调试 使用jstack调试实时Java生产服务器的指南 jstack就像U2一样-从时间的黎明就一直在我们身边,我们似乎无法摆脱它 . 除了笑话,到目前为止,jstack是您的工具库中用于 ...

  2. LoRa节点如何以ABP方式入网TTN服务器?

    目录 前言 一.通用频段快速配置连接步骤(以EU868频段为例) AT配置指令示例如下: 二.运行AT指令后,显示界面示例 结语 前言 当你将LoRaWAN网关和LoRa节点都添加到TTN上,这时候, ...

  3. .net Redis缓存优化提高加载速度和服务器性能(一)

    距离上次服务器将图片转义至oss服务器提交加载速度已经有一段时日了 对于图片转移至oss服务器优化前后的结果可以查看我之前编写的文章点击查看 如今随着商户数的增多,数据的增多,服务器的性能再一次达到了 ...

  4. 服务器响应速度是上行速度吗,服务器带宽与速度之间的关系

    服务器的带宽,决定了服务器的上传的和下载速度,带宽越大,上传下载速度就越快,对服务器的访问速度也就越快.那么,带宽和速度之间的关系具体怎么来计算呢? 我们以10M带宽为例,10M带宽不是指上传下载速度 ...

  5. LoRa节点如何以OTAA方式入网TTN服务器?

    目录 前言 一.通用频段快速配置连接步骤(以EU868频段为例) 1.获取节点的三参数dev_eui.app_eui.app_key 2.在TTN服务器上添加LoRa节点 3.在TTN上,对LoRa节 ...

  6. 网站虚拟服务器1核1g速度,云服务器1核1g速度怎么样

    云服务器1核1g速度怎么样 内容精选 换一换 查看方法分为以下两种:安装Agent监控云硬盘使用情况手动查看云硬盘使用情况不同操作系统查看云硬盘空间的方法不同,本文分别以Windows 2008.Wi ...

  7. 10步教你来优化WordPress速度 为服务器和访客减压

    1.Cookie的静态化制作 约有80%至90%的时间,访客要花费大量的时间等你的WordPress加载静态内容.这意味着,有大部分的时间,用户浏览您的网站,他们正在等待加载,如:图像,CSS,JS脚 ...

  8. 网站虚拟服务器1核1g速度,云服务器1核1g打开速度

    云服务器1核1g打开速度 内容精选 换一换 简要介绍Snappy是一个C++的用来压缩和解压缩的开发包.其目标不是最大限度压缩或者兼容其他压缩格式,而是旨在提供高速压缩速度和合理的压缩率.Snappy ...

  9. .net Redis缓存优化提高加载速度和服务器性能(二)

    上文详细测试了每次都读取数据库的接口和通过缓存读取接口的性能对比 这里我们就准备实际简介肿么将原来的数据库加上Redis缓存优化部分接口 1.下载Redis和Redis视图管理工具 点击下载 提取码: ...

最新文章

  1. 计算机、数学、运筹学等领域32个重要算法
  2. 因你不同,2021 阿里云开发者大会重磅开启 @ 所有开发者!
  3. 【python数字信号处理】——Z变换
  4. 复仇!3:1 KO叙利亚!.NET程序员用算法推演出国足进世界杯概率...
  5. 智能机器人正催生新的工业革命
  6. django 多并发,多线程。
  7. MATLAB中移动平均滤波器smooth函数的用法
  8. 使用python读取kafka实时topic数据demo,包括安装kafka module
  9. [转载] Python集合set
  10. 小米笔记本PRO(双系统)黑果体验
  11. 敏捷软件开发与极限编程
  12. Spring教程动画文字版
  13. 怎么把PDF转换成图片?推荐6个终极解决方法!
  14. 一个 Duang~ 的CSS3动画
  15. 电脑风扇转,屏幕、键盘和鼠标都不亮
  16. 【第3章】局域网概述
  17. 手把手教你怎么批量压缩视频文件
  18. echarts自定义X轴、Y轴间距
  19. c语言九三字符串的字母个数,C语言判断闰年和平年
  20. 3D软件视频制作:unity timeline cinemachine, blender 视频制作编辑器

热门文章

  1. 三条中线分的六个三角形_八年级数学上册:三角形已知两条边如何求第三边
  2. 18000 6c java_面向ISO18000-6C协议的无源超高频射频识别标签芯片设计
  3. java编译器API——使用编译工具
  4. wcf:rest_REST:管理多对多关系
  5. aws生态系统集成商_通过通用数据访问扩展AWS生态系统
  6. apache.camel_Apache Camel 2.18发布–包含内容
  7. 开源java性能分析工具_Java性能监控:您应该知道的5个开源工具
  8. 工业互联网二级节点建设_建设者还是二传手?
  9. 上下文异常中的上下文属性_在没有适当上下文的情况下引发异常是一种不良习惯...
  10. javafx 内存占用_JavaFX:TouchGesture内存泄漏?