寻找随机的错误-一个真实的故事

几周前,我完成了RapidFTR开源项目的错误查找 ,这花了我三个晚上。 我认为可能值得分享狩猎的故事。

本文将介绍我的工作。 我将概述我的旅程,以实际找到正在发生的事情的根本原因。 我在本文中的目标是突出显示可以使用的技术示例,以实际跟踪奇怪的和随机的错误。

最后,我找到了一个非常清楚的解释,说明问题发生的原因和原因。 本文标题中存在“随机性”并非巧合。

开始–问题出在哪

问题是,在遵循使用开发虚拟机指南时,有时启动应用程序会花费很长时间,然后失败。 两次启动应用程序后,我马上遇到了问题。 其他人也有同样的问题。

有人告诉我,没有人真正知道它为什么会以这种方式运行-但是重新启动VM可能会解决它。 它不适合我。

但是我喜欢深入研究问题-所以我想知道出了什么问题。

将档案耙到Solr

运行rake app:run 有时会发生错误。 通过使用--trace --verbose (调试选项)运行rake,我可以看到该应用程序正在等待黑子启动Apache Solr搜索服务。

所以问题是,该过程始终花在哪里? 开始的好处是,rake和sunspot用Ruby编写。 因此,我阅读了代码,并添加了一些输出语句,以查看哪个语句花费了很长时间。 原来,这是Java进程启动了Solr。

挖掘Java

Apache Solr将一些输出发送到sdtout-但黑子将其隐藏在您的面前。 但是由于调试时任何输出都非常有用,因此我想查看输出。

我使用ps -aux查找了ps -aux发出的确切命令行参数,并从命令行手动启动了该过程。 幸运的是,它仍然花费了一些时间-所以我知道问题不在Ruby代码中。

通过端口映射程序nmap,我发现启动该服务需要2秒钟到2分钟以上的时间。 但是耙任务只等待了10秒钟。

现在,有了控制台输出,我可以看到,Solr在内部使用Jetty在版本6.1.3中Jetty ,这花了很多时间– 在这种情况下,它花了时间。 因此,我从源代码管理中下载了6.1.3版的代码,并查看了代码。

我发现了一个名为DEBUG的系统属性,它会增加输出。 我启用了它,并看到最后的调试输出(花了很长时间)与启动会话服务有关(不幸的是,我丢失了指向代码的指针)。

这并没有真正帮助我。 我尝试使Jetty日志与log4j一起工作以最终看到更多内容,但未成功-但我失败了,不得不放弃当晚(第二个)。

调试Java代码

因此,如果您没有从日志中获取任何信息,则仍然可以使用调试器。 但是,代码在VM(Ubuntu盒)上失败了,但在我的本地计算机上却失败了。 但是幸运的是Java有一个远程调试器

我使用远程调试参数启动Java进程,并使用SVN中的Jetty代码在IntelliJ中附加了一个侦听器。 我试图使执行在最后一个日志输出附近的断点处停止–但是此方法经常被调用,而我没有在正确的时机到达断点。

但是,当事情花费很长时间时,仅停止正在运行的进程并查看堆栈跟踪可能会有所帮助。 因此,我停止了执行,并从Jetty中搜索了最后一个方法框架,该框架正在调用JDK –在这里,我发现了以下注释:

//This operation may block on some systems with low entropy. See this page
//for workaround suggestions:
//http://docs.codehaus.org/display/JETTY/Connectors+slow+to+startup
Log.debug('Init SecureRandom.');
_random=new SecureRandom();


解决方案

最后–我确实转到了引用的Jetty Wiki页面 。 我发现,Java的java.util.SecureRandom使用来自操作系统的真实熵-当没有可用的熵时,它将阻塞。

仅使用普通的java.util.Random的方法,来自Wiki页面的解决方案将很困难,因为配置文件位于sunspot和Solr内部。 但是行“ NB一些解决方法报告使用/dev/./urandom而不是/ dev / urandom”给了我一个提示,那就是另找。

我用Google搜索解决方案,并在Stack Overflow上发现,可以在Java进程/dev/./urandom /dev/urandom随机替换为/dev/./urandom 。 这可以通过使用命令行参数-Djava.security.egd=file:/dev/./urandom或通过将其替换为文件/usr/lib/jvm/java-6-openjdk/jre/lib/security/java.security (在Ubuntu机器上)。

那怎么了? Java的安全随机数将不接受/dev/urandom作为随机数的源/dev/urandom是无阻塞的,这意味着它将在没有可用的实际熵的情况下返回可以猜测的随机数。 因此,Java默认为/dev/random ,它将阻塞并等待,直到出现熵为止。

这就是为什么在生产或开发机器上极不可能发生阻塞的原因-但是在使用虚拟机时,它确实发生了,因为虚拟机的网络流量和IO并不多。 当您经常重启应用程序时(尤其是在某些情况下无法正常工作时),这种情况通常会发生。

解决方法有点有趣。 Java根据字符串拒绝/dev/urandom 。 它不会拒绝/dev/./urandom ,它当然指向同一个可能不安全的随机数生成器。

最后的话

该修补程序会带来潜在的安全风险–但是在开发虚拟机上,这不是问题。

如您所见,在系统中查找错误或问题涉及使用技术,这些技术使您更接近根本原因。 但是,没有黄金路。 有时,一种技术将无法为您提供更多信息。 因此,您将不得不尝试另一种技术。 有时,您的直觉也会对您有所帮助。

到达这里后,您对这个故事有何看法?

参考:Johannes Thones博客博客上,我们的JCG合作伙伴 Johannes Thones 狩猎随机的错误-一个真实的故事


翻译自: https://www.javacodegeeks.com/2012/10/hunting-random-bug-true-story.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值