-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
636 lines (444 loc) · 65.4 KB
/
index.html
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
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
<meta charset="utf-8">
<title>Benson's IT notes or summaries</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta property="og:type" content="website">
<meta property="og:title" content="Benson's IT notes or summaries">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Benson's IT notes or summaries">
<meta property="og:locale" content="English or Chinese">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Benson's IT notes or summaries">
<link rel="alternate" href="/atom.xml" title="Benson's IT notes or summaries" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/css/style.css">
</head>
</html>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Benson's IT notes or summaries</a>
</h1>
<h2 id="subtitle-wrap">
<a href="/" id="subtitle">Continuously updated on a irregular basis</a>
</h2>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
<a id="nav-search-btn" class="nav-icon" title="Search"></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-connect_is_not_available" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/20/connect_is_not_available/" class="article-date">
<time datetime="2019-04-20T09:27:00.000Z" itemprop="datePublished">2019-04-20</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/20/connect_is_not_available/">HikariPool-1 - Connection is not available</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>This afternoon, I got a report that website A is not accessible. I login the server and first checked the nginx error log. It says connection to upstream is timed out.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line">2019/04/20 09:58:42 [error] 6327#0: *129762 upstream timed out (110: Connection timed out) while reading response header from upstream, client: <xxx.xxx.xx.xx>, server: <xxx.xxxxxxxx.xxx>, request: "GET /api/user/me HTTP/1.1", upstream: "http://127.0.0.1:5000/api/user/me", host: "<xxx.xxxxxxxx.xxx>", referrer: "https://<xxx.xxxxxxxx.xxx>/page/home"</span><br><span class="line">2019/04/20 09:58:42 [error] 6327#0: *129763 upstream timed out (110: Connection timed out) while reading response header from upstream, client: <xxx.xxx.xx.xx>, server: <xxx.xxxxxxxx.xxx>, request: "GET /api/home/loadHomeData HTTP/1.1", upstream: "http://127.0.0.1:5000/api/home/loadHomeData", host: "<xxx.xxxxxxxx.xxx>", referrer: "https://<xxx.xxxxxxxx.xxx>/page/home"</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>Then I checked log from Spring</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection</span><br><span class="line"> ...</span><br><span class="line">Caused by: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection</span><br><span class="line"> ... 61 common frames omitted</span><br><span class="line">Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.</span><br><span class="line"> ...</span><br></pre></td></tr></table></figure>
<p>It clearly indicates that connection pool is running out of free connections. Connections are not returned to connection pool as expected. Incoming requests temping to acquire connection wait on it and finally timed out, which further caused the reading from nginx timed out.</p>
<p>For interest, I checked the network connection status with</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -peanut</span><br></pre></td></tr></table></figure>
<p>As shown below, majortiy of them are in <code>CLOSE_WAIT</code>. If you still remember the state transition for TCP, the sever side of a TCP connection will enter <code>CLOSE_WAIT</code> state when it receive <code>FIN</code> from its client. Thus, we can infer that the connection is originally issued from <code>127.0.0.1:xxxxx</code> to <code>127.0.0.1:5000</code>. This make sense, as <code>127.0.0.1:5000</code> is the upstream server to which where Nginx proxy incoming requests.</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name</span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13160 CLOSE_WAIT 1000 66628224 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13152 CLOSE_WAIT 1000 66628218 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:57766 CLOSE_WAIT 1000 62175223 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:21812 CLOSE_WAIT 1000 71135785 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13150 CLOSE_WAIT 1000 66628836 4209/java </span><br><span class="line">...</span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13794 CLOSE_WAIT 1000 66644609 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13154 CLOSE_WAIT 1000 66628222 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13792 CLOSE_WAIT 1000 66637431 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:30190 CLOSE_WAIT 1000 64263646 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13228 CLOSE_WAIT 1000 66629637 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:35004 CLOSE_WAIT 1000 72919978 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13210 CLOSE_WAIT 1000 66629002 4209/java </span><br><span class="line">tcp 1 0 127.0.0.1:5000 127.0.0.1:13198 CLOSE_WAIT 1000 66628344 4209/java</span><br></pre></td></tr></table></figure>
<p>So, the problem is clear. Then what’s the cause? Unfortunately, previously I didn’t enable <code>HikariCP</code>‘s Connect leak detection. And I also didn’t enable Postgresql’s slow log.</p>
<p><code>HikariCP</code> is the default connection pool used by Spring boot since 2.0. I checked its configuration with Spring boot actuator endpoint.</p>
<p>For your interest, the actuator was configed as following<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ActuatorSecurityConfig</span> <span class="keyword">extends</span> <span class="title">WebSecurityConfigurerAdapter</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests()</span><br><span class="line"> .anyRequest().hasRole(<span class="string">"SUPER_ADMIN"</span>)</span><br><span class="line"> .and()</span><br><span class="line"> .httpBasic();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>Since the upstream server is only bind to 127.0.0.1, I can only invoke that endpoint within the server.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -u <account>:<password> http://127.0.0.1:5000/actuator/configprops</span><br></pre></td></tr></table></figure>
<p>Yes, sad but true, <code>leakDetectionThreshold</code> is the default value 0 (disabled).</p>
<p>To enable it, add the following config in my <code>application.yml</code></p>
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"><span class="attr"> datasource:</span></span><br><span class="line"><span class="attr"> hikari:</span></span><br><span class="line"><span class="attr"> leak-detection-threshold:</span> <span class="number">30000</span> <span class="comment"># 30 seconds</span></span><br></pre></td></tr></table></figure>
<p>By the way, I also change <code>com.zaxxer.hikari</code>‘s log level to <code>DEBUG</code> by following the adivce from the Author of <code>HikariCP</code> <a href="https://github.com/brettwooldridge/HikariCP/issues/1111#issuecomment-373111306" target="_blank" rel="noopener">here</a>.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// logback-spring.xml in classpath root</span><br><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"><span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">include</span> <span class="attr">resource</span>=<span class="string">"org/springframework/boot/logging/logback/base.xml"</span>/></span></span><br><span class="line"> <span class="tag"><<span class="name">logger</span> <span class="attr">name</span>=<span class="string">"com.zaxxer.hikari"</span> <span class="attr">level</span>=<span class="string">"DEBUG"</span>/></span></span><br><span class="line"><span class="tag"></<span class="name">configuration</span>></span></span><br></pre></td></tr></table></figure>
<p>That’s what I have done to enhance my spring-boot server. Hope it can catch some useful info when the same problem happened again.</p>
<p>That’s not enough, Postgresql as the database should be able to tell something useful too. So I enable the slow query log there. Edit in <code>postgresql.conf</code>.<br><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># log to file with suffix ".log"</span></span><br><span class="line"><span class="string">log_destination</span> <span class="string">=</span> <span class="string">'stderr'</span></span><br><span class="line"><span class="comment"># required to be on for generating log</span></span><br><span class="line"><span class="string">loggin_collector</span> <span class="string">=</span> <span class="string">on</span></span><br><span class="line"><span class="comment"># the direction should exist and postgres server should has the read&write permission</span></span><br><span class="line"><span class="string">log_directly</span> <span class="string">=</span> <span class="string">'/var/log/postgresql'</span></span><br><span class="line"><span class="string">log_filename</span> <span class="string">=</span> <span class="string">'postgresql-%Y-%m-%d_%H%M%S.log'</span></span><br><span class="line"><span class="comment"># enable log file rotation</span></span><br><span class="line"><span class="string">log_truncate_on_rotation</span> <span class="string">=</span> <span class="string">on</span></span><br><span class="line"><span class="comment"># rotate log file on a daily basis</span></span><br><span class="line"><span class="string">log_rotation_age</span> <span class="string">=</span> <span class="number">1</span><span class="string">d</span></span><br><span class="line"><span class="comment"># if a query takes more that 2 seconds, log it out</span></span><br><span class="line"><span class="string">log_min_duration_statement</span> <span class="string">=</span> <span class="number">2000</span></span><br><span class="line"><span class="comment"># if this set to not `none`, then log_min_duration_statement will be ignored</span></span><br><span class="line"><span class="string">log_statement</span> <span class="string">=</span> <span class="string">'none'</span></span><br><span class="line"><span class="string">log_timezone</span> <span class="string">=</span> <span class="string">'Asia/Shanghai'</span></span><br></pre></td></tr></table></figure></p>
<p>You can locate <code>postgresql.conf</code> file with query:</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">show</span> config_file;</span><br></pre></td></tr></table></figure>
<p>Some fields require a restarting after modified. If not required, then simple execute the below SQL is enough to make it take effect.</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> pg_reload_conf();</span><br></pre></td></tr></table></figure>
<p>Try with</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> pg_sleep(<span class="number">7.5</span>);</span><br></pre></td></tr></table></figure>
<p>A corresponding log should have been logged into the correct place.</p>
<p><em>You can also read this <a href="https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing" target="_blank" rel="noopener">article</a> which mentions that simply increasing <code>maximumPoolSize</code> as a countermeansure for this problem is not a good idea.</em></p>
<p>References:</p>
<p><a href="https://dev.to/pythonmeister/how-to-identify-slow-queries-in-postgresql-4igk" target="_blank" rel="noopener">How to identify slow queries in PostgreSQL</a></p>
<p><a href="https://tableplus.io/blog/2018/10/how-to-show-queries-log-in-postgresql.html" target="_blank" rel="noopener">How to show queries log in PostgreSQL?</a></p>
<p><a href="https://github.com/brettwooldridge/HikariCP" target="_blank" rel="noopener">HikariCP</a></p>
<p><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html" target="_blank" rel="noopener">Production Ready Endpoints</a></p>
<p><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html" target="_blank" rel="noopener">logging</a></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/20/connect_is_not_available/" data-id="cjuphwy860000y4qaqjwq52mx" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-copy_file" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/copy_file/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/copy_file/">How to copy files fastly</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>First let’s generate a dummy file for test. We can do it with the following cmd superly fast.<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fallocate -l 2G copy_test.img</span><br></pre></td></tr></table></figure></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> File source = <span class="keyword">new</span> File(<span class="string">"/home/benson/develop/test/copy_test.img"</span>);</span><br><span class="line"> File target1 = <span class="keyword">new</span> File(<span class="string">"/home/benson/develop/test/target1.img"</span>);</span><br><span class="line"> File target2 = <span class="keyword">new</span> File(<span class="string">"/home/benson/develop/test/target2.img"</span>);</span><br><span class="line"> File target3 = <span class="keyword">new</span> File(<span class="string">"/home/benson/develop/test/target3.img"</span>);</span><br><span class="line"> System.out.println(<span class="string">"Source file is of size: "</span> + source.length());</span><br><span class="line"> <span class="keyword">long</span> pre = System.currentTimeMillis();</span><br><span class="line"> <span class="keyword">long</span> now = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">try</span>(FileInputStream fin = <span class="keyword">new</span> FileInputStream(source); FileOutputStream fout = <span class="keyword">new</span> FileOutputStream(target1)) {</span><br><span class="line"> fin.getChannel().transferTo(<span class="number">0</span>, source.length(), fout.getChannel());</span><br><span class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> now = System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"NIO tranfer takes: "</span> + (now - pre));</span><br><span class="line"> pre = now;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Files.copy(source.toPath(), target2.toPath());</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> now = System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"Files.copy takes: "</span> + (now - pre));</span><br><span class="line"> pre = now;</span><br><span class="line"> <span class="keyword">try</span> (BufferedInputStream bin = <span class="keyword">new</span> BufferedInputStream(<span class="keyword">new</span> FileInputStream(source));</span><br><span class="line"> BufferedOutputStream bout = <span class="keyword">new</span> BufferedOutputStream(<span class="keyword">new</span> FileOutputStream(target3));) {</span><br><span class="line"> <span class="keyword">byte</span>[] bs = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">512</span>];</span><br><span class="line"> <span class="keyword">int</span> count = -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> ((count = bin.read(bs)) != -<span class="number">1</span>) {</span><br><span class="line"> bout.write(bs, <span class="number">0</span>, count);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">catch</span> (FileNotFoundException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> now = System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"BufferedInputStream takes: "</span> + (now - pre));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Output:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Source file is of size: 2147483648</span><br><span class="line">NIO tranfer takes: 893</span><br><span class="line">Files.copy takes: 3087</span><br><span class="line">BufferedInputStream takes: 13113</span><br></pre></td></tr></table></figure></p>
<p>NIO <code>FileChannel::transfer</code> has the best performance. It utilizes direct ByteBuffer, which directly operates the file data in OS’s kernal space. While <code>Files::copy</code> and BufferedInputStream has to transfer data from kernal space and vise versa.</p>
<p>I planned to also test for <code>MappedByteBuffer</code>, but it doesn’t support to map more than 2 GB(precisely 2^31-1 bytes) data into memory directly. So I give it up. But basically, I guess it would have the same performace as <code>FileChannel::transferTo</code>.</p>
<p><em>But currently I don’t have a clue why BufferedInputStream is way worse than Files.copy. Let’s explore it later.</em></p>
<p>Please not that direct buffer is allocated outside of Java heap space. And it’s only cleaned at Full GC. So we have to use it carefully to avoid OOM. To adjust max direct memory size, we can use<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-XX:MaxDirectMemorySize=512M</span><br></pre></td></tr></table></figure></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/copy_file/" data-id="cju7m62pg0007c6qa5heh2wa0" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-create-your-own-blog" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/create-your-own-blog/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/create-your-own-blog/">Create blog with Hexo on Git Page</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>After several comparison, I choose to use <code>Hexo</code> to build my personal blog. And for simplicity, I decide to use <code>Github Page</code> to host my blog. </p>
<p>Basically, you need to maintain two git repositories. One for <code>Hexo</code> itself, and another for the generated static files. The second is needed as <code>Github Page</code> requires its content to be push to a repository of certain name.</p>
<p>generate static files<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo generate</span><br></pre></td></tr></table></figure></p>
<p>Copy generated files to the deploy folder (to be pushed to github)<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># the first folder is where static files generated </span><br><span class="line"># You may need to also add the "-n" option to perform a dry run to see the changes in advance.</span><br><span class="line">rsync -avzh --delete --exclude '.git' <SOME_PATH>/blog/public/ <SOME_PATH>/blog_deploy/</span><br></pre></td></tr></table></figure></p>
<p><a href="https://www.createdbypete.com/articles/a-practical-guide-to-using-rsync/" target="_blank" rel="noopener">rsync usage reference</a></p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/create-your-own-blog/" data-id="cju7m62pg0008c6qasloilr1x" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-gaaccess" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/gaaccess/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/gaaccess/">Using GoAccess to monitor your nginx access log</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Suppose you built a Web site, you must be curious at how much traffic your site attract and how do people using it.</p>
<p>You use Nginx as the coordinator server and you know you can analyze its access log.</p>
<p>Analyzing plain text from stratch is hard, and here comes <a href="https://goaccess.io/" target="_blank" rel="noopener">GoAccess</a>, which is amazing.</p>
<p>Here is how it looks.</p>
<p><img src="/images/goaccess.png" alt=""></p>
<p>It’s straight forward to setup GoAccess by following the offical <code>Get Started</code>. I just going through serveral points that you may need to take care.</p>
<h2 id="1-Firstly-put-the-configuration-file-to-the-right-place"><a href="#1-Firstly-put-the-configuration-file-to-the-right-place" class="headerlink" title="1. Firstly put the configuration file to the right place"></a>1. Firstly put the configuration file to the right place</h2><p>Accordign to the doc</p>
<blockquote>
<p>The configuration file is located under ~/.goaccessrc or %sysconfdir%/goaccess.conf where %sysconfdir% is either /etc/, /usr/etc/ or /usr/local/etc/.</p>
</blockquote>
<p>It would be a good idea to make changes in the config file, otherwise you have to pass in them everytime your invoke <code>goaccess</code> in command line.</p>
<h2 id="2-You-probably-need-to-change-the-log-format-for-nginx"><a href="#2-You-probably-need-to-change-the-log-format-for-nginx" class="headerlink" title="2. You probably need to change the log-format for nginx"></a>2. You probably need to change the log-format for nginx</h2><p>If you have several <code>Server</code>s (virtual hosts in Apache) configed in Nginx, you may need to change GoAccess’s default <code>COMBINED</code> log format.</p>
<p>The <code>COMMBINED</code> format is<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%h %^[%d:%t %^] "%r" %s %b "%R" "%u"</span><br></pre></td></tr></table></figure></p>
<p>and it does work perfectly with Nginx’s default access log format, which is<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">'$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'</span><br></pre></td></tr></table></figure></p>
<p>However, as you can see, it doesn’t contain any info for virtual hosts. To make GoAccess analyze virtual host as well, we need to change both Nginx access log format and GoAccess’s log format.</p>
<p>Here is what I did. For backward compatibility, I just switch Nginx’s <code>$remote_user</code> to <code>$host</code><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">'$remote_addr - $host [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'</span><br></pre></td></tr></table></figure></p>
<p>and change GoAccess <code>log-format</code> to<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">%h %^ %v [%d:%t %^] "%r" %s %b "%R" "%u"</span><br></pre></td></tr></table></figure></p>
<p><em>Please note that while using custom <code>log-format</code>, we need to specify <code>date-format</code> and <code>time-format</code> explict.</em></p>
<p>That’s all for GoAccess for now.</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/gaaccess/" data-id="cju7m62ph0009c6qaj60oc78a" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-import_spring_framework_source" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/import_spring_framework_source/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/import_spring_framework_source/">Import spring-framework into Eclipse</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Basically, you just need to follow this guide from spring-framwork <a href="https://github.com/spring-projects/spring-framework/blob/master/import-into-eclipse.md" target="_blank" rel="noopener">github page</a></p>
<blockquote>
<p>Note that I checkout the <code>master</code> branch</p>
</blockquote>
<p>From the offical guide, there are 6 steps.</p>
<ol>
<li>Precompile spring-oxm with ./gradlew :spring-oxm:compileTestJava</li>
<li>Import into Eclipse (File -> Import -> Gradle -> Existing Gradle Project -> Navigate to directory -> Select Finish)</li>
<li>If prompted, exclude the spring-aspects module (or after the import by closing or deleting the project)</li>
<li>In the spring-oxm project, add the two folders (castor and jaxb) in build/generated-sources to the build path (right click on them and select Build Path -> Use as Source Folder)</li>
<li>To apply project specific settings run ./gradlew eclipseBuildship</li>
<li>Code away</li>
</ol>
<p>Here I record problems encountered which may be helpful to someone else.</p>
<blockquote>
<ol>
<li>Precompile spring-oxm with ./gradlew :spring-oxm:compileTestJava</li>
</ol>
</blockquote>
<p>I have network problem in downloading gradle distribution online, it’s extremely slow.</p>
<p>To workaround it, I first used the greate tool <code>aria2c</code> to download gradle zip file to my local.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aria2c -x 8 -s 8 -k 1M https://services.gradle.org/distributions/gradle-4.10.3-bin.zip</span><br></pre></td></tr></table></figure>
<p>It issues 8 threads to download the target file parallelly.</p>
<p>Then, locate the <code>gradle-wrapper.properties</code> file under <code>spring-framework/gradle/wrapper</code>, modify its <code>distributionUrl</code> property<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip</span></span><br><span class="line">distributionUrl=file:///home/benson/Downloads/gradle-4.10.3-bin.zip</span><br></pre></td></tr></table></figure></p>
<p>In this way, <code>gradlew</code> will download the zip file from your local.</p>
<blockquote>
<ol start="4">
<li>In the spring-oxm project, add the two folders (castor and jaxb) in build/generated-sources to the build path (right click on them and select Build Path -> Use as Source Folder)</li>
</ol>
</blockquote>
<p>Successfully go through step 2 to 3. But then I couldn’t find <code>build</code> folder under <code>spring-oxm</code>, in Eclipse package exploreer.</p>
<p>To show it, you need to ensure</p>
<ul>
<li><p>The <code>Java Element Filter</code> in package explorer have <code>Gradle build folder</code> unchecked.</p>
</li>
<li><p><code>Resource > Resource Filters</code> in project property doesn’t have rule to exclude build folder.</p>
</li>
</ul>
<p>Besides this, I also encountered error that</p>
<blockquote>
<p>xxx is not accessible due to restriction on required library C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar</p>
</blockquote>
<p>I found one solution for this from Stackoverlow <a href="https://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-required-library-rt-jar" target="_blank" rel="noopener">here</a></p>
<p>I quote the solution here</p>
<ol>
<li>Go to the Build Path settings in the project properties.</li>
<li>Remove the JRE System Library</li>
<li>Add it back; Select “Add Library” and select the JRE System Library. The default worked for me.</li>
</ol>
<p>Lastly, there is another error under project <code>spring-beans</code>. It says that</p>
<blockquote>
<p>GroovyDynamicElementReader cannot be resolved to a type</p>
</blockquote>
<p>It requires to download corresponding Groovy plugin to resolve this problem.</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/import_spring_framework_source/" data-id="cju7m62pi000ac6qayfaw1tll" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-jvm_monitor" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/jvm_monitor/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/jvm_monitor/">Monitor JVM Process Remotely</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h2 id="Monitor-JVM-from-command-line-locally"><a href="#Monitor-JVM-from-command-line-locally" class="headerlink" title="Monitor JVM from command line locally"></a>Monitor JVM from command line locally</h2><p>You can monitor your target JVM process with many tools, say <code>jstat</code>, <code>jinfo</code>, <code>jstack</code>, <code>jmap</code> and so on.</p>
<p>First find out <code>vimid</code> with</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jps -l</span><br></pre></td></tr></table></figure>
<p>and then run</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jinfo <vimid></span><br></pre></td></tr></table></figure>
<p>But for the first time, you may get the following errors</p>
<blockquote>
<p>Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can’t attach to the process … not permitted …</p>
</blockquote>
<p>After some googling, we can slove it by (it’s due to a bug of Linux kernal)</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope</span><br></pre></td></tr></table></figure>
<h2 id="Mointor-JVM-with-graphical-tools-remotely"><a href="#Mointor-JVM-with-graphical-tools-remotely" class="headerlink" title="Mointor JVM with graphical tools remotely"></a>Mointor JVM with graphical tools remotely</h2><h3 id="Setup-JMX-RMI"><a href="#Setup-JMX-RMI" class="headerlink" title="Setup JMX RMI"></a>Setup JMX RMI</h3><p>Besides using commands locally, we can also use graphical tools like <code>Jconsole</code> or <code>VisualVM</code> to monitor a JVM process remotely. The latter one is a replacement for the former one.</p>
<p>To enable such remote monitoring, you need to make your remote JVM process to be ready for remote JMX RMI connections.</p>
<p>Here is the <a href="https://docs.oracle.com/javase/9/management/monitoring-and-management-using-jmx-technology.htm" target="_blank" rel="noopener">official reference</a>.</p>
<p>I summarize my steps as following.</p>
<p>cp JRE_HOME/lib/management/management.properties to home directory<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">com.sun.management.jmxremote.port=xxx</span><br><span class="line">com.sun.management.jmxremote.ssl=false</span><br><span class="line">com.sun.management.jmxremote.authenticate=true</span><br><span class="line">com.sun.management.jmxremote.password.file=/home/benson/jmxremote.password</span><br><span class="line">com.sun.management.jmxremote.access.file=/home/benson/jmxremote.access</span><br><span class="line">com.sun.management.jmxremote.rmi.port=xxx // this is very important, let's talk about it later</span><br></pre></td></tr></table></figure></p>
<p>cp JRE_HOME/lib/management/jmxremote.password.template to home directory as jmxremote.password.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">monitorRole xxx</span><br><span class="line">controlRole xxx</span><br></pre></td></tr></table></figure></p>
<p>For security reason, you have to change it as owner readable/writable only<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod 600 jmxremote.password</span><br></pre></td></tr></table></figure></p>
<p>cp JRE_HOME/lib/management/jmxremote.access to home directory.<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">monitorRole readonly</span><br><span class="line">controlRole readwrite \</span><br><span class="line"> create javax.management.monitor.*,javax.management.timer.* \</span><br><span class="line"> unregiste</span><br></pre></td></tr></table></figure></p>
<p>start your jar with your mangement file specified<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar -Dcom.sun.management.config.file=$HOME/management.properties -Djava.rmi.server.hostname=xx.xx.xx.xx xxx.jar</span><br></pre></td></tr></table></figure></p>
<p>Please note that <code>java.rmi.server.hostname</code> is also important here. According to the offical document</p>
<blockquote>
<p>By default, the remote stubs for locally created remote objects that are sent to client contains the IP address of the local host in dotted-quad format. For remote stubs to be associated with a specific interface address, the java.rmi.server.hostname system property must be set to IP address of that interface.</p>
</blockquote>
<p>In my case, if I start my remote Java VM without <code>java.rmi.server.hostname</code> being specified to the remote public IP, with Jconsole started with <code>-debug</code>, I got error</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is: </span><br><span class="line"> java.net.ConnectException: Connection refused (Connection refused)</span><br><span class="line"> at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:619)</span><br></pre></td></tr></table></figure>
<p>As I mentioned earilier, if you are in a serious production environment(with restrcit firewall rule), you probably need to setup <code>com.sun.management.jmxremote.rmi.port</code> as well.</p>
<p>According to the offical document</p>
<blockquote>
<p>setting this property(<code>com.sun.management.jmxremote.port=portNum</code>) publishes an additional RMI connector in a private read-only registry at the specified port using the name, jmxrmi. The port number to which the RMI connector will be bound using the system property:<br><strong>com.sun.management.jmxremote.rmi.port</strong></p>
</blockquote>
<p>If this property is not specified, it will randomly pick an unused port. As a result, if you are using white list for your firewall rule, connections to your remote JVM process will be blocked.</p>
<p>Lastly, please notice that when adding JMX connection in VisualVM, you need to specify <code>com.sun.management.jmxremote.port</code> rather than <code>com.sun.management.jmxremote.rmi.port</code>. Then former one should be where the RMI registry listen to. </p>
<h3 id="Connect-to-remote-server-with-jvisualvm"><a href="#Connect-to-remote-server-with-jvisualvm" class="headerlink" title="Connect to remote server with jvisualvm"></a>Connect to remote server with jvisualvm</h3><p>It’s straight forward to setup your jvisualvm client. Just note that if you follow my preivous steps, you need to specify the credentials configed in file <code>jmxremote.password</code>.</p>
<h3 id="Setup-Jstatd-Optional"><a href="#Setup-Jstatd-Optional" class="headerlink" title="Setup Jstatd (Optional)"></a>Setup Jstatd (Optional)</h3><p>Alike to JMX, Jstatd also provides you ability to monitor JVM. But it’s much more limited. There is a comparison between JMX and Jstatd <a href="https://blog.jakubholy.net/2012/09/21/visualvm-monitoring-remote-jvm-over-ssh-jmx-or-not/" target="_blank" rel="noopener">here</a>.</p>
<p>In average cases, JMX is enough for you. The reason why I need to setup <code>Jstatd</code> is that <code>Visual GC</code> plugin is based on it. The <code>heap</code> graph coming with raw VisualVM is too simple to do meanful JVM memory monitoring.</p>
<p>Starting <code>Jstatd</code> directly will give you error<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Could not create remote object</span><br><span class="line">access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")</span><br><span class="line">java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")</span><br><span class="line"> at java.security.AccessControlContext.checkPermission(AccessControlContext.java:372)</span><br><span class="line"> ...</span><br></pre></td></tr></table></figure></p>
<p>You can refer to the offical document <a href="https://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstatd.html" target="_blank" rel="noopener">Jstatd</a> and <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/security/PolicyFiles.html" target="_blank" rel="noopener">Policy File Syntax</a>.</p>
<p>Basically, you need to first setup a policy file<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">grant codebase "file:${java.home}/../lib/tools.jar" {</span><br><span class="line"> permission java.security.AllPermission;</span><br><span class="line">};</span><br></pre></td></tr></table></figure></p>
<p>The above config uses <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/security/PolicyFiles.html#PropertyExp" target="_blank" rel="noopener">Property Expansion</a>. Please note that</p>
<blockquote>
<p>If a property can’t be expanded in a grant entry, permission entry, or keystore entry, that entry is ignored.</p>
</blockquote>
<p>Then start jstatd with<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jstatd -J-Djava.security.policy=/home/benson/jmxremote/jstatd.all.policy -J-Djava.rmi.server.hostname=xxx</span><br></pre></td></tr></table></figure></p>
<p>you may also specify <code>-J-Djava.rmi.server.logCalls=true</code> for debugging purpose.<br>Please note that you need to specify <code>java.rmi.server.hostname</code> as before.</p>
<p>By default, the above command will start jstatd with an internal RMI registry, bound to the default port 1099. Besides, it will also randomly pick a port for the RMI connector.</p>
<blockquote>
<p>Note: If your JVM process is behind a firewall, you need to take special care to have this random port open to your monitor client.</p>
</blockquote>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/jvm_monitor/" data-id="cju7m62pj000bc6qahgmas9hh" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-setup_nginx_for_msa_development" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/setup_nginx_for_msa_development/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/setup_nginx_for_msa_development/">Setup Nginx for MSA Development</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<h2 id="Problems-to-solve"><a href="#Problems-to-solve" class="headerlink" title="Problems to solve"></a>Problems to solve</h2><p>Our product consists of several sub-systems. Each sub-system is developed and maintained by a different team. And code-wise, the entire product is organized with Maven in a big Git repository (acutally, better to be splitted) and each sub-system is maintained as a Maven module.</p>
<p>Originally, to setup environment for development, we have to build all modules besides the ones we are turely responsible for. The drawback is obvious, it takes two much time to build the whole project. And as the number of modules increases, this problem becomes worser. In addition, to incooperate changes from other module during development, each time we have to recompile those modules. Although we can utilize Maven to only build partial or specific modules, it’s still a bit annoying.<br>Last but not least, it can be quite difficult to setup everything you needed if one modules have many indirect dependencies, which may require different configurations to startup. </p>
<h2 id="Solution"><a href="#Solution" class="headerlink" title="Solution"></a>Solution</h2><p>To migarte this problem, we maintain a running product instance containing all sub-systems, which is updated on a regular basis (Say one day). Let’s call such environment as “Development environment”. And setup Nginx locally to route the requests generated during development to the right place. Specifically, say I’m developing module A, then I will instruct the Nginx instance to route all requests to module A to my local web server, while route all other requests to “Development enviroment”.</p>
<p>In this way, we only need to care about the module we developed. Other modules are built and updated automatically.</p>
<h2 id="Setup-Nginx-for-routing"><a href="#Setup-Nginx-for-routing" class="headerlink" title="Setup Nginx for routing"></a>Setup Nginx for routing</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> {</span><br><span class="line"> <span class="comment"># make your nginx listen to 8089</span></span><br><span class="line"> <span class="attribute">listen</span> <span class="number">8089</span> default_server; </span><br><span class="line"></span><br><span class="line"> <span class="attribute">root</span> /var/www/html;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">index</span> index.html index.htm;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">server_name</span> _;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">location</span> / {</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line"> <span class="comment"># suppose your local server listens to 8080</span></span><br><span class="line"> <span class="attribute">proxy_pass</span> http://localhost:8080;</span><br><span class="line"> <span class="comment"># enable intercepting HTTP errors codes </span></span><br><span class="line"> <span class="attribute">proxy_intercept_errors</span> <span class="literal">on</span>;</span><br><span class="line"> <span class="comment"># internal rediret to error page defined by "@404found" when the error code is 404, and override the return code</span></span><br><span class="line"> <span class="attribute">error_page</span> <span class="number">404</span> = @404found;</span><br><span class="line"> <span class="comment"># the following config is needed for websocket proxying</span></span><br><span class="line"> <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Connection <span class="string">"Upgrade"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="attribute">location</span> @404found {</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Host <span class="variable">$http_host</span>;</span><br><span class="line"> <span class="attribute">proxy_pass</span> <URL for your development enviroment>;</span><br><span class="line"> <span class="comment"># the following config is needed for websocket proxying</span></span><br><span class="line"> <span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Upgrade <span class="variable">$http_upgrade</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> Connection <span class="string">"Upgrade"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>The above Nginx config, you need to access your local development server via localhost:8089 and the Nginx server will do the routing for you.</p>
<h2 id="Debug-Nginx-Setting"><a href="#Debug-Nginx-Setting" class="headerlink" title="Debug Nginx Setting"></a>Debug Nginx Setting</h2><p>It would be greate to debug your Nginx setting. It can be annoying when you make some wrong configuration but don’t know where it is. Refer to this URL for <a href="https://kimsereyblog.blogspot.com/2018/08/inspect-proxied-requests-from-nginx-to.html" target="_blank" rel="noopener">debugging</a> </p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/setup_nginx_for_msa_development/" data-id="cju7m62pk000cc6qave9wrbul" class="article-share-link">Share</a>
</footer>
</div>
</article>
<article id="post-tmux" class="article article-type-post" itemscope="" itemprop="blogPost">
<div class="article-meta">
<a href="/2019/04/08/tmux/" class="article-date">
<time datetime="2019-04-08T00:00:00.000Z" itemprop="datePublished">2019-04-08</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2019/04/08/tmux/">Use tmux to manage your remote server</a>
</h1>
</header>
<div class="article-entry" itemprop="articleBody">
<p>Concepts: one sesson can have multiple windows, and one window can have multiple panels.</p>
<p>Suppose now you just ssh to your remote server.<br>First create a new tmux session. By default, it has one window and one panel in it.<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tmux</span><br></pre></td></tr></table></figure></p>
<p>Give the session a meaningful name, so that you can later attach to it easily<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> $</span><br></pre></td></tr></table></figure></p>
<p>Give the current window a meaningful name<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> ,</span><br></pre></td></tr></table></figure></p>
<p>Split the current panel<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><prefix> % // horizontally</span><br><span class="line"><prefix> <span class="string">" // vertically</span></span><br></pre></td></tr></table></figure></p>
<p>Oops, you create a new panel by mistake. Let’s close it<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> x</span><br></pre></td></tr></table></figure></p>
<p>And now you have too many panels in one window, let’s create a new window<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> c</span><br></pre></td></tr></table></figure></p>
<p>Switch between windows<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><prefix> n // to next</span><br><span class="line"><prefix> p // to previous</span><br></pre></td></tr></table></figure></p>
<p>And close a window<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> & // close a window</span><br></pre></td></tr></table></figure></p>
<p>Now you have your work done. While closing your connection to remote server, you want your program keep running.<br>Or, you want to pick up where you was later. It’s easy, just detach the session<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><prefix> d</span><br></pre></td></tr></table></figure></p>
<p>Serval days later, you come back and want to resume your work. First, list all session alive in the backend.<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tmux ls</span><br></pre></td></tr></table></figure></p>
<p>Attach to your desired session by name<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tmux a -t <name></span><br></pre></td></tr></table></figure></p>
<p>These commands are pretty much you need for tmux.</p>
</div>
<footer class="article-footer">
<a data-url="http://yoursite.com/2019/04/08/tmux/" data-id="cju7m62pk000dc6qa6udpro3s" class="article-share-link">Share</a>
</footer>
</div>
</article>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Archives</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/04/">April 2019</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">Recent Posts</h3>
<div class="widget">
<ul>
<li>
<a href="/2019/04/20/connect_is_not_available/">HikariPool-1 - Connection is not available</a>
</li>
<li>
<a href="/2019/04/08/copy_file/">How to copy files fastly</a>
</li>
<li>
<a href="/2019/04/08/create-your-own-blog/">Create blog with Hexo on Git Page</a>
</li>
<li>
<a href="/2019/04/08/gaaccess/">Using GoAccess to monitor your nginx access log</a>
</li>
<li>
<a href="/2019/04/08/import_spring_framework_source/">Import spring-framework into Eclipse</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2019 Beson<br>
Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
<script src="/fancybox/jquery.fancybox.pack.js"></script>
<script src="/js/script.js"></script>
</div>
</body>
</html>