I’m back: 最近的几个case

最近工作实在是忙的不行,一直没抽出时间来写写,实在是对不起各位订阅的,不过估计有些订阅了都忘记了订阅过这个账号吧,:)

简单说下最近的几个小case吧。
1. 关于cms gc remark时间长的case
有一个应用出现了cms gc remark通常要消耗4–5s的现象,由于remark是stw(stop-the-world)的,因此造成了应用暂停时间过长的现象。

cms gc由以下几个主要步骤构成:
* initial-mark: 这步是stw的;
* concurrent-mark: 这步是和应用并发同时做的;
* preclean: 和应用并发,忘记是1.5哪个版本后增加的一个优化;
* remark: 这步是stw的;
* concurrent-sweep: 这步是和应用并发做的;
可见,对于CMS GC而言,在暂停时间这点上最重要的关注点是initial-mark和remark两个阶段(在一些jdk版本上,jstat看到一次cms gc会被统计成两次fgc,原因就是它其实是按stw次数来统计的,这个小bug由当时还在淘宝的撒迦同学fix了)。

remark如果耗时较长,通常原因是在cms gc已经结束了concurrent-mark步骤后,旧生代的引用关系仍然发生了很多的变化,旧生代的引用关系发生变化的原因主要是:
* 在这个间隔时间段内,新生代晋升到旧生代的对象比较多;
* 在这个间隔时间段内,新生代没怎么发生ygc,但创建出来的对象又比较多,这种通常就只能是新生代比较大的原因;

这个应用当时的启动参数的-Xmn为16g,但每次ygc后存活的其实不多,因此基本可以确定是由于新生代太大导致的,于是建议应用方将-Xmn降到了4g,remark时间很快就缩短到了几百ms,基本符合预期。

2. 一个catch引发的重大故障
一个应用依赖了后端的一个应用,突然在某天后端这个应用的rt突然出现了抖动,超时比较多,产生了很多拒绝请求的异常,但前面这个应用并没捕捉相应的异常,导致的结果就是系统处理请求直接失败。

这个故障看起来貌似没什么问题,但其实依赖的这个应用不是关键逻辑(就例如淘宝上的运费,下单的时候如果获取不到运费信息是可以用默认的运费价格的,尽管这样也有问题,但不至于下不了单,毕竟价格还可以由卖家来修改等), 因此本应该在处理失败的情况下仍然继续做其他的处理动作。

这种方式是追求高可用系统常用的招数,只要不是关键路径上的处理逻辑,在即使失败的情况下都应该可以做自动的降级等来避免引发更大的故障。

3. linux 2.6.32内核高精度定时器带来的cpu sy暴涨的“问题”
linux在2.6.32内核以后支持了高精度的调度,在.32以前的内核里,即使你在java里写queue.await(1ns)之类的代码,其实都是需要1ms左右才会执行的,但.32以后则可以支持ns级的调度,对于实时性要求非常非常高的性能而言,这本来是个好特性。

但不幸的是很多人在写代码的时候其实压根就没有要ns级调度的需求,纯粹只是随便写了一个类似10ns唤醒的策略,这个在内核升级到.32后就悲催了,直接就会看到cpu sy猛增,很容易以为是内核的bug,话说其实这可以认为是程序本身的bug。

在linux上可通过cat /proc/timer_list | grep .resolution来查看调度器的精度。

可通过修改/boot/grub/grub.conf,在相应的kernel行的最后增加highres=off nohz=off来关闭高精度(不建议这样做,最好还是程序本身做相应的修改)。

4. jstack core.*失败的bug
在6u29之后的几个版本,如果想从core dump里通过jstack去提取java thread stack信息,可能会碰到如下的错误:
Caused by: sun.jvm.hotspot.debugger.UnmappedAddressException
这个有可能是jvm本身的bug造成的,具体可见:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7133122
这个bug影响还是有些的,会导致在一些莫名的crash的情况下不知道该怎么去排查问题。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

《I’m back: 最近的几个case》有1个想法

  1. 感谢分享。对于case 1,是否可以试试用–XX:+CMSScavengeBeforeRemark ?还是说old gen等不及再来一次young gc的时间?

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*