-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
456 lines (361 loc) · 75.3 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>刘梓</title>
<link href="/atom.xml" rel="self"/>
<link href="http://zclau.com/"/>
<updated>2018-01-25T16:52:30.000Z</updated>
<id>http://zclau.com/</id>
<author>
<name>zclau</name>
<email>[email protected]</email>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>线程池执行UncaughtExceptionHandler失效问题分析</title>
<link href="http://zclau.com/2018/01/26/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%89%A7%E8%A1%8CUncaughtExceptionHandler%E5%A4%B1%E6%95%88%E9%97%AE%E9%A2%98%E5%88%86%E6%9E%90/"/>
<id>http://zclau.com/2018/01/26/线程池执行UncaughtExceptionHandler失效问题分析/</id>
<published>2018-01-25T16:51:56.000Z</published>
<updated>2018-01-25T16:52:30.000Z</updated>
<content type="html"><![CDATA[<h1 id="场景"><a href="#场景" class="headerlink" title="场景"></a>场景</h1><p>我们知道可以对一个Thread对象设置UncaughtExceptionHandler来进行自定义的未捕捉异常处理。具体可参考上一篇文章<a href="https://www.jianshu.com/p/65fb5d5198e2" target="_blank" rel="external">Thread自定义异常处理</a></p>
<p>但是,如果交由线程池来执行的话,</p>
<figure class="highlight livescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line">public static <span class="literal">void</span> main(String[] args) {</div><div class="line"> Thread task = <span class="keyword">new</span> Thread<span class="function"><span class="params">(() -> {</span></span></div><div class="line"> System.out.println(<span class="string">"Before..."</span>);</div><div class="line"> System.out.println(<span class="number">10</span> / <span class="number">0</span>);</div><div class="line"> System.out.println(<span class="string">"After..."</span>);</div><div class="line"> });</div><div class="line"></div><div class="line"></div><div class="line"> <span class="title">task</span>.<span class="title">setName</span><span class="params">(<span class="string">"Thread-demo"</span>)</span>;</div><div class="line"> <span class="title">task</span>.<span class="title">setUncaughtExceptionHandler</span><span class="params">((t1, e) -> {</span></div><div class="line"> System.out.println(<span class="string">"自定义异常: "</span> + t1);</div><div class="line"> System.out.println(e);</div><div class="line"> });</div><div class="line"></div><div class="line"></div><div class="line"> <span class="title">ExecutorService</span> <span class="title">exec</span> = <span class="title">Executors</span>.<span class="title">newCachedThreadPool</span><span class="params">()</span>;</div><div class="line"> <span class="title">exec</span>.<span class="title">execute</span><span class="params">(task)</span>;</div><div class="line"> <span class="title">exec</span>.<span class="title">shutdown</span><span class="params">()</span>;</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>从代码可以看到,线程task设置了UncaughtExceptionHandler,并交给线程池来执行,结果:<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-057f20be970597f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-057f20be970597f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到,结果并不像我们设想的那样,居然没有走我们自己定义的异常处理的方法。</p>
<h1 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h1><p>为什么UncaughtExceptionHandler会失效呢,冷静下来仔细回想一下。从上一篇文章的分析中,我们知道只有为线程设置了UncaughtExceptionHandler,该线程在发生异常时,才会执行对应的uncaughtException方法。</p>
<p>如此说来,提交给线程池执行的时候,有可能实际运行task的线程并不是task线程本身(这可能有点拗口)。如果不是task线程本身,又是谁在执行task呢?于是决定对两种方式进行debug,</p>
<p>1、 线程池执行<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-be6957df6dcbe0f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-be6957df6dcbe0f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>很明显,当前运行task的是线程池创建的线程”pool-1-thread-1”,而我们只是为线程”Thread-demo”设置了uncaughtExceptionHandler,所以就解释了为什么没有走自定义的处理了。</p>
<p>2、单线程执行<br>把上面的例子改为task.start()执行,再debug<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-2b2663e7710812db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-2b2663e7710812db.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到,这一次就是task线程本身也就是”Thread-demo”在执行了,而uncaughtExceptionHandler属性也就不为null。</p>
<h1 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h1><p>1、如果让线程池执行的同时,也能走自定义uncaughtExceptionHandler,可以在task的开头加上<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">Thread task = new Thread(() -> {</div><div class="line"> Thread.currentThread(). setUncaughtExceptionHandler((<span class="name">t1</span>, e) -> {</div><div class="line"> System.out.println(<span class="string">"自定义异常: "</span> + t1)<span class="comment">;</span></div><div class="line"> System.out.println(<span class="name">e</span>)<span class="comment">;</span></div><div class="line"> })<span class="comment">;</span></div><div class="line"></div><div class="line"> System.out.println(<span class="string">"Before..."</span>)<span class="comment">;</span></div><div class="line"> System.out.println(<span class="number">10</span> / <span class="number">0</span>)<span class="comment">;</span></div><div class="line"> System.out.println(<span class="string">"After..."</span>)<span class="comment">;</span></div><div class="line"> })<span class="comment">;</span></div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<h1 id="&#x573A;&#x666F;"><a href="#&#x573A;&#x666F;" class="headerlink" title="&#x573A;&#x666F;"></a>&#x573A;&#x666F;</h1><p>&#x6211;&#x4EE
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="多线程" scheme="http://zclau.com/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
<entry>
<title>Thread自定义异常处理</title>
<link href="http://zclau.com/2018/01/25/Thread%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86/"/>
<id>http://zclau.com/2018/01/25/Thread自定义异常处理/</id>
<published>2018-01-25T08:01:48.000Z</published>
<updated>2018-01-25T08:03:37.000Z</updated>
<content type="html"><![CDATA[<h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><p>先来看一个例子<br><figure class="highlight livescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">Thread t = <span class="keyword">new</span> Thread<span class="function"><span class="params">(() -> {</span></span></div><div class="line"> System.out.println(<span class="string">"Before..."</span>);</div><div class="line"> System.out.println(<span class="number">10</span> / <span class="number">0</span>);</div><div class="line"> System.out.println(<span class="string">"After..."</span>);</div><div class="line"> });</div><div class="line"> <span class="title">t</span>.<span class="title">start</span><span class="params">()</span>;</div></pre></td></tr></table></figure></p>
<p>这段代码运行结果是会抛出一个未捕获的异常<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-5357159889618f98.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-5357159889618f98.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>实际来说,这样是很危险的,因为当线程遇到这种未捕获的异常时,就会立即退出,不会再继续执行之后的代码,这样就无法回收一些系统资源,或者没有关闭当前的连接等等。。。</p>
<h1 id="自定义异常处理"><a href="#自定义异常处理" class="headerlink" title="自定义异常处理"></a>自定义异常处理</h1><p>我们可以为Thread设定<code>UncaughtExceptionHandler</code>,在遇到异常中断时,交由它来处理</p>
<figure class="highlight livescript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"> Thread t = <span class="keyword">new</span> Thread<span class="function"><span class="params">(() -> {</span></span></div><div class="line"> System.out.println(<span class="string">"Before..."</span>);</div><div class="line"> System.out.println(<span class="number">10</span> / <span class="number">0</span>);</div><div class="line"> System.out.println(<span class="string">"After..."</span>);</div><div class="line"> });</div><div class="line"></div><div class="line"> <span class="title">t</span>.<span class="title">setUncaughtExceptionHandler</span><span class="params">((t1, e) -> {</span></div><div class="line"> System.out.println(<span class="string">"Exception: "</span> + t1);</div><div class="line"> System.out.println(e);</div><div class="line"> });</div><div class="line"></div><div class="line"><span class="title">t</span>.<span class="title">start</span><span class="params">()</span>;</div></pre></td></tr></table></figure>
<h2 id="UncaughtExceptionHandler"><a href="#UncaughtExceptionHandler" class="headerlink" title="UncaughtExceptionHandler"></a>UncaughtExceptionHandler</h2><p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-bd763bec2cf92bc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-bd763bec2cf92bc3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>UncaughtExceptionHandler在Thread类下定义的一个接口,里面只有一个方法uncaughtException,当一个Thread因为异常而终止时,JVM会触发调用dispatchUncaughtException方法,<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-ea01aa16f5c221b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-ea01aa16f5c221b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>此方法会调用getUncaughtExceptionHandler去找对应的handler<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-db9a27d09e314dad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-db9a27d09e314dad.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>如果我们没有自定义UncaughtExceptionHandler的话,就会由当前线程的ThreadGroup对象来处理。<br>找到handler后,把当前Thread对象以及异常Throwable对象作为参数,传入uncaughtException方法,由该方法来处理这次异常。</p>
<p>文章开头例子的运行结果,就是由ThreadGroup的uncaughtException来输出那一堆的异常栈信息。</p>
]]></content>
<summary type="html">
<h1 id="&#x80CC;&#x666F;"><a href="#&#x80CC;&#x666F;" class="headerlink" title="&#x80CC;&#x666F;"></a>&#x80CC;&#x666F;</h1><p>&#x5148;&#x676
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="多线程" scheme="http://zclau.com/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
</entry>
<entry>
<title>常用JVM Crash分析</title>
<link href="http://zclau.com/2017/12/29/%E5%B8%B8%E7%94%A8JVM-Crash%E5%88%86%E6%9E%90/"/>
<id>http://zclau.com/2017/12/29/常用JVM-Crash分析/</id>
<published>2017-12-29T15:25:21.000Z</published>
<updated>2017-12-29T15:25:48.000Z</updated>
<content type="html"><![CDATA[<h1 id="1-JVM-的Error文件"><a href="#1-JVM-的Error文件" class="headerlink" title="1. JVM 的Error文件"></a>1. JVM 的Error文件</h1><p>JDK在意外退出时,会该程序的运行目录生成一个hs<em>error</em>{PID}.log的Error文件,提供一些基本的信息。</p>
<figure class="highlight mel"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">-XX:ErrorFile=${LOGDIR}/hs_err_%p.<span class="keyword">log</span></div></pre></td></tr></table></figure>
<h1 id="2-CoreDump"><a href="#2-CoreDump" class="headerlink" title="2. CoreDump"></a>2. CoreDump</h1><p>在启动脚本中加入<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">ulimit</span> -c unlimited</div></pre></td></tr></table></figure></p>
<p>在进程意外退出时, 将生成CoreDump文件, 在该应用的执行目录下,有一个core.{PID} 文件。</p>
<p>如果没找到,进行全局搜索。</p>
<figure class="highlight golo"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">find</span> / -name core.* <span class="number">2</span>>/dev/<span class="literal">null</span></div></pre></td></tr></table></figure>
<p>如果想固定目录,需要修改内核参数,修改/etc/sysctl.conf,增加</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">kernel.core_pattern=<span class="regexp">/apps/</span>logs<span class="regexp">/core</span></div></pre></td></tr></table></figure>
<p>获得coredump文件后,必须在服务器上,使用运行该应用的java, 可获得下列内容</p>
<ul class="ui list">
<li>获得threaddump</li>
</ul>
<figure class="highlight dts"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">jstack <span class="meta-keyword">/apps/</span>svr<span class="meta-keyword">/jdk/</span>bin/<span class="class">java </span>{coredump_file} > <span class="meta-keyword">/tmp/</span>threaddump.log</div></pre></td></tr></table></figure>
<ul class="ui list">
<li>获得heapdump</li>
</ul>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">jmap -<span class="keyword">dump</span>:format=b,<span class="keyword">file</span>=<span class="regexp">/tmp/</span>heap.hprof <span class="regexp">/apps/</span>svr<span class="regexp">/jdk/</span>bin<span class="regexp">/java {coredump_file}</span></div></pre></td></tr></table></figure>
<ul class="ui list">
<li>gdb大法。</li>
</ul>
<h1 id="2-OOM-Killer"><a href="#2-OOM-Killer" class="headerlink" title="2 OOM Killer"></a>2 OOM Killer</h1><figure class="highlight perl"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">dmesg | <span class="keyword">grep</span> -i <span class="keyword">kill</span></div></pre></td></tr></table></figure>
<p>可以看看有无OOM Killer信息</p>
<p>ps.dmesg中时间戳的转换</p>
<figure class="highlight mel"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">date</span> -d <span class="string">"1970-01-01 UTC `echo "</span>$(<span class="keyword">date</span> +%s)-$(cat /<span class="keyword">proc</span>/uptime|cut -f <span class="number">1</span> -d<span class="string">' '</span>)+{需转换的时间戳}<span class="string">"|bc ` seconds"</span></div></pre></td></tr></table></figure>
]]></content>
<summary type="html">
<h1 id="1-JVM-&#x7684;Error&#x6587;&#x4EF6;"><a href="#1-JVM-&#x7684;Error&#x6587;&#x4EF6;" class="headerlink" title="1. JVM &#x7684;Error&#
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="JVM" scheme="http://zclau.com/tags/JVM/"/>
</entry>
<entry>
<title>常用Heap分析</title>
<link href="http://zclau.com/2017/12/29/%E5%B8%B8%E7%94%A8Heap%E5%88%86%E6%9E%90/"/>
<id>http://zclau.com/2017/12/29/常用Heap分析/</id>
<published>2017-12-29T15:23:31.000Z</published>
<updated>2017-12-29T15:24:51.000Z</updated>
<content type="html"><![CDATA[<h1 id="1-Heap统计信息"><a href="#1-Heap统计信息" class="headerlink" title="1. Heap统计信息"></a>1. Heap统计信息</h1><ul class="ui list">
<li>打印heap信息,如新老代大小,使用率。</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">jmap -heap <span class="tag"><<span class="name">PID</span>></span></div></pre></td></tr></table></figure>
<h1 id="2-对象统计信息"><a href="#2-对象统计信息" class="headerlink" title="2. 对象统计信息"></a>2. 对象统计信息</h1><ul class="ui list">
<li>打印所有heap对象的统计信息,如对象的个数与所占大小。</li>
</ul>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 打印所有对象的信息</span></div><div class="line">jmap -histo PID > <span class="regexp">/tmp/</span>histo.log</div><div class="line"></div><div class="line"><span class="comment">// 仅打印存活对象的信息</span></div><div class="line">jmap -<span class="string">histo:</span>live PID > <span class="regexp">/tmp/</span>histo-live.log</div></pre></td></tr></table></figure>
<blockquote>
<p>不要随便加 -F 参数,可能把进程搞崩溃,仅当JVM已经假死状态,才用-F最后一搏。live参数实际效果是先执行一次Full GC清理掉已经过期的对象,因此要注意对线上业务的超时影响,尽量摘流量执行。</p>
</blockquote>
<ul class="ui list">
<li>打印各个分代中的对象统计信息,见<a href="https://github.com/alibaba/TBJMap" target="_blank" rel="external">TBJMap</a> </li>
</ul>
<h1 id="3-获取HeapDump"><a href="#3-获取HeapDump" class="headerlink" title="3. 获取HeapDump"></a>3. 获取HeapDump</h1><figure class="highlight stylus"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 获取所有对象的dump</span></div><div class="line">jmap -dump:format=<span class="selector-tag">b</span>,file=/tmp/heap<span class="selector-class">.hprof</span> <PID></div><div class="line"></div><div class="line"><span class="comment">// 获取存活对象的dump,实际效果是先执行一次FULL GC</span></div><div class="line">jmap -dump:live,format=<span class="selector-tag">b</span>,file=/tmp/heap-live<span class="selector-class">.hprof</span> <PID></div></pre></td></tr></table></figure>
<blockquote>
<p>heap dump会造成JVM比较长时间的停顿,必须摘流量执行</p>
</blockquote>
<p>dump文件一定要zip后再传输,节约不少时间</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">tar -zcf /tmp/heap<span class="selector-class">.hprof</span><span class="selector-class">.gz</span> /tmp/heap.hprof</div></pre></td></tr></table></figure>
<h1 id="4-分析HeapDump"><a href="#4-分析HeapDump" class="headerlink" title="4. 分析HeapDump"></a>4. 分析HeapDump</h1><p>使用JDK自带的VisaulVM(以jvisualvm启动)或Eclipse的MAT均可</p>
<p>留意对象有两个大小,很多时候<code>Retained Size</code>更有意义:</p>
<ul class="ui list">
<li>本身大小(Shallow Size):对象本来的大小。</li>
<li>保留大小(Retained Size): 当前对象大小 + 当前对象直接或间接引用到的对象的大小总和。</li>
</ul>
<p>注意,Eclipse MAT分析时,如果想看到非存活状态的对象,需要特别勾选。</p>
<h1 id="5-分析HeapDump进阶"><a href="#5-分析HeapDump进阶" class="headerlink" title="5. 分析HeapDump进阶"></a>5. 分析HeapDump进阶</h1><p>使用OQL进行高级查询。</p>
<ul class="ui list">
<li><a href="https://visualvm.github.io/documentation.html" target="_blank" rel="external">VisualVM的OQL语法</a></li>
</ul>
<h1 id="6-Out-Of-Memory时自动HeapDump"><a href="#6-Out-Of-Memory时自动HeapDump" class="headerlink" title="6. Out Of Memory时自动HeapDump"></a>6. Out Of Memory时自动HeapDump</h1><p>OOM时生成HeapDump文件.<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">-<span class="string">XX:</span>+HeapDumpOnOutOfMemoryError -<span class="string">XX:</span>HeapDumpPath=${LOGDIR}/</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<h1 id="1-Heap&#x7EDF;&#x8BA1;&#x4FE1;&#x606F;"><a href="#1-Heap&#x7EDF;&#x8BA1;&#x4FE1;&#x606F;" class="headerlink" title="1. Heap&#x7EDF;&
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="JVM" scheme="http://zclau.com/tags/JVM/"/>
</entry>
<entry>
<title>Gson ParameterizedTypeImpl初始化校验参数失败问题</title>
<link href="http://zclau.com/2017/12/22/Gson-ParameterizedTypeImpl%E5%88%9D%E5%A7%8B%E5%8C%96%E6%A0%A1%E9%AA%8C%E5%8F%82%E6%95%B0%E5%A4%B1%E8%B4%A5%E9%97%AE%E9%A2%98/"/>
<id>http://zclau.com/2017/12/22/Gson-ParameterizedTypeImpl初始化校验参数失败问题/</id>
<published>2017-12-22T14:32:26.000Z</published>
<updated>2017-12-26T02:12:46.000Z</updated>
<content type="html"><![CDATA[<h1 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h1><p>今天在对某个接口做junit测试时,报如下错误</p>
<p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-c33bef422e7f3680.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-c33bef422e7f3680.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>发生错误的本质就是:某个bean在初始化时使用了gson做参数类型映射, 旗下ParameterizedTypeImpl 解析泛型数据时出错,导致创建bean失败,从而导致spring 容器启动失败</p>
<p>而奇怪的是,通过gradle打包运行却是正常的,但跑junit测试却一直报错。</p>
<h1 id="分析"><a href="#分析" class="headerlink" title="分析"></a>分析</h1><p>从堆栈错误可以看到,是在初始化ParameterizedTypeImpl时,调用checkArgument方法时报错, 这时用的gson版本是2.2.2。找到对应的源码位置<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-5b841939f074f386.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-5b841939f074f386.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>然后再来看看客户端初始化ParameterizedTypeImpl传入的参数:<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-72b8836e2f0b8418.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-72b8836e2f0b8418.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<ul class="ui list">
<li>ownerType是null</li>
<li>rawType是ClientService类下的一个静态内部类Response</li>
</ul>
<p>第一个checkArgument校验,ownerType不为null或者rawType不是内部类的条件明显不满足,所以就是在这里抛的illegalArgumentException。</p>
<p>通过gradle打包方式运行,发现使用的是gson 2.8.0(这里注意一下,我们的系统同时存在2.2.2, 2.6.2以及2.8.0版本的gson,gralde解决版本冲突的策略是选取最新的那个版本),没有抛错,而2.8.0对应ParameterizedTypeImpl初始化的代码<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-ec31e8288b975523.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-ec31e8288b975523.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到2.8.0对应的校验条件发生了变化:</p>
<ul class="ui list">
<li>ownerType不为null 或</li>
<li>rawType是静态类,或者不是内部类</li>
</ul>
<p>我们的Response类是静态类,所以通过校验,没有报错。</p>
<h1 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h1><ul class="ui list">
<li>强制使用gson 2.8.0,具体参考 <a href="https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html" target="_blank" rel="external">Gradle ResolutionStrategy</a></li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul class="ui list">
<li>ParameterizedTypeImpl初始化从2.3.0版本开始更改了校验参数的方式的,如果你在使用的时候发现出现参数校验异常,并且使用的是2.2.2及之前的版本,可以考虑升级gson版本</li>
</ul>
]]></content>
<summary type="html">
<h1 id="&#x95EE;&#x9898;&#x80CC;&#x666F;"><a href="#&#x95EE;&#x9898;&#x80CC;&#x666F;" class="headerlink" title="&#x95EE;&#x9898;&#x80CC;&#x6
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="Gson" scheme="http://zclau.com/tags/Gson/"/>
</entry>
<entry>
<title>Jmeter分布式压测</title>
<link href="http://zclau.com/2017/12/08/Jmeter%E5%88%86%E5%B8%83%E5%BC%8F%E5%8E%8B%E6%B5%8B/"/>
<id>http://zclau.com/2017/12/08/Jmeter分布式压测/</id>
<published>2017-12-08T06:43:43.000Z</published>
<updated>2017-12-08T06:44:49.000Z</updated>
<content type="html"><![CDATA[<blockquote>
<p>进行性能测试时,由于单台机器模拟并发用户数量有限,希望用多台负载机进行负载模拟。我们可以在多台机器上分别部署Jmeter,然后用其中一台做master,控制其他slave实例产生负载。</p>
</blockquote>
<h1 id="step-one"><a href="#step-one" class="headerlink" title="step one"></a>step one</h1><p>部署节点:假设我部署了三台,分别10.199.206.76、10.199.147.249、10.199.205.113<br>首先确保所有节点:<br>运行相同版本的Jmeter<br>运行相同版本的jdk<br>如果需要用到额外的数据文件,例如我的例子需要用到自定义Java Sampler以及外部properties,每个实例需要各来一份。<br>master还需要保存一份xxx.jmx测试脚本</p>
<p>如何编写自定义Java Sampler可参看 </p>
<p><a href="http://www.jianshu.com/p/f18b69c68459" target="_blank" rel="external">Jmeter使用自定义Java代码压测</a></p>
<h1 id="step-two-(optional)"><a href="#step-two-(optional)" class="headerlink" title="step two (optional)"></a>step two (optional)</h1><p>配置节点:<br>这里我选择10.199.206.76做master,10.199.147.249、10.199.205.113作为slave<br>在master的$JMETER_HOME/bin/jmeter.properties的 remote_hosts属性后配置<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-676cce21bd7aa0ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-676cce21bd7aa0ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>#step three<br>启动slave<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-66db6dbcecbee800.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-66db6dbcecbee800.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>然后检查一下控制台输出:<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-ffc8094fd02629f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-ffc8094fd02629f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>检查日志,默认会在当前目录写日志<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-097cb5e688f46bc1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-097cb5e688f46bc1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>有以上输出,没有报错,证明slave启动成功</p>
<h1 id="step-four"><a href="#step-four" class="headerlink" title="step four"></a>step four</h1><p>启动master进行压测,有两种启动方式<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-33250028bec43497.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-33250028bec43497.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>或</p>
<p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-6ad1757cdba3b445.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-6ad1757cdba3b445.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>注意:如果step two 没有配置 remote_hosts,就必须用第一条命令,通过-R 指定slave</p>
<p>然后master就会发送指令给slave执行实际的压测,然后会等待接收slave压测的结果<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-68bffc4c5f7cd527.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-68bffc4c5f7cd527.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<h1 id="结果解读"><a href="#结果解读" class="headerlink" title="结果解读"></a>结果解读</h1><p>46303 in 00:00:15 = 3134.7/s 表示 在15秒内发送46303条请求,平均每秒处理3134条<br>Avg:504 表示平均响应时间 504ms<br>Min:3 表示最小响应时间3ms<br>Max:14524 表示最长响应时间14524ms</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="http://jmeter.apache.org/usermanual/remote-test.html" target="_blank" rel="external">http://jmeter.apache.org/usermanual/remote-test.html</a></p>
<p><a href="https://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf" target="_blank" rel="external">https://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf</a></p>
]]></content>
<summary type="html">
<blockquote>
<p>&#x8FDB;&#x884C;&#x6027;&#x80FD;&#x6D4B;&#x8BD5;&#x65F6;&#xFF0C;&#x7531;&#x4E8E;&#x5355;&#x53F0;&#x673A;&#x5668;&#x6A21;&#x6
</summary>
<category term="性能测试" scheme="http://zclau.com/categories/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/"/>
<category term="Jmeter" scheme="http://zclau.com/tags/Jmeter/"/>
</entry>
<entry>
<title>Jmeter使用自定义Java代码压测</title>
<link href="http://zclau.com/2017/11/30/Jmeter%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89Java%E4%BB%A3%E7%A0%81%E5%8E%8B%E6%B5%8B/"/>
<id>http://zclau.com/2017/11/30/Jmeter使用自定义Java代码压测/</id>
<published>2017-11-30T03:27:13.000Z</published>
<updated>2017-11-30T03:27:36.000Z</updated>
<content type="html"><![CDATA[<p>Jmeter有几种Sampler,如果想用自定义Java代码来进行压测,就要使用Java Sampler。</p>
<p>那么如何编写Java Sampler,并引入到jmeter进行压测呢?很简单</p>
<h1 id="step-one"><a href="#step-one" class="headerlink" title="step one"></a>step one</h1><p>首先需要引入依赖<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><dependency></div><div class="line"> <groupId>org.apache.jmeter</groupId></div><div class="line"> <artifactId>ApacheJMeter_java</artifactId></div><div class="line"> <version>3.3</version></div><div class="line"> <scope>provided</scope></div><div class="line"></dependency></div></pre></td></tr></table></figure></p>
<blockquote>
<p>这里只是编译时需要用到,实际运行时代码会放在 ${JMETER_HOME}/lib/ext 下,${JMETER_HOME}/lib 下已经有对应依赖了,所以 这里 scope设置为provided即可。</p>
</blockquote>
<h1 id="step-two"><a href="#step-two" class="headerlink" title="step two"></a>step two</h1><p>然后就可以编写测试代码了<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SdkTest</span> <span class="keyword">extends</span> <span class="title">AbstractJavaSamplerClient</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Logger logger = LoggerFactory.getLogger(SdkTest.class);</div><div class="line"></div><div class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ConfigCenter configCenter = ConfigCenterFactory.getConfigCenter();</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 自定义java方法入参的, 设置可用参数及默认值</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> Arguments <span class="title">getDefaultParameters</span><span class="params">()</span> </span>{</div><div class="line"> Arguments params = <span class="keyword">new</span> Arguments();</div><div class="line"> params.addArgument(<span class="string">"name"</span>, <span class="string">""</span>);</div><div class="line"> params.addArgument(<span class="string">"tag"</span>, <span class="string">""</span>);</div><div class="line"></div><div class="line"> <span class="keyword">return</span> params;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 每个线程测试前执行一次,做一些初始化工作;</div><div class="line"> * <span class="doctag">@param</span> context</div><div class="line"> */</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setupTest</span><span class="params">(JavaSamplerContext context)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.setupTest(context);</div><div class="line"> }</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 开始测试,从args参数可以获得参数值;</div><div class="line"> * <span class="doctag">@param</span> args</div><div class="line"> * <span class="doctag">@return</span></div><div class="line"> */</div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> SampleResult <span class="title">runTest</span><span class="params">(JavaSamplerContext args)</span> </span>{</div><div class="line"> String name = args.getParameter(<span class="string">"name"</span>);</div><div class="line"> String tag = args.getParameter(<span class="string">"tag"</span>);</div><div class="line"></div><div class="line"> SampleResult result = <span class="keyword">new</span> SampleResult();</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> result.sampleStart();</div><div class="line"></div><div class="line"> </div><div class="line"> <span class="comment">//这里就是自定义压测的代码</span></div><div class="line"> .........</div><div class="line"> ..........</div><div class="line"> ..........</div><div class="line"> </div><div class="line"> <span class="comment">//请求成功,设置测试结果为成功</span></div><div class="line"> result.setSuccessful(<span class="keyword">true</span>);</div><div class="line"> } <span class="keyword">catch</span> (Exception e) {</div><div class="line"> result.setSuccessful(<span class="keyword">false</span>);</div><div class="line"> e.printStackTrace();</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> result.sampleEnd();</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> result;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="meta">@Override</span></div><div class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">teardownTest</span><span class="params">(JavaSamplerContext context)</span> </span>{</div><div class="line"> <span class="keyword">super</span>.teardownTest(context);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p>
<blockquote>
<p>需要注意:Sampler类需要扩展JMeter的类org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient 或 实现 org.apache.jmeter.protocol.java.sampler.JavaSamplerClient接口</p>
</blockquote>
<h1 id="step-three"><a href="#step-three" class="headerlink" title="step three"></a>step three</h1><p>编写完成后,通过 mvn package 打成一个jar包,为了方便,我这里打成的是一个fat包,然后讲其放进 $JMETER_HOME/lib/ext目录下</p>
<h1 id="step-four"><a href="#step-four" class="headerlink" title="step four"></a>step four</h1><p>打开Jmeter,创建一个Java Request<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-176d4d6732d414c5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-176d4d6732d414c5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>然后就能看到刚才编写的Sampler类了<br><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-6c5514d3ee932347.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-6c5514d3ee932347.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>红色框处可以定义测试的输入,刚才上面的代码例子中的runTest方法中,就可用通过JavaSamplerContext来获取这些输入</p>
<p>然后就可以开心地进行压测了</p>
<h3 id="坑"><a href="#坑" class="headerlink" title="坑"></a>坑</h3><p>1、如果Sampler代码需要获取外部配置的话,例如需要配置zk server、host等配置,而这些配置是在外部properties中的,需要在启动jmeter的时候加上<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sh jmeter<span class="selector-class">.sh</span> -Dcom<span class="selector-class">.vipshop</span><span class="selector-class">.mobile</span><span class="selector-class">.serconfig</span>=./configcenter.properties</div></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<p>Jmeter&#x6709;&#x51E0;&#x79CD;Sampler&#xFF0C;&#x5982;&#x679C;&#x60F3;&#x7528;&#x81EA;&#x5B9A;&#x4E49;Java&#x4EE3;&#x7801;&#x6765;&#x8FDB;
</summary>
<category term="性能测试" scheme="http://zclau.com/categories/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/"/>
<category term="Jmeter" scheme="http://zclau.com/tags/Jmeter/"/>
</entry>
<entry>
<title>性能测试关注的指标</title>
<link href="http://zclau.com/2017/11/29/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%85%B3%E6%B3%A8%E7%9A%84%E6%8C%87%E6%A0%87/"/>
<id>http://zclau.com/2017/11/29/性能测试关注的指标/</id>
<published>2017-11-29T14:32:02.000Z</published>
<updated>2017-11-30T03:26:11.000Z</updated>
<content type="html"><![CDATA[<h3 id="性能测试时我们需要关注的指标"><a href="#性能测试时我们需要关注的指标" class="headerlink" title="性能测试时我们需要关注的指标"></a>性能测试时我们需要关注的指标</h3><ul class="ui list">
<li><p>RT:响应时间</p>
</li>
<li><p>TPS:每秒完成事务数</p>
</li>
<li><p>CPU性能指标:利用率、负载</p>
</li>
<li><p>Mem:内存性能指标,可用物理内存、虚拟内存使用率</p>
</li>
<li><p>Disk:磁盘性能指标,Disk Time、IO等待</p>
</li>
<li><p>NetWork:网络指标,带宽使用率、任务队列长度</p>
</li>
</ul>
<ul class="ui list">
<li><p>TCP连接数,可以用netstat命令统计得到</p>
</li>
<li><p>中间件建立的线程池,监控线程状态</p>
</li>
<li><p>JVM性能指标,GC情况、Heap使用情况</p>
</li>
<li><p>CPU负载队列长度</p>
</li>
<li><p>服务器与中间件之间建立的连接数及连接状态</p>
</li>
</ul>
<h3 id="一般性能分析的过程"><a href="#一般性能分析的过程" class="headerlink" title="一般性能分析的过程"></a>一般性能分析的过程</h3><ul class="ui list">
<li>检查RT: 客户端响应时间 </li>
<li>检查TPS: TPS大时RT小, 说明性能良好 </li>
<li>检查负载机资源消耗: 检查CPU使用率 </li>
<li>检查被压服务器的资源消耗: CPU 、 内存、磁盘IO、带宽、响应时间</li>
<li>检查中间件配置: 确定是否有配置参数问题 </li>
<li>数据库服务器: CPU、内存、IO繁忙程度、数据库监控</li>
</ul>
<h3 id="相关参考"><a href="#相关参考" class="headerlink" title="相关参考"></a>相关参考</h3><ul class="ui list">
<li>左耳朵大神写过一篇博客,阐述他对性能测试的一些看法 <a href="https://coolshell.cn/articles/17381.html" target="_blank" rel="external">性能测试应该怎么做?</a></li>
<li>关于GC分析,可以参看<a href="http://www.jianshu.com/p/5ace2a0cafa4" target="_blank" rel="external">初步诊断你的GC</a></li>
</ul>
<p>待续……</p>
]]></content>
<summary type="html">
<h3 id="&#x6027;&#x80FD;&#x6D4B;&#x8BD5;&#x65F6;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x5173;&#x6CE8;&#x7684;&#x6307;&#x6807;"><a href="#&#x6027;
</summary>
<category term="性能测试" scheme="http://zclau.com/categories/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/"/>
<category term="性能测试" scheme="http://zclau.com/tags/%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95/"/>
</entry>
<entry>
<title>线程池拒绝策略源码小析</title>
<link href="http://zclau.com/2017/11/10/%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5%E6%BA%90%E7%A0%81%E5%B0%8F%E6%9E%90/"/>
<id>http://zclau.com/2017/11/10/线程池拒绝策略源码小析/</id>
<published>2017-11-10T07:17:15.000Z</published>
<updated>2017-11-10T07:23:19.000Z</updated>
<content type="html"><![CDATA[<ul class="ui list">
<li><p>提交一个新的task到线程池后,此时如果ThreadPool内的所有工作线程都在忙碌时(没有可用的线程去处理该task),并且任务队列也到达界限,这时候就需要用到拒绝策略。</p>
</li>
<li><p>在 java.util.concurrent包下有个RejectedExecutionHandler接口,该接口定义了rejectedExecution方法,用来实现具体的拒绝行为。</p>
</li>
</ul>
<p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-e39226683758c31e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-e39226683758c31e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<ul class="ui list">
<li>再往下看,Java预定义了四种拒绝策略:<br><img src="http://upload-images.jianshu.io/upload_images/8923118-08fa4589a940767c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png"></li>
</ul>
<p>下面就分析一下这四种拒绝策略有什么不一样:</p>
<h3 id="AbortPolicy"><a href="#AbortPolicy" class="headerlink" title="AbortPolicy"></a>AbortPolicy</h3><p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-6d7b6ecd5323eb21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-6d7b6ecd5323eb21.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到AbortPolicy其实就是直接抛了个exception,并丢弃该task。</p>
<h3 id="DiscardPolicy"><a href="#DiscardPolicy" class="headerlink" title="DiscardPolicy"></a>DiscardPolicy</h3><p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-0f93f7ce1cedd7e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-0f93f7ce1cedd7e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>DiscardPolicy什么都没做,静静地丢弃该task</p>
<h3 id="DiscardOldestPolicy"><a href="#DiscardOldestPolicy" class="headerlink" title="DiscardOldestPolicy"></a>DiscardOldestPolicy</h3><p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-80005ac373773c29.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-80005ac373773c29.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到DiscardOldestPolicy会先通过poll方法,将任务队列的队头,也就是最旧的那个任务remove掉,然后将最新的task放进线程池</p>
<h3 id="CallerRunsPolicy"><a href="#CallerRunsPolicy" class="headerlink" title="CallerRunsPolicy"></a>CallerRunsPolicy</h3><p><a class="magnific-img" href="http://upload-images.jianshu.io/upload_images/8923118-5623a7e77443ac0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"><img src="http://upload-images.jianshu.io/upload_images/8923118-5623a7e77443ac0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" class="ui centered image"></a></p>
<p>可以看到,CallerRunsPolicy就是直接调用Runnable的实例方法run去执行该task,说白了就是该task直接由调用者线程来执行</p>
<h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><p>当然,以上四种拒绝策略只是jdk预定义的,我们也可以根据实际情况自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可</p>
]]></content>
<summary type="html">
<ul class="ui list">
<li><p>&#x63D0;&#x4EA4;&#x4E00;&#x4E2A;&#x65B0;&#x7684;task&#x5230;&#x7EBF;&#x7A0B;&#x6C60;&#x540E;&#xFF0C;&#x6B64;&#x6
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="Core Java" scheme="http://zclau.com/tags/Core-Java/"/>
</entry>
<entry>
<title>maven依赖调解</title>
<link href="http://zclau.com/2017/07/04/maven%E4%BE%9D%E8%B5%96%E8%B0%83%E8%A7%A3/"/>
<id>http://zclau.com/2017/07/04/maven依赖调解/</id>
<published>2017-07-04T13:35:10.000Z</published>
<updated>2017-07-04T14:01:41.000Z</updated>
<content type="html"><![CDATA[<p>项目有以下依赖:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">dependency</span>></span></div><div class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.vips.components<span class="tag"></<span class="name">groupId</span>></span></div><div class="line"> <span class="tag"><<span class="name">artifactId</span>></span>vips-common-cache<span class="tag"></<span class="name">artifactId</span>></span></div><div class="line"> <span class="tag"><<span class="name">version</span>></span>2.0<span class="tag"></<span class="name">version</span>></span></div><div class="line"><span class="tag"></<span class="name">dependency</span>></span></div><div class="line"><span class="tag"><<span class="name">dependency</span>></span></div><div class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.poi<span class="tag"></<span class="name">groupId</span>></span></div><div class="line"> <span class="tag"><<span class="name">artifactId</span>></span>poi<span class="tag"></<span class="name">artifactId</span>></span></div><div class="line"> <span class="tag"><<span class="name">version</span>></span>3.9<span class="tag"></<span class="name">version</span>></span></div><div class="line"><span class="tag"></<span class="name">dependency</span>></span></div></pre></td></tr></table></figure>
<p>其中</p>
<p>vips-common-cache —> vip-common-util —> commons-codec(1.6)</p>
<p>poi —> commons-codec(1.5)</p>
<p>使用 mvn dependency:tree 分析依赖后,发现maven实际使用的是 poi下的commons-codec(1.5)</p>
<p><a class="magnific-img" href="http://7xp2k4.com1.z0.glb.clouddn.com/5FB88141-2E41-47A3-B09C-AD6986A6A56E.png"><img src="http://7xp2k4.com1.z0.glb.clouddn.com/5FB88141-2E41-47A3-B09C-AD6986A6A56E.png" alt="" class="ui centered image"></a></p>
<p>再来看以下情形:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">dependency</span>></span></div><div class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.httpcomponents<span class="tag"></<span class="name">groupId</span>></span></div><div class="line"> <span class="tag"><<span class="name">artifactId</span>></span>httpclient<span class="tag"></<span class="name">artifactId</span>></span></div><div class="line"> <span class="tag"><<span class="name">version</span>></span>4.4.1<span class="tag"></<span class="name">version</span>></span></div><div class="line"><span class="tag"></<span class="name">dependency</span>></span></div><div class="line"><span class="tag"><<span class="name">dependency</span>></span></div><div class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.apache.poi<span class="tag"></<span class="name">groupId</span>></span></div><div class="line"> <span class="tag"><<span class="name">artifactId</span>></span>poi<span class="tag"></<span class="name">artifactId</span>></span></div><div class="line"> <span class="tag"><<span class="name">version</span>></span>3.9<span class="tag"></<span class="name">version</span>></span></div><div class="line"><span class="tag"></<span class="name">dependency</span>></span></div></pre></td></tr></table></figure>
<p>httpclient —> commons-codec(1.9)</p>
<p>poi —> commons-codec(1.5)</p>
<p>分析依赖后发现,maven选择了commons-codec(1.9)</p>
<p><a class="magnific-img" href="http://7xp2k4.com1.z0.glb.clouddn.com/WX20170620-102526.png"><img src="http://7xp2k4.com1.z0.glb.clouddn.com/WX20170620-102526.png" alt="" class="ui centered image"></a></p>
<h2 id="结论:"><a href="#结论:" class="headerlink" title="结论:"></a>结论:</h2><p>maven遇到依赖冲突后,主要两种原则解决:</p>
<p>1.路径优先原则:如第一个例子,</p>
<p>vips-common-cache —> vip-common-util —> commons-codec(1.6)</p>
<p>poi —> commons-codec(1.5)</p>
<p>commons-codec(1.6)路径深度是3, commons-codec(1.5)是2,所以maven选择较短路径的那个</p>
<p>2.声明优先原则:如第二个例子,当冲突依赖所处的路径相同,声明在前的会被引用</p>
]]></content>
<summary type="html">
<p>&#x9879;&#x76EE;&#x6709;&#x4EE5;&#x4E0B;&#x4F9D;&#x8D56;&#xFF1A;</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><di
</summary>
<category term="Java" scheme="http://zclau.com/categories/Java/"/>
<category term="Maven" scheme="http://zclau.com/tags/Maven/"/>
</entry>
</feed>