5月
12
2014
1

Swap对响应时间敏感应用的影响

最近排查的一个线上应用load高的问题,和GC以及Swap有关系。

现象是机器load突然升高,查看占用CPU的线程发现是JVM自己的线程。

jstat发现一个奇怪的现象,Eden Gen到了100%之后会持续好几秒,但Old Gen没有明显增大,说明并不是Eden Gen不够用promote到Old Gen了,感觉似乎是Young GC出了问题。

进一步查看GC Log,发现一次Young GC要1秒多,正常情况下20~30ms都应该结束了。

然而仔细去看那条log会发现CPU消耗并不高:

[Times: user=0.23 sys=0.00, real=1.31 secs]

多出来的时间如果不在CPU上,那就是耗在了I/O上了,GC的I/O不会在网络上,只能是磁盘了。

free -m看了下,果然Swap的空间快被用满了都。

在排查到最终的内存原因前,先把Swap关掉:

sudo swapoff -a

对于Web应用等对响应时间(rt)非常敏感的系统来说,关闭Swap通常都是一个好的实践。

因为一般来说宁愿应用OOM挂掉也不愿意导致rt飙高,使得应用hang在那里的。

另外建议开启这两个参数:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=path

帮助你在发生OOM时dump heap,一般这时候的heap dump质量都比较高:)

Written by Hesey Wang in: Java,Linux,技术 |
5月
06
2014
14

面向GC的Java编程

Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题。以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象,就交给GC来做吧!甚至有人说,如果在编程过程中频繁考虑内存问题,是一种退化,这些事情应该交给编译器,交给虚拟机来解决。

这话其实也没有太大问题,的确,大部分场景下关心内存、GC的问题,显得有点“杞人忧天”了,高老爷说过:

过早优化是万恶之源。

但另一方面,什么才是“过早优化”?

If we could do things right for the first time, why not?

事实上JVM的内存模型( JMM )理应是Java程序员的基础知识,处理过几次JVM线上内存问题之后就会很明显感受到,很多系统问题,都是内存问题。

对JVM内存结构感兴趣的同学可以看下 浅析Java虚拟机结构与机制 这篇文章,本文就不再赘述了,本文也并不关注具体的GC算法,相关的文章汗牛充栋,随时可查。

另外,不要指望GC优化的这些技巧,可以对应用性能有成倍的提高,特别是对I/O密集型的应用,或是实际落在YoungGC上的优化,可能效果只是帮你减少那么一点YoungGC的频率。

但我认为,优秀程序员的价值,不在于其所掌握的几招屠龙之术,而是在细节中见真著,就像前面说的,如果我们可以一次把事情做对,并且做好,在允许的范围内尽可能追求卓越,为什么不去做呢(more…)

Written by Hesey Wang in: Java,技术 |
11月
26
2013
6

一次CMS GC的调优工作

某台机器的内存比较大,之前的JVM参数是4G的堆,在压测过程中发现当QPS上来以后,Full GC会开始抬头,YoungGC的频率就不用说了,比较高。

观察GC日志和jstat -gcutil,感觉是QPS在峰值的时候对象创建比较多,也有大对象产生。于是打算加大堆的大小来延缓GC的时机,并且有一些GC参数的优化,反复调整后找到了一个适合我们的参数(没有一个best的参数,还是得按照应用的的情况去测量,最好是一遍压测一遍调整,最终找到一个best fit的参数组)。

在把堆调大的过程中比较担心下面几个问题:

1、GC的压力会不会增大?

2、一次GC的耗时会不会增加?

3、如果在GC stop-the-world的时间里,rt飙高怎么办? (more…)

Written by Hesey Wang in: Java,技术 |
11月
18
2013
10

消除Java应用中的Exception开销

抛异常最大的消耗在于构造整个异常栈的过程,如果你的栈很深,特别是用了一些框架的话,这个开销基本是不可忽视的,之前做的一个优化显示当时应用中的一个异常使得整个应用的性能下降至少30%。 (more…)

Written by Hesey Wang in: Java,技术 |
11月
16
2013
2

如何真实压测一个Web浏览型应用的性能

对于应用压测大家应该都有一些自己的方式,通常都是构造一些请求,不过构造请求学问就大了。

构造什么样的请求?构造的请求是否真实?构造的请求各种业务场景的配比?读写比例?

对于一个Web浏览型应用来说,相比对纯DB的压测,会更复杂一些,主要因为涉及缓存。 (more…)

Written by Hesey Wang in: 分布式,技术,架构 |
9月
03
2013
1

Java应用线上问题排查的常用工具和方法

在长期排查线上问题的过程中,总结了一些工具的用法和排查问题的思路,这里跟大家分享一下,在遇到类似的问题时,希望能给予一些帮助。 (more…)

Written by Hesey Wang in: Java,Linux,技术 |
4月
13
2013
3

支持生产阻塞的线程池

在各种并发编程模型中,生产者-消费者模式大概是最常用的了。在实际工作中,对于生产消费的速度,通常需要做一下权衡。通常来说,生产任务的速度要大于消费的速度。一个细节问题是,队列长度,以及如何匹配生产和消费的速度。 (more…)

Written by Hesey Wang in: Java,并发,技术 |
4月
05
2013
2

何时对null值做Cache

前几天发现某个系统对某个远程调用接口的调用量大幅上升,涨幅不可思议。根据接口调用上升的时间点和发布记录,查看SVN提交记录,发现是在系统主路径中添加了这个接口的调用,难道这个接口没有做Cache吗?仔细一看,倒是也做了Cache,并且这个RPC对应的DB表的数据量非常小,按理说是能全部被缓存起来的。那么为什么会反复调用,看起来仿佛没有Cache一样呢?

直觉是缓存被不存在的数据击穿了,马上验证。

通过对系统方法的追踪,发现每次调用传入的参数都是0,再去DB里面查,0对应的结果确实为空。

所以这是一个典型的因为空记录导致的缓存被击穿的案例。

解决方法很简单,对不存在的记录做一个null的Cache,下次就不会落到远端了。不过这里结合业务的特定场景,我只是加了一个判断,当值大于0才会去查询,这样连一次查询Cache的开销也省掉了。

这个简单的问题可以衍生出一些思考。 (more…)

Written by Hesey Wang in: Java,分布式,技术 |
3月
29
2013
0

流水线中的大冒险

上一节说到,流水线中的分支预测本身是为了提高整条流水线的并行度,为此,CPU做了很多努力,例如乱序执行,甚至于流水线本身也是为了这个目的而诞生的。

和我们编写一般程序一样,顺序执行总是最简单、最安全的,指令被一条接着一条地顺序执行,没有人会思考任何有关并发的隐患。但是一旦踏入并发编程的范畴,似乎就开始变得一团糟,你需要考虑数据竞争、锁、内存等等一系列问题。和分支预测一样,有时候你会采用一些试探性的方法去处理并发中产生的问题,例如经典的CAS(Compare And Swap)算法,可能成功可能失败,喜忧参半。

在流水线中也存在着类似的大冒险,典型的有三种:

数据冒险

结构冒险

控制冒险

对应的,也有一些方法去辅助CPU在这些冒险的过程中,尽可能地达到我们期望的结果。 (more…)

Written by Hesey Wang in: 并发,技术 |
3月
18
2013
0

流水线中的分支预测

在现代CPU中,为了提高执行的性能,CPU的多个单元会同时执行多条指令。例如当取址单元正在寻找下一条指令前,上一条指令的译码和执行已经在进行中了,这一套机制被称作CPU流水线(pipeline)。

CPU流水线架构把指令的执行分为了多个阶段,每个单元只负责完成指令执行过程中的一个阶段,而中间结果由专门的流水线寄存器暂存。这样理论上,一条指令的执行假设被分为5个阶段,那么当5个单元同时运行一段时间后,理论上相同时间可以同时执行5条指令,当然这只是最简单的情况,实际的情况要复杂得多。

400px-5_Stage_Pipeline.svg

流水线的引入相当于程序中引入了并发,相应的,会带来很多额外的问题。例如为了更好地让指令流水般地执行,不涉及顺序一致性的指令会被重排序。这里不详细讨论太多流水线的技术细节,只要知道指令并不是一条一条顺序执行的,那样会严重阻碍处理器的性能。

CPU流水线引入的目的在于,希望能够在每个CPU的时钟周期都发射一条新的指令,这样理论上可以达到最高效率。但这有一个前提:如果指令的执行是每个时钟周期一条,那么指令的取值也必须达到每个时钟周期一条,如此,当你在取址阶段拿到要执行的指令时,下一条指令的地址必须被确定了,否则下一个时钟周期便无法取出对应的指令。 (more…)

Written by Hesey Wang in: 并发,技术 |

©2006 - 2016 Hesey (舒)