-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
550 lines (266 loc) · 436 KB
/
atom.xml
File metadata and controls
550 lines (266 loc) · 436 KB
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>才学浅</title>
<link href="https://chengzc.club/atom.xml" rel="self"/>
<link href="https://chengzc.club/"/>
<updated>2023-05-09T06:15:48.000Z</updated>
<id>https://chengzc.club/</id>
<author>
<name>ChengZC</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>反编译第三方jar包</title>
<link href="https://chengzc.club/posts/3671369038/"/>
<id>https://chengzc.club/posts/3671369038/</id>
<published>2023-05-09T06:15:46.000Z</published>
<updated>2023-05-09T06:15:48.000Z</updated>
<content type="html"><![CDATA[<p>修改一个已经编译好的第三方jar包的class文件,需要先反编译jar包,将其转化成可编辑的Java源码文件。可以使用一些反编译工具如jad、jd-gui、procyon等来实现反编译。这里以jd-gui为例,具体步骤如下:</p><ol><li>下载并安装<a href="https://github.com/java-decompiler/jd-gui/releases/tag/v1.6.6">JD-GUI 1.6.6</a>软件;</li><li>打开jd-gui软件,选择“File”→“Open”,在弹出的窗口中找到需要修改的jar包,然后点击“OK”;<br><img src="https://img.chengzc.club/i/2023/05/09/6459e6fbc4b93.png" alt="https://img.chengzc.club/i/2023/05/09/6459e6fbc4b93.png"></li><li>在jd-gui中找到需要修改的类文件,右键点击该文件,选择“Save All Source”,将该jar包输出到本地目录。<br><img src="https://img.chengzc.club/i/2023/05/09/6459e73d9d27d.png" alt="https://img.chengzc.club/i/2023/05/09/6459e73d9d27d.png"></li><li>使用IDEA或者其他开发工具打开项目目录,配置class文件输出目录<br><img src="https://img.chengzc.club/i/2023/05/09/6459eff62e72b.png" alt="https://img.chengzc.club/i/2023/05/09/6459eff62e72b.png"></li><li>根据编译器提示,导入需要的包,保证项目编译通过<br><img src="https://img.chengzc.club/i/2023/05/09/6459f052a7554.png" alt="https://img.chengzc.club/i/2023/05/09/6459f052a7554.png"></li><li>修改对应的Java源码文件,生成class文件;<br><img src="https://img.chengzc.club/i/2023/05/09/6459f35f6d719.jpg" alt="https://img.chengzc.club/i/2023/05/09/6459f35f6d719.jpg"></li><li>将修改后的class文件替换原来的class文件,放到项目中测试。<br><img src="https://img.chengzc.club/i/2023/05/09/6459f5e2e1dd2.png" alt="https://img.chengzc.club/i/2023/05/09/6459f5e2e1dd2.png"><br><img src="https://img.chengzc.club/i/2023/05/09/6459f6135a655.png" alt="https://img.chengzc.club/i/2023/05/09/6459f6135a655.png"></li></ol>]]></content>
<summary type="html"><p>修改一个已经编译好的第三方jar包的class文件,需要先反编译jar包,将其转化成可编辑的Java源码文件。可以使用一些反编译工具如jad、jd-gui、procyon等来实现反编译。这里以jd-gui为例,具体步骤如下:</p>
<ol>
<li>下载并安装<a hre</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="java" scheme="https://chengzc.club/tags/java/"/>
<category term="编译" scheme="https://chengzc.club/tags/%E7%BC%96%E8%AF%91/"/>
</entry>
<entry>
<title>使用自建RocketMq消息队列调试服务</title>
<link href="https://chengzc.club/posts/712115305/"/>
<id>https://chengzc.club/posts/712115305/</id>
<published>2023-04-24T09:25:24.000Z</published>
<updated>2023-04-24T16:32:39.000Z</updated>
<content type="html"><![CDATA[<h2 id="一-背景"><a href="#一-背景" class="headerlink" title="一 背景"></a><strong>一 背景</strong></h2><p>公司很多服务都用到消息队列,不过之前只有正式的mq,和测试分不开,之前的crm补丁用的Play,服务在接收测试消息时影响到正式服务,还有一方面,因为网站端把注册,登录,推广,提醒消息都往一个mq里面发,这样会导致消息积累,注册数据进入CRM有延时,所以之前自建了一个mq,将消息进行转发,防止消息积累,也可以方便自己测试,和查看mq运行情况</p><h2 id="二-安装环境"><a href="#二-安装环境" class="headerlink" title="二 安装环境"></a><strong>二 安装环境</strong></h2><ol><li>公网服务器一台</li><li>安装JDK环境</li><li>安装MAVEN环境</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64464b3b213d3.png" alt="https://img.chengzc.club/i/2023/04/24/64464b3b213d3.png"></p><h2 id="三-RocketMQ下载"><a href="#三-RocketMQ下载" class="headerlink" title="三 RocketMQ下载"></a><strong>三 RocketMQ下载</strong></h2><ol><li><a href="https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.6.0/rocketmq-all-4.6.0-source-release.zip">从Apcehe下载</a></li><li><a href="https://github.com/apache/rocketmq">从GitHup上下载</a></li><li><a href="https://github.com/apache/rocketmq-externals">下载rocketmq管理可视化页面</a></li><li>下载完成,解压文件</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64464b4cc6e82.png" alt="https://img.chengzc.club/i/2023/04/24/64464b4cc6e82.png">![]</p><h2 id="四-配置文件修改"><a href="#四-配置文件修改" class="headerlink" title="四 配置文件修改"></a><strong>四 配置文件修改</strong></h2><ol><li>进入rocket4.7.1/conf,修改broker.conf配置文件</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64464b5bd195e.png" alt="https://img.chengzc.club/i/2023/04/24/64464b5bd195e.png"></p><blockquote><p>注意:默认服务端口是9876,在防火墙我们不仅需要放开9876端口,同时还要放开10911, 10912, 10909这三个端口才行,不然连接服务会报错。</p></blockquote><ol><li>10911是remotingServer使用的监听端口,remotingServer主要处理以下三类消息</li><li>producer发送的消息</li><li>conumser在消费失败或者消费超时发送的消息</li><li>consumer拉取消息</li><li>10912是主broker用于监听从broker请求的监听端口。</li><li>10909是fastRemotingServer使用的监听端口,与remotingServer相似,但是不包含处理拉取消息的请求。在vipChannelEnabled开启时,producer,consumer发送消息才发送到</li><li>进入rocket4.7.1/bin,修改bin/目录下的runserver.sh、runbroker.sh这两个文件,我的服务器配置比较拉,内存设置稍微小一点,不然会经常报内存溢出</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64464b69c8334.png" alt="https://img.chengzc.club/i/2023/04/24/64464b69c8334.png"></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464b735586f.png" alt="https://img.chengzc.club/i/2023/04/24/64464b735586f.png">![]</p><h2 id="五-MQ服务启动"><a href="#五-MQ服务启动" class="headerlink" title="五 MQ服务启动"></a><strong>五 MQ服务启动</strong></h2><p>启动mqnamesrv和mqbroker</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup sh /usr/local/rocketMQ/rocket4.7.1/bin/mqnamesrv -n 119.29.217.197:9876 &nohup sh /usr/local/rocketMQ/rocket4.7.1/bin/mqbroker -n 119.29.217.197:9876 -c /usr/local/rocketMQ/rocket4.7.1/conf/broker.conf &</span><br></pre></td></tr></table></figure><p><img src="https://img.chengzc.club/i/2023/04/24/64464b81e93fd.png" alt="https://img.chengzc.club/i/2023/04/24/64464b81e93fd.png"></p><h2 id="六-安装RockeMQ-可视化界面"><a href="#六-安装RockeMQ-可视化界面" class="headerlink" title="六 安装RockeMQ****可视化界面"></a><strong>六</strong> <strong>安装RockeMQ****可视化界面</strong></h2><ol><li>进入之前下载解压好的文件夹下rocketMQ/rocketUI/rocketmq-console</li></ol><p><code>修改配置文件/usr/local/rocketMQ/rocketUI/rocketmq-console/src/main/resources</code></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464c148517d.png" alt="https://img.chengzc.club/i/2023/04/24/64464c148517d.png"></p><ol start="2"><li>编译mq可视化服务</li></ol><figure class="highlight shell"><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">cd /usr/local/rocketMQ/rocketUI/rocketmq-console</span><br><span class="line">mvn clean package -Dmaven.test.skip=true</span><br></pre></td></tr></table></figure><p><img src="https://img.chengzc.club/i/2023/04/24/64464b8c5c9ea.png" alt="https://img.chengzc.club/i/2023/04/24/64464b8c5c9ea.png"></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464ba01f45a.png" alt="https://img.chengzc.club/i/2023/04/24/64464ba01f45a.png"></p><h2 id="七-运行服务,查看服务状态"><a href="#七-运行服务,查看服务状态" class="headerlink" title="七 运行服务,查看服务状态"></a><strong>七 运行服务,查看服务状态</strong></h2><p><code>nohup java -jar /usr/local/rocketMQ/rocketUI/rocketmq-console/target/rocketmq-console-ng-2.0.0.jar &</code></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464babc0738.png" alt="https://img.chengzc.club/i/2023/04/24/64464babc0738.png"></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464bb40d381.png" alt="https://img.chengzc.club/i/2023/04/24/64464bb40d381.png"></p><p><img src="https://img.chengzc.club/i/2023/04/24/64464bbcdaa15.png" alt="https://img.chengzc.club/i/2023/04/24/64464bbcdaa15.png"></p><p>可以看到服务已正常启动,可以根据需要自己创建topic,group,连接mq进行消息发送,也能在可视化界面手动发送指定消息</p>]]></content>
<summary type="html"><h2 id="一-背景"><a href="#一-背景" class="headerlink" title="一 背景"></a><strong>一 背景</strong></h2><p>公司很多服务都用到消息队列,不过之前只有正式的mq,和测试分不开,之前的crm补丁用的Pl</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="RocketMq" scheme="https://chengzc.club/tags/RocketMq/"/>
<category term="服务器" scheme="https://chengzc.club/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
</entry>
<entry>
<title>PlayFramework请求堵塞</title>
<link href="https://chengzc.club/posts/1361951458/"/>
<id>https://chengzc.club/posts/1361951458/</id>
<published>2023-04-24T09:20:35.000Z</published>
<updated>2023-04-24T09:20:34.000Z</updated>
<content type="html"><![CDATA[<h3 id="我"><a href="#我" class="headerlink" title="我"></a>我</h3><p>playframework请求堵塞</p><h3 id="ChatGPT"><a href="#ChatGPT" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>Play框架是一种异步的Web框架,它使用非阻塞I/O模型来处理请求。这意味着每个请求都不会阻塞线程,而是在异步的执行上下文中处理。</p><p>然而,如果您的应用程序中存在某些阻塞操作(如数据库查询或网络请求),它们可能会导致请求堵塞。这样做会使应用程序的性能变差,因为它会占用服务器上的线程,从而减少可用的线程池大小。</p><p>为了避免这种情况,您可以使用Play框架提供的异步API。这些API允许您将阻塞操作委托给另一个执行上下文,从而使请求不会被阻塞。</p><p>例如,如果您需要执行一个数据库查询,您可以使用Play的异步API来执行该查询并在完成后返回结果。这样,您的线程将在查询执行期间保持空闲状态,从而允许其他请求使用该线程。</p><p>总之,为了避免Play框架请求堵塞,您应该尽可能使用异步API,并避免在请求处理期间执行阻塞操作。</p><h3 id="我-1"><a href="#我-1" class="headerlink" title="我"></a>我</h3><p>异步api示例</p><h3 id="ChatGPT-1"><a href="#ChatGPT-1" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>以下是一个使用Play框架异步API的示例</p><h3 id="我-2"><a href="#我-2" class="headerlink" title="我"></a>我</h3><p>异步api示例</p><h3 id="ChatGPT-2"><a href="#ChatGPT-2" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>以下是一个使用Play框架异步API的示例:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyController</span> <span class="keyword">extends</span> <span class="title class_">Controller</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> CompletionStage<Result> <span class="title function_">getUserDetails</span><span class="params">(String userId)</span> {</span><br><span class="line"> <span class="comment">// 使用异步API执行数据库查询</span></span><br><span class="line"> <span class="keyword">return</span> CompletableFuture.supplyAsync(() -> {</span><br><span class="line"> <span class="keyword">return</span> User.find.byId(userId);</span><br><span class="line"> }).thenApplyAsync(user -> {</span><br><span class="line"> <span class="comment">// 在异步执行上下文中处理结果</span></span><br><span class="line"> <span class="keyword">if</span> (user == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> notFound(<span class="string">"User not found"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> ok(Json.toJson(user));</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在上面的示例中,我们使用了<code>CompletableFuture.supplyAsync</code>方法来异步执行数据库查询。然后,我们使用<code>thenApplyAsync</code>方法将查询结果处理为<code>Result</code>对象。在这个过程中,我们没有阻塞任何线程,因为查询是在另一个执行上下文中执行的。</p><p>请注意,如果您使用的是Java 8之前的版本,则可以使用<code>play.libs.F.Function0</code>和<code>play.libs.F.Promise</code>来执行相同的操作。例如:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyController</span> <span class="keyword">extends</span> <span class="title class_">Controller</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Promise<Result> <span class="title function_">getUserDetails</span><span class="params">(String userId)</span> {</span><br><span class="line"> <span class="comment">// 使用异步API执行数据库查询</span></span><br><span class="line"> Promise<User> promise = Promise.promise(() -> {</span><br><span class="line"> <span class="keyword">return</span> User.find.byId(userId);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在异步执行上下文中处理结果</span></span><br><span class="line"> <span class="keyword">return</span> promise.map(user -> {</span><br><span class="line"> <span class="keyword">if</span> (user == <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> notFound(<span class="string">"User not found"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> ok(Json.toJson(user));</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这个示例中,我们使用了<code>Promise.promise</code>方法来异步执行数据库查询,并使用<code>map</code>方法将结果处理为<code>Result</code>对象。</p><h3 id="我-3"><a href="#我-3" class="headerlink" title="我"></a>我</h3><p>查看mysql用户拥有的权限</p><h3 id="ChatGPT-3"><a href="#ChatGPT-3" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>可以使用以下命令查看MySQL用户拥有的权限:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">SHOW GRANTS FOR 'username'@'localhost';</span><br></pre></td></tr></table></figure><p>其中,<code>username</code>为要查看权限的用户的用户名,<code>localhost</code>为该用户的主机名。如果该用户可以从任何主机登录,则可以使用<code>%</code>代替<code>localhost</code>。</p><p>执行上述命令后,MySQL将显示该用户拥有的所有权限。</p><h3 id="我-4"><a href="#我-4" class="headerlink" title="我"></a>我</h3><p>linux查看哪些服务占用内存</p><h3 id="ChatGPT-4"><a href="#ChatGPT-4" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>可以使用以下命令查看Linux系统中占用内存的服务:</p><ol><li>top命令</li></ol><p>在终端输入top命令,可以查看系统中所有进程的信息,包括CPU和内存占用情况。按下Shift+M可以将进程按照内存使用量排序,从而找到占用内存较多的服务。</p><ol start="2"><li>ps命令</li></ol><p>在终端输入ps aux命令,可以查看系统中所有进程的详细信息,包括进程号、用户、CPU和内存占用情况等。可以根据内存占用情况进行排序,找到占用内存较多的服务。</p><ol start="3"><li>systemctl命令</li></ol><p>在终端输入systemctl status命令,可以查看系统中所有正在运行的服务的状态信息,包括内存占用情况。可以根据内存占用情况进行排序,找到占用内存较多的服务。</p><ol start="4"><li>htop命令</li></ol><p>htop是一个类似于top的命令行工具,可以更加直观地显示系统中进程的信息,包括CPU和内存占用情况。可以按下F6键选择按照内存占用情况排序,找到占用内存较多的服务。</p><h3 id="我-5"><a href="#我-5" class="headerlink" title="我"></a>我</h3><p>ps aux如何根据内存占用排序</p><h3 id="ChatGPT-5"><a href="#ChatGPT-5" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>可以使用ps aux命令结合sort命令来根据内存占用排序。具体操作如下:</p><ol><li><p>在终端输入ps aux命令,查看系统中所有进程的详细信息,包括进程号、用户、CPU和内存占用情况等。</p></li><li><p>在终端输入以下命令,将进程根据内存占用情况进行排序:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux --sort=-%mem</span><br></pre></td></tr></table></figure><p>这个命令中,–sort表示排序的方式,-表示降序排列,%mem表示根据内存占用情况进行排序。</p></li><li><p>执行以上命令后,系统会按照内存占用情况从大到小排序,显示所有进程的详细信息。可以根据需要找到占用内存较多的服务。</p></li></ol><p>注意:如果使用该命令查看进程的内存占用情况,需要注意单位是KB。如果需要以MB或GB为单位显示,可以在命令中加上–human选项,例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux --sort=-%mem --human</span><br></pre></td></tr></table></figure><p>这样就可以以MB或GB为单位显示进程的内存占用情况了。</p>]]></content>
<summary type="html"><h3 id="我"><a href="#我" class="headerlink" title="我"></a>我</h3><p>playframework请求堵塞</p>
<h3 id="ChatGPT"><a href="#ChatGPT" class="headerlin</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="chatgpt" scheme="https://chengzc.club/tags/chatgpt/"/>
<category term="Play" scheme="https://chengzc.club/tags/Play/"/>
<category term="Linux" scheme="https://chengzc.club/tags/Linux/"/>
</entry>
<entry>
<title>数据库表结构导出</title>
<link href="https://chengzc.club/posts/2340987232/"/>
<id>https://chengzc.club/posts/2340987232/</id>
<published>2023-04-24T09:18:03.000Z</published>
<updated>2023-04-24T16:52:48.000Z</updated>
<content type="html"><![CDATA[<h1 id="数据库表结构导出"><a href="#数据库表结构导出" class="headerlink" title="数据库表结构导出"></a>数据库表结构导出</h1><h2 id="来自你的消息"><a href="#来自你的消息" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>mysqldump导出数据库的表结构,不需要数据</p><h2 id="来自-ChatGPT-的消息"><a href="#来自-ChatGPT-的消息" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>,可以使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u [用户名] -p[密码] --no-data [数据库名] > [导出的文件名].sql</span><br></pre></td></tr></table></figure><p>其中,<code>--no-data</code>参数表示不导出数据,只导出表结构。 <code>[用户名]</code>、<code>[密码]</code>和<code>[数据库名]</code>分别为你的数据库的用户名、密码和数据库名,<code>[导出的文件名].sql</code>为你想要导出的文件名。</p><p>例如:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u root -p --no-data testdb > testdb_structure.sql</span><br></pre></td></tr></table></figure><p>这个命令将testdb数据库的表结构导出为testdb_structure.sql文件,不包含数据。</p><h2 id="来自你的消息-1"><a href="#来自你的消息-1" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>解释下mysqldump -h localhost -u u_app -pczbRp~wd123 –skip-lock-tables -d caizhaobang > caizhaobang.sql</p><h2 id="来自-ChatGPT-的消息-1"><a href="#来自-ChatGPT-的消息-1" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>这个命令是使用mysqldump工具从远程的MySQL服务器 <code>localhost</code> 的 <code>caizhaobang</code> 数据库中导出表结构,不包含数据。以下是对命令中各参数的解释:</p><ul><li><code>-h</code>: 指定MySQL服务器的主机名或IP地址;</li><li><code>-u</code>: 指定MySQL服务器的登录用户名;</li><li><code>-p</code>: 指定MySQL服务器的登录密码;</li><li><code>--skip-lock-tables</code>: 在导出表结构时跳过锁定表的操作。这是为了防止在导出时其他进程修改表的结构而造成的数据不一致性;</li><li><code>-d</code>: 指定要导出的数据库名。这里指导出 <code>caizhaobang</code> 数据库的表结构;</li><li><code>></code>: 将命令输出的结果重定向到一个文件中;</li><li><code>caizhaobang.sql</code>: 指定要导出到的文件名。执行完该命令后,表结构将被保存到 <code>caizhaobang.sql</code> 文件中。</li></ul><h2 id="来自你的消息-2"><a href="#来自你的消息-2" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>mysqldump导出数据表结构卡住</p><h2 id="来自-ChatGPT-的消息-2"><a href="#来自-ChatGPT-的消息-2" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>使用mysqldump导出数据表结构卡住的可能原因有以下几个方面:</p><ol><li>数据库表过大,导致mysqldump处理时间过长,导致卡住。可以尝试将表拆成多个较小的表进行导出,或者增加服务器的CPU和内存等资源;</li><li>没有使用<code>--skip-lock-tables</code>参数,导致mysqldump在导出表结构时尝试锁定表,而其他进程正在使用该表,造成了死锁。可以使用该参数来避免锁定表。</li></ol><p>可以尝试使用以下命令来导出表结构:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u [用户名] -p[密码] --skip-lock-tables --no-data [数据库名] [表名] > [导出的文件名].sql</span><br></pre></td></tr></table></figure><p>其中,<code>[数据库名]</code>和<code>[表名]</code>分别为你要导出的数据库名和数据表名,可以只导出特定的数据表。使用该命令时,需要将<code>--skip-lock-tables</code>参数加入,避免锁定表造成死锁。如果仍然卡住,可以尝试分批导出,或者根据实际情况优化MySQL服务器配置。</p><h2 id="来自你的消息-3"><a href="#来自你的消息-3" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>mysqldump 提示mysqldump: Got error: 2013: “Lost connection to MySQL server at ‘reading initial communication packet’, system error: 104” when trying to connect</p><h2 id="来自-ChatGPT-的消息-3"><a href="#来自-ChatGPT-的消息-3" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>该错误通常发生在mysqldump无法与MySQL服务器建立连接时,可能是由于网络或MySQL服务器配置不正确导致的。以下是可能的解决方案:</p><ol><li>检查网络连接是否正常,确保可以从客户端主机连接到MySQL服务器;</li><li>检查MySQL服务器是否正在运行,并确保正确地配置了IP地址、端口号和其他连接参数;</li><li>检查MySQL服务器的防火墙设置,确保mysqldump客户端的IP地址被允许访问MySQL服务器;</li><li>通过增加<code>--host</code>选项并指定MySQL服务器的主机名或IP地址,强制指定mysqldump连接哪个MySQL服务器:<code>mysqldump -u [用户名] -p [密码] --host=[MySQL服务器IP地址] [数据库名] > [导出的文件名].sql</code>。</li></ol><p>如果这些解决方案无效,可能需要进一步检查MySQL服务器的配置,以确定是否需要对其进行代码修复或升级。</p><h2 id="来自你的消息-4"><a href="#来自你的消息-4" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>本地数据库和正式数据库结构不一样,怎么在不删除本地表的情况下,把正式的表结构导入下来</p><h2 id="来自-ChatGPT-的消息-4"><a href="#来自-ChatGPT-的消息-4" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>你可以使用MySQL Workbench或 Navicat等工具,通过比较本地和正式数据库的表结构差异,自动生成相应的SQL脚本,然后再执行这些SQL脚本将正式数据库的表结构同步到本地数据库中。</p><p>以下是具体步骤:</p><ol><li>连接本地和正式数据库,并打开其Schema,将它们按照需要进行比较。</li><li>导出正式数据库的表结构:在工具的图形界面中,选择需要导出表结构的数据库,右键单击该数据库,然后选择“导出”选项。在导出对话框中,选择“只导出结构”选项,然后选择要导出的表,生成需要同步结构的SQL脚本。</li><li>将生成的SQL脚本复制到本地数据库的查询窗口中,执行该脚本。</li><li>执行脚本之后,正式数据库的表结构就同步到了本地数据库中,且本地表数据不会受到影响。</li></ol><p>需要注意的是,在同步表结构的过程中,如果正式数据库中的某个表或字段的设置与本地数据库不同,则可能会出现一些问题。此时,需要手动处理这些问题,并根据具体情况进行修复。</p>]]></content>
<summary type="html"><h1 id="数据库表结构导出"><a href="#数据库表结构导出" class="headerlink" title="数据库表结构导出"></a>数据库表结构导出</h1><h2 id="来自你的消息"><a href="#来自你的消息" class="headerli</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="chatgpt" scheme="https://chengzc.club/tags/chatgpt/"/>
<category term="数据库" scheme="https://chengzc.club/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
</entry>
<entry>
<title>Git删除远程已提交文件,保留本地副本</title>
<link href="https://chengzc.club/posts/1579996637/"/>
<id>https://chengzc.club/posts/1579996637/</id>
<published>2023-04-24T09:01:26.000Z</published>
<updated>2023-04-24T09:08:05.000Z</updated>
<content type="html"><![CDATA[<h1 id="不想推送文件"><a href="#不想推送文件" class="headerlink" title="不想推送文件"></a>不想推送文件</h1><h2 id="来自你的消息"><a href="#来自你的消息" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git commit的文件不想push到远程库,怎么解决</p><h2 id="来自-ChatGPT-的消息"><a href="#来自-ChatGPT-的消息" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>可以使用git的忽略文件机制来解决这个问题。</p><ol><li>在仓库根目录下创建一个名为.gitignore的文件。</li><li>在该文件中列出您想忽略的文件和/或文件夹的名称。例如,如果您想忽略文件“temp.txt”,则可以这样编写:</li></ol><p>temp.txt</p><p>如果您想忽略整个文件夹“logs”,则可以这样编写:</p><p>logs/</p><ol start="3"><li>执行git add和git commit命令以将.gitignore文件添加到本地仓库中。</li><li>提交更改后,git将不会跟踪列在.gitignore文件中的文件和文件夹。</li></ol><p>请注意,如果.gitignore文件中列出的文件/文件夹已经被git跟踪,那么您需要使用git rm –cached命令将它们从git跟踪列表中删除,然后再添加到.gitignore文件中。</p><h2 id="来自你的消息-1"><a href="#来自你的消息-1" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git rm –cached 怎么删除指定的文件</p><h2 id="来自-ChatGPT-的消息-1"><a href="#来自-ChatGPT-的消息-1" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>可以使用以下命令删除指定文件:</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">git <span class="built_in">rm</span> --cached <filename></span><br></pre></td></tr></table></figure><p>其中,<code><filename></code> 指定要从Git缓存中删除的文件名。</p><p>注意,使用 <code>--cached</code> 参数只会从缓存中删除文件,而不会从工作目录中删除文件。如果您想同时从缓存和工作目录中删除一个文件,需要去掉 <code>--cached</code> 参数,并在执行 <code>git rm</code> 命令后再执行 <code>rm</code> 命令,例如:</p><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">git <span class="built_in">rm</span> <filename></span><br><span class="line"><span class="built_in">rm</span> <filename></span><br></pre></td></tr></table></figure><p>这将从缓存和工作目录中删除指定的文件。</p><p>在执行 <code>git rm</code> 命令后还需要执行 <code>git commit</code> 命令提交更改,以使指定文件从仓库中删除。</p><h2 id="来自你的消息-2"><a href="#来自你的消息-2" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git push 的时候提示push rejected</p><h2 id="来自-ChatGPT-的消息-2"><a href="#来自-ChatGPT-的消息-2" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当执行 <code>git push</code> 命令时,如果远程库拒绝了push操作,通常会出现 “push rejected” 的提示信息。 这种情况通常有以下几种原因:</p><ol><li>您没有权限向该仓库推送代码。这种情况可能是因为您没有通过认证或您没有被授权访问该仓库。您可以联系仓库管理员来解决这个问题。</li><li>您试图推送到一个保护分支,但没有被授权。 对于受保护的分支,只有授权用户才能推送更改。您可以查看仓库的分支保护规则以了解更多信息。</li><li>远程仓库的更新使您的推送不再是快进合并。 这种情况下,你需要先将远程库的更新pull到本地仓库,然后再push您的更改。 您可以使用 <code>git pull</code> 命令或 <code>git pull --rebase</code> 命令拉取远程库的更改,然后再执行您的推送操作。</li><li>您正在尝试推送一个空的分支。 Git默认情况下不会推送空分支。 请确保您的本地分支中有更改并且已经提交。 或者,您可以使用 <code>git push --force</code> 命令强制推送一个空分支。</li><li>远程分支已被删除。 在此情况下,您需要使用 <code>git fetch --prune</code> 命令清理您的本地分支,然后重新拉取新的分支。</li></ol><p>以上是常见的几种 push rejected 的原因。您可以根据具体情况进行调整。</p><h2 id="来自你的消息-3"><a href="#来自你的消息-3" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git pull 提示app/xiaoke/utils/XiaokeTest.java</p><h2 id="来自-ChatGPT-的消息-3"><a href="#来自-ChatGPT-的消息-3" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当执行 <code>git pull</code> 命令时,如果提示某个文件被修改,这通常是由于您的本地分支和远程分支之间存在冲突而引起的。</p><p>如果提示的文件是 <code>app/xiaoke/utils/XiaokeTest.java</code>,则说明该文件在远程分支上发生了变化,并且和您当前的本地分支发生了冲突。</p><p>在这种情况下,需要进行合并操作,合并操作的具体步骤如下:</p><ol><li>在合并之前,您需要先保存当前分支的更改,可以使用以下命令进行提交:</li></ol><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">git add .</span><br><span class="line">git commit -m <span class="string">"save the local changes"</span></span><br></pre></td></tr></table></figure><ol start="2"><li>然后,拉取远程分支:</li></ol><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">git pull</span><br></pre></td></tr></table></figure><ol start="3"><li>如果有冲突,则需要您手动解决冲突,并再次提交:</li></ol><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">git add .</span><br><span class="line">git commit -m <span class="string">"resolve the conflict"</span></span><br></pre></td></tr></table></figure><ol start="4"><li>最后,您可以将更改推送到远程分支:</li></ol><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">git push</span><br></pre></td></tr></table></figure><p>在合并冲突时,请确保仔细查看每个更改以确保不会丢失任何重要更改。</p><h2 id="来自你的消息-4"><a href="#来自你的消息-4" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git pull提示refusing to merge unrelated histories</p><h2 id="来自-ChatGPT-的消息-4"><a href="#来自-ChatGPT-的消息-4" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当执行 <code>git pull</code> 命令时,如果提示 “refusing to merge unrelated histories”,这表示您的本地分支和远程分支没有共同的祖先。它们是两个独立的仓库,不能合并。</p><p>这种情况通常出现在您使用了 <code>git init</code> 命令创建了一个新的本地仓库,然后尝试将其与远程仓库进行合并的情况下。</p><p>要解决这个问题,您可以尝试以下几种方法:</p><ol><li>如果您的本地仓库不需要保留历史记录,可以使用以下命令强制合并:</li></ol><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">git pull origin master --allow-unrelated-histories</span><br></pre></td></tr></table></figure><ol start="2"><li>如果您希望保留本地仓库中的所有更改,而不是采用远程仓库的版本,则可以使用以下命令将本地分支推送到远程分支:</li></ol><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">git push --set-upstream origin master</span><br></pre></td></tr></table></figure><p>这将创建一个新的远程分支,它的历史记录将从您的本地分支开始。</p><ol start="3"><li>如果您想要通过合并来保留您的本地更改并获得远程版本的更新,则可以使用以下命令:</li></ol><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">git fetch origin</span><br><span class="line">git merge origin/master</span><br></pre></td></tr></table></figure><p>请注意,在这种情况下,如果您的本地分支和远程分支有任何冲突,您需要手动解决冲突。</p><p>希望以上方法有助于解决您的问题。</p><h2 id="来自你的消息-5"><a href="#来自你的消息-5" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>提示fatal: refusing to merge unrelated histories</p><h2 id="来自-ChatGPT-的消息-5"><a href="#来自-ChatGPT-的消息-5" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当执行 <code>git merge</code> 命令或 <code>git pull</code> 命令时,如果提示 “fatal: refusing to merge unrelated histories”,这表示您的本地分支和远程分支没有共同的祖先,它们是两个独立的仓库,不能合并。</p><p>这种情况通常出现在您使用了 <code>git init</code> 命令创建了一个新的本地仓库,然后尝试将其与远程仓库进行合并的情况下。</p><p>要解决这个问题,您可以尝试以下几种方法:</p><ol><li>如果您的本地仓库不需要保留历史记录,可以使用以下命令强制合并:</li></ol><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">git merge origin/master --allow-unrelated-histories</span><br></pre></td></tr></table></figure><ol start="2"><li>如果您希望保留本地仓库中的所有更改,而不是采用远程仓库的版本,则可以使用以下命令将本地分支推送到远程分支:</li></ol><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">git push --set-upstream origin master</span><br></pre></td></tr></table></figure><p>这将创建一个新的远程分支,它的历史记录将从您的本地分支开始。</p><ol start="3"><li>如果您想要通过合并来同时保留您的本地更改和远程版本的更新,则可以使用以下命令:</li></ol><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">git fetch origin</span><br><span class="line">git merge origin/master</span><br></pre></td></tr></table></figure><p>请注意,在这种情况下,如果您的本地分支和远程分支有任何冲突,您需要手动解决冲突。</p><p>希望以上方法有助于解决您的问题。</p><h2 id="来自你的消息-6"><a href="#来自你的消息-6" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git merge origin/master 提示refusing to merge unrelated histories</p><h2 id="来自-ChatGPT-的消息-6"><a href="#来自-ChatGPT-的消息-6" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当您执行以下命令时:</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">git merge origin/master</span><br></pre></td></tr></table></figure><p>并且提示 “refusing to merge unrelated histories”,这通常表示您的本地分支和远程分支是两个不相关的历史记录。这种情况经常出现在您从远程仓库中拉取了新的代码,而您的本地仓库中也有独立的更改(可能是使用 <code>git init</code> 命令创建了新的本地仓库)。</p><p>如果您想要通过合并来同时保留您的本地更改和远程版本的更新,可以使用以下命令:</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">git pull origin master --allow-unrelated-histories</span><br></pre></td></tr></table></figure><p>这将拉取远程分支并将其合并到您的本地分支,同时保留两者的历史记录。在执行此命令时,您需要手动解决任何冲突。</p><p>如果您希望保留本地仓库中的所有更改,则可以使用以下命令将本地分支推送到远程分支:</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">git push --set-upstream origin master</span><br></pre></td></tr></table></figure><p>这将创建一个新的远程分支,它的历史记录将从您的本地分支开始。</p><p>希望以上方法有助于解决您的问题。</p><h2 id="来自你的消息-7"><a href="#来自你的消息-7" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>执行git pull origin master –allow-unrelated-histories 提示Automatic merge failed; fix conflicts and then commit the result</p><h2 id="来自-ChatGPT-的消息-7"><a href="#来自-ChatGPT-的消息-7" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>当您执行以下命令时:</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">git pull origin master --allow-unrelated-histories</span><br></pre></td></tr></table></figure><p>并且提示 “Automatic merge failed; fix conflicts and then commit the result”,这通常表示拉取远程分支并将其合并到您的本地分支时出现了冲突。</p><p>要解决这个问题,您需要手动解决冲突。通常,Git 将使用合并工具将冲突标记为 <code><<<<<<<</code>,<code>=======</code> 和 <code>>>>>>>></code>,您需要编辑文件以手动解决冲突。</p><p>一旦您解决了冲突,您需要使用以下命令将更改的文件添加到暂存区:</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">git add <file></span><br></pre></td></tr></table></figure><p>然后,使用以下命令提交更改:</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">git commit -m <span class="string">"Resolved conflict"</span></span><br></pre></td></tr></table></figure><p>在提交更改后,您可以使用以下命令将更改推送到远程仓库:</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">git push origin master</span><br></pre></td></tr></table></figure><p>希望这可以帮助您解决问题,如果您需要更多帮助,请告诉我。</p><h2 id="来自你的消息-8"><a href="#来自你的消息-8" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>git rm –cached 整个文件夹</p><h2 id="来自-ChatGPT-的消息-8"><a href="#来自-ChatGPT-的消息-8" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>如果您想要从 Git 中删除整个文件夹(包括它下面的所有文件和子文件夹),需要使用以下命令:</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">git <span class="built_in">rm</span> -r --cached <folder></span><br></pre></td></tr></table></figure><p>其中,<code>-r</code> 选项表示要递归地删除文件夹及其所有子文件夹和文件,<code>--cached</code> 选项表示只从 Git 中删除该文件夹的跟踪,而不会删除在本地已经存在的文件。</p><p>请注意,这只会从 Git 中删除该文件夹的跟踪。如果文件夹之前已经被提交并被其他人克隆了该仓库,则不会删除他们本地的文件夹。如果您要在所有克隆该仓库的计算机中删除该文件夹,您需要通知每个克隆库的用户,让他们手动删除该文件夹。</p><p>希望这可以回答您的问题。</p><h1 id="去除远程-svn文件夹"><a href="#去除远程-svn文件夹" class="headerlink" title="去除远程.svn文件夹"></a>去除远程.svn文件夹</h1><h2 id="来自你的消息-9"><a href="#来自你的消息-9" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>不小心.svn文件夹提交 push到了远程,怎么处理去掉.svn文件夹</p><h2 id="来自-ChatGPT-的消息-9"><a href="#来自-ChatGPT-的消息-9" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><ol><li>使用svn命令从远程仓库中删除.svn文件夹:</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">svn delete <repository_url>/.svn --force</span><br></pre></td></tr></table></figure><ol start="2"><li>从本地文件夹中删除.svn文件夹:</li></ol><figure class="highlight plaintext"><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">cd path/to/local/folder</span><br><span class="line">rm -rf .svn</span><br></pre></td></tr></table></figure><ol start="3"><li>将修改提交到远程仓库:</li></ol><figure class="highlight plaintext"><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">git add .</span><br><span class="line">git commit -m "remove .svn folder"</span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p>注意:上述方法会从远程仓库中删除所有.svn文件夹,所以请确保其它人员不需要这些文件夹。同时,由于.svn文件夹可能包含重要的版本控制信息,因此请谨慎处理。</p><h2 id="来自你的消息-10"><a href="#来自你的消息-10" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>如何从远程里面删除,本地不删除</p><h2 id="来自-ChatGPT-的消息-10"><a href="#来自-ChatGPT-的消息-10" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>如果你想在远程仓库中删除<code>.svn</code>文件夹而不删除本地副本中的<code>.svn</code>文件夹,可以使用以下命令:</p><figure class="highlight plaintext"><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">git rm -r --cached <repository_url>/.svn</span><br><span class="line">git commit -m "Remove .svn folder from remote repository"</span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p>这将从远程仓库中删除<code>.svn</code>文件夹,并在提交更改后将其重新推送到远程仓库中。在这个过程中,本地副本中的<code>.svn</code>文件夹将不会被修改或删除。</p><p>请注意,如果<code>.svn</code>文件夹包含有关远程仓库中文件的更改历史信息,则删除它可能会影响版本控制。因此,请先做好备份,谨慎操作。</p><h2 id="来自你的消息-11"><a href="#来自你的消息-11" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>删除后,不想把.svn文件夹纳入git跟踪,需要怎么处理</p><h2 id="来自-ChatGPT-的消息-11"><a href="#来自-ChatGPT-的消息-11" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>如果你不想将<code>.svn</code>文件夹纳入Git的跟踪中,可以将其添加到<code>.gitignore</code>文件中,以便Git忽略这些文件夹的更改和提交。</p><ol><li>在你的项目根目录下,创建一个<code>.gitignore</code>文件(如果你的项目已经有了<code>.gitignore</code>文件,则可以跳过此步骤)。</li><li>用文本编辑器打开<code>.gitignore</code>文件,并添加以下一行:</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.svn/</span><br></pre></td></tr></table></figure><ol start="3"><li>保存<code>.gitignore</code>文件,并将其推送到远程仓库。此时,Git将忽略任何位于<code>.svn</code>文件夹中的更改和提交。</li></ol><p>注意,添加<code>.svn/</code>到<code>.gitignore</code>文件只是不让Git跟踪<code>.svn</code>文件夹的更改,但是Git会继续跟踪其他未被忽略的文件。如果你希望停止跟踪整个文件夹,可以使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rm -r --cached .svn/</span><br></pre></td></tr></table></figure><p>这将从Git中删除<code>.svn</code>文件夹的所有内容,并停止跟踪它的更改和提交。接下来,将<code>.svn</code>文件夹添加到<code>.gitignore</code>文件中,以确保以后Git不会再次开始跟踪它。</p><h2 id="来自你的消息-12"><a href="#来自你的消息-12" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>删除.svn文件夹提示fatal: pathspec ‘.svn/‘ did not match any files</p><h2 id="来自-ChatGPT-的消息-12"><a href="#来自-ChatGPT-的消息-12" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>如果你尝试从 Git 跟踪中移除 <code>.svn</code> 文件夹时,提示 <code>fatal: pathspec '.svn/' did not match any files</code>,可能是因为该文件夹已经被提交了,但是在本地找不到对应的目录。</p><p>在这种情况下,你需要使用 <code>git ls-files</code> 命令来查看规范化后的 Git 文件列表,确认一下 <code>.svn</code> 文件夹是否包含在内。</p><p>如果确认<code>.svn</code>文件夹被跟踪了,可以使用以下命令将其从 Git 跟踪中删除,并且保留本地 <code>.svn</code> 文件夹:</p><figure class="highlight plaintext"><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">git rm -r --cached .svn</span><br><span class="line">git commit -m "Removed .svn from Git tracking"</span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p>如果仅仅是想在以后的 Git 提交中忽略 <code>.svn</code>,可以在项目根目录下的 <code>.gitignore</code> 文件中添加以下一行:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">.svn/</span><br></pre></td></tr></table></figure><p>保存 <code>.gitignore</code> 文件,然后将其推送到 Git 仓库中。现在,Git 将忽略 <code>.svn</code> 文件夹的任何更改或提交。</p><h2 id="来自你的消息-13"><a href="#来自你的消息-13" class="headerlink" title="来自你的消息:"></a>来自你的消息:</h2><p>已经add. 但是没有commit的文件,怎么加入到忽略文件里,后面都不进行提交</p><h2 id="来自-ChatGPT-的消息-13"><a href="#来自-ChatGPT-的消息-13" class="headerlink" title="来自 ChatGPT 的消息:"></a>来自 ChatGPT 的消息:</h2><p>如果文件已经 add 进 Git 缓存区,但是还没有 commit,可以使用以下命令将其忽略:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git update-index --assume-unchanged <file></span><br></pre></td></tr></table></figure><p>其中 <code><file></code> 是你想要忽略的文件。</p><p>如果你想重新跟踪这个文件,可以使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git update-index --no-assume-unchanged <file></span><br></pre></td></tr></table></figure><p>但是请注意,在这种情况下,这个文件将重新被添加进 Git 缓存区。因此,在以后的提交中,它将再次被包含。如果你想要永久忽略这个文件,你应该将其添加到 <code>.gitignore</code> 文件中。这将确保在以后的提交中都不被包含。</p><p>如果你已经将文件添加到 <code>.gitignore</code> 文件中,并希望将其从 Git 缓存区中删除,可以使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rm --cached <file></span><br></pre></td></tr></table></figure><p>这将从 Git 缓存区中删除指定的文件,但不会将其从文件系统中删除。这使得你可以在本地保留副本,但在以后的提交中不包含它。</p>]]></content>
<summary type="html"><h1 id="不想推送文件"><a href="#不想推送文件" class="headerlink" title="不想推送文件"></a>不想推送文件</h1><h2 id="来自你的消息"><a href="#来自你的消息" class="headerlink" titl</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="git" scheme="https://chengzc.club/tags/git/"/>
<category term="chatgpt" scheme="https://chengzc.club/tags/chatgpt/"/>
</entry>
<entry>
<title>服务器CPU占用异常问题查找</title>
<link href="https://chengzc.club/posts/2912589436/"/>
<id>https://chengzc.club/posts/2912589436/</id>
<published>2023-04-23T15:51:14.000Z</published>
<updated>2023-04-24T08:54:16.000Z</updated>
<content type="html"><![CDATA[<h2 id="背景:阿里云app相关服务器,频繁报警,提示cpu占用异常"><a href="#背景:阿里云app相关服务器,频繁报警,提示cpu占用异常" class="headerlink" title="背景:阿里云app相关服务器,频繁报警,提示cpu占用异常"></a><strong>背景:阿里云app相关服务器,频繁报警,提示cpu占用异常</strong></h2><h2 id="困难-amp-问题:没有相关云资源权限,无法查看报警提示,不知道服务器上运行哪些服务"><a href="#困难-amp-问题:没有相关云资源权限,无法查看报警提示,不知道服务器上运行哪些服务" class="headerlink" title="困难&问题:没有相关云资源权限,无法查看报警提示,不知道服务器上运行哪些服务"></a><strong>困难&问题:没有相关云资源权限,无法查看报警提示,不知道服务器上运行哪些服务</strong></h2><h2 id="解决步骤:"><a href="#解决步骤:" class="headerlink" title="解决步骤:"></a><strong>解决步骤:</strong></h2><ol><li>开通服务器权限,登录服务器,查看当前服务器使用情况</li><li>top命令:查看占用比较多的应用</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455b13587ff.png" alt="1682266898282.png"></p><ol start="3"><li>jps:查看运行的java服务</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455aa189823.png" alt="1682266748093.png"></p><ol start="4"><li>ll /proc/19703/cwd 查看对应pid运行的服务路径</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455aa1d9721.png" alt="1682266754979.png"></p><ol start="5"><li>crontab -l 查看服务定时启动脚本</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455aa28d6bd.png" alt="1682266765377.png"></p><ol start="6"><li>top -p 21972 -H 查看该java应用所用线程占用情况</li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455aa32d6a3.png" alt="1682266776106.png"></p><ol start="7"><li><p>出CPU消耗较多的线程id,如22055,将22055转换为16进制0x5627,注意是小写</p></li><li><p>使用jstack 21972|grep -A 10 0x5627来查询出具体的线程状态</p></li></ol><p><img src="https://img.chengzc.club/i/2023/04/24/64455aa410e4a.png" alt="1682266782713.png"></p><ol start="9"><li>分析负载高的线程栈都是什么业务操作,优化程序并处理问题</li></ol>]]></content>
<summary type="html"><h2 id="背景:阿里云app相关服务器,频繁报警,提示cpu占用异常"><a href="#背景:阿里云app相关服务器,频繁报警,提示cpu占用异常" class="headerlink" title="背景:阿里云app相关服务器,频繁报警,提示cpu占用异常"></a</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="服务器" scheme="https://chengzc.club/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
</entry>
<entry>
<title>Git使用子模块</title>
<link href="https://chengzc.club/posts/2367184701/"/>
<id>https://chengzc.club/posts/2367184701/</id>
<published>2023-04-03T03:12:00.000Z</published>
<updated>2023-04-13T17:32:15.328Z</updated>
<content type="html"><![CDATA[<h3 id="我"><a href="#我" class="headerlink" title="我"></a>我</h3><p>git如何创建子模块关联远程仓库,然后进行拉取和提交</p><h3 id="ChatGPT"><a href="#ChatGPT" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><ol><li>创建子模块并关联远程仓库</li></ol><p>在父仓库中执行以下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule add <远程仓库地址> <子模块目录></span><br></pre></td></tr></table></figure><p>例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule add https://github.com/user/repo.git submodules/repo</span><br></pre></td></tr></table></figure><p>这将在父仓库中创建一个子模块,并将其关联到远程仓库的地址。</p><ol start="2"><li>拉取子模块</li></ol><p>在父仓库中执行以下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule update --init --recursive</span><br></pre></td></tr></table></figure><p>这将拉取子模块的代码,并将其更新到父仓库中。</p><ol start="3"><li>提交子模块</li></ol><p>在父仓库中进行修改后,需要将子模块的修改提交到子模块的仓库中。可以进入子模块目录,使用普通的git命令进行提交。</p><p>例如:</p><figure class="highlight shell"><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">cd submodules/repo</span><br><span class="line">git add .</span><br><span class="line">git commit -m "修改了子模块"</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p>完成子模块的提交后,返回到父仓库,使用普通的git命令提交父仓库的修改即可。</p><p>例如:</p><figure class="highlight shell"><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">cd ..</span><br><span class="line">git add .</span><br><span class="line">git commit -m "修改了父仓库和子模块"</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><h3 id="我-1"><a href="#我-1" class="headerlink" title="我"></a>我</h3><p>可以直接进入子模块目录进行pull吗</p><h3 id="ChatGPT-1"><a href="#ChatGPT-1" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>是的,可以进入子模块目录进行 pull 操作。但是需要注意的是,在父仓库中执行 <code>git submodule update</code> 命令时,可能会出现子模块版本不一致的情况,因为子模块的版本是被固定在父仓库中的。所以在进行 pull 操作之前,最好先进入父仓库中,执行 <code>git submodule update</code> 命令,确保子模块版本和父仓库中的版本一致,再进入子模块目录进行 pull 操作。</p><h3 id="我-2"><a href="#我-2" class="headerlink" title="我"></a>我</h3><p>完整的流程</p><h3 id="ChatGPT-2"><a href="#ChatGPT-2" class="headerlink" title="ChatGPT"></a>ChatGPT</h3><p>下面是使用子模块的完整流程:</p><ol><li>在父仓库中添加子模块并关联远程仓库:</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule add <远程仓库地址> <子模块目录></span><br></pre></td></tr></table></figure><p>例如:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule add https://github.com/user/repo.git submodules/repo</span><br></pre></td></tr></table></figure><ol start="2"><li>提交父仓库的修改:</li></ol><figure class="highlight shell"><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">git add .</span><br><span class="line">git commit -m "添加子模块"</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><ol start="3"><li>拉取子模块:</li></ol><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git submodule update --init --recursive</span><br></pre></td></tr></table></figure><ol start="4"><li>进入子模块目录并拉取子模块的代码:</li></ol><figure class="highlight shell"><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">cd submodules/repo</span><br><span class="line">git pull origin master</span><br></pre></td></tr></table></figure><ol start="5"><li>提交子模块的修改:</li></ol><figure class="highlight shell"><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">git add .</span><br><span class="line">git commit -m "修改子模块"</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><ol start="6"><li>返回父仓库,提交父仓库和子模块的修改:</li></ol><figure class="highlight shell"><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">cd ..</span><br><span class="line">git add .</span><br><span class="line">git commit -m "修改父仓库和子模块"</span><br><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p>这样就完成了使用子模块的流程。在以后的开发中,如果需要更新子模块的代码,只需要进入子模块目录,执行 <code>git pull</code> 命令即可。</p>]]></content>
<summary type="html"><h3 id="我"><a href="#我" class="headerlink" title="我"></a>我</h3><p>git如何创建子模块关联远程仓库,然后进行拉取和提交</p>
<h3 id="ChatGPT"><a href="#ChatGPT" class="</summary>
<category term="生活" scheme="https://chengzc.club/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="git" scheme="https://chengzc.club/tags/git/"/>
<category term="chatgpt" scheme="https://chengzc.club/tags/chatgpt/"/>
</entry>
<entry>
<title>Jenkins持续化管理工具配置</title>
<link href="https://chengzc.club/posts/207851142/"/>
<id>https://chengzc.club/posts/207851142/</id>
<published>2020-04-11T11:14:19.000Z</published>
<updated>2023-04-13T17:28:02.863Z</updated>
<content type="html"><![CDATA[<h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><h4 id="1-准备-Git-仓库"><a href="#1-准备-Git-仓库" class="headerlink" title="1. 准备 Git 仓库"></a>1. 准备 Git 仓库</h4><ul><li><p>1.1. 通过网站右上角的「+」号,选择「新建仓库」,进入新建仓库页面</p></li><li><p><a href=""><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ef879fe2b.png"></a></p></li><li><p>1.2. 新建仓库</p></li><li><p>1.3. 打开项目并点击菜单栏上的【CVS】–》【Import into version control】–》【Create Git Repository】创建本地仓库</p></li><li><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f084633eb.jpg"></p></li><li><p>1.4. 在打开的【Create Git Repository】对话框内选择本地仓库的位置,这里我选择项目的根目录。</p></li><li><p>1.5. 右击项目点击【Git】–》【Add】,接着点击【Git】–》【Commit Directory】在打开的窗口中选择要上传到本地仓库的代码并添加注释后提交到本地仓库内。</p></li><li><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f27061e7a.png"></p></li><li><p>1.6. 右击项目点击【Git】–》【Repository】–》【Remotes…】。在打开的【Git Remotes】窗口中添加码云的远程仓库。码云的远程仓库地址可以在码云仓库内找到。</p></li><li><p>1.7. 点击【OK】后接着输入码云的账号密码。</p></li><li><p>1.8. 上传代码到码云,右击项目点击【Git】–》【Repository】–》【Push…】在打开的【Push commits】内可以看到已提交到本地仓库的提交信息。点击【Push】按钮将本地仓库的代码上传到码云上,上传成功后就可以在码云上看到啦。</p></li></ul><p>如果要同时要提交到github上,可以使用git remote add 命令</p><p><code>git remote add github https://github.com/xxx/test.git</code></p><p>查看远程仓库,可以看到同时有github和gitee选择对应的仓库进行推送和拉取</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">git remote</span><br><span class="line">github</span><br><span class="line">oschina</span><br><span class="line"></span><br><span class="line">git remote -v</span><br><span class="line">github https://github.com/xxx/test.git (fetch)</span><br><span class="line">github https://github.com/xxx/test.git (push)</span><br><span class="line">oschina https://git.oschina.net/xxx/test.git (fetch)</span><br><span class="line">oschina https://git.oschina.net/xxx/test.git (push)</span><br></pre></td></tr></table></figure><p>[========]</p><h3 id="项目部署"><a href="#项目部署" class="headerlink" title="项目部署"></a>项目部署</h3><h4 id="1-准备代码,提交到码云Git库"><a href="#1-准备代码,提交到码云Git库" class="headerlink" title="1. 准备代码,提交到码云Git库"></a>1. 准备代码,提交到码云Git库</h4><p>代码中需要包含以下几部分内容:</p><p>(1)代码中需要包含Dockerfile文件</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f471aa9c0.png"></p><p>文件内容:</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></pre></td><td class="code"><pre><span class="line">FROM openjdk:<span class="number">8</span>-jdk-alpine</span><br><span class="line">VOLUME /tmp</span><br><span class="line">COPY ./target/demojenkins.jar demojenkins.jar</span><br><span class="line">ENTRYPOINT [<span class="string">"java"</span>,<span class="string">"-jar"</span>,<span class="string">"/demojenkins.jar"</span>, <span class="string">"&"</span>]</span><br></pre></td></tr></table></figure><p>(2)在项目pom文件中指定打包类型,包含build部分内容<br><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f4b7d5f4f.png"></p><h4 id="2-安装JAVA-运行环境"><a href="#2-安装JAVA-运行环境" class="headerlink" title="2. 安装JAVA 运行环境"></a>2. 安装JAVA 运行环境</h4><p>第一步:上传或下载安装包</p> <figure class="highlight shell"><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">cd /usr/local</span><br><span class="line">jdk-8u121-linux-x64.tar.gz</span><br></pre></td></tr></table></figure><p>第二步:解压安装包</p><p><code>tar -zxvf jdk-8u121-linux-x64.tar.gz</code></p><p>第三步:建立软连接</p><p><code>ln -s /usr/local/jdk1.8.0_121/ /usr/local/jdk</code></p><p>第四步:修改环境变量</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">vim /etc/profile</span><br><span class="line"></span><br><span class="line">export JAVA_HOME=/usr/local/jdk</span><br><span class="line"></span><br><span class="line">export JRE_HOME=$JAVA_HOME/jre</span><br><span class="line"></span><br><span class="line">export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib</span><br><span class="line"></span><br><span class="line">export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin</span><br></pre></td></tr></table></figure><p>通过命令source /etc/profile让profile文件立即生效</p><p><code>source /etc/profile</code></p><p>第五步、测试是否安装成功</p><p>使用java -version,出现版本</p><h4 id="3-安装maven"><a href="#3-安装maven" class="headerlink" title="3. 安装maven"></a>3. 安装maven</h4><p>第一步:上传或下载安装包</p><figure class="highlight shell"><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">cd/usr/local</span><br><span class="line">apache-maven-3.6.1-bin.tar.gz</span><br></pre></td></tr></table></figure><p>第二步:解压安装包</p><p><code>tar -zxvf apache-maven-3.6.1-bin.tar.gz</code></p><p>第三步:建立软连接</p><p><code>ln -s /usr/local/apache-maven-3.6.1/ /usr/local/maven</code></p><p>第四步:修改环境变量</p><figure class="highlight shell"><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">vim /etc/profile</span><br><span class="line">export MAVEN_HOME=/usr/local/maven</span><br><span class="line">export PATH=$PATH:$MAVEN_HOME/bin</span><br></pre></td></tr></table></figure><p>通过命令source /etc/profile让profile文件立即生效</p><p><code>source /etc/profile</code></p><p>第五步、修改镜像源为阿里<br><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee20bc2d016a.png"></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"><span class="tag"><<span class="name">mirror</span>></span></span><br><span class="line"><span class="tag"><<span class="name">id</span>></span>alimaven<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"><span class="tag"><<span class="name">name</span>></span>aliyun maven<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"><span class="tag"><<span class="name">url</span>></span>http://maven.aliyun.com/nexus/content/groups/public/<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"><span class="tag"><<span class="name">mirrorOf</span>></span>central<span class="tag"></<span class="name">mirrorOf</span>></span></span><br><span class="line"><span class="tag"></<span class="name">mirror</span>></span></span><br></pre></td></tr></table></figure><p>第六步、测试是否安装成功</p><p><code>mvn –v</code></p><h4 id="4-安装git"><a href="#4-安装git" class="headerlink" title="4. 安装git"></a>4. 安装git</h4><p><code>yum -y install git</code></p><h4 id="5-安装docker"><a href="#5-安装docker" class="headerlink" title="5. 安装docker"></a>5. 安装docker</h4><p>第一步:安装必要的一些系统工具</p><p><code>yum install -y yum-utils device-mapper-persistent-data lvm2</code></p><p>第二步:添加软件源信息</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span><br></pre></td></tr></table></figure><p>第三步:更新并安装Docker-CE</p><figure class="highlight shell"><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">yum makecache fast</span><br><span class="line"></span><br><span class="line">使用yum list docker-ce --showduplicates | sort -r查看所有仓库中所有docker版本,并选择特定版本安装</span><br></pre></td></tr></table></figure><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f62091565.png"></p><p><code>yum -y install docker-ce-18.03.1.ce</code></p><p>第四步:开启Docker服务</p><p><code>service docker start</code></p><p>第五步、测试是否安装成功</p><p><code>docker -v</code></p><h4 id="6-安装Jenkins"><a href="#6-安装Jenkins" class="headerlink" title="6. 安装Jenkins"></a>6. 安装Jenkins</h4><p>下面采用rpm方式安装,你也可以选择使用war包安装</p><p>下载对应版本的jenkins</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f6e6ebe38.png"></p><p><code>wget https://pkg.jenkins.io/redhat-stable/jenkins-2.222.1-1.1.noarch.rpm</code></p><p>到对应下载目录执行</p><p><code> rpm -ivh jenkins-2.164.1-1.1.noarch.rpm</code></p><p>等待安装完成,修改jenkins配置</p><p>一、在jenkins配置文件中配置jdk环境变量</p><p><code>vim /etc/init.d/jenkins</code></p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f7a5eb07e.png"></p><p>二、配置Jenkins的端口(若果端口被占用)<br><code>vim /etc/sysconfig/jenkins</code></p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f7ce65efa.png"></p><p>三、修改jenkins默认的操作用户(<strong>重要,后面使用git可能会提示没权限</strong>)</p><p>linux下jenkins默认使用jenkins用户进行脚本和文件的操作,如果不修改,在部署项目时需要调整涉及到的文件和目录的操作权限,可以调整jenkins配置文件,将用户修改为root用户。将JENKINS_USER=”jenkins”调整为JENKINS_USER=“root”:</p><p><code>vim /etc/sysconfig/jenkins</code></p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1f92f1eb54.png"></p><p>修改相应的权限</p><figure class="highlight shell"><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">chown -R root /var/log/jenkins</span><br><span class="line">chgrp -R root /var/log/jenkins</span><br><span class="line">chown -R root /var/log/jenkins</span><br><span class="line">chgrp -R root /var/log/jenkins`</span><br></pre></td></tr></table></figure><p>五、启用端口</p><p> <code>vim /etc/sysconfig/iptables</code></p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fa762afcb.png"></p><p>六、启动jenkins</p><p><code> service jenkins start</code></p><p>七、访问jenkins,初始化配置jenkins</p><ul><li>初始化jenkins</li><li>解锁jenkins</li><li>查看管理员密码</li></ul><p><code>cat /var/lib/jenkins/secrets/initialAdminPassword</code></p><p>复制粘贴密码后,点击继续</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fac998688.png"></p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fad0030ac.png"></p><p><strong>注意:配置国内的镜像<br>官方下载插件慢 更新下载地址</strong></p><p>cd {你的Jenkins工作目录}/updates #进入更新配置位置</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json</span><br></pre></td></tr></table></figure><p>这是直接修改的配置文件,如果前边Jenkins用sudo启动的话,那么这里的两个sed前均需要加上sudo</p><p>重启Jenkins,安装插件,耐心等待安装完成</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fb1f11707.png"></p><p>创建管理员用户</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fd6e9f523.png"></p><p>配置jenkinsURL</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fd7c1cb79.png"></p><h3 id="开始使用jenkins"><a href="#开始使用jenkins" class="headerlink" title="开始使用jenkins"></a>开始使用jenkins</h3><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fd8a2792c.png"></p><p>一、配置jenkins<br>1.系统管理</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fdb30a5cc.png"></p><p>2.全局安全配置</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fdbf5fc37.png"></p><p>安全矩阵说明:</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fdcb72e7b.png"></p><p>给用户配置权限</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fdda43585.png"></p><p>3.全局工具配置</p><p>Maven 配置</p><p>这里可以选择默认,主要在下面配置Maven路径<br><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee20c4a4e0f3.png"></p><p>使用which jdk查看jdk环境变量</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1febf613b0.png"></p><p>添加jdk,配置git路径</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1fefd77fab.png"></p><p>配置maven路径</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ff57eb80f.png"></p><p>以上三个都选择上面准备好的那个路径(不要选自动安装)</p><ol start="4"><li>构建作业<br>4.1点击创建一个新任务,进入创建项目类型选择页面</li></ol><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ff9d892bc.png"></p><p>填好信息点击“确认”</p><p>4.2配置“General”</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ffbcb4f38.png"></p><p>4.3配置“源码管理”</p><p>填写源码的git地址</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ffc75e554.png"></p><p>添加git用户,git的用户名与密码</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ffd1645ea.png"></p><p>选择添加的用户,上面的红色提示信息消失,说明连接成功,如下图</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee1ffed32ad7.png"></p><p>4.4构建作业</p><p>到源码中找到docker脚本</p><p>选择“执行shell”</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee2008f7c671.png"></p><p>4.5构建</p><p>构建作业之后,就可以执行构建过程了。</p><p>4.5.1执行构建过程</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee200eb18ff3.png"></p><p>日志内容:</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee201107cd00.png"></p><p>看到Finsh Success 那应该问题就不大了</p><p><img src="https://doc.chengzc.club/Public/Uploads/2020-06-11/5ee201419529f.png"></p><h3 id="问题记录"><a href="#问题记录" class="headerlink" title="问题记录"></a>问题记录</h3><ol><li>全局git配置要到具体的bin目录下的/usr/local/git/bin/git (不是直接配置git路径名就行)</li><li>授予jenkins权限,不然后面拉取项目时,提示git没权限</li><li>注意配置对应git的用户名和密码(github,gitee),配置正确后,源码下面那块爆红提示会消失的</li><li>在执行Execute shell时注意如果出现mvn 命令未找到,但是ssh中可以正常使用mvn命令,可能是因为下面的问题</li></ol><blockquote><p>Jenkins下执行 mvn 命令会提示“命令未找到”,但是执行如 ls 等原生命令没有任何问题。在Linux主机是通过修改 /etc/profile 文件来配置环境变量,则问题可能是Jenkins在执行shell脚本时没有加载 /etc/profile 文件,因此找不到 nmvn命令,会提示“命令未找到”。</p></blockquote><blockquote><p>Jenkins默认情况下执行shell脚本是使用非登录方式,然而非登录方式不会加载 /etc/profile 文件,在 Execute shell 中 添加如 #!/bin/sh -l 命令修改为登录方式即可解决问题。</p></blockquote>]]></content>
<summary type="html"><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><h4 id="1-准备-Git-仓库"><a href="#1-准备-Git-仓库" class="headerlink" ti</summary>
<category term="JAVA" scheme="https://chengzc.club/tags/JAVA/"/>
<category term="Jenkins" scheme="https://chengzc.club/tags/Jenkins/"/>
<category term="工具" scheme="https://chengzc.club/tags/%E5%B7%A5%E5%85%B7/"/>
</entry>
<entry>
<title>python自带的mail函数发送邮件</title>
<link href="https://chengzc.club/posts/2702640281/"/>
<id>https://chengzc.club/posts/2702640281/</id>
<published>2019-03-01T15:32:12.000Z</published>
<updated>2023-04-13T17:28:01.785Z</updated>
<content type="html"><![CDATA[<blockquote><p>smtplib与email模块(实现邮件的发送)<br>SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。</p><p>Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。</p></blockquote><h1 id="smtplib模块"><a href="#smtplib模块" class="headerlink" title="smtplib模块"></a>smtplib模块</h1><p>smtplib模块定义了一个简单的SMTP客户端,可以用来在互联网上发送邮件。</p><p>定义的类有如下:</p><figure class="highlight plaintext"><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">class smtplib.SMTP([host[, port[, local_hostname[, timeout]]]])</span><br><span class="line">class smtplib.SMTP_SSL([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])</span><br><span class="line">class smtplib.LMTP([host[, port[, local_hostname]]])</span><br></pre></td></tr></table></figure><p>还有一些已经定义好的异常</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">exception smtplib.SMTPException</span><br><span class="line">exception smtplib.SMTPServerDisconnected</span><br><span class="line">exception smtplib.SMTPResponseException</span><br><span class="line">exception smtplib.SMTPSenderRefused</span><br><span class="line">exception smtplib.SMTPRecipientsRefused</span><br><span class="line">exception smtplib.SMTPDataError</span><br><span class="line">exception smtplib.SMTPConnectError</span><br><span class="line">exception smtplib.SMTPHeloError</span><br><span class="line">exception smtplib.SMTPAuthenticationError</span><br></pre></td></tr></table></figure><p>这么多已定义的类中,我们最常用的的还是smtplib.SMTP类用法:<br> smtp实例封装一个smtp连接,它支持所有的SMTP和ESMTP操作指令,如果host和port参数被定义,则smtp会在初始化期间自动调用connect()方法,如果connect()方法失败,则会触发SMTPConnectError异常,timeout参数设置了超时时间。在一般的调用过程中,应该遵**connetc()、sendmail()、quit()**步骤。</p><p>smtplib.SMTP提供的方法:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">SMTP.set_debuglevel(level):#设置是否为调试模式。默认为False,</span><br><span class="line"></span><br><span class="line">SMTP.connect([host[, port]]):#连接到指定的smtp服务器。参数分别表示smpt主机和端口。</span><br><span class="line"># 默认是本机的25端口。也可以写成hostname:port的形式。</span><br><span class="line"></span><br><span class="line"> SMTP.docmd(cmd[, argstring]):#向smtp服务器发送指令。可选参数argstring表示指令的参数。</span><br><span class="line"></span><br><span class="line"> SMTP.helo([hostname]) :#使用"helo"指令向服务器确认身份。相当于告诉smtp服务器“我是谁”。</span><br><span class="line"></span><br><span class="line"> SMTP.has_extn(name):#判断指定名称在服务器邮件列表中是否存在。</span><br><span class="line"> #出于安全考虑,smtp服务器往往屏蔽了该指令。</span><br><span class="line"></span><br><span class="line"> SMTP.verify(address) :#判断指定邮件地址是否在服务器中存在。</span><br><span class="line"> #出于安全考虑,smtp服务器往往屏蔽了该指令。</span><br><span class="line"></span><br><span class="line"> SMTP.login(user, password) :#登陆到smtp服务器。</span><br><span class="line"> #现在几乎所有的smtp服务器,都必须在验证用户信息合法之后才允许发送邮件。</span><br><span class="line"></span><br><span class="line"> SMTP.sendmail(self, from_addr, to_addrs, msg, mail_options=[],</span><br><span class="line"> rcpt_options=[])</span><br><span class="line">:#发送邮件。 #这里要注意一下第三个参数,msg是字符串,表示邮件。 #我们知道邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意msg的格式。 #这个格式就是smtp协议中定义的格式。 SMTP.quit() :#断开与smtp服务器的连接,相当于发送"quit"指令。</span><br></pre></td></tr></table></figure><h1 id="email模块"><a href="#email模块" class="headerlink" title="email模块"></a>email模块</h1><p>emial模块用来处理邮件消息,其包括的类有:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">class email.mime.base.MIMEBase(_maintype, _subtype, **_params):#这是MIME的一个基类。一般不需要在使用时创建实例。其中_maintype是内容类型,如text或者image。_subtype是内容的minor type 类型,如plain或者gif。 **_params是一个字典,直接传递给Message.add_header()。</span><br><span class="line"></span><br><span class="line"> class email.mime.multipart.MIMEMultipart([_subtype[, boundary[, _subparts[, _params]]]]:#MIMEBase的一个子类,多个MIME对象的集合,_subtype默认值为mixed。boundary是MIMEMultipart的边界,默认边界是可数的。</span><br><span class="line"></span><br><span class="line"> class email.mime.application.MIMEApplication(_data[, _subtype[, _encoder[, **_params]]]):#MIMEMultipart的一个子类。</span><br><span class="line"></span><br><span class="line"> class email.mime.audio. MIMEAudio(_audiodata[, _subtype[, _encoder[, **_params]]]): MIME音频对象</span><br><span class="line"></span><br><span class="line"> class email.mime.image.MIMEImage(_imagedata[, _subtype[, _encoder[, **_params]]]):#MIME二进制文件对象。</span><br><span class="line"></span><br><span class="line"> class email.mime.text.MIMEText(_text[, _subtype[, _charset]]):#MIME文本对象,其中_text是邮件内容,_subtype邮件类型,可以是text/plain(普通文本邮件),html/plain(html邮件), _charset编码,可以是gb2312等等。</span><br><span class="line"></span><br><span class="line"> class email.mime.message.MIMEMessage(_msg[, _subtype]):#具体的一个message实例,使用方法如下:</span><br><span class="line"> msg=mail.Message.Message() #一个实例 </span><br><span class="line"> msg['to']='XXX@XXX.com' #发送到哪里 </span><br><span class="line"> msg['from']='YYY@YYYY.com' #自己的邮件地址 </span><br><span class="line"> msg['date']='2012-3-16' #时间日期 </span><br><span class="line"> msg['subject']='hello world' #邮件主题</span><br></pre></td></tr></table></figure><h2 id="smtplib-SMTP"><a href="#smtplib-SMTP" class="headerlink" title="smtplib.SMTP"></a>smtplib.SMTP</h2><h3 id="利用smtplib-SMTP发送一份普通文本邮件"><a href="#利用smtplib-SMTP发送一份普通文本邮件" class="headerlink" title="利用smtplib.SMTP发送一份普通文本邮件"></a>利用smtplib.SMTP发送一份普通文本邮件</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import smtplib</span><br><span class="line">from email.mime.text import MIMEText</span><br><span class="line"></span><br><span class="line">sender = 'wxtysg@163.com' # 发件人邮箱账号</span><br><span class="line">my_pass= 'gahghfh' # 发件人邮箱授权码</span><br><span class="line">receiver="888888@qq.com" #接收人邮箱</span><br><span class="line">def mail():</span><br><span class="line"> ret = True</span><br><span class="line"> try:</span><br><span class="line"> content = "hello world"# 邮件内容</span><br><span class="line"> msg = MIMEText(content, 'plain', 'utf-8')</span><br><span class="line"> msg['From'] = sender #发件人邮箱账号</span><br><span class="line"> msg['To']=receiver</span><br><span class="line"> msg['Subject'] = "Python发送邮件测试" # 邮件的主题</span><br><span class="line">#创建连接对象并连接到服务器</span><br><span class="line"> server = smtplib.SMTP("smtp.163.com")# 发件人邮箱中的SMTP服务器,端口是25</span><br><span class="line"> server.login(sender, my_pass)# 发件人邮箱账号、授权码</span><br><span class="line"> server.sendmail(sender, receiver, msg.as_string())</span><br><span class="line"> server.quit() # 关闭连接</span><br><span class="line"> except Exception as e: </span><br><span class="line"> ret = False</span><br><span class="line"> print(e)</span><br><span class="line"> return ret</span><br><span class="line"></span><br><span class="line">ret = mail()</span><br><span class="line">if ret:</span><br><span class="line"> print("邮件发送成功")</span><br><span class="line">else:</span><br><span class="line"> print("邮件发送失败")</span><br></pre></td></tr></table></figure><p><em><strong>ps:使用标准的25端口连接SMTP服务器时,使用的是明文传输,发送邮件的整个过程可能会被窃听。要更安全地发送邮件,可以加密SMTP会话,实际上就是先创建SSL安全连接,然后再使用SMTP协议发送邮件</strong></em></p><h2 id="smtplib-SMTP-SSL"><a href="#smtplib-SMTP-SSL" class="headerlink" title="smtplib.SMTP_SSL"></a>smtplib.SMTP_SSL</h2><h3 id="利用smtplib-SMTP-SSL发送qq邮件"><a href="#利用smtplib-SMTP-SSL发送qq邮件" class="headerlink" title="利用smtplib.SMTP_SSL发送qq邮件"></a>利用smtplib.SMTP_SSL发送qq邮件</h3><p>注意要:发送QQ邮件需建立SSL安全连接。故需将<code>smtplib.SMTP() </code>改成了<code>smtplib.SMTP_SSL()</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">class smtplib.SMTP_SSL([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])</span><br></pre></td></tr></table></figure><p> 这是一个派生自SMTP的子类,通过SSL加密的套接字连接(使用此类,您需要使用SSL支持编译的套接字模块)。如果未指定主机,则使用“(本地主机)”。如果省略端口,则使用标准的SMTP-over-SSL端口(465)。 local_hostname和source_address与SMTP类中的含义相同。密钥文件和证书文件也是可选的 - 它们可以包含用于SSL连接的PEM格式的私钥和证书链文件。上下文也是可选的,可以包含SSLContext,是keyfile和certfile的替代方法;如果指定keyfile和certfile都必须为None。</p><h4 id="发送一个普通文本邮件"><a href="#发送一个普通文本邮件" class="headerlink" title="发送一个普通文本邮件"></a>发送一个普通文本邮件</h4><p>QQ邮箱POP3 和 SMTP 服务器地址设置如下:</p><table><thead><tr><th>邮箱</th><th>POP3服务器(端口995)</th><th>SMTP服务器(端口465或587)</th></tr></thead><tbody><tr><td>qq.com</td><td>pop.qq.com</td><td>smtp.qq.com</td></tr></tbody></table><p>注:<br> 1. SMTP服务器需要身份验证。<br> 2. 如果是设置POP3和SMTP的SSL加密方式,则端口如下:<br> 1)POP3接收邮件服务器(端口995);<br> 2)SMTP发送邮件服务器(端口465或587)。</p><p>另外,用qq邮件服务器发送邮件需要先到邮箱里设开启SMTP/POP3服务。然后获取授权码, 在代码中要填写的密码是这个授权码, 而不是邮箱密码!</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import smtplib</span><br><span class="line">from email.mime.text import MIMEText</span><br><span class="line"></span><br><span class="line">msg_from = '6666666@qq.com' # 发送方邮箱</span><br><span class="line">passwd = 'aczbvlbtrsaadjda' # 填入发送方邮箱的授权码</span><br><span class="line">msg_to = '888888@qq.com' # 收件人邮箱</span><br><span class="line">mail_host="smtp.qq.com" #发送人邮件的stmp服务器</span><br><span class="line">port= 465 #端口号</span><br><span class="line">#邮件</span><br><span class="line">subject = "python邮件测试" # 主题</span><br><span class="line">content = "Hello World"# 正文</span><br><span class="line">msg = MIMEText(content)</span><br><span class="line">msg['Subject'] = subject</span><br><span class="line">msg['From'] = msg_from</span><br><span class="line">msg['To'] = msg_to</span><br><span class="line">#创建连接对象并连接到服务器</span><br><span class="line">s = smtplib.SMTP_SSL(mail_host,port) # 邮件服务器及端口号,SMTP_SSL默认使用465端口号,端口号可省略</span><br><span class="line"># 登录服务器</span><br><span class="line">s.login(msg_from, passwd)</span><br><span class="line">try:</span><br><span class="line"> s.sendmail(msg_from, msg_to, msg.as_string())</span><br><span class="line"> print("发送成功")</span><br><span class="line">except s.SMTPException as e:</span><br><span class="line"> print(e)</span><br><span class="line"> print("发送失败")</span><br><span class="line">finally:</span><br><span class="line"> s.quit()</span><br></pre></td></tr></table></figure><h4 id="发送HTML格式的邮件"><a href="#发送HTML格式的邮件" class="headerlink" title="发送HTML格式的邮件"></a>发送HTML格式的邮件</h4><p> <br>在构造MIMEText对象时,把HTML字符串传进去,再把第二个参数由plain变为html就可以了:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import smtplib</span><br><span class="line">from email.mime.text import MIMEText</span><br><span class="line">msg_from = '2419636244@qq.com' # 发送方邮箱</span><br><span class="line">passwd = 'qfzgdumpeswjdjic' # 填入发送方邮箱的授权码</span><br><span class="line"># tolist=["2419636231@qq.com","2419636244@qq.com"]</span><br><span class="line">msg_to = "2419636231@qq.com" # 收件人邮箱 ,可以一次发给多个人</span><br><span class="line">mail_host="smtp.qq.com" #服务器</span><br><span class="line">port= 465 #端口号</span><br><span class="line">#邮件</span><br><span class="line">subject = "python邮件测试" # 主题</span><br><span class="line">content = """"</span><br><span class="line"><p>Python 邮件发送测试...</p></span><br><span class="line"><p><a href="http://www.cnblogs.com/freely/">戳它</a></p></span><br><span class="line">"""#内容</span><br><span class="line">msg = MIMEText(content,"html",'utf-8')#三个参数:第一个为文本内容,第二个MIME的subtype,设置文本格式,传入'plain',最终的MIME就是'text/plain',第三个 utf-8 设置编码</span><br><span class="line">#plain 页面上原样显示这段代码</span><br><span class="line">msg['Subject'] = subject</span><br><span class="line">msg['From'] = msg_from</span><br><span class="line">msg['To'] = msg_to</span><br><span class="line">#创建连接对象并连接到</span><br><span class="line">s = smtplib.SMTP_SSL(mail_host,port) # 邮件服务器及端口号</span><br><span class="line"># 登录服务器</span><br><span class="line">s.login(msg_from, passwd)</span><br><span class="line">try:</span><br><span class="line"> s.sendmail(msg_from,msg_to, msg.as_string())</span><br><span class="line"> print("发送成功")</span><br><span class="line">except Exception as e:</span><br><span class="line"> print(e)</span><br><span class="line"> print("发送失败")</span><br><span class="line">finally:</span><br><span class="line"> s.quit()</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p>smtplib与email模块(实现邮件的发送)<br>SMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。</p>
<p>Python对SMTP支持有smtplib和email两个模块,e</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="python" scheme="https://chengzc.club/tags/python/"/>
</entry>
<entry>
<title>ssh连接失败</title>
<link href="https://chengzc.club/posts/2727272333/"/>
<id>https://chengzc.club/posts/2727272333/</id>
<published>2019-03-01T11:32:12.000Z</published>
<updated>2023-04-21T08:16:50.000Z</updated>
<content type="html"><![CDATA[<blockquote><p>使用面板出现ssh连接失败如何处理</p></blockquote><h1 id="查看sshd运行情况"><a href="#查看sshd运行情况" class="headerlink" title="查看sshd运行情况"></a>查看sshd运行情况</h1><p>升级完php和面板出现了ssh连接失败的问题,按照百度提示方法,查看端口占用,替换端口</p><p>在服务器上逐条执行下:</p><figure class="highlight plaintext"><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">pip install paramiko==2.0.2</span><br><span class="line">bt reload</span><br></pre></td></tr></table></figure><p>如果第一种没有解决,就逐条执行下一面的每条命令:</p><figure class="highlight plaintext"><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">ssh-keygen -q -t rsa -P "" -f /root/.ssh/id_rsa</span><br><span class="line">cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys</span><br><span class="line">chmod 600 /root/.ssh/authorized_keys</span><br></pre></td></tr></table></figure><p>到此基本能解决您的ssh连接失败的问题。倘若问题不能解决,请尝试使用putty或者xshell连接下试试。</p><p>然而,执行上面的命令均无用 尝试使用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl status sshd.service;</span><br></pre></td></tr></table></figure><p>得到日志如下</p><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140926258.webp"></p><h1 id="根据连接异常进行处理"><a href="#根据连接异常进行处理" class="headerlink" title="根据连接异常进行处理"></a>根据连接异常进行处理</h1><p>从日志就可以很明确的看出登录ssh失败的原因了,就是权限的问题,本来我没有动过.ssh文件夹的权限,但是不知为何变为<strong>damen 755</strong>了<br>修改文件夹权限ssh就额可以正常连接了,顺便记录下登录密码错误时的日志<br><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140925276.webp"></p><h1 id="加入开机自启动"><a href="#加入开机自启动" class="headerlink" title="加入开机自启动"></a>加入开机自启动</h1><p>如想要把Tomcat加入开机自启动,可按下步骤</p><ol><li>注意:centos7 使用 systemctl 替换了 service命令</li><li>tomcat增加启动参数<br>tomcat 需要增加一个pid文件<br>在tomca/bin 目录下面,增加 setenv.sh 配置,catalina.sh启动的时候会调用,同时配置java内存参数。</li></ol><figure class="highlight plaintext"><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">[plain] view plain copy</span><br><span class="line">#add tomcat pid </span><br><span class="line">CATALINA_PID="/tomcat.pid" </span><br><span class="line">#add java opts </span><br><span class="line">JAVA_OPTS="-server -XX:PermSize=256M -XX:MaxPermSize=1024m -Xms512M -Xmx1024M -XX:MaxNewSize=256m"</span><br></pre></td></tr></table></figure><ol start="3"><li>增加tomcat.service<br>在/usr/lib/systemd/system目录下增加tomcat.service,目录必须是绝对目录。</li></ol><figure class="highlight plaintext"><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">[plain] view plain copy</span><br><span class="line">[Unit] </span><br><span class="line">Description=Tomcat </span><br><span class="line">After=syslog.target network.target remote-fs.target nss-lookup.target </span><br><span class="line"> </span><br><span class="line">[Service] </span><br><span class="line">Type=forking </span><br><span class="line">PIDFile=/data/tomcat/tomcat.pid </span><br><span class="line">ExecStart=/data/tomcat/bin/startup.sh </span><br><span class="line">ExecReload=/bin/kill -s HUP </span><br><span class="line">ExecStop=/bin/kill -s QUIT </span><br><span class="line">PrivateTmp=true </span><br><span class="line"> </span><br><span class="line">[Install] </span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><p>[unit]配置了服务的描述,规定了在network启动之后执行。[service]配置服务的pid,服务的启动,停止,重启。[install]配置了使用用户。</p><ol start="4"><li>使用tomcat.service<br>配置开机启动<br>启动tomcat</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start tomcat</span><br></pre></td></tr></table></figure><p>停止tomcat</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop tomcat</span><br></pre></td></tr></table></figure><p>重启tomcat</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart tomcat</span><br></pre></td></tr></table></figure><p>因为配置pid,在启动的时候会再tomcat根目录生成tomcat.pid文件,停止之后删除。</p><p>同时tomcat在启动时候,执行start不会启动两个tomcat,保证始终只有一个tomcat服务在运行。</p><p>多个tomcat可以配置在多个目录下,互不影响。</p><h1 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h1><p>学会找问题远比解决问题重要的多,善用日志分析查看问题出在哪里</p>]]></content>
<summary type="html">文章访问需要密码</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="Markdown" scheme="https://chengzc.club/tags/Markdown/"/>
</entry>
<entry>
<title>常用的Linux命令</title>
<link href="https://chengzc.club/posts/3337116772/"/>
<id>https://chengzc.club/posts/3337116772/</id>
<published>2019-03-01T08:32:12.000Z</published>
<updated>2023-04-13T17:32:15.448Z</updated>
<content type="html"><![CDATA[<h1 id="常用的命令"><a href="#常用的命令" class="headerlink" title="常用的命令"></a>常用的命令</h1><h2 id="查看自启动项:"><a href="#查看自启动项:" class="headerlink" title="查看自启动项:"></a>查看自启动项:</h2><figure class="highlight plaintext"><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">systemctl list-unit-files</span><br><span class="line">systemctl list-unit-files | grep enable 过滤查看启动项</span><br><span class="line">systemctl list-unit-files | grep zabbix 过滤查看某服务名</span><br></pre></td></tr></table></figure><h2 id="加入开机启动"><a href="#加入开机启动" class="headerlink" title="加入开机启动"></a>加入开机启动</h2><figure class="highlight plaintext"><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">systemctl enable mysqld;</span><br><span class="line">systemctl enable firewalld.service ;</span><br><span class="line">systemctl enable httpd.service;</span><br></pre></td></tr></table></figure><h2 id="先关闭-停止运行服务"><a href="#先关闭-停止运行服务" class="headerlink" title="先关闭,停止运行服务"></a>先关闭,停止运行服务</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop firewalld.service ;</span><br></pre></td></tr></table></figure><h2 id="加入开机禁用"><a href="#加入开机禁用" class="headerlink" title="加入开机禁用"></a>加入开机禁用</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl disable firewalld.service;</span><br></pre></td></tr></table></figure><h2 id="查看状态"><a href="#查看状态" class="headerlink" title="查看状态"></a>查看状态</h2><figure class="highlight plaintext"><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">systemctl status iptables.service;</span><br><span class="line">systemctl status mysqld;</span><br></pre></td></tr></table></figure><h2 id="端口连接情况"><a href="#端口连接情况" class="headerlink" title="端口连接情况"></a>端口连接情况</h2><p><code>netstat -atunlp </code></p><h2 id="端口占用情况"><a href="#端口占用情况" class="headerlink" title="端口占用情况"></a>端口占用情况</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsof i:3000</span><br></pre></td></tr></table></figure><h2 id="查看某项服务的状态"><a href="#查看某项服务的状态" class="headerlink" title="查看某项服务的状态"></a>查看某项服务的状态</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux|grep tomcat</span><br></pre></td></tr></table></figure><h2 id="系统信息"><a href="#系统信息" class="headerlink" title="系统信息"></a>系统信息</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">arch 显示机器的处理器架构(1) </span><br><span class="line">uname -m 显示机器的处理器架构(2) </span><br><span class="line">uname -r 显示正在使用的内核版本 </span><br><span class="line">dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI) </span><br><span class="line">hdparm -i /dev/hda 罗列一个磁盘的架构特性 </span><br><span class="line">hdparm -tT /dev/sda 在磁盘上执行测试性读取操作 </span><br><span class="line">cat /proc/cpuinfo 显示CPU info的信息 </span><br><span class="line">cat /proc/interrupts 显示中断 </span><br><span class="line">cat /proc/meminfo 校验内存使用 </span><br><span class="line">cat /proc/swaps 显示哪些swap被使用 </span><br><span class="line">cat /proc/version 显示内核的版本 </span><br><span class="line">cat /proc/net/dev 显示网络适配器及统计 </span><br><span class="line">cat /proc/mounts 显示已加载的文件系统 </span><br><span class="line">lspci -tv 罗列 PCI 设备 </span><br><span class="line">lsusb -tv 显示 USB 设备 </span><br><span class="line">date 显示系统日期 </span><br><span class="line">cal 2007 显示2007年的日历表 </span><br><span class="line">date 041217002007.00 设置日期和时间 - 月日时分年.秒 </span><br><span class="line">clock -w 将时间修改保存到 BIOS </span><br></pre></td></tr></table></figure><h2 id="关机-系统的关机、重启以及登出"><a href="#关机-系统的关机、重启以及登出" class="headerlink" title="关机 (系统的关机、重启以及登出 )"></a>关机 (系统的关机、重启以及登出 )</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">shutdown -h now 关闭系统(1) </span><br><span class="line">init 0 关闭系统(2) </span><br><span class="line">telinit 0 关闭系统(3) </span><br><span class="line">shutdown -h hours:minutes & 按预定时间关闭系统 </span><br><span class="line">shutdown -c 取消按预定时间关闭系统 </span><br><span class="line">shutdown -r now 重启(1) </span><br><span class="line">reboot 重启(2) </span><br><span class="line">logout 注销</span><br></pre></td></tr></table></figure><h2 id="文件和目录"><a href="#文件和目录" class="headerlink" title="文件和目录"></a>文件和目录</h2><figure class="highlight plaintext"><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">cd /home 进入 '/ home' 目录' </span><br><span class="line">cd .. 返回上一级目录 </span><br><span class="line">cd ../.. 返回上两级目录 </span><br><span class="line">cd 进入个人的主目录 </span><br><span class="line">cd ~user1 进入个人的主目录 </span><br><span class="line">cd - 返回上次所在的目录 </span><br><span class="line">pwd 显示工作路径 </span><br><span class="line">ls 查看目录中的文件 </span><br><span class="line">ls -F 查看目录中的文件 </span><br><span class="line">ls -l 显示文件和目录的详细资料 </span><br><span class="line">ls -a 显示隐藏文件 </span><br><span class="line">ls *[0-9]* 显示包含数字的文件名和目录名 </span><br><span class="line">tree 显示文件和目录由根目录开始的树形结构(1) </span><br><span class="line">lstree 显示文件和目录由根目录开始的树形结构(2) </span><br><span class="line">mkdir dir1 创建一个叫做 'dir1' 的目录' </span><br><span class="line">mkdir dir1 dir2 同时创建两个目录 </span><br><span class="line">mkdir -p /tmp/dir1/dir2 创建一个目录树 </span><br><span class="line">rm -f file1 删除一个叫做 'file1' 的文件' </span><br><span class="line">rmdir dir1 删除一个叫做 'dir1' 的目录' </span><br><span class="line">rm -rf dir1 删除一个叫做 'dir1' 的目录并同时删除其内容 </span><br><span class="line">rm -rf dir1 dir2 同时删除两个目录及它们的内容 </span><br><span class="line">mv dir1 new_dir 重命名/移动 一个目录 </span><br><span class="line">cp file1 file2 复制一个文件 </span><br><span class="line">cp dir/* . 复制一个目录下的所有文件到当前工作目录 </span><br><span class="line">cp -a /tmp/dir1 . 复制一个目录到当前工作目录 </span><br><span class="line">cp -a dir1 dir2 复制一个目录 </span><br><span class="line">ln -s file1 lnk1 创建一个指向文件或目录的软链接 </span><br><span class="line">ln file1 lnk1 创建一个指向文件或目录的物理链接 </span><br><span class="line">touch -t 0712250000 file1 修改一个文件或目录的时间戳 - (YYMMDDhhmm) </span><br><span class="line">file file1 outputs the mime type of the file as text </span><br><span class="line">iconv -l 列出已知的编码 </span><br><span class="line">iconv -f fromEncoding -t toEncoding inputFile > outputFile creates a new from the given input file by assuming it is encoded in fromEncoding and converting it to toEncoding. </span><br><span class="line">find . -maxdepth 1 -name *.jpg -print -exec convert "{" -resize 80x60 "thumbs/{}" \; batch resize files in the current directory and send them to a thumbnails directory (requires convert from Imagemagick) }</span><br></pre></td></tr></table></figure><h2 id="文件搜索"><a href="#文件搜索" class="headerlink" title="文件搜索"></a>文件搜索</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">find / -name file1 从 '/' 开始进入根文件系统搜索文件和目录 </span><br><span class="line">find / -user user1 搜索属于用户 'user1' 的文件和目录 </span><br><span class="line">find /home/user1 -name \*.bin 在目录 '/ home/user1' 中搜索带有'.bin' 结尾的文件 </span><br><span class="line">find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件 </span><br><span class="line">find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件 </span><br><span class="line">find / -name \*.rpm -exec chmod 755 '{' \; 搜索以 '.rpm' 结尾的文件并定义其权限 </span><br><span class="line">find / -xdev -name \*.rpm 搜索以 '.rpm' 结尾的文件,忽略光驱、捷盘等可移动设备 </span><br><span class="line">locate \*.ps 寻找以 '.ps' 结尾的文件 - 先运行 'updatedb' 命令 </span><br><span class="line">whereis halt 显示一个二进制文件、源码或man的位置 </span><br><span class="line">which halt 显示一个二进制文件或可执行文件的完整路径 </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="挂载一个文件系统"><a href="#挂载一个文件系统" class="headerlink" title="挂载一个文件系统"></a>挂载一个文件系统</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在 </span><br><span class="line">umount /dev/hda2 卸载一个叫做hda2的盘 - 先从挂载点 '/ mnt/hda2' 退出 </span><br><span class="line">fuser -km /mnt/hda2 当设备繁忙时强制卸载 </span><br><span class="line">umount -n /mnt/hda2 运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用 </span><br><span class="line">mount /dev/fd0 /mnt/floppy 挂载一个软盘 </span><br><span class="line">mount /dev/cdrom /mnt/cdrom 挂载一个cdrom或dvdrom </span><br><span class="line">mount /dev/hdc /mnt/cdrecorder 挂载一个cdrw或dvdrom </span><br><span class="line">mount /dev/hdb /mnt/cdrecorder 挂载一个cdrw或dvdrom </span><br><span class="line">mount -o loop file.iso /mnt/cdrom 挂载一个文件或ISO镜像文件 </span><br><span class="line">mount -t vfat /dev/hda5 /mnt/hda5 挂载一个Windows FAT32文件系统 </span><br><span class="line">mount /dev/sda1 /mnt/usbdisk 挂载一个usb 捷盘或闪存设备 </span><br><span class="line">mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share 挂载一个windows网络共享 </span><br></pre></td></tr></table></figure><h2 id="磁盘空间"><a href="#磁盘空间" class="headerlink" title="磁盘空间"></a>磁盘空间</h2><figure class="highlight plaintext"><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">df -h 显示已经挂载的分区列表 </span><br><span class="line">ls -lSr |more 以尺寸大小排列文件和目录 </span><br><span class="line">du -sh dir1 估算目录 'dir1' 已经使用的磁盘空间' </span><br><span class="line">du -sk * | sort -rn 以容量大小为依据依次显示文件和目录的大小 </span><br><span class="line">rpm -q -a --qf '%10{SIZEt%{NAME}n' | sort -k1,1n 以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统) </span><br><span class="line">dpkg-query -W -f='tn' | sort -k1,1n 以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统) }</span><br></pre></td></tr></table></figure><h2 id="用户和群组"><a href="#用户和群组" class="headerlink" title="用户和群组"></a>用户和群组</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">groupadd group_name 创建一个新用户组 </span><br><span class="line">groupdel group_name 删除一个用户组 </span><br><span class="line">groupmod -n new_group_name old_group_name 重命名一个用户组 </span><br><span class="line">useradd -c "Name Surname " -g admin -d /home/user1 -s /bin/bash user1 创建一个属于 "admin" 用户组的用户 </span><br><span class="line">useradd user1 创建一个新用户 </span><br><span class="line">userdel -r user1 删除一个用户 ( '-r' 排除主目录) </span><br><span class="line">usermod -c "User FTP" -g system -d /ftp/user1 -s /bin/nologin user1 修改用户属性 </span><br><span class="line">passwd 修改口令 </span><br><span class="line">passwd user1 修改一个用户的口令 (只允许root执行) </span><br><span class="line">chage -E 2005-12-31 user1 设置用户口令的失效期限 </span><br><span class="line">pwck 检查 '/etc/passwd' 的文件格式和语法修正以及存在的用户 </span><br><span class="line">grpck 检查 '/etc/passwd' 的文件格式和语法修正以及存在的群组 </span><br><span class="line">newgrp group_name 登陆进一个新的群组以改变新创建文件的预设群组 </span><br></pre></td></tr></table></figure><h2 id="文件的权限-使用-“-”-设置权限,使用-“-“-用于取消"><a href="#文件的权限-使用-“-”-设置权限,使用-“-“-用于取消" class="headerlink" title="文件的权限 - 使用 “+” 设置权限,使用 “-“ 用于取消"></a>文件的权限 - 使用 “+” 设置权限,使用 “-“ 用于取消</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">ls -lh 显示权限 </span><br><span class="line">ls /tmp | pr -T5 -W 将终端划分成5栏显示 </span><br><span class="line">chmod ugo+rwx directory1 设置目录的所有人(u)、群组(g)以及其他人(o)以读(r )、写(w)和执行(x)的权限 </span><br><span class="line">chmod go-rwx directory1 删除群组(g)与其他人(o)对目录的读写执行权限 </span><br><span class="line">chown user1 file1 改变一个文件的所有人属性 </span><br><span class="line">chown -R user1 directory1 改变一个目录的所有人属性并同时改变改目录下所有文件的属性 </span><br><span class="line">chgrp group1 file1 改变文件的群组 </span><br><span class="line">chown user1:group1 file1 改变一个文件的所有人和群组属性 </span><br><span class="line">find / -perm -u+s 罗列一个系统中所有使用了SUID控制的文件 </span><br><span class="line">chmod u+s /bin/file1 设置一个二进制文件的 SUID 位 - 运行该文件的用户也被赋予和所有者同样的权限 </span><br><span class="line">chmod u-s /bin/file1 禁用一个二进制文件的 SUID位 </span><br><span class="line">chmod g+s /home/public 设置一个目录的SGID 位 - 类似SUID ,不过这是针对目录的 </span><br><span class="line">chmod g-s /home/public 禁用一个目录的 SGID 位 </span><br><span class="line">chmod o+t /home/public 设置一个文件的 STIKY 位 - 只允许合法所有人删除文件 </span><br><span class="line">chmod o-t /home/public 禁用一个目录的 STIKY 位 </span><br><span class="line">chattr +a file1 只允许以追加方式读写文件 </span><br><span class="line">chattr +c file1 允许这个文件能被内核自动压缩/解压 </span><br><span class="line">chattr +d file1 在进行文件系统备份时,dump程序将忽略这个文件 </span><br><span class="line">chattr +i file1 设置成不可变的文件,不能被删除、修改、重命名或者链接 </span><br><span class="line">chattr +s file1 允许一个文件被安全地删除 </span><br><span class="line">chattr +S file1 一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘 </span><br><span class="line">chattr +u file1 若文件被删除,系统会允许你在以后恢复这个被删除的文件 </span><br><span class="line">lsattr 显示特殊的属性 </span><br></pre></td></tr></table></figure><h2 id="打包和压缩文件"><a href="#打包和压缩文件" class="headerlink" title="打包和压缩文件"></a>打包和压缩文件</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">bunzip2 file1.bz2 解压一个叫做 'file1.bz2'的文件 </span><br><span class="line">bzip2 file1 压缩一个叫做 'file1' 的文件 </span><br><span class="line">gunzip file1.gz 解压一个叫做 'file1.gz'的文件 </span><br><span class="line">gzip file1 压缩一个叫做 'file1'的文件 </span><br><span class="line">gzip -9 file1 最大程度压缩 </span><br><span class="line">rar a file1.rar test_file 创建一个叫做 'file1.rar' 的包 </span><br><span class="line">rar a file1.rar file1 file2 dir1 同时压缩 'file1', 'file2' 以及目录 'dir1' </span><br><span class="line">rar x file1.rar 解压rar包 </span><br><span class="line">unrar x file1.rar 解压rar包 </span><br><span class="line">tar -cvf archive.tar file1 创建一个非压缩的 tarball </span><br><span class="line">tar -cvf archive.tar file1 file2 dir1 创建一个包含了 'file1', 'file2' 以及 'dir1'的档案文件 </span><br><span class="line">tar -tf archive.tar 显示一个包中的内容 </span><br><span class="line">tar -xvf archive.tar 释放一个包 </span><br><span class="line">tar -xvf archive.tar -C /tmp 将压缩包释放到 /tmp目录下 </span><br><span class="line">tar -cvfj archive.tar.bz2 dir1 创建一个bzip2格式的压缩包 </span><br><span class="line">tar -jxvf archive.tar.bz2 解压一个bzip2格式的压缩包 </span><br><span class="line">tar -cvfz archive.tar.gz dir1 创建一个gzip格式的压缩包 </span><br><span class="line">tar -zxvf archive.tar.gz 解压一个gzip格式的压缩包 </span><br><span class="line">zip file1.zip file1 创建一个zip格式的压缩包 </span><br><span class="line">zip -r file1.zip file1 file2 dir1 将几个文件和目录同时压缩成一个zip格式的压缩包 </span><br><span class="line">unzip file1.zip 解压一个zip格式压缩包 </span><br></pre></td></tr></table></figure><h2 id="RPM-包-(Fedora-Redhat及类似系统)"><a href="#RPM-包-(Fedora-Redhat及类似系统)" class="headerlink" title="RPM 包 - (Fedora, Redhat及类似系统)"></a>RPM 包 - (Fedora, Redhat及类似系统)</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">rpm -ivh package.rpm 安装一个rpm包 </span><br><span class="line">rpm -ivh --nodeeps package.rpm 安装一个rpm包而忽略依赖关系警告 </span><br><span class="line">rpm -U package.rpm 更新一个rpm包但不改变其配置文件 </span><br><span class="line">rpm -F package.rpm 更新一个确定已经安装的rpm包 </span><br><span class="line">rpm -e package_name.rpm 删除一个rpm包 </span><br><span class="line">rpm -qa 显示系统中所有已经安装的rpm包 </span><br><span class="line">rpm -qa | grep httpd 显示所有名称中包含 "httpd" 字样的rpm包 </span><br><span class="line">rpm -qi package_name 获取一个已安装包的特殊信息 </span><br><span class="line">rpm -qg "System Environment/Daemons" 显示一个组件的rpm包 </span><br><span class="line">rpm -ql package_name 显示一个已经安装的rpm包提供的文件列表 </span><br><span class="line">rpm -qc package_name 显示一个已经安装的rpm包提供的配置文件列表 </span><br><span class="line">rpm -q package_name --whatrequires 显示与一个rpm包存在依赖关系的列表 </span><br><span class="line">rpm -q package_name --whatprovides 显示一个rpm包所占的体积 </span><br><span class="line">rpm -q package_name --scripts 显示在安装/删除期间所执行的脚本l </span><br><span class="line">rpm -q package_name --changelog 显示一个rpm包的修改历史 </span><br><span class="line">rpm -qf /etc/httpd/conf/httpd.conf 确认所给的文件由哪个rpm包所提供 </span><br><span class="line">rpm -qp package.rpm -l 显示由一个尚未安装的rpm包提供的文件列表 </span><br><span class="line">rpm --import /media/cdrom/RPM-GPG-KEY 导入公钥数字证书 </span><br><span class="line">rpm --checksig package.rpm 确认一个rpm包的完整性 </span><br><span class="line">rpm -qa gpg-pubkey 确认已安装的所有rpm包的完整性 </span><br><span class="line">rpm -V package_name 检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间 </span><br><span class="line">rpm -Va 检查系统中所有已安装的rpm包- 小心使用 </span><br><span class="line">rpm -Vp package.rpm 确认一个rpm包还未安装 </span><br><span class="line">rpm2cpio package.rpm | cpio --extract --make-directories *bin* 从一个rpm包运行可执行文件 </span><br><span class="line">rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm 从一个rpm源码安装一个构建好的包 </span><br><span class="line">rpmbuild --rebuild package_name.src.rpm 从一个rpm源码构建一个 rpm 包 </span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="YUM-软件包升级器-(Fedora-RedHat及类似系统)"><a href="#YUM-软件包升级器-(Fedora-RedHat及类似系统)" class="headerlink" title="YUM 软件包升级器 - (Fedora, RedHat及类似系统)"></a>YUM 软件包升级器 - (Fedora, RedHat及类似系统)</h2><figure class="highlight plaintext"><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">yum install package_name 下载并安装一个rpm包 </span><br><span class="line">yum localinstall package_name.rpm 将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系 </span><br><span class="line">yum update package_name.rpm 更新当前系统中所有安装的rpm包 </span><br><span class="line">yum update package_name 更新一个rpm包 </span><br><span class="line">yum remove package_name 删除一个rpm包 </span><br><span class="line">yum list 列出当前系统中安装的所有包 </span><br><span class="line">yum search package_name 在rpm仓库中搜寻软件包 </span><br><span class="line">yum clean packages 清理rpm缓存删除下载的包 </span><br><span class="line">yum clean headers 删除所有头文件 </span><br><span class="line">yum clean all 删除所有缓存的包和头文件</span><br></pre></td></tr></table></figure><h2 id="DEB-包-Debian-Ubuntu-以及类似系统"><a href="#DEB-包-Debian-Ubuntu-以及类似系统" class="headerlink" title="DEB 包 (Debian, Ubuntu 以及类似系统)"></a>DEB 包 (Debian, Ubuntu 以及类似系统)</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">dpkg -i package.deb 安装/更新一个 deb 包 </span><br><span class="line">dpkg -r package_name 从系统删除一个 deb 包 </span><br><span class="line">dpkg -l 显示系统中所有已经安装的 deb 包 </span><br><span class="line">dpkg -l | grep httpd 显示所有名称中包含 "httpd" 字样的deb包 </span><br><span class="line">dpkg -s package_name 获得已经安装在系统中一个特殊包的信息 </span><br><span class="line">dpkg -L package_name 显示系统中已经安装的一个deb包所提供的文件列表 </span><br><span class="line">dpkg --contents package.deb 显示尚未安装的一个包所提供的文件列表 </span><br><span class="line">dpkg -S /bin/ping 确认所给的文件由哪个deb包提供 </span><br></pre></td></tr></table></figure><h2 id="APT-软件工具-Debian-Ubuntu-以及类似系统"><a href="#APT-软件工具-Debian-Ubuntu-以及类似系统" class="headerlink" title="APT 软件工具 (Debian, Ubuntu 以及类似系统)"></a>APT 软件工具 (Debian, Ubuntu 以及类似系统)</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">apt-get install package_name 安装/更新一个 deb 包 </span><br><span class="line">apt-cdrom install package_name 从光盘安装/更新一个 deb 包 </span><br><span class="line">apt-get update 升级列表中的软件包 </span><br><span class="line">apt-get upgrade 升级所有已安装的软件 </span><br><span class="line">apt-get remove package_name 从系统删除一个deb包 </span><br><span class="line">apt-get check 确认依赖的软件仓库正确 </span><br><span class="line">apt-get clean 从下载的软件包中清理缓存 </span><br><span class="line">apt-cache search searched-package 返回包含所要搜索字符串的软件包名称 </span><br></pre></td></tr></table></figure><h2 id="查看文件内容"><a href="#查看文件内容" class="headerlink" title="查看文件内容"></a>查看文件内容</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">cat file1 从第一个字节开始正向查看文件的内容 </span><br><span class="line">tac file1 从最后一行开始反向查看一个文件的内容 </span><br><span class="line">more file1 查看一个长文件的内容 </span><br><span class="line">less file1 类似于 'more' 命令,但是它允许在文件中和正向操作一样的反向操作 </span><br><span class="line">head -2 file1 查看一个文件的前两行 </span><br><span class="line">tail -2 file1 查看一个文件的最后两行 </span><br><span class="line">tail -f /var/log/messages 实时查看被添加到一个文件中的内容 </span><br></pre></td></tr></table></figure><h2 id="文本处理"><a href="#文本处理" class="headerlink" title="文本处理"></a>文本处理</h2><figure class="highlight plaintext"><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><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">cat file1 file2 ... | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT </span><br><span class="line">cat file1 | command( sed, grep, awk, grep, etc...) > result.txt 合并一个文件的详细说明文本,并将简介写入一个新文件中 </span><br><span class="line">cat file1 | command( sed, grep, awk, grep, etc...) >> result.txt 合并一个文件的详细说明文本,并将简介写入一个已有的文件中 </span><br><span class="line">grep Aug /var/log/messages 在文件 '/var/log/messages'中查找关键词"Aug" </span><br><span class="line">grep ^Aug /var/log/messages 在文件 '/var/log/messages'中查找以"Aug"开始的词汇 </span><br><span class="line">grep [0-9] /var/log/messages 选择 '/var/log/messages' 文件中所有包含数字的行 </span><br><span class="line">grep Aug -R /var/log/* 在目录 '/var/log' 及随后的目录中搜索字符串"Aug" </span><br><span class="line">sed 's/stringa1/stringa2/g' example.txt 将example.txt文件中的 "string1" 替换成 "string2" </span><br><span class="line">sed '/^$/d' example.txt 从example.txt文件中删除所有空白行 </span><br><span class="line">sed '/ *#/d; /^$/d' example.txt 从example.txt文件中删除所有注释和空白行 </span><br><span class="line">echo 'esempio' | tr '[:lower:]' '[:upper:]' 合并上下单元格内容 </span><br><span class="line">sed -e '1d' result.txt 从文件example.txt 中排除第一行 </span><br><span class="line">sed -n '/stringa1/p' 查看只包含词汇 "string1"的行 </span><br><span class="line">sed -e 's/ *$//' example.txt 删除每一行最后的空白字符 </span><br><span class="line">sed -e 's/stringa1//g' example.txt 从文档中只删除词汇 "string1" 并保留剩余全部 </span><br><span class="line">sed -n '1,5p;5q' example.txt 查看从第一行到第5行内容 </span><br><span class="line">sed -n '5p;5q' example.txt 查看第5行 </span><br><span class="line">sed -e 's/00*/0/g' example.txt 用单个零替换多个零 </span><br><span class="line">cat -n file1 标示文件的行数 </span><br><span class="line">cat example.txt | awk 'NR%2==1' 删除example.txt文件中的所有偶数行 </span><br><span class="line">echo a b c | awk '{print ' 查看一行第一栏 </span><br><span class="line">echo a b c | awk '{print cat file1 file2 ... | command <> file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT </span><br><span class="line">cat file1 | command( sed, grep, awk, grep, etc...) > result.txt 合并一个文件的详细说明文本,并将简介写入一个新文件中 </span><br><span class="line">cat file1 | command( sed, grep, awk, grep, etc...) >> result.txt 合并一个文件的详细说明文本,并将简介写入一个已有的文件中 </span><br><span class="line">grep Aug /var/log/messages 在文件 '/var/log/messages'中查找关键词"Aug" </span><br><span class="line">grep ^Aug /var/log/messages 在文件 '/var/log/messages'中查找以"Aug"开始的词汇 </span><br><span class="line">grep [0-9] /var/log/messages 选择 '/var/log/messages' 文件中所有包含数字的行 </span><br><span class="line">grep Aug -R /var/log/* 在目录 '/var/log' 及随后的目录中搜索字符串"Aug" </span><br><span class="line">sed 's/stringa1/stringa2/g' example.txt 将example.txt文件中的 "string1" 替换成 "string2" </span><br><span class="line">sed '/^$/d' example.txt 从example.txt文件中删除所有空白行 </span><br><span class="line">sed '/ *#/d; /^$/d' example.txt 从example.txt文件中删除所有注释和空白行 </span><br><span class="line">echo 'esempio' | tr '[:lower:]' '[:upper:]' 合并上下单元格内容 </span><br><span class="line">sed -e '1d' result.txt 从文件example.txt 中排除第一行 </span><br><span class="line">sed -n '/stringa1/p' 查看只包含词汇 "string1"的行 </span><br><span class="line">sed -e 's/ *$//' example.txt 删除每一行最后的空白字符 </span><br><span class="line">sed -e 's/stringa1//g' example.txt 从文档中只删除词汇 "string1" 并保留剩余全部 </span><br><span class="line">sed -n '1,5p;5q' example.txt 查看从第一行到第5行内容 </span><br><span class="line">sed -n '5p;5q' example.txt 查看第5行 </span><br><span class="line">sed -e 's/00*/0/g' example.txt 用单个零替换多个零 </span><br><span class="line">cat -n file1 标示文件的行数 </span><br><span class="line">cat example.txt | awk 'NR%2==1' 删除example.txt文件中的所有偶数行 </span><br><span class="line">echo a b c | awk '{print ,}' 查看一行的第一和第三栏 </span><br><span class="line">paste file1 file2 合并两个文件或两栏的内容 </span><br><span class="line">paste -d '+' file1 file2 合并两个文件或两栏的内容,中间用"+"区分 </span><br><span class="line">sort file1 file2 排序两个文件的内容 </span><br><span class="line">sort file1 file2 | uniq 取出两个文件的并集(重复的行只保留一份) </span><br><span class="line">sort file1 file2 | uniq -u 删除交集,留下其他的行 </span><br><span class="line">sort file1 file2 | uniq -d 取出两个文件的交集(只留下同时存在于两个文件中的文件) </span><br><span class="line">comm -1 file1 file2 比较两个文件的内容只删除 'file1' 所包含的内容 </span><br><span class="line">comm -2 file1 file2 比较两个文件的内容只删除 'file2' 所包含的内容 </span><br><span class="line">comm -3 file1 file2 比较两个文件的内容只删除两个文件共有的部分 }</span><br></pre></td></tr></table></figure><h2 id="字符设置和文件格式转换"><a href="#字符设置和文件格式转换" class="headerlink" title="字符设置和文件格式转换"></a>字符设置和文件格式转换</h2><figure class="highlight plaintext"><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">dos2unix filedos.txt fileunix.txt 将一个文本文件的格式从MSDOS转换成UNIX </span><br><span class="line">unix2dos fileunix.txt filedos.txt 将一个文本文件的格式从UNIX转换成MSDOS </span><br><span class="line">recode ..HTML < page.txt > page.html 将一个文本文件转换成html </span><br><span class="line">recode -l | more 显示所有允许的转换格式 </span><br></pre></td></tr></table></figure><h2 id="文件系统分析"><a href="#文件系统分析" class="headerlink" title="文件系统分析"></a>文件系统分析</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">badblocks -v /dev/hda1 检查磁盘hda1上的坏磁块 </span><br><span class="line">fsck /dev/hda1 修复/检查hda1磁盘上linux文件系统的完整性 </span><br><span class="line">fsck.ext2 /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性 </span><br><span class="line">e2fsck /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性 </span><br><span class="line">e2fsck -j /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性 </span><br><span class="line">fsck.ext3 /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性 </span><br><span class="line">fsck.vfat /dev/hda1 修复/检查hda1磁盘上fat文件系统的完整性 </span><br><span class="line">fsck.msdos /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性 </span><br><span class="line">dosfsck /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性 </span><br></pre></td></tr></table></figure><h2 id="初始化一个文件系统"><a href="#初始化一个文件系统" class="headerlink" title="初始化一个文件系统"></a>初始化一个文件系统</h2><figure class="highlight plaintext"><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">mkfs /dev/hda1 在hda1分区创建一个文件系统 </span><br><span class="line">mke2fs /dev/hda1 在hda1分区创建一个linux ext2的文件系统 </span><br><span class="line">mke2fs -j /dev/hda1 在hda1分区创建一个linux ext3(日志型)的文件系统 </span><br><span class="line">mkfs -t vfat 32 -F /dev/hda1 创建一个 FAT32 文件系统 </span><br><span class="line">fdformat -n /dev/fd0 格式化一个软盘 </span><br><span class="line">mkswap /dev/hda3 创建一个swap文件系统 </span><br></pre></td></tr></table></figure><h2 id="SWAP文件系统"><a href="#SWAP文件系统" class="headerlink" title="SWAP文件系统"></a>SWAP文件系统</h2><figure class="highlight plaintext"><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">mkswap /dev/hda3 创建一个swap文件系统 </span><br><span class="line">swapon /dev/hda3 启用一个新的swap文件系统 </span><br><span class="line">swapon /dev/hda2 /dev/hdb3 启用两个swap分区</span><br></pre></td></tr></table></figure><h2 id="备份"><a href="#备份" class="headerlink" title="备份"></a>备份</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">dump -0aj -f /tmp/home0.bak /home 制作一个 '/home' 目录的完整备份 </span><br><span class="line">dump -1aj -f /tmp/home0.bak /home 制作一个 '/home' 目录的交互式备份 </span><br><span class="line">restore -if /tmp/home0.bak 还原一个交互式备份 </span><br><span class="line">rsync -rogpav --delete /home /tmp 同步两边的目录 </span><br><span class="line">rsync -rogpav -e ssh --delete /home ip_address:/tmp 通过SSH通道rsync </span><br><span class="line">rsync -az -e ssh --delete ip_addr:/home/public /home/local 通过ssh和压缩将一个远程目录同步到本地目录 </span><br><span class="line">rsync -az -e ssh --delete /home/local ip_addr:/home/public 通过ssh和压缩将本地目录同步到远程目录 </span><br><span class="line">dd bs=1M if=/dev/hda | gzip | ssh user@ip_addr 'dd of=hda.gz' 通过ssh在远程主机上执行一次备份本地磁盘的操作 </span><br><span class="line">dd if=/dev/sda of=/tmp/file1 备份磁盘内容到一个文件 </span><br><span class="line">tar -Puf backup.tar /home/user 执行一次对 '/home/user' 目录的交互式备份操作 </span><br><span class="line">( cd /tmp/local/ && tar c . ) | ssh -C user@ip_addr 'cd /home/share/ && tar x -p' 通过ssh在远程目录中复制一个目录内容 </span><br><span class="line">( tar c /home ) | ssh -C user@ip_addr 'cd /home/backup-home && tar x -p' 通过ssh在远程目录中复制一个本地目录 </span><br><span class="line">tar cf - . | (cd /tmp/backup ; tar xf - ) 本地将一个目录复制到另一个地方,保留原有权限及链接 </span><br><span class="line">find /home/user1 -name '*.txt' | xargs cp -av --target-directory=/home/backup/ --parents 从一个目录查找并复制所有以 '.txt' 结尾的文件到另一个目录 </span><br><span class="line">find /var/log -name '*.log' | tar cv --files-from=- | bzip2 > log.tar.bz2 查找所有以 '.log' 结尾的文件并做成一个bzip包 </span><br><span class="line">dd if=/dev/hda of=/dev/fd0 bs=512 count=1 做一个将 MBR (Master Boot Record)内容复制到软盘的动作 </span><br><span class="line">dd if=/dev/fd0 of=/dev/hda bs=512 count=1 从已经保存到软盘的备份中恢复MBR内容 </span><br></pre></td></tr></table></figure><h2 id="光盘"><a href="#光盘" class="headerlink" title="光盘"></a>光盘</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">cdrecord -v gracetime=2 dev=/dev/cdrom -eject blank=fast -force 清空一个可复写的光盘内容 </span><br><span class="line">mkisofs /dev/cdrom > cd.iso 在磁盘上创建一个光盘的iso镜像文件 </span><br><span class="line">mkisofs /dev/cdrom | gzip > cd_iso.gz 在磁盘上创建一个压缩了的光盘iso镜像文件 </span><br><span class="line">mkisofs -J -allow-leading-dots -R -V "Label CD" -iso-level 4 -o ./cd.iso data_cd 创建一个目录的iso镜像文件 </span><br><span class="line">cdrecord -v dev=/dev/cdrom cd.iso 刻录一个ISO镜像文件 </span><br><span class="line">gzip -dc cd_iso.gz | cdrecord dev=/dev/cdrom - 刻录一个压缩了的ISO镜像文件 </span><br><span class="line">mount -o loop cd.iso /mnt/iso 挂载一个ISO镜像文件 </span><br><span class="line">cd-paranoia -B 从一个CD光盘转录音轨到 wav 文件中 </span><br><span class="line">cd-paranoia -- "-3" 从一个CD光盘转录音轨到 wav 文件中(参数-3) </span><br><span class="line">cdrecord --scanbus 扫描总线以识别scsi通道 </span><br><span class="line">dd if=/dev/hdc | md5sum 校验一个设备的md5sum编码,例如一张 CD</span><br></pre></td></tr></table></figure><h2 id="网络-(以太网和WIFI无线)"><a href="#网络-(以太网和WIFI无线)" class="headerlink" title="网络 - (以太网和WIFI无线)"></a>网络 - (以太网和WIFI无线)</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">ifconfig eth0 显示一个以太网卡的配置 </span><br><span class="line">ifup eth0 启用一个 'eth0' 网络设备 </span><br><span class="line">ifdown eth0 禁用一个 'eth0' 网络设备 </span><br><span class="line">ifconfig eth0 192.168.1.1 netmask 255.255.255.0 控制IP地址 </span><br><span class="line">ifconfig eth0 promisc 设置 'eth0' 成混杂模式以嗅探数据包 (sniffing) </span><br><span class="line">dhclient eth0 以dhcp模式启用 'eth0' </span><br><span class="line">route -n show routing table </span><br><span class="line">route add -net 0/0 gw IP_Gateway configura default gateway </span><br><span class="line">route add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.1.1 configure static route to reach network '192.168.0.0/16' </span><br><span class="line">route del 0/0 gw IP_gateway remove static route </span><br><span class="line">echo "1" > /proc/sys/net/ipv4/ip_forward activate ip routing </span><br><span class="line">hostname show hostname of system </span><br><span class="line">host www.example.com lookup hostname to resolve name to ip address and viceversa(1) </span><br><span class="line">nslookup www.example.com lookup hostname to resolve name to ip address and viceversa(2) </span><br><span class="line">ip link show show link status of all interfaces </span><br><span class="line">mii-tool eth0 show link status of 'eth0' </span><br><span class="line">ethtool eth0 show statistics of network card 'eth0' </span><br><span class="line">netstat -tup show all active network connections and their PID </span><br><span class="line">netstat -tupl show all network services listening on the system and their PID </span><br><span class="line">tcpdump tcp port 80 show all HTTP traffic </span><br><span class="line">iwlist scan show wireless networks </span><br><span class="line">iwconfig eth1 show configuration of a wireless network card </span><br><span class="line">hostname show hostname </span><br><span class="line">host www.example.com lookup hostname to resolve name to ip address and viceversa </span><br><span class="line">nslookup www.example.com lookup hostname to resolve name to ip address and viceversa </span><br><span class="line">whois www.example.com lookup on Whois database </span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="常用的命令"><a href="#常用的命令" class="headerlink" title="常用的命令"></a>常用的命令</h1><h2 id="查看自启动项:"><a href="#查看自启动项:" class="headerlink" title=</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="Linux" scheme="https://chengzc.club/tags/Linux/"/>
</entry>
<entry>
<title>备案顶级域名和二级域名分别启用ssl</title>
<link href="https://chengzc.club/posts/2561287811/"/>
<id>https://chengzc.club/posts/2561287811/</id>
<published>2019-03-01T02:32:12.000Z</published>
<updated>2023-04-14T03:14:06.000Z</updated>
<content type="html"><![CDATA[<p>如何在备案完成后,同时让顶级域名和二级域名都具有ssl的访问</p><h1 id="在申请备案的云上面申请免费证书"><a href="#在申请备案的云上面申请免费证书" class="headerlink" title="在申请备案的云上面申请免费证书"></a>在申请备案的云上面申请免费证书</h1><p>以腾讯云为例</p><ol><li>申请入口</li><li>填写申请</li><li>选择自动 DNS 验证方式</li><li>提交申请后验证身份</li><li>等待验证</li></ol><h1 id="使用Nginx,Apache,iis,tomcat部署证书"><a href="#使用Nginx,Apache,iis,tomcat部署证书" class="headerlink" title="使用Nginx,Apache,iis,tomcat部署证书"></a>使用Nginx,Apache,iis,tomcat部署证书</h1><p>我是用的Nginx:</p><h2 id="获取证书"><a href="#获取证书" class="headerlink" title="获取证书"></a>获取证书</h2><p>Nginx 文件夹内获得 SSL <strong>证书文件 1_<a href="http://www.domain.com_bundle.crt/">www.domain.com_bundle.crt</a></strong> 和<strong>私钥文件 2_<a href="http://www.domain.com.key/">www.domain.com.key</a></strong>。<br>1_<a href="http://www.domain.com_bundle.crt/">www.domain.com_bundle.crt</a> 文件包括两段证书代码 “—–BEGIN CERTIFICATE—–” 和 “—–END CERTIFICATE—–”,<br>2_<a href="http://www.domain.com.key/">www.domain.com.key</a> 文件包括一段私钥代码 “—–BEGIN RSA PRIVATE KEY—–” 和 “—–END RSA PRIVATE KEY—–”。</p><h2 id="证书安装"><a href="#证书安装" class="headerlink" title="证书安装"></a>证书安装</h2><p>将域名 <a href="http://www.domain.com/">www.domain.com</a> 的证书文件 1_<a href="http://www.domain.com_bundle.crt/">www.domain.com_bundle.crt</a> 、私钥文件 2_<a href="http://www.domain.com.key/">www.domain.com.key</a> 保存到同一个目录,例如 /usr/local/nginx/conf 目录下。<br>修改 Nginx 根目录下 conf/nginx.conf 文件,内容如下:</p><figure class="highlight plaintext"><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">server {</span><br><span class="line"> listen 443;</span><br><span class="line"> server_name www.domain.com; #填写绑定证书的域名</span><br><span class="line"> ssl on;</span><br><span class="line"> ssl_certificate 1_www.domain.com_bundle.crt;</span><br><span class="line"> ssl_certificate_key 2_www.domain.com.key;</span><br><span class="line"> ssl_session_timeout 5m;</span><br><span class="line"> ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置</span><br><span class="line"> ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置</span><br><span class="line"> ssl_prefer_server_ciphers on;</span><br><span class="line"> location / {</span><br><span class="line"> root html; #站点目录</span><br><span class="line"> index index.html index.htm;</span><br><span class="line"> </span><br><span class="line">}}</span><br></pre></td></tr></table></figure><p>配置完成后,请先执行命令 <code>bin/nginx –t</code> 测试 Nginx 配置是否有误。若无报错,重启 Nginx 之后,即可使用 <code>https://www.domain.com</code> 来访问。</p><p>相关参数说明如下:</p><table><thead><tr><th>配置文件参数</th><th>说明</th></tr></thead><tbody><tr><td>listen 443</td><td>SSL 访问端口号为 443</td></tr><tr><td>ssl on</td><td>启用 SSL 功能</td></tr><tr><td>ssl_certificate</td><td>证书文件</td></tr><tr><td>ssl_certificate_key</td><td>私钥文件</td></tr><tr><td>ssl_protocols</td><td>使用的协议</td></tr><tr><td>ssl_ciphers</td><td>配置加密套件,写法遵循 openssl 标准</td></tr></tbody></table><h2 id="使用全站加密,HTTP-自动跳转-HTTPS(可选)"><a href="#使用全站加密,HTTP-自动跳转-HTTPS(可选)" class="headerlink" title="使用全站加密,HTTP 自动跳转 HTTPS(可选)"></a>使用全站加密,HTTP 自动跳转 HTTPS(可选)</h2><p>对于用户不知道网站可以进行 HTTPS 访问的情况下,让服务器自动把 HTTP 的请求重定向到 HTTPS。<br>在服务器这边的话配置的话,可以在页面里加 js 脚本,也可以在后端程序里写重定向,当然也可以在 web 服务器来实现跳转。Nginx 是支持 rewrite 的(只要在编译的时候没有去掉 pcre)<br>在 HTTP 的 server 里增加 <code>rewrite ^(.*) https:// permanent;</code><br>这样就可以实现 80 进来的请求,重定向为 HTTPS 了 。</p><h1 id="二级域名开启SSL"><a href="#二级域名开启SSL" class="headerlink" title="二级域名开启SSL"></a>二级域名开启SSL</h1><p>由于获取的证书不是<a href="https://buy.cloud.tencent.com/ssl?fromSource=dv_ssl_warning"><strong>泛域名证书</strong></a>,想要实现二级域名也七月ssl,需要在次申请二级域名的证书,并同时配置Nginx,配置后如下</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">server </span><br><span class="line">{</span><br><span class="line"> listen 443;</span><br><span class="line"> server_name chengzc.club; #填写绑定证书的域名</span><br><span class="line"> ssl on;</span><br><span class="line"> ssl_certificate /ssl/1_chengzc.club_bundle.crt;</span><br><span class="line"> ssl_certificate_key /ssl/2_chengzc.club.key;</span><br><span class="line"> ssl_session_timeout 5m;</span><br><span class="line"> ssl_protocols TLSv1.2; #按照这个协议配置</span><br><span class="line"> ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;#按照这个套件配置</span><br><span class="line"> ssl_prefer_server_ciphers on;</span><br><span class="line"> location / {</span><br><span class="line"> root /opt/abc; #站点目录</span><br><span class="line"> index index.html index.htm;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">server </span><br><span class="line">{</span><br><span class="line"> listen 443;</span><br><span class="line">server_name abc.chengzc.club; #填写绑定证书的域名</span><br><span class="line">root /usr/abc/; #站点目录</span><br><span class="line"> index index.html index.htm index.php;</span><br><span class="line"> ssl on;</span><br><span class="line"> ssl_certificate /ssl/1_abc.chengzc.club_bundle.crt;</span><br><span class="line"> ssl_certificate_key /vhost/ssl/2_abc.chengzc.club.key;</span><br><span class="line"> ssl_session_timeout 5m;</span><br><span class="line"> ssl_protocols TLSv1.2; #按照这个协议配置</span><br><span class="line"> ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;#按照这个套件配置</span><br><span class="line"> ssl_prefer_server_ciphers on;</span><br><span class="line"> location / {</span><br><span class="line"> if (!-e $request_filename){</span><br><span class="line"> rewrite ^(.*)$ /index.php?s=$1 last; break;</span><br><span class="line"> } </span><br><span class="line"> }</span><br><span class="line"> location ~ \.php(.*)$ {</span><br><span class="line"> fastcgi_pass unix:/tmp/php-cgi-71.sock;</span><br><span class="line"> fastcgi_index index.php;</span><br><span class="line"> fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;</span><br><span class="line"> fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;</span><br><span class="line"> fastcgi_param PATH_INFO $fastcgi_path_info;</span><br><span class="line"> fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;</span><br><span class="line"> include fastcgi_params;</span><br><span class="line"> } </span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>如何在备案完成后,同时让顶级域名和二级域名都具有ssl的访问</p>
<h1 id="在申请备案的云上面申请免费证书"><a href="#在申请备案的云上面申请免费证书" class="headerlink" title="在申请备案的云上面申请免费证书"></a>在申请</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="ssl" scheme="https://chengzc.club/tags/ssl/"/>
<category term="域名" scheme="https://chengzc.club/tags/%E5%9F%9F%E5%90%8D/"/>
</entry>
<entry>
<title>nginx使用php出现502的问题</title>
<link href="https://chengzc.club/posts/300622489/"/>
<id>https://chengzc.club/posts/300622489/</id>
<published>2019-02-28T16:13:12.000Z</published>
<updated>2023-04-13T17:28:01.953Z</updated>
<content type="html"><![CDATA[<blockquote><p>使用Nginx映射静态资源却出现502 http错误<br>查看nginx和php-fpm启动正常,查看日志发现php未连接就退出了<br>刚开始以为是端口未放行或者被占用,然而改完端口仍未解决,百度后解决方案如下:</p></blockquote><p>Php-fpm启动后没有查询到9000端口的问题<br>今天通过 oneinstack 脚本安装php环境后发现了一个奇怪的现象,php-fpm进程在运行,但是看不到监听的端口号。原来是我漏掉了一个知识点。</p><h1 id="知识点"><a href="#知识点" class="headerlink" title="知识点"></a>知识点</h1><p>nginx与php-fpm通信的两种方式: <code>tcp socket(带端口方式访问)</code> 和 <code>unix socket(通过pid进程间相互访问)</code>。</p><p>unix socket 是一种终端,可以使同一台操作系统上的两个或多个进程进行数据通信。这种方式需要再nginx配置文件中填写php-fpm的pid文件位置,效率要比tcp socket高。<br>tcp socket的优点是可以跨服务器,当nginx和php-fpm不在同一台机器上时,只能使用这种方式。<br>可以参考nginx与php-fpm通信的两种方式</p><h2 id="unix-socket配置方法"><a href="#unix-socket配置方法" class="headerlink" title="unix socket配置方法"></a>unix socket配置方法</h2><p>我用oneinstack安装的php,打开<code>/usr/local/php/etc/php-fpm.conf</code>中关于监听的部分配置如下:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[www]</span><br><span class="line">listen = /dev/shm/php-cgi.sock</span><br><span class="line">listen.backlog = -1</span><br><span class="line">listen.allowed_clients = 127.0.0.1</span><br><span class="line">listen.owner = www</span><br><span class="line">listen.group = www</span><br><span class="line">listen.mode = 0666</span><br><span class="line">user = www</span><br><span class="line">group = www</span><br></pre></td></tr></table></figure><p>所以,nginx我们应该这么配置:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">location ~ \.php(.*)$ {</span><br><span class="line"> fastcgi_pass unix:/dev/shm/php-cgi.sock;</span><br><span class="line"> fastcgi_index index.php;</span><br><span class="line"> fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;</span><br><span class="line"> fastcgi_param SCRIPT_FILENAME ;</span><br><span class="line"> fastcgi_param PATH_INFO ;</span><br><span class="line"> fastcgi_param PATH_TRANSLATED ;</span><br><span class="line"> include fastcgi_params;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种方式会遇到 access denied 的问题,参考本博客另外一篇文章。</p><h2 id="tcp-socket配置方法"><a href="#tcp-socket配置方法" class="headerlink" title="tcp socket配置方法"></a>tcp socket配置方法</h2><p>以前自己安装php都用的端口号的写法,打开/usr/local/php/etc/php-fpm.conf中关于监听的部分配置如下:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[www]</span><br><span class="line">listen = 127.0.0.1:9000</span><br><span class="line">listen.backlog = -1</span><br><span class="line">listen.allowed_clients = 127.0.0.1</span><br><span class="line">listen.owner = www</span><br><span class="line">listen.group = www</span><br><span class="line">listen.mode = 0666</span><br><span class="line">user = www</span><br><span class="line">group = www</span><br></pre></td></tr></table></figure><p>所以,nginx我们应该这么配置:</p><figure class="highlight plaintext"><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">location ~ \.php(.*)$ {</span><br><span class="line"> fastcgi_pass 127.0.0.1:9000;</span><br><span class="line"> fastcgi_index index.php;</span><br><span class="line"> fastcgi_param SCRIPT_FILENAME ;</span><br><span class="line"> include fastcgi_params;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h1><p>以前只是在mysql里看到过unix socket的用法,在php里还是头一回,涨知识了。<br>记录:</p><ol><li>注意安装完php后,php-fpm的调用方式时tcp_socket还是unix_socket,通过<strong>php-fpm.conf</strong>配置判断</li><li>修改apache默认端口:不仅要修改httpd.conf中的端口,还要修改xampp里的test端口</li><li>xampp: lsof -i:3306</li><li>博客: lsof -i:3307</li></ol>]]></content>
<summary type="html"><blockquote>
<p>使用Nginx映射静态资源却出现502 http错误<br>查看nginx和php-fpm启动正常,查看日志发现php未连接就退出了<br>刚开始以为是端口未放行或者被占用,然而改完端口仍未解决,百度后解决方案如下:</p>
</blockquot</summary>
<category term="原创" scheme="https://chengzc.club/categories/%E5%8E%9F%E5%88%9B/"/>
<category term="nginx" scheme="https://chengzc.club/tags/nginx/"/>
<category term="php" scheme="https://chengzc.club/tags/php/"/>
</entry>
<entry>
<title>关于tomcat指定主目录和虚拟目录的问题</title>
<link href="https://chengzc.club/posts/3851689809/"/>
<id>https://chengzc.club/posts/3851689809/</id>
<published>2019-02-11T08:32:12.000Z</published>
<updated>2023-04-13T17:28:01.446Z</updated>
<content type="html"><![CDATA[<blockquote><p><strong>Tomcat部署web项目,虚拟目录,上下文(Context),WEB-INF,web.xml,servlet,404<br>Web项目的uri模型大致如下:</strong></p></blockquote><figure class="highlight plaintext"><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">http://localhost:8080 (/context) (/resource)</span><br><span class="line">站点/上下文/资源</span><br></pre></td></tr></table></figure><h1 id="Tomcat中指定上下文(Context)"><a href="#Tomcat中指定上下文(Context)" class="headerlink" title="Tomcat中指定上下文(Context)"></a>Tomcat中指定上下文(Context)</h1><ul><li><p>方法一,位于webapps文件夹中的web项目,无需指定Context,Tomcat默认解析Context为该web项目根文件夹的名称,即为真实目录名称。</p></li><li><p>方法二,在server.xml中指定Context。 编辑conf\server.xml文件,在<host>元素之间加入子元素,内容如下:</p></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><Context docBase=”web项目根文件夹的文件路径” path=”/虚拟目录名称”/></span><br></pre></td></tr></table></figure><ul><li>方法三,创建*.xml文件指定Context。 在conf\Catalina\localhost文件夹中创建xml文件,文件名为“虚拟目录名称”+“.xml”,内容如下:</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><Context docBase=”web项目根文件夹的文件路径” path=”/虚拟目录名称</span><br></pre></td></tr></table></figure><h1 id="Web项目中指定资源标识"><a href="#Web项目中指定资源标识" class="headerlink" title="Web项目中指定资源标识"></a>Web项目中指定资源标识</h1><p>web项目规范:</p><ol><li>web项目的根文件夹中必须包含名称为“WEB-INF”的子文件夹。</li><li>WEB-INF中包含名称为“classes”的子文件夹,其中存放经编译后的java类。若带包名的话,应该具备匹配包名的目录结构。</li><li>WEB-INF中包含名称为“web.xml”的文件,内容如下:</li></ol> <figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"> <?xml version="1.0" encoding="ISO-8859-1"?></span><br><span class="line"></span><br><span class="line"><web-app xmlns="http://java.sun.com/xml/ns/javaee"</span><br><span class="line"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</span><br><span class="line"> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee</span><br><span class="line"> http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"</span><br><span class="line"> version="3.0"</span><br><span class="line"> metadata-complete="true"></span><br><span class="line"></web-app></span><br></pre></td></tr></table></figure><h1 id="在WEB-INF-web-xml中注册servlet"><a href="#在WEB-INF-web-xml中注册servlet" class="headerlink" title="在WEB-INF\web.xml中注册servlet"></a>在WEB-INF\web.xml中注册servlet</h1><p>编辑WEB-INF\web.xml文件,在< web-app >元素之间加入成对地添加子元素<code><servlet></code>和<code><servlet-mapping></code>,内容如下:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"><servlet></span><br><span class="line"> <servlet-name>任意命名</servlet-name></span><br><span class="line"> <servlet-class>包名+类名</servlet-class></span><br><span class="line"></servlet></span><br><span class="line"><servlet-mapping></span><br><span class="line"> <servlet-name>和上面任意命名保持一致</servlet-name></span><br><span class="line"> <url-pattern>/随意命名的资源标识符</url-pattern></span><br><span class="line"></servlet-mapping></span><br></pre></td></tr></table></figure><p>在默认安装后,tomcat的主目录是webapps/root目录,如果我们想改变tomcat的主目录的话可以这样做:</p><p>1.打开<strong>C:/Tomcat/conf/server.xml</strong>,在**<host></host>**之间加入代码:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><Context path="" docBase="E:/tomcatApp/JeasyCMS" debug="0" reloadable="true" crossContext="true"/></span><br></pre></td></tr></table></figure><p>这样重新启动tomcat,我们的主目录就被设置为jeasyCMS这个项目了。</p><p>2.另外tomcat会生成一个<strong>C:/Tomcat/conf/Catalina/localhost</strong>目录,里面自动生成了一个<strong>ROOT.xml</strong>(root大写)文件,我们打开文件可以看到这些代码:</p><figure class="highlight plaintext"><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"><?xml version='1.0' encoding='utf-8'?></span><br><span class="line">< Context crossContext="true" docBase="E:/tomcatApp/JeasyCMS" path="" reloadable="true"></span><br><span class="line">< /Context></span><br></pre></td></tr></table></figure><p>3.注意:我们创建虚拟目录的时候也是这样来进行设置的,只是context这个标签的path属性不为空。</p><p>4.我们设置虚拟目录和主目录,都会在<strong>C:/Tomcat/conf/Catalina/localhost</strong>目录下生成相应的xml文件,因此,当我们在server.xml里面删除了主目录和虚拟目录的设置后,如果系统还没有生效,这时候我们就要察看一下这个目录下的xml文件是不是已经被删除了,如果没有被删除,他还是对tomcat起作用的,我们必须手动删除。</p><p>5.基于第4点,通过测试我发现,每当我们访问一个地址的时候,tomcat首先是到<strong>C:/Tomcat/conf/Catalina/localhost</strong>目录下去察看有没有存在主目录或虚拟目录的xml文件,如果有xml文件,就按xml里的路径进行访问,如果没有xml文件,就到server.xml文件里去察看是否配置context标签,如果配置了context标签,则在<strong>C:/Tomcat/conf/Catalina/localhost</strong>目录下生成一个对应的xml文件,以便于下次直接验证而不再访问server.xml,与此同时打开context里指定的路径,如果server.xml里没有配置context标签,则返回访问错误页面。<br>6.基于第5点,我们其实可以直接在<strong>C:/Tomcat/conf/Catalina/localhost</strong>下建立一个xml文件,用于主目录或者虚拟目录,而不需要去修改server.xml就可以达到配置主目录和虚拟目录的目的,具体xml的格式可以如下:</p><figure class="highlight plaintext"><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"><?xml version='1.0' encoding='utf-8'?></span><br><span class="line">< Context crossContext="true" docBase="E:/tomcatApp/JeasyCMS" path="" reloadable="true"></span><br><span class="line">< /Context></span><br></pre></td></tr></table></figure><p>具体是主目录的配置还是虚拟目录的配置取决于path的值。另外***主目录文件名必须是ROOT.XML(root大写)***,而虚拟目录的文件名称和虚拟目录的名称一致并且为小写,譬如:</p><figure class="highlight plaintext"><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"><?xml version='1.0' encoding='utf-8'?></span><br><span class="line">< Context crossContext="true" docBase="E:/tomcatApp/JeasyCMS" path="/cms" reloadable="true"></span><br><span class="line">< /Context></span><br></pre></td></tr></table></figure><p>以上则定义了一个名为:cms的虚拟目录,同时要将以上文本保存为cms.xml文件。</p><p>7.以上住目录配置好后就可以按以下地址访问了:</p><figure class="highlight plaintext"><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">http://localhost:8080/(访问主目录)</span><br><span class="line"></span><br><span class="line">http://localhost:8080/cms (访问名为cms的虚拟目录)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote>
<p><strong>Tomcat部署web项目,虚拟目录,上下文(Context),WEB-INF,web.xml,servlet,404<br>Web项目的uri模型大致如下:</strong></p>
</blockquote>
<figure c</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="tomcat" scheme="https://chengzc.club/tags/tomcat/"/>
</entry>
<entry>
<title>JAVA学习</title>
<link href="https://chengzc.club/posts/969553277/"/>
<id>https://chengzc.club/posts/969553277/</id>
<published>2019-01-23T01:12:10.000Z</published>
<updated>2023-04-13T17:28:03.066Z</updated>
<content type="html"><![CDATA[<h1 id="annotation"><a href="#annotation" class="headerlink" title="annotation"></a>annotation</h1><h2 id="元注解:"><a href="#元注解:" class="headerlink" title="元注解:"></a>元注解:</h2><figure class="highlight plaintext"><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">1. @Target</span><br><span class="line">2. @Document</span><br><span class="line">3. @Retention</span><br><span class="line">4. @Inherited</span><br></pre></td></tr></table></figure><h2 id="Target,注解的修饰的范围"><a href="#Target,注解的修饰的范围" class="headerlink" title="@Target,注解的修饰的范围"></a>@Target,注解的修饰的范围</h2><figure class="highlight plaintext"><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">1. ElementType.CONSTRUCTOR 构造器</span><br><span class="line">2. ElementType.METHOD 方法</span><br><span class="line">3. ElementType.FIELD 属性</span><br><span class="line">4. ElementType.TYPE 接口或者类</span><br><span class="line">5. ElementType.PARAMETER 参数</span><br><span class="line">6. ElementType.PACKAGE 包</span><br></pre></td></tr></table></figure><h2 id="Retention-注释修饰的时间"><a href="#Retention-注释修饰的时间" class="headerlink" title="Retention 注释修饰的时间"></a>Retention 注释修饰的时间</h2><figure class="highlight plaintext"><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">1. RetentionPolicy.RESOURCE 源文件保留</span><br><span class="line">2. RetentionPolicy.RUNTIME 运行时保留</span><br><span class="line">3. RetentionPolicy.CLASS class文件保留</span><br></pre></td></tr></table></figure><h2 id="Inherited-元注解的一个标记注解,被标注的类型是被继承的。"><a href="#Inherited-元注解的一个标记注解,被标注的类型是被继承的。" class="headerlink" title="@Inherited 元注解的一个标记注解,被标注的类型是被继承的。"></a>@Inherited 元注解的一个标记注解,被标注的类型是被继承的。</h2><h1 id="cdn"><a href="#cdn" class="headerlink" title="cdn"></a>cdn</h1><h2 id="CDN简介:"><a href="#CDN简介:" class="headerlink" title="CDN简介:"></a>CDN简介:</h2><p>CDN就是内容分发网络 <code>Content Delivery NetWork</code>,构建在Internet上一种先进的流量分配网络。在现有的Internet<br>中添加一层新的网络架构,将网络内容分发到离用户最近的网络边缘,使用户可以就近取得所需的内容。</p><h2 id="CDN缓存内容:"><a href="#CDN缓存内容:" class="headerlink" title="CDN缓存内容:"></a>CDN缓存内容:</h2><p>目前CDN都以缓存网站中静态数据为主,如CSS. JS. 图片和静态页面等数据。用户在主站服务器请求到动态内容后,再从CDN上下载<br>这些静态数据,从而加速网站数据内容的下载速度。</p><h2 id="CDN要达到的目标:"><a href="#CDN要达到的目标:" class="headerlink" title="CDN要达到的目标:"></a>CDN要达到的目标:</h2><ol><li>可扩展性. 2. 安全性. 3. 可靠性. 响应和执行</li></ol><h2 id="负载均衡:"><a href="#负载均衡:" class="headerlink" title="负载均衡:"></a>负载均衡:</h2><ol><li>链路负载均衡:DNS解析成不同IP</li><li>集群负载均衡:由硬件和软件负载均衡</li><li>系统负载均衡:利用操作系统级别的软中断和硬中断来达到负载均衡,例如可以设置多列网卡。</li></ol><h2 id="CDN动态加速"><a href="#CDN动态加速" class="headerlink" title="CDN动态加速"></a>CDN动态加速</h2><ol><li>CDN动态加速原理;在CDN的DNS解析中,通过动态的链路探测来寻找回源最好的一条路径,然后将DNS调度将所有请求调度到选定<br>的这条路径上回源,从而加速用户的访问效率。</li><li>如何选择源站链路最好的路径让用户走,一个简单的原则就是在每个CDN节点上,从源站下载一个一定大小的文件,看哪个路径耗时最短,<br>可以构成一个链路列表,绑定到DNS解析上。</li></ol><h1 id="class"><a href="#class" class="headerlink" title="class"></a>class</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>1:任何一个Class文件都对应唯一一个类或者接口的定义信息。Class文件是一组8位字节码为基础单位的二进制流,各个项目岩哥按照顺序紧凑的排列在Class文件中,中间没有添加任何的分隔符,Class文件存储的几乎是全部的必要数据。<br>2:Class文件格式采用二中类型数据:无符号数和表。无符号数:无符号数属于基本数据类型,用来描述数字. 索引引用. 数量值或者按照UTF-8编码组成的字符串。表:是由多个无符号数或者其他表作为数据项构成的符合数据类型,所有的表都习惯性的以”_info”结尾。<br>3:每个Class文件的头4个字节成为”魔数”,它的唯一作用就是确定这个文件是否为一个能够被虚拟机接受的Class文件,很多文件存储标准中都使用魔数来进行身份识别。<br>4:Class文件的魔数值为oxCAFEBABE</p><h2 id="类的加载时机"><a href="#类的加载时机" class="headerlink" title="类的加载时机"></a>类的加载时机</h2><ol><li>类从加载到虚拟机内存开始,到卸载出内存位置。它的生命周期包括:加载. 连接. 初始化. 使用. 卸载。连接:验证. 准备. 解析。</li></ol><h2 id="类的初始化"><a href="#类的初始化" class="headerlink" title="类的初始化"></a>类的初始化</h2><ol><li>遇到new. getstatic. putstatic或invokestatic这4条字节码指令的时候,如果类没有初始化,则需要初始化。new创建一个对象,获取或者设置静态属性. 调用静态方法时,需要初始化。</li><li>使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。</li><li>当初始化一个类的时候,发现其父类没有初始化,则需要先触发其父类的初始化。</li><li>当使用jdk7动态语言支持时,有些方法句柄对应的类,没有进行初始化,需要触发其初始化。</li></ol><h2 id="类的加载过程"><a href="#类的加载过程" class="headerlink" title="类的加载过程"></a>类的加载过程</h2><ol><li>在加载阶段,虚拟机需要完成一下3件事情,1:通过一个类的权限名来获取定义此类的二进制字节流。<br>2:将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构。3:在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。</li></ol><h2 id="类加载过程:"><a href="#类加载过程:" class="headerlink" title="类加载过程:"></a>类加载过程:</h2><ol><li>加载:查找和导入class文件</li><li>连接:<br> 2.1:验证:检查载入Class文件是否符合JVM规范。<br> 2.2:准备:将静态变量分配存储空间。<br> 2.3:解析:将符号引用,转换成直接引用。</li><li>初始化:对类的静态变量,静态代码块初始化操作。</li></ol><h2 id="类的加载过程:"><a href="#类的加载过程:" class="headerlink" title="类的加载过程:"></a>类的加载过程:</h2><ol><li>类的主动引用(一定会发生类的初始化)<br>1.1 new一个类的对象<br>1.2 调用一个类的静态成员或者静态方法<br>1.3 使用反射方法对类进行反射调用<br>1.4 启动main方法所在的类<br>1.5 当初始化一个类时,其父类如果没有被初始化,则先初始化父类</li><li>类的被动引用(不会发生类的初始化)<br>2.1 当访问一个静态域时,只有真正声明的这个类才会被初始化<br> 通过子类引用父类的静态变量,子类不会被初始化<br>2.2 通过数组定义引用类,不会触发类的初始化<br>2.3 引用常量不会触发此类的初始化</li></ol><h2 id="类加载器的代理模式:"><a href="#类加载器的代理模式:" class="headerlink" title="类加载器的代理模式:"></a>类加载器的代理模式:</h2><ol><li>代理模式:交给其他加载器来加载指定的类</li><li>双亲委托机制:在加载类时,首先将加载任务交给父类加载器加载。双亲委托机制是为了保证java核心类库的类型安全。</li></ol><h2 id="类加载器的层次结构:"><a href="#类加载器的层次结构:" class="headerlink" title="类加载器的层次结构:"></a>类加载器的层次结构:</h2><ol><li>引导类加载器(根加载器)</li><li>扩展类加载器</li><li>应用程序加载器</li><li>自定义加载器</li></ol><h2 id="线程上下文加载器:"><a href="#线程上下文加载器:" class="headerlink" title="线程上下文加载器:"></a>线程上下文加载器:</h2><ol><li>当需要动态加载资源的时候,你至少有三个classloader可以选择:<br>1.1系统类加载器叫做应用加载器<br>1.2当前类加载器<br>1.3当前线程加载器<br>1.4线程类加载器是为了抛弃双亲委派加载链模式<br>每个线程都有一个关联的上下文类加载器。如果使用new Thread方式生成新的线程,新线程将继承父线程的上下文加载器</li></ol><h1 id="concurrent"><a href="#concurrent" class="headerlink" title="concurrent"></a>concurrent</h1><ul><li>jdk1.5以后,推出了java.util.concurrent包</li><li>Executor:具体的Runnable的执行者</li><li>ExecutorService:一个线程池的管理者,其实现类有很多,可以把Runnable. Callable提交到线程池中调用。</li><li>Semaphore:信号量。</li><li>ReentrantLock:可重入的互斥锁。</li><li>Future:与Runnable. Callable接口进行交互。</li><li>BlockingQueue:阻塞队列。</li><li>CompletionService:ExecutorService的扩展,可以活得最先执行完线程的结果,底层实现是通过阻塞队列。</li><li>CountDownLatch:一个同步辅助类,完成一组正在其他线程中执行的操作之前,允许一个或者多个线程一直等待。</li><li>CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到达到某个屏障点。</li><li>CopyOnWriteArrayList:</li></ul><ol><li>在CopyOnWriteArrayList在处理写(包括add. set. remove)操作的时候,先将原始数据通过Array.copyOf来生成一个新的数组,<br>在新的数据对象上写,写完后再将原来的引用指向当前的数据对象,并加锁。</li><li>读操作在引用的当前引用的对象上进行读,不存在加锁和阻塞。</li><li>因为每次使用CopyOnWriteArrayList.add都要引起数组拷贝,所以应该避免在循环中使用。可以在初始化完成之后设置到CopyeOnWriteArrayList中,或者使用CopyOnWriteArrayList.addAll方法。</li><li>CopyOnWriteArrayList采用“写入时复制”策略,对容器的写操作将导致的容器中基本数据的复制,性能开销较大。所以在有写操作的情况下,CopyOnWriteArayList性能不佳,而且如果容器容量较大的话容易造成溢出。</li></ol><ul><li><p>线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。<br>说明:Executors 返回的线程池对象的弊端如下:<br>1)FixedThreadPool 和 SingleThreadPool:<br>允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。<br>2)CachedThreadPool 和 ScheduledThreadPool:<br>允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。</p></li><li><p>SimpleDateFormat 是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。</p></li></ul><p>正例:注意线程安全,使用 DateUtils。亦推荐如下处理:</p><figure class="highlight plaintext"><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">private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override</span><br><span class="line">protected DateFormat initialValue() {</span><br><span class="line">return new SimpleDateFormat("yyyy-MM-dd");</span><br><span class="line"> };}</span><br></pre></td></tr></table></figure><ul><li><p>高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能 锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。</p></li><li><p>对多个资源. 数据库表. 对象同时加锁时,需要保持一致的加锁顺序,否则可能会造 成死锁。<br>说明:线程一需要对表 A. B. C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序 也必须是 A. B. C,否则可能出现死锁。</p></li><li><p>并发修改同一记录时,避免更新丢失,要么在应用层加锁,要么在缓存加锁,要么在 数据库层使用乐观锁,使用 version 作为更新依据。<br>说明:如果每次访问冲突概率小于20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于3次。</p></li><li><p>多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获 抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。</p></li><li><p>使用 CountDownLatch 进行异步转同步操作,每个线程退出前必须调用 countDown方法,线程执行代码注意 catch 异常,<br>确保 countDown 方法可以执行,避免主线程无法执行 至 countDown 方法,直到超时才返回结果。 说明:注意,子线程抛出异常堆栈,不能在主线程 try-catch 到。</p></li><li><p>避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 seed 导致的性能下降。<br>说明:Random 实例包括 java.util.Random 的实例或者 Math.random()实例。<br>正例:在 JDK7 之后,可以直接使用 API ThreadLocalRandom,在 JDK7 之前,可以做到每个 线程一个实例。</p></li><li><p>volatile 解决多线程内存不可见问题。对于一写多读,是可以解决变量同步问题, 但是如果多写,同样无法解决线程安全问题。如果是 count++操作,使用如下类实现:<br>AtomicInteger count = new AtomicInteger(); count.addAndGet(1);如果是 JDK8,推 荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)。</p></li><li><p>HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,在 开发过程中注意规避此风险</p></li><li><p>ThreadLocal 无法解决共享对象的更新问题,ThreadLocal 对象建议使用 static 修饰。<br>这个变量是针对一个线程内所有操作共有的,所以设置为静态变量,所有此类实例共享 此静态变量 ,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只 要是这个线程内定义的)都可以操控这个变量。</p></li></ul><h1 id="core"><a href="#core" class="headerlink" title="core"></a>core</h1><h2 id="volatile"><a href="#volatile" class="headerlink" title="volatile"></a>volatile</h2><ol><li>volatile修饰的变量,可以保证从主内存加载到线程内存的值是最新的。</li><li>volatile可以防止指令重排序。</li></ol><h2 id="单例模式失效"><a href="#单例模式失效" class="headerlink" title="单例模式失效"></a>单例模式失效</h2><p>双重锁检测,可能会失效。原因在于:初始化Singleton和将地址写入到instance字段的顺序是不确定的。在某个线程new Singleton()时,在构造方法之前,就为<br>该对象分配了内存空间并将对象的字段设置成默认值。此时就可以将分配的内存地址赋值给instance字段了,然而改对象可能还没有初始化;此时若另外一个线程来调用<br>getInstance,渠道的状态就是不正确的对象。</p><h2 id="一致性Hash算法"><a href="#一致性Hash算法" class="headerlink" title="一致性Hash算法"></a>一致性Hash算法</h2><ol><li>一个分布式系统,要将数据存储到具体的节点。如果普通的hash方法,将数据映射到具体的节点上,如key%N,key是数据的key,N是机器节点,如果有一个机器加入<br>或者退出这个集群,则所有的数据映射都无效,如果是持久化存储则要做数据迁移,如果是分布式存储,则其他存储就失效了。</li><li>把数据用户hash函数(如MD5),映射到一个很大的空间。数据的存储时,先得到一个hash值,对应到这个环上的每个位置。数据沿着顺时针找到一个机器节点,将数据<br>存储到这个机器上。</li><li>当其中一个机器节点挂掉后,另外一个节点会承担挂掉节点的数据,另外一个节点很容易宕机。</li><li>引入”虚拟节点”的概念:即把想象在这个环上有很多“虚拟节点”,数据的存储是沿着环的顺时针方向找一个虚拟节点,每个虚拟节点都会关联到一个真实节点。由于这些<br>虚拟节点数量很多,均匀分布,因此不会造成“雪崩”现象。</li></ol><h2 id="equals-和-hashcode"><a href="#equals-和-hashcode" class="headerlink" title="equals 和 hashcode"></a>equals 和 hashcode</h2><p>在Java中任何一个对象都具备equals(Object obj)和hashcode()这两个方法,因为他们是在Object类中定义的。<br>equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。<br>hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。<br>若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值<br>Oject类中的equals方法用来比较两个引用值,hashCode用来返回引用的内地址的十六进制数值。在Set以及Map集合中,判断两个元素是否重复时,往往需要使用这两个方法。这两个方法往往被子类覆盖</p><ol><li><p>如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。 </p></li><li><p>如果两个对象不equals,他们的hashcode有可能相等。 </p></li><li><p>如果两个对象hashcode相等,他们不一定equals。 </p></li><li><p>如果两个对象hashcode不相等,他们一定不equals。<br>for testsdsdsd</p></li><li><p>如果两个对象hashcode相等,他们不一定equals。</p></li><li><p>如果两个对象hashcode不相等,他们一定不equals。</p></li></ol><h1 id="design"><a href="#design" class="headerlink" title="design"></a>design</h1><h2 id="设计模式的六大原则:"><a href="#设计模式的六大原则:" class="headerlink" title="设计模式的六大原则:"></a>设计模式的六大原则:</h2><ol><li>开闭原则:对扩展开放,对修改关闭。为了程序可扩展. 易于维护和升级,需要使用接口和抽象类。</li><li>里氏替换原则:任何基类出现的地方,子类一定可以出现。</li><li>依赖反转原则:针对接口编程,依赖抽象,不依赖具体。</li><li>接口隔离原则:使用多个隔离的接口,比使用单个接口要好。</li><li>迪米特法则(最少知道原则):一个实体应该尽量少的和其他实体之间发生交互。</li><li>合成复用原则:尽量使用聚合,合成方式,而不是使用继承。</li></ol><h2 id="设计模式分类"><a href="#设计模式分类" class="headerlink" title="设计模式分类"></a>设计模式分类</h2><ol><li>创建型模式:工厂模式. 抽象工厂模式. 单例模式. 建造者模式,原型模式。</li><li>结构型模式:适配器. 装饰器. 代理. 外观. 桥接. 组合. 享元模式</li><li>行为型模式:策略模式. 模板方法. 观察者模式. 迭代子模式. 责任链模式. 命令模式. 备忘录模式. 状态模式. 访问者模式. 中介模式. 解析器模式。</li><li>其他2种:并发型模式. 线程池模式。</li></ol><h2 id="常见设计模式:"><a href="#常见设计模式:" class="headerlink" title="常见设计模式:"></a>常见设计模式:</h2><ol><li>策略模式:定义了一系列算法,并将每个算法封装起来,使他们可以互相替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为<br>一系列实现类提供方法,多个实现类实现该接口。</li><li>模板方法:准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式展现,然后声明一些抽象方法来迫使子类实现剩余逻辑。不同的子类可以以不同<br>的逻辑来实现。</li><li>工厂方法:建立一个工厂类,对实现了同一个接口的一些类做实例化。</li><li>适配器模式:适配器模式将某个类的接口转换成希望的另外一个接口表示,目的是为了消除由于接口不匹配造成的兼容性问题。主要包括三类,类的适配器.<br>对象的适配模式. 接口的适配模式。<br>类的适配器:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里。<br>对象的适配器:基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。<br>接口的适配器:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,<br>有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,<br>只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行</li><li>装饰模式:装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例</li><li>代理模式:代理模式就是多一个代理类出来,替原对象进行一些操作</li></ol><h2 id="面向对象的五大基本原则-solid"><a href="#面向对象的五大基本原则-solid" class="headerlink" title="面向对象的五大基本原则(solid)"></a>面向对象的五大基本原则(solid)</h2><ol><li>S单一职责SRP:Single-Responsibility Principle 一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合,高内聚在面向对象原则的引申,将职责定义为引起变化的原因,以提高内聚性减少引起变化的原因。</li><li>O开放封闭原则OCP:Open-Closed Principle 软件实体应该是可扩展的,而不是可修改的。对扩展开放,对修改封闭</li><li>L里氏替换原则LSP:Liskov-Substitution Principle 子类必须能够替换其基类。这一思想表现为对继承机制的约束规范,只有子类能够替换其基类时,才能够保证系统在运行期内识别子类,这是保证继承复用的基础。</li><li>I接口隔离原则ISP:Interface-Segregation Principle 使用多个小的接口,而不是一个大的总接口</li><li>D依赖倒置原则DIP:Dependency-Inversion Principle 依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者共同依赖于抽象。抽象不依赖于具体,具体依赖于抽象。</li></ol><h1 id="EasyCoding"><a href="#EasyCoding" class="headerlink" title="EasyCoding"></a>EasyCoding</h1><h2 id="Cpu与内存"><a href="#Cpu与内存" class="headerlink" title="Cpu与内存"></a>Cpu与内存</h2><ol><li>Cpu是一块超大规模集成电路板,是计算机的核心部件。CPU包括:控制器. 运算器. 寄存器;</li><li>控制器组成:控制单元. 指令译码器. 指令寄存器组成;控制单元是CPU的大脑,由时序控制器和指令控制器组成;指令译码器是在控制单元的协调下完成指令读取,<br>分析并交由运算器执行;指令寄存器是存成指令集,当前流行的指令集包括:X86,SSE,MMX等。</li><li>运算器:核心是算术逻辑运算单元,ALU,能执行算术运算或逻辑运算等各种指令。运算单元会从寄存器中提取或者存储数据。</li><li>寄存器:最著名的寄存器是CPU的高速缓存L1. L2,缓存容量是在组装计算机逼问的CPU性能问题之一;CPU缓存部分指令和数据,以提升性能;</li><li>L0寄存器. L1一级缓存. L2二级缓存. 内存. 本地磁盘. 分布式存储. 云端存储;</li></ol><h2 id="TCP-IP协议"><a href="#TCP-IP协议" class="headerlink" title="TCP. IP协议"></a>TCP. IP协议</h2><ol><li>传输控制协议/因特网互联协议。是当前流行的网络传输协议框架。</li><li>OSI模型:物理层. 数据链路层. 网络层. 传输层. 会话层. 表示层. 应用层;</li></ol><h2 id="影响RPC性能的因素如下:"><a href="#影响RPC性能的因素如下:" class="headerlink" title="影响RPC性能的因素如下:"></a>影响RPC性能的因素如下:</h2><ol><li>序列化。常用的RPC序列化协议包括:Thrift. Protobuf. Avro. Kryo. MsgPack. Hessian. Jackson。</li><li>传输协议。常用的传输协议包括:HTTP. Socket. TCP. UDP等;</li><li>连接。连接包括:长连接. 短链接;</li><li>IO模型。常用的网络IO模型:同步阻塞IO. 同步非阻塞IO. IO多路复用. 异步IO;<br>注释:stub一般翻译成存根,即在本地存在一个和远程一样的方法;</li></ol><h2 id="Protobuf"><a href="#Protobuf" class="headerlink" title="Protobuf"></a>Protobuf</h2><p>protobuf是一个高性能. 易扩展的序列化框架,通常是rpc调用追求高性能的首选。结合Netty可以非常便捷的实现RPC调用。Protobuf比JSON. XML更快. 更轻. 更小<br>,并且可以跨平台。Protobuf首先要编写proto文件,即IDL文件,后缀为“.proto”的文件。然后通过客户端生成Java相关类进行序列化. 反序列化。</p><h2 id="Rest"><a href="#Rest" class="headerlink" title="Rest"></a>Rest</h2><p>Rest是Representaitional State Transfer的缩写,通常翻译成“表现层状态转换”;</p><ol><li>协议:API基于HTTP协议;</li><li>域名:需要一个域名例如:<a href="http://api.xx.com/">http://api.xx.com</a>;</li><li>版本:需要版本信息,例如<a href="http://api.xx.com/v1/">http://api.xx.com/v1/</a></li><li>路径:rest开发又被称作是面向资源的开发。例如<a href="http://api.xx.com/v1/user/">http://api.xx.com/v1/user/</a></li><li>方法:一般包含的方法包括:get(获取资源,一个或者多个);post(创建资源);put(修改资源,客户端提供修改后的完整资源);<br>patch(对已知资源进行全局更新,客户端需要提供改变的属性);delete(删除,回收资源);head(获取资源的元数据);option(读取对资源的访问权限);<br>注释:SLA:需要提供相应时间. 吞吐量. 可用性等关键指标;</li></ol><h2 id="HTTP-x2F-2协议"><a href="#HTTP-x2F-2协议" class="headerlink" title="HTTP/2协议"></a>HTTP/2协议</h2><p>HTTP/2对比HTTP/1.x进行了大量简化,使得性能大幅提升;HTTP/2是基于二进制协议的。<br>HTTP/1.x的语义只支持客户端发起请求,服务端响应数据。HTTP/2改变了这种模式,只需要客户端发送一次请求,服务端便把所有的资源都推送到客户端。</p><h2 id="Cloud-Native属性总结"><a href="#Cloud-Native属性总结" class="headerlink" title="Cloud Native属性总结"></a>Cloud Native属性总结</h2><p>分布式. 弹性. 多租户. 自服务. 按需计量和计费. 增量部署和测试;</p><h2 id="gRPC"><a href="#gRPC" class="headerlink" title="gRPC"></a>gRPC</h2><ol><li>gRPC默认使用Protobuf进行序列化和反序列化。</li><li>gRPC默认采用HTTP/2进行传输。HTTP/2支持流(streaming),在批量发送数据的场景下使用流可以显著提升性能;</li><li>gRPC流可以分为三类:客户端流式发送. 服务端流式返回. 客户端/服务端同时流式处理;</li><li>gRPC并非完美,相比非IDL描述的RPC(Hession. Kyro)方式,定义proto文件是一个比较麻烦的事情。另外HTTP/2相比于基于TCP的通信协议,心梗也有显著的差异;</li></ol><h2 id="微服务框架"><a href="#微服务框架" class="headerlink" title="微服务框架"></a>微服务框架</h2><p>服务治理. 容量规划. 高效通信(需要微服务框架实现高效的序列化. 反序列化. 支持并行. 异步. 非阻塞转换以及多语言支持). 负载均衡(微服务框架需要支持常用<br>负载均衡. 故障转移. 支持自由的流量切换);</p><h2 id="Dubbo"><a href="#Dubbo" class="headerlink" title="Dubbo"></a>Dubbo</h2><ol><li>Dubbot中的角色:Provider提供者,Consumer消费者. Registry注册中心. Montiro监控中心。</li><li>消费者启动后,会查询注册中心,注册中心返回提供者地址列表给消费者。如果有变更,注册中心将以长连接推送变更数据给消费者。</li></ol><h2 id="Etcd"><a href="#Etcd" class="headerlink" title="Etcd"></a>Etcd</h2><p>Etcd是一个高可用的键值存储系统,主要用于共享配置和服务发现。它使用Go语言编写,并通过Raft一致性算法处理日志复制以保障强一致性。Etcd并不是强一致的。</p><h2 id="微服务部署策略"><a href="#微服务部署策略" class="headerlink" title="微服务部署策略"></a>微服务部署策略</h2><p>服务独享数据库. 服务独享虚拟机/容器;</p><h2 id="容器VS虚拟机"><a href="#容器VS虚拟机" class="headerlink" title="容器VS虚拟机"></a>容器VS虚拟机</h2><p>虚拟机是在硬件的基础上进行虚拟化,隔离性更高,而容器是在操作系统上进行的虚拟化。容器更像软件中的集装箱,能够把环境. 配置. 依赖. 软件等封装起来。<br>Docker可以让开发者大宝应用及依赖包到一个轻量级. 可移植的容器中,然后发布到任何安装了Docker的物理机或者虚拟机上,而不必担心是否安装了依赖项,<br>不必考虑编译器或其他任何需要支持的基础设施;</p><h2 id="分布式消息中间件"><a href="#分布式消息中间件" class="headerlink" title="分布式消息中间件"></a>分布式消息中间件</h2><p>通过分布式消息中间件解耦。系统之间可以进行可靠的异步通信,从而降低系统之间的耦合度,系统能够得到更好的扩展性和可用性。通过分布式消息中间件降低响应<br>时间。通过分布式消息中间件提升吞吐率。</p><h2 id="Kafka的设计原理"><a href="#Kafka的设计原理" class="headerlink" title="Kafka的设计原理"></a>Kafka的设计原理</h2><p>在Kafka中,消息被持久化到磁盘,Kafka需要依赖于ZooKeeper管理元数据。<br>Borker:Kafka的服务端,负责接收数据,并持久化数据,Broker可以有多个,每隔Broker可以包含多个Topic,Broker并不保存Offset数据,由Consumer自己<br>负责保存,默认保存在Zookeeper中。<br>Producer:生产者,生成数据发送到Broker存储数据,Producer将会和Topic下所有Partition Leader保持连接。<br>Consumer:消费者,每个Partition只能被一个消费者订阅,一个消费者可以订阅多个Partition,消费者挂掉后会从新进行负载均衡。<br>Topic:主题,每个Topic包含多个Partition,所有的元数据都存储在ZooKeeper中。<br>Partition:分区,Kafka为了扩展性,可以将一个Topic拆分为多个分区,每个分区可以独立放到一个Broker上。</p><h1 id="generic"><a href="#generic" class="headerlink" title="generic"></a>generic</h1><h2 id="概念:"><a href="#概念:" class="headerlink" title="概念:"></a>概念:</h2><ol><li>泛型是参数化类型,使用广泛的类型。</li><li>起因:数据类型不明确,装入的类型被当做Object对待,从而”丢失”自己的实际类型。获取数据的时候往往需要转型,效率低,容易产生错误。</li><li>作用:3.1安全,在编译的时候检查类型安全。3.2省心,所有强制类型转换都是自动和隐式的,提高代码的重用率。</li></ol><h2 id="定义:"><a href="#定义:" class="headerlink" title="定义:"></a>定义:</h2><p>class 类名 <字母列表> {<br> 修饰符 字母 属性<br> 修饰符 构造器{<br> }<br> 修饰符 返回类型 方法(){<br> }<br>}<br>泛型常见的字母列表:<br>T type 表示类型<br>K V 分别表示键中的key 和 value的值。<br>E 代表Element<br>? 代表不确定的类型</p><h2 id="泛型使用需注意问题:"><a href="#泛型使用需注意问题:" class="headerlink" title="泛型使用需注意问题:"></a>泛型使用需注意问题:</h2><ol><li>不能用在静态属性. 静态方法上</li><li>泛型使用不能指定基本类型</li><li>接口中泛型只能使用在接口方法中,不能使用在全局变量中</li></ol><h1 id="http"><a href="#http" class="headerlink" title="http"></a>http</h1><h2 id="HTTP协议特点:"><a href="#HTTP协议特点:" class="headerlink" title="HTTP协议特点:"></a>HTTP协议特点:</h2><ol><li>支持客户端和服务端</li><li>简单:客户向服务器发送请求时,只需要传送请求方法和路径。</li><li>灵活:HTTP允许传输任意类型的数据对象</li><li>无连接:无连接限制每次连接只处理一次请求。服务器处理完客户的请求后,并收到客户的应答后,立即断开连接,采用这种方式节省时间</li><li>无状态:HTTP协议时无状态的,对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则必须重传</li></ol><h2 id="Cookie和Session"><a href="#Cookie和Session" class="headerlink" title="Cookie和Session"></a>Cookie和Session</h2><ol><li>Cookie数据存放到客户端的浏览器上,sessions数据存放在服务器上。</li><li>cookie不是很安全,别人可以分析本地的cookie并进行cookie欺骗。</li><li>单个cookie保存的数据不能超过4k,很多浏览器限制一个站点最多保存20个cookie</li><li>Cookie 客户端需要每次将Cookie的值传送给服务端,如果Cookie的值很大,无形中增加了客户端与服务端数据传输的数量</li><li>Session 同一个客户端和服务端交互,不需要每次都回传所有的cookie值,而是只需要传递一个JssionId</li></ol><h2 id="HTTP介绍"><a href="#HTTP介绍" class="headerlink" title="HTTP介绍"></a>HTTP介绍</h2><ol><li>大多数传统的c/s互联网应用采用长连接方式</li><li>http采用无状态的端连接,采用这种方式的目的是未来同时服务更多的用户。</li><li>互联网所有的资源都需要用一个URL标识,URL是统一资源定位符</li><li>发起一个HTTP请求就是建立一个Socket的过程。</li><li>Http Header是控制着互联网用户数据的传输,控制着浏览器的渲染行为和服务器的执行逻辑。</li><li>http请求头,包括accept-charset 指定客户端接受的字符集。Accept-Encoding 用于接受可接受的内容编码。Accept-Language,<br>用于指定一种自然语言。</li></ol><h2 id="DNS"><a href="#DNS" class="headerlink" title="DNS"></a>DNS</h2><ol><li>将域名解析成IP</li><li>DNS解析过程<br>2.1 检查缓存中是否有域名对应的IP,如果有直接使用,缓存大小,缓存时间都有限制。缓存时间太长一旦域名对应的IP有变化,这段时间会有部分用户无法访问。<br>时间太短,每次访问都需要重新解析。<br>2.2 如果浏览器没有缓存,操作系统也可以存储。windows在host中存储,linux在etc/host中存储。</li><li>几种域名解析方式<br>3.1:A记录,A代表Address,用来指定域名对应的IP地址。A记录可以将多个域名解析到一个IP地址。但是不能将多个域名解析到多个IP地址。<br>3.2:CNAME记录,全称(别名解析),所谓的别名解析就是将一个域名设置一个或者多个别名。</li></ol><h2 id="Http和Https的区别"><a href="#Http和Https的区别" class="headerlink" title="Http和Https的区别"></a>Http和Https的区别</h2><ol><li>Https即Secure Hypertext Transfer Protocol,即安全超文本传输协议,它是一个安全通信信道,基于Http开发,用于在客户机和服务器间交换信息。它使用安全套接字层SSL进行信息交换,是Http的安全版。</li><li>Https协议需要到CA申请证书,一般免费证书很少,需要交费。</li><li>Http是超文本传输协议,信息是明文传输,https则是具有安全性的tls/ssl加密传输协议。</li><li>http是80端口,https是443端口</li></ol><h2 id="浏览器输入一个URL的过程"><a href="#浏览器输入一个URL的过程" class="headerlink" title="浏览器输入一个URL的过程"></a>浏览器输入一个URL的过程</h2><ol><li>浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址</li><li>解析出IP地址后,根据IP地址和默认端口80和服务器建立TCP连接</li><li>浏览器发出Http请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器</li><li>服务器做出响应,把对应的请求资源发送给浏览器</li><li>释放TCP连接</li><li>浏览器解析并显示内容</li></ol><h2 id="LinuxIO模型"><a href="#LinuxIO模型" class="headerlink" title="LinuxIO模型"></a>LinuxIO模型</h2><ol><li>阻塞IO模型 以socket为例,在进程空间调用recvfrom,其系统调用知道数据包到达且被复制到应用进程的缓冲区或者发生错误才返回,在此期间一直等待,进程从调用recvfrom开始到它返回的整段时间内都是被阻塞的,因此称为阻塞IO</li><li>非阻塞IO模型 应用进程调用recvfrom,如果缓冲区没有数据直接返回EWOULDBLOCK错误。一般对非阻塞IO进行轮询,以确定是否有数据到来。</li><li>IO多路复用模型<br>Linux提供select/poll,通过将一个或多个fd传递给select或poll系统调用,阻塞在select上。select/poll顺序扫描fd是否就绪。</li><li>信号驱动IO<br>开启套接字接口信号驱动IO功能,并通过系统调用sigaction执行信号处理函数。当数据准备就绪时,为该进程生成SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主函数处理数据。</li><li>异步IO<br>告知内核启动某个操作,并让内核在整个操作完成后通知我们。它与信号驱动IO的区别在于信号驱动IO由内核通知我们何时可以开始IO操作。而异步IO模型由内核通知我们IO操作已经完成。</li></ol><h1 id="instrumentation"><a href="#instrumentation" class="headerlink" title="instrumentation"></a>instrumentation</h1><h2 id="Instrumentation"><a href="#Instrumentation" class="headerlink" title="Instrumentation"></a>Instrumentation</h2><p>Instrumentation类为JVM上运行时的程序提供测量手段。很多工具通过Instrumentation修改方法字节码,实现数据收集的目的。<br>这些通过Instrumentation搜集数据的工具不会改变程序的状态和行为。这些良好的工作包括,monitoring agents, profilers, coverage analyzers, 和event loggers。</p><h2 id="获取Instrumentation接口的方式"><a href="#获取Instrumentation接口的方式" class="headerlink" title="获取Instrumentation接口的方式"></a>获取Instrumentation接口的方式</h2><ol><li>启动JVM时指定agent类,这种方式,instrumentation的实例通过agent class的premain方法被传入。</li><li>JVM提供了一种当JVM启动完成后启动agent机制,这种情况下,Instrumentation通过agent代码中的agentmain方式传入。<br>java agent 在JDK package specification中解释:一个agent 是被作为Jar 文件形式来部署的。在Jar文件中manifest中指定哪个类作为agent类。</li></ol><h1 id="Interview"><a href="#Interview" class="headerlink" title="Interview"></a>Interview</h1><h2 id="导致服务器频繁fullGC的原因有那些?"><a href="#导致服务器频繁fullGC的原因有那些?" class="headerlink" title="导致服务器频繁fullGC的原因有那些?"></a>导致服务器频繁fullGC的原因有那些?</h2><h2 id="限流算法"><a href="#限流算法" class="headerlink" title="限流算法"></a>限流算法</h2><ol><li>在高并发的系统中,缓存. 降级. 限流是三把利器。</li><li>限流就是限制流量,很好的控制系统的qps,从而达到保护系统的作用。</li><li>限流的方法<br>1)计数器:计数器是最简单最容易实现的算法。设置一个计数器counter,没当一个请求过来的时候,counter加1,如果counter的值大于100,并且<br>请求与第一个请求的间隔时间在1分钟以内,那么说明请求数过多。算法简单,最容易出现的是临界值问题。<br>2)滑动窗口:滑动窗口为了解决临界值问题,很多个矩形框组成时间窗口,每个时间窗口是1分钟,将滑动窗口划分为6个格子,每个格代表10秒钟,没过<br>10秒钟,格子向右滑动一格,每个各自有自己的counter。滑动窗口划分的格子越多,滑动窗口的滚动就越平滑,限流的统计就越精确。</li></ol><p>滑动窗口指收发两端分别维护一个发送窗口和接收窗口,发送窗口有一个窗口值Wt,窗口值Wt代表在没有收到对方确认的情况下最多可以发送的帧的数目。<br>当发送的帧的序号被接收窗口正确收下后,接收端向前滑动并向发送端发去确认,发送端收到确认后,发送窗口向前滑动。收发两端按规律向前推进.<br>滑动窗口指接收和发送两端的窗口按规律不断向前推进,是一种流量控制的策略.</p><p>3)漏桶算法:有个固定容量的桶,有水流进来,也有水流出去,对于进来的水,无法估量有多少,水流的速度也无法估计,但是对于流出去的水来说,可以固定流出的频率。而且<br>当桶满后,多余的水会流出去。<br>我们将算法中的水换成实际应用中的请求,我们可以看到漏桶算法天生就限制了请求的速度。当使用了漏桶算法,我们可以保证接口会以一个常速速率来处理请求。所以漏桶算法天生不会出现临界问题。<br>4)令牌桶算法:令牌桶算法比漏桶算法稍显复杂。首先,我们有一个固定容量的桶,桶里存放着令牌(token)。桶一开始是空的,token以 一个固定的速率r往桶里填充,直到达到桶的容量,多余的令牌将会被丢弃。<br>每当一个请求过来时,就会尝试从桶里移除一个令牌,如果没有令牌的话,请求无法通过。<br>我们会发现我们默认从桶里移除令牌是不需要耗费时间的。如果给移除令牌设置一个延时时间,那么实际上又采用了漏桶算法的思路。Google的guava库下的SmoothWarmingUp类就采用了这个思路。</p><p>Java实现<br>我们可以使用Guava 的 RateLimiter 来实现基于令牌桶的流控,RateLimiter 令牌桶算法是单桶实现。RateLimiter 对简单的令牌桶算法做了一些工程上的优化,具体的实现是 SmoothBursty。<br>需要注意的是,RateLimiter 的另一个实现SmoothWarmingUp,就不是令牌桶了,而是漏桶算法。也许是出于简单起见,RateLimiter 中的时间窗口能且仅能为 1s。<br>SmoothBursty 有一个可以放 N 个时间窗口产生的令牌的桶,系统空闲的时候令牌就一直攒着,最好情况下可以扛 N 倍于限流值的高峰而不影响后续请求。<br>RateLimite允许某次请求拿走超出剩余令牌数的令牌,但是下一次请求将为此付出代价,一直等到令牌亏空补上,并且桶中有足够本次请求使用的令牌为止。<br>当某次请求不能得到所需要的令牌时,这时涉及到一个权衡,是让前一次请求干等到令牌够用才走掉呢,还是让它先走掉后面的请求等一等呢?Guava 的设计者选择的是后者,先把眼前的活干了,后面的事后面再说。</p><h2 id="线程池排队策略"><a href="#线程池排队策略" class="headerlink" title="线程池排队策略"></a>线程池排队策略</h2><ol><li>直接提交:工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。<br>当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。</li><li>无界队列:使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。<br>(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;</li><li>有界队列:有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:<br>使用大型队列和小型池可以最大限度地降低 CPU 使用率. 操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。<br>四种预定义的处理程序策略:<br>在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时RejectedExecutionException。<br>在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。<br>在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。<br>在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。</li></ol><ul><li>除了kv类型的数据存储外,redis适合的业务场景</li><li>如果解决写操作跨库的数据一致性问题</li><li>spring aop如何实现,两种的区别,描述一下java动态代理的实现</li><li>什么是乐观锁,乐观锁的机制是什么,<br>乐观锁实现的机制就是CAS操作</li></ul><h2 id="线程通信"><a href="#线程通信" class="headerlink" title="线程通信"></a>线程通信</h2><p>线程间通信和同步的方式主要有锁. 信号. 信号量<br>进程间的通信:通信机制主要有:管道. 有名管道. 消息队列. 信号量. 共享空间. 信号. 套接字(socket)<br>java线程通信 wait. notify. notifyAll. concurrent包lock下的condition里的await. signal. signalALl方法</p><h1 id="io"><a href="#io" class="headerlink" title="io"></a>io</h1><h2 id="字节流:"><a href="#字节流:" class="headerlink" title="字节流:"></a>字节流:</h2><ol><li>字节流可以处理一切(文本. 音频. 视频)</li><li>输入流 InputStream FileInputStream ByteArrayInputStream ObjectInputStream BufferedInputStream FilterInputStream DataInputStream</li><li>操作read字节数组<br>中间容器 byte[] flush = new byte[长度],接收长度 int len = 0,循环读取while(-1!=(len=流.read(flush)))。输出拷贝</li><li>输出流 OutputStream FileOutputStream ByteArrayOutputStream ObjectOutputStream BufferedOutputStream DataOutputStream</li><li>操作write(字节数组,0,长度)</li></ol><h2 id="字符流"><a href="#字符流" class="headerlink" title="字符流"></a>字符流</h2><ol><li>字符流,只能处理纯文本</li><li>输入流 Reader FileReader</li><li>操作read(字符数组)</li><li>中间容器 byte[] flush = new byte[长度],接收长度 int len = 0,循环读取while(-1!=(len=流.read(flush)))。输出拷贝</li><li>输出流:Writer FileWriter</li><li>操作write(字节数组,0,长度)</li></ol><h2 id="字节流和字符流转换"><a href="#字节流和字符流转换" class="headerlink" title="字节流和字符流转换"></a>字节流和字符流转换</h2><ol><li>输入流 InputStreamReader 解码</li><li>输出流 OutputStreamWriter 编码</li></ol><h2 id="缓冲流"><a href="#缓冲流" class="headerlink" title="缓冲流"></a>缓冲流</h2><ol><li>输入流:BufferedInputStream BufferedReader</li><li>输出流:BufferedOutputStream BufferedWriter</li></ol><h2 id="处理数据-类型"><a href="#处理数据-类型" class="headerlink" title="处理数据+类型"></a>处理数据+类型</h2><ol><li>输入流:DataInputStream readXxx</li><li>输出流:DataOutputStream writeXxx</li><li>引用类型<br>3.1 反序列化 ObjectInputStream readObject<br>3.2 序列化 ObjectOutputStream wirteObject</li></ol><h2 id="打印流:PrintStream"><a href="#打印流:PrintStream" class="headerlink" title="打印流:PrintStream"></a>打印流:PrintStream</h2><h2 id="IO流分类"><a href="#IO流分类" class="headerlink" title="IO流分类"></a>IO流分类</h2><ol><li>基于字节操作的IO接口:InputStream. OutputStream</li><li>基于字符操作的IO接口:Reader. Writer</li><li>基于磁盘操作的IO接口:File</li><li>基于网络操作的IO接口:Socket</li></ol><h2 id="字节和字符转换"><a href="#字节和字符转换" class="headerlink" title="字节和字符转换"></a>字节和字符转换</h2><ol><li>InputStreamReader:从字节流转换成字符流,转换是需要指定编码格式,否则很容易出现乱码,StreamDecoder正是完成字节到字符的解码实现类。</li><li>OutputStreamWriter:从字符流转换成字节流,由StreamEncoder完成编码过程。</li></ol><h2 id="磁盘IO工作机制:"><a href="#磁盘IO工作机制:" class="headerlink" title="磁盘IO工作机制:"></a>磁盘IO工作机制:</h2><p>9.1几种访问文件的方式:</p><ol><li>标准访问文件方式:<br>read接口,首先读取用户地址空间的缓存是否存在,如果存在直接返回,如果不存在,读取内核空间的高速页缓存,如果没有则读取磁盘空间。<br>write接口,首先将数据从用户地址空间复制到内核地址空间的缓存中,这时对用户来说操作已经完成,至于什么时候写入磁盘由操作系统决定,也可以调用sync同步完成。</li><li>直接IO访问方式:就是应用程序直接访问磁盘,不经过操作系统内核数据缓存区,目的为了减少一次从内核缓冲区到用户缓冲区数据的复制。例如数据库管理系统。操作系统很难知道哪些是热点数据,操作系统<br>只是简单的缓存最近一次从磁盘读取的数据。直接IO访问数据,如果不在应用程序缓存中,那么每次直接从磁盘加载,会非常慢。<br>read接口:首先读取用户地址空间的缓存,如果有直接返回,没有则直接访问磁盘空间。<br>write接口:首先写入应用地址空间的缓存,然后再写入磁盘空间。</li><li>同步访问文件方式:同步访问文件的方式就是数据的读取和写入都是同步操作的,与标准访问文件方式不同的是,只有当数据被成功写入到磁盘时,才返回给应用程序成功的标识。<br>这种访问方式性能比较差,只有在一些对数据安全要求比较高的场景才使用。</li><li>异步访问文件方式:当访问数据的线程发出请求后,线程会继续处理其他事情,而不是阻塞等待,当请求的数据返回后继续处理下面的操作。这种访问方式明显提高应用程序的效率,但是不会改变访问文件的效率。</li><li>内存映射的方式:内存映射是操作系统将内存中的某一个区域与磁盘中的文件关联起来,当要访问内存中的一段数据时,转换成访问文件的某一段数据,这种方式的目的是同样减少数据从内核空间缓存到用户空间的数据<br>复制操作,因为这两个空间的数据是共享的。<br>9.2java访问磁盘文件:<br>java中通常的File并不代表是一个真是存在的文件对象,当你指定一个路径描述符时,它就会返回一个代表这个路径的虚拟对象,可能是一个真是存在的文件或者是一个包含多个文件的目录。FileDescriptor对象,就是<br>真正代表一个存在文件对象的描述。<br>9.3 JAVA序列化:</li><li>概念:将一个对象转换成一串二进制表示的字节数组,通过保存或者转意这些字节数据来达到持久化的目的,需要持久化就必须实现java.io.Serializable接口。反序列化时,必须有原始类作为模板,才能将对象还原。</li><li>java序列化的一些总结<br>2.1:当父类序列化时,所有子类都可以被序列化。<br>2.2:子类实现Serializable接口,父类没有,父类中的属性不会序列化(不报错,数据会丢失)<br>2.3:如果序列化的属性是对象,则这个对象必须实现Serializable接口,否则会报错。<br>2.4:在反序列化是,如果对象的属性有修改或者删除,则修改的部分属性会丢失,但是不会报错。<br>2.5:在反序列化时,如果serialVersionUID被修改,那么反序列化时会失败。</li></ol><h2 id="影响网络传输的因素:"><a href="#影响网络传输的因素:" class="headerlink" title="影响网络传输的因素:"></a>影响网络传输的因素:</h2><ol><li>网络带宽:一条物理链路上在1s内能够传输的最大比特数。</li><li>传输距离:也就是数据在光纤中要走的距离,数据在光纤中移动并不是直线,所以有一个折射率,大概是光的2/3,这段时间也就是我们常说的网络延迟。</li><li>TCP拥塞控制:</li></ol><h2 id="BIO-NIO-AIO"><a href="#BIO-NIO-AIO" class="headerlink" title="BIO. NIO. AIO"></a>BIO. NIO. AIO</h2><ol><li>IO的方式通常分为几种,同步阻塞的BIO. 同步非阻塞的NIO. 异步非阻塞的AIO</li><li>同步阻塞IO(JAVA BIO):<br>同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,<br>当然可以通过线程池机制改善。</li><li>同步非阻塞IO(Java NIO) :<br>同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。</li><li>异步阻塞IO(Java NIO):<br>此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,<br>那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄(如果从UNP的角度看,select属于同步操作。<br>因为select之后,进程还需要读写数据),从而提高系统的并发性!</li><li>Java AIO(NIO.2))异步非阻塞IO:<br>在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,<br>因为真正的IO读取或者写入操作已经由内核完成了。</li></ol><h2 id="BIO-NIO-AIO适用场景分析"><a href="#BIO-NIO-AIO适用场景分析" class="headerlink" title="BIO. NIO. AIO适用场景分析:"></a>BIO. NIO. AIO适用场景分析:</h2><ol><li>BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。 </li><li>NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。 </li><li>AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。</li></ol><h1 id="jvm"><a href="#jvm" class="headerlink" title="jvm"></a>jvm</h1><h2 id="判断对象是否已死?"><a href="#判断对象是否已死?" class="headerlink" title="判断对象是否已死?"></a>判断对象是否已死?</h2><ol><li>引用计数法:给对象添加一个引用计数器,当对象被引用,加1,引用失效,减1,计数器的值为0,那么可以回收。缺陷:当2个对象相互引用时,导致2个计数器的值都不为0。</li><li>可达性分析:Gc roots。Gc roots包括的对象有 1 虚拟机栈中引用的对象。方法区中静态属性引用的对象,方法区中常量方法引用的对象。本地方法栈中,引用的对象。</li><li>引用包括,强引用. 软引用. 弱引用. 虚引用。强引用:对象被引用不能被回收。软引用:用来描述一些还有用但是并非必须的对象。当系统将要发生内存溢出的时候,将会把这些对象进行第二次回收。弱引用:弱引用用来描述非必须对系那个,但是它的强度比软引用更弱一些,被弱引用的对象只能生存到下一次垃圾搜集发生之前。无论内存是否足够都会被回收。虚引用:虚引用也被称为幽灵引用或者幻影引用,它是最弱的一种引用关系。为对象设置一个虚引用唯一的目的就是能在这个对象被回收时收到一个系统通知。</li></ol><h2 id="java的类被回收的条件:"><a href="#java的类被回收的条件:" class="headerlink" title="java的类被回收的条件:"></a>java的类被回收的条件:</h2><ol><li>该类所有的实例都已经被回收,java堆中不存在该类的任何实例。</li><li>加载该类的classloader已经被回收。</li><li>该类对应的java.lang.class对象没有任何地方被引用。</li></ol><h2 id="基本回收算法"><a href="#基本回收算法" class="headerlink" title="基本回收算法"></a>基本回收算法</h2><p> 1:引用计数:比较古老的回收算法。原理是此对象有一个引用,即增加一个技术,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法时致命的是无法处理循环引用的问题。<br> 2:标记-清除:此算法执行分为两个阶段。第一个阶段从引用根节点开始标记所有被引用的对象;第二个阶段便利整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。<br> 3:复制:此算法把内存空间划分为两个相同的区域,每次只是用其中的一个区域。垃圾回收时,便利当前使用区域,把正在使用中的对象复制到另外一个区域。此算法每次只处理正在使用中的对象,因此复制成本比较小,同事复制过去以后还能进行相应的内存整理,不过会出现碎片问题。当然,此算法的缺点也是很明显的,就是需要两倍的内存。<br> 4:标记-整理:此算法结合了“标记-清除”和”复制”两个算法的有点。也是分两个阶段,第一个阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象”压缩”到堆的其中一块,按顺序排放。此算法避免了”标记-清除”碎片问题,同时也避免了复制算法的空间问题。<br> 5:增量收集:实施垃圾回收算法,即应用进行的同时进行垃圾回收。<br> 6:分代算法:基于对象生命周期分析后得出的垃圾回收算法。把对象分为年轻代. 年老带. 持久代,对不同生命周期的对象使用不同的算法进行回收。</p><h2 id="SavePoint安全点和安全区"><a href="#SavePoint安全点和安全区" class="headerlink" title="SavePoint安全点和安全区"></a>SavePoint安全点和安全区</h2><ol><li>程序执行时并非所有的地方都能停顿下来开始GC,只有到达安全点才能停顿。SafePoint的选定既不讷讷个太少导致让GC等待时间太长,也不能过于频繁已至过分增加运行的负荷。安全点的选定基本上是已”是否具有让程序长时间执行的特征”为标准进行选定的。</li><li>让所有的线程到达安全的方案有2中:抢先式终端,和主动式中断。抢先式中断:不需要线程的执行代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有的线程不在安全点上,就恢复线程,让它跑到安全点。主动式中断:当GC需要中断时,仅仅简单地这只一个标识,各个线程执行时主动去轮训这个标志。发现终端标志为真时,就将自己挂起。</li><li>安全区:在一段代码片段中,引用关系不会发生变化,在这个区域的任意地方开始GC都是安全的。例如,有些时候是程序不执行的时候,当线程处于Sleep状态或者Blocked状态,无法响应jvm的中段请求。当线程进入安全区以后,会标识自己已经进入安全区,当jvm要发起gc时,就不用管标识自己为safe region状态的线程了。</li></ol><h2 id="垃圾收集器"><a href="#垃圾收集器" class="headerlink" title="垃圾收集器"></a>垃圾收集器</h2><ol><li>Serial收集器<br>Serial收集器是一个单线程收集器,它在进行垃圾回收时,需要stop the world。</li><li>ParNew收集器<br>ParNew收集器是Serial的多线程版本。是Server模式下新生代默认的收集器,目前除了Serial收集器外只有它能与CMS收集器配合使用。</li><li>Parallel Scavenge收集器<br>是一款新生代收集器,它采用赋值算法,又是并行的多线程收集器。主要关注的是吞吐量。吞吐量=用户代码执行时间/用户代码执行时间+垃圾回收时间。Parallel Scavenge收集器提供了两个参数用于青雀控制吞吐量,分别是控制最大垃圾手机停顿时间和直接设置吞吐量大小的参数。</li><li>Serial Old收集器<br>Serial Old是Serial的老年代版本,同样是单线程收集器。主要作用是作为CMS收集器的备用方案。</li><li>Parallel Old收集器<br>Parallel Old收集器是 Parallel Scavenge的老年代版本,使用的是多线程和标记-整理算法。</li><li>CMS收集器<br>CMS:Concurrent Mark Sweep 收集器是一种以获取最短回收停顿时间为目的的收集器。CMS收集器是给予标记-清除算法实现的整个过程包括4个步骤:1初始标记2. 并发标记. 3. 重新标记. 4并发清除。CMS的有点是并发收集. 低停顿。</li><li>G1收集器<br>分代概念在G1中仍然得已保留。G1从整体来看是给予标记整理算法实现的收集器. 从局部上来看是给予复制算法实现的。G1在运作期间不会出现内存空间碎片,收集后能提供规整的可用内存。有利于程序长时间运行,分配大对象。<br>可预测的停顿,这是G1与CMS的另一大优势。降低停顿时间是G1和CMS共同关注点。G1除了追求低停顿外,还能建立可预测的停顿时间模型。能够让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾回收的时间不能超过N秒。G1跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先级列表。根据每次允许的收集时间,优先回收价值最大的Resion。G1收集器运作的步骤包括:初始标记. 并发标记. 最终标记. 筛选回收。</li></ol><h2 id="JVM中并行与并发的区别"><a href="#JVM中并行与并发的区别" class="headerlink" title="JVM中并行与并发的区别"></a>JVM中并行与并发的区别</h2><ol><li>并行:指多条垃圾收集线程并行狗牯脑做,但此时用户线程仍然处于等待状态。</li><li>并发:指用户线程与垃圾搜集线程同事执行,单不一定是并行,可能是交替执行。</li></ol><h2 id="基本回收算法-1"><a href="#基本回收算法-1" class="headerlink" title="基本回收算法"></a>基本回收算法</h2><p> 1:引用计数:比较古老的回收算法。原理是此对象有一个引用,即增加一个技术,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法时致命的是无法处理循环引用的问题。<br> 2:标记-清除:此算法执行分为两个阶段。第一个阶段从引用根节点开始标记所有被引用的对象;第二个阶段便利整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。<br> 3:复制:此算法把内存空间划分为两个相同的区域,每次只是用其中的一个区域。垃圾回收时,便利当前使用区域,把正在使用中的对象复制到另外一个区域。此算法每次只处理正在使用中的对象,因此复制成本比较小,同事复制过去以后还能进行相应的内存整理,不过会出现碎片问题。当然,此算法的缺点也是很明显的,就是需要两倍的内存。<br> 4:标记-整理:此算法结合了“标记-清除”和”复制”两个算法的有点。也是分两个阶段,第一个阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象”压缩”到堆的其中一块,按顺序排放。此算法避免了”标记-清除”碎片问题,同时也避免了复制算法的空间问题。<br> 5:增量收集:实施垃圾回收算法,即应用进行的同时进行垃圾回收。<br> 6:分代算法:基于对象生命周期分析后得出的垃圾回收算法。把对象分为年轻代. 年老带. 持久代,对不同生命周期的对象使用不同的算法进行回收。</p><h2 id="基于分代算法"><a href="#基于分代算法" class="headerlink" title="基于分代算法"></a>基于分代算法</h2><p> 1. 年轻代:年轻代分为三个区。一个Eden区,两个Survivor区。大部分对象都是在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象被复制到另外一个Survivor区,当这个Survivor区也满了时,会从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到老年代。需要注意的是Survivor区是对称的,没有先后关系,所以同一个区中可能同时存在从Eden复制过来的对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor过来的对象。而且Survivor总有一个是空的。<br> 2. 年老代:年老代存放从年轻带存货的对象。一般来说年老代都是存放生命周期较长的对象。<br> 3. 持久代:用于存放静态文件,例如java类. 方法等。持久代对垃圾回收没有显著的影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程总新增的类。持久代大小通过-XX:MAXPermSize进行设置。</p><h2 id="java运行时数据区域:"><a href="#java运行时数据区域:" class="headerlink" title="java运行时数据区域:"></a>java运行时数据区域:</h2><ol><li>程序计数器:当前线程所执行的字节码的行号指示器。</li><li>虚拟机栈:是线程私有的,它的生命周期和线程相同,每个方法在执行的时候会创建一个栈帧,用于存储变量表. 操作数栈. 方法出口. 动态连接等。</li><li>本地方法区:本地方法栈是为虚拟机使用到的native方法服务。</li><li>堆:是java虚拟机所管理的内存中最大的一块。java堆是所有线程共享的一块内存区域,目的是为了存放对象实例。</li><li>方法区:方法区也是各个线程共享的一块区域,用于存储虚拟机加载的类信息. 常量. 静态变量. 即时编译后的代码等。</li></ol><h1 id="kafka"><a href="#kafka" class="headerlink" title="kafka"></a>kafka</h1><ul><li>Kafka是一个高性能. 高可用. 可持久化的,为分布式设计的消息中间件。Kafka主要包括,consumer. broker. producer。</li><li>每一种消息的分类叫做topic,一个消息中间可以包括多个topic。为了分布式设计,每个主题又可以分成多个分区。每个分区都是一个顺序写入<br>,且不可变的文件。每个新的消息总是追加到文件末尾。每个主题可以多个分区,每个分区又可以分布到不同的机器上,所以实现了分布式系统的功能。<br>Kafka通过zk实现注册中心,将消息生产者,消费者,消息中介元数据存储到zk上,kafka也会将分区分配到不同机器。</li><li>对于消息发送到哪个分区,默认是轮训调度的方式,也可以根据自己的业务场景,进行定制实现消息分区的逻辑。</li><li>每个分区的消费都是顺序的,但是跨分区的消息不保证顺序性。kafka的消费者提供了GroupId的功能,同时只能拥有同样的GroupId的消费者,<br>消费一个分区。消息中间件分为queue和topic两种模式,如果每个消费者拥有相同的groupId,那么这个主题就被当做为queue方式消费,因为不会<br>有消费者消费相同的消息。如果每个消费者拥有不同的GroupId,那么这个主题会被当做Topic模式消费,每个消费者都会消费一遍这个消息。</li><li>消息的消费者使用标准的推送push模型,将消息推送到消息中介,但是消费者不同,消费者使用拉取pull模型,主动的将消息从消息中介拉取<br>到客户端,这样消息中介不需要维护消息的状态。为了提升吞吐量可以批量拉取。</li><li>kafka的消息中介不会存储消息状态,而是把消费到哪里的偏移量存储到客户端,并且同步到zk,可以选择批量同步,这样可以提升吞吐量,风险<br>是如果消费者崩溃,未同步的消息偏移量将导致重复消费。系统提供了3种可能消费的传递保障方式,至多一次,至少一次,仅仅一次。至多一次,无论<br>消费者是否成功,消息不会在重新推送。至少一次,消息被消费时,如果由于网络原因导致重复消费,需要业务实现幂等性,无论消费多少次都是相同<br>的结果。仅仅一次,如果消息已经被消费,再次消费消息的时候会回滚。Kafka由于设计的理念不同,只支持至少一次。</li><li>kafka的存储方式,kafka直接使用磁盘进行存储,没有使用缓存,由于操作系统本身就有缓存,先将数据放入缓存,经过一定时间再刷盘。<br>Kafka最大限度的利用了操作系统的缓存,所以如果想提升kafka的性能,最好使用固态硬盘。Kafka是追加数据顺序读,不会随机读写,所以及时<br>直接使用磁盘效率也很高。如果不想丢弃消息,可以修改kafka的配置参数,每发送一条消息就同步一次磁盘,用降低性能的方式提高安全性。kafka<br>会自动清理过期的消息,默认保留1个星期。</li><li>kafka收到消息后会向主节点和从节点发送消息。主节点用于接收和消费消息,从节点用于同步消息,kafka的主从节点不是以服务器为粒度,而<br>是以topic主体为粒度,这样每台机器都会有主从分区,最大限度的利用了机器资源。</li></ul><h1 id="lock"><a href="#lock" class="headerlink" title="lock"></a>lock</h1><ol><li>Lock能完成几乎所有synchronized的功能,并有一些后者不具备的功能,如锁投票. 定时锁等候. 可中断锁等候等。</li><li>synchronized 是Java 语言层面的,是内置的关键字;Lock 则是JDK 5中出现的一个包,在使用时,synchronized 同步的代码块可以由JVM自动释放;<br>Lock 需要程序员在finally块中手工释放,如果不释放,可能会引起难以预料的后果</li></ol><h2 id="主内存和工作内存:"><a href="#主内存和工作内存:" class="headerlink" title="主内存和工作内存:"></a>主内存和工作内存:</h2><ol><li>Java内存模型中规定了所有的变量都存储在主内存中,每个线程还有自己的工作内存,线程的工作内存,保存了该线程使用到的主内存副本拷贝,线程对变量的所有操作必须在工作内存中,而不能直接读写主内存中的变量,<br>不同线程之间无法直接访问对方工作内存中的变量,线程间值的传递均需要通过主内存来完成。</li></ol><h2 id="什么是自旋锁:"><a href="#什么是自旋锁:" class="headerlink" title="什么是自旋锁:"></a>什么是自旋锁:</h2><p>自旋锁jdk1.6后默认自动开启,基于之前的观察,共享数据的锁定状态只会持续很短的时间,为了这一段时间而去挂起和恢复线程有点浪费,然后面请求锁的那个线程稍等一会,但是不放弃处理器的执行时间,看看只有线程的锁<br>是否能很快释放。为了让线程等待,所以需要让线程执行一个忙循环自旋操作。</p><h2 id="锁消除"><a href="#锁消除" class="headerlink" title="锁消除"></a>锁消除</h2><p>虚拟机即使编译器在运行时,对于代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。如果判断一段代码,在堆上的数据都不会逃逸,被其他线程访问到,那么认为是线程私有的,同步加锁也就没有必要了。</p><h2 id="锁粗化"><a href="#锁粗化" class="headerlink" title="锁粗化"></a>锁粗化</h2><p>原则上,在编写代码时,推荐将同步块的作用范围限制的尽量小,仅仅在共享数据的实际作用域才进行同步,这样目的是使得需要同步的操作尽可能小,如果存在锁竞争,那等待锁的线程也能尽快拿到锁。但是如果一系列的连续<br>操作都对同一个对象反复加锁和解锁,甚至锁出现在循环体内,及时没有线程竞争,频繁的进行互斥操作也会带来性能损耗。</p><h2 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h2><p>偏向锁意思是这个锁会偏向第一个获取它的线程,如果在接下来的过程中,该锁没有被其他线程获取,则只有偏向锁的线程将永远不需要进行同步,偏向锁可以提高带有同步但是没有竞争的程序的性能。偏向锁也不一定总是对程序<br>有利的,如果程序中的锁大部分都是被多个不同的线程访问,那么偏向模式就是多余的。</p><h2 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h2><p>轻量级锁能提升程序同步性能的依据是”对于绝大部分的锁,在整个同步周期内都是不存在竞争”,这是一个经验值。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥所的开销,但如果存在竞争,除了互斥锁的开销外,还额外<br>发生了CAS操作,一次在竞争的情况下,轻量级锁会比传统重量级锁更慢。</p><h2 id="volatile变量"><a href="#volatile变量" class="headerlink" title="volatile变量"></a>volatile变量</h2><p>volatile能够实现可见性,但是不能保证原子性。</p><h2 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h2><p>CAS包括三个操作数,内存位置,预期旧值,新值。如果内存位置的值和预期的旧值相同,那么使用新值替换旧值。</p><h2 id="如何实现互斥同步?"><a href="#如何实现互斥同步?" class="headerlink" title="如何实现互斥同步?"></a>如何实现互斥同步?</h2><p>java中最基本的互斥就是synchronized关键字,synchronized在经过编译后,会在同步块的前后分别形成monitorenter和moitorexit这两个字节码指令。在执行monitorenter指令时,首先要去尝试获取对象的锁,<br>如果这个对象没有被锁定,或者当前线程已经拥有了那个对象的锁,把锁的计数器加1,相应的,在执行monitorexit指令时会把锁计数器减1,当计数器为0时,锁就被释放了。如果获取对象的锁失败,当当前线程就要阻塞等待,<br>知道对象的锁被另一个线程释放为止。synchronized对于同一个线程来说是可重入的,不会出现自己把自己锁死的问题。除了synchronized指望,JUC中的Lock也能实现互斥同步,ReentrantLock,写法上更加可见,<br>lock和unlock配合try/finally来配合完成,ReentrantLock比synchronized有几个高级的特性。</p><h2 id="ReentrantLock的高级特性有那几个?"><a href="#ReentrantLock的高级特性有那几个?" class="headerlink" title="ReentrantLock的高级特性有那几个?"></a>ReentrantLock的高级特性有那几个?</h2><ol><li>等待可中断,当持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,改为处理其他事情;</li><li>可以实现公平锁,公平锁指多个线程在等待同一个锁时,必须按照申请锁的顺序依次获得锁,synchronized是非公平锁,ReentrantLock默认也是非公平的,只不过可以通过构造函数来制定实现公平锁;</li><li>锁绑定多个条件,ReentrantLock对象可以同时绑定多个Condition对象,在synchronized中,锁对象的wait/notify/notifyall方法可以实现一个隐含的条件,如果要多一个条件关联的时候,就需要额外的增加一个锁;</li></ol><h2 id="关于sunchronized的几个注意点?"><a href="#关于sunchronized的几个注意点?" class="headerlink" title="关于sunchronized的几个注意点?"></a>关于sunchronized的几个注意点?</h2><ol><li>当一个线程访问object的一个synchronized(this)同步代码块时, 另一个线程仍然可以访问该object中的非synchronized(this)同步代码块;</li><li>当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时, 一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块;</li><li>尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时, 其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞;</li><li>Java中的每一个对象都可以作为锁,对于同步方法,锁是当前实例对象,对于静态同步方法,锁是当前对象的Class对象,对于同步方法块,锁是Synchonized括号里配置的对象;</li></ol> <figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">## JAVA concurrent包下的类:</span><br><span class="line">Executors</span><br><span class="line"> Executor</span><br><span class="line"> ExecutorService</span><br><span class="line"> ScheduledExecutorService</span><br><span class="line"> Callable</span><br><span class="line"> Future</span><br><span class="line"> ScheduledFuture</span><br><span class="line"> Delayed</span><br><span class="line"> CompletionService</span><br><span class="line"> ThreadPoolExecutor</span><br><span class="line"> ScheduledThreadPoolExecutor</span><br><span class="line"> AbstractExecutorService</span><br><span class="line"> Executors</span><br><span class="line"> FutureTask</span><br><span class="line"> ExecutorCompletionService</span><br><span class="line">Queues</span><br><span class="line"> BlockingQueue</span><br><span class="line"> ConcurrentLinkedQueue</span><br><span class="line"> LinkedBlockingQueue</span><br><span class="line"> ArrayBlockingQueue</span><br><span class="line"> SynchronousQueue</span><br><span class="line"> PriorityBlockingQueue</span><br><span class="line"> DelayQueue</span><br><span class="line">Concurrent Collections</span><br><span class="line"> ConcurrentMap</span><br><span class="line"> ConcurrentHashMap</span><br><span class="line"> CopyOnWriteArray{List,Set</span><br><span class="line">Synchronizers</span><br><span class="line"> CountDownLatch</span><br><span class="line"> Semaphore</span><br><span class="line"> Exchanger</span><br><span class="line"> CyclicBarrier</span><br><span class="line">Timing</span><br><span class="line"> TimeUnit</span><br><span class="line">Locks</span><br><span class="line"> Lock</span><br><span class="line"> Condition</span><br><span class="line"> ReadWriteLock</span><br><span class="line"> AbstractQueuedSynchronizer</span><br><span class="line"> LockSupport</span><br><span class="line"> ReentrantLock</span><br><span class="line"> ReentrantReadWriteLock</span><br><span class="line">Atomics</span><br><span class="line"> Atomic[Type], Atomic[Type]Array</span><br><span class="line"> Atomic[Type], FieldUpdater</span><br><span class="line"> Atomic{Markable, Stampable}Reference}</span><br></pre></td></tr></table></figure><h2 id="原子性-可见性-有序性"><a href="#原子性-可见性-有序性" class="headerlink" title="原子性. 可见性. 有序性"></a>原子性. 可见性. 有序性</h2><ol><li>原子性:由java内存模型来直接保证原子性变量操作包括:lock. unlock. read. load. assign. use. store和write 。</li><li>可见性:当一个线程修改了共享变量的值,其他线程能够立即知道这个修改。java内存模型是通过在变量修改后将新值同步回<br>主内存,在变量读取之前需要从主内存刷新变量值这种依赖猪内存作为传递媒介的方式来实现的可见性。除了volatitle关键字外,<br>还有2个synchronized. final。</li><li>有序性:java提供了volatitle和synchronized关键字来保证线程之间操作的有序性。</li></ol><h1 id="mongodb"><a href="#mongodb" class="headerlink" title="mongodb"></a>mongodb</h1><h2 id="MongoDB简介"><a href="#MongoDB简介" class="headerlink" title="MongoDB简介"></a>MongoDB简介</h2><ol><li>MongoDB是一个开源的. 面向文档的存储的NoSql数据库。</li><li>模式自由. 支持动态查询. 完全索引. 可以轻易查询文档中内嵌的对象及数组。</li><li>面向文档存储,易存储对象类型的数据。</li><li>高效的文档存储,支持二进制数据及大型对象。</li><li>支持复制和故障恢复</li><li>自动分片支持云级别的伸缩性,支持水平的数据库集群。</li></ol><h2 id="特点"><a href="#特点" class="headerlink" title="特点:"></a>特点:</h2><p>高性能. 易部署. 易使用,存储数据非常方便。主要功能特性有:<br>面向集合存储,易存储对象类型的数据。<br>模式自由。<br>支持动态查询。<br>支持完全索引,包含内部对象。<br>支持查询。<br>支持复制和故障恢复。<br>使用高效的二进制数据存储,包括大型对象(如视频等)。<br>自动处理碎片,以支持云计算层次的扩展性<br>支持Python,PHP,Ruby,Java,C,C#,Javascript,Perl及C++语言的驱动程序,社区中也提供了对Erlang及.NET等平台的驱动程序。<br>文件存储格式为BSON(一种JSON的扩展)。<br>可通过网络访问。</p><h2 id="功能"><a href="#功能" class="headerlink" title="功能:"></a>功能:</h2><p>面向集合的存储:适合存储对象及JSON形式的数据。<br>动态查询:Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。<br>完整的索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。<br>查询监视:Mongo包含一个监视工具用于分析数据库操作的性能。<br>复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目标是提供冗余及自动故障转移。<br>高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)<br>自动分片以支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器。</p><h2 id="适用场合"><a href="#适用场合" class="headerlink" title="适用场合:"></a>适用场合:</h2><p>网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。<br>缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源 过载。<br>大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。<br>高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对MapReduce引擎的内置支持。<br>用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储及查询。</p><h2 id="与传统数据库对比"><a href="#与传统数据库对比" class="headerlink" title="与传统数据库对比"></a>与传统数据库对比</h2><p>MongoDb是由数据库databse. 集合collection. 文档对象document三个层次组成。</p><h2 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h2><p>MongoDB提供了多样性的索引支持,索引信息被保存在sytem.indexes中,且默认为_id创建索引,它的索引使用基本和mysql一样。</p><h1 id="mysql"><a href="#mysql" class="headerlink" title="mysql"></a>mysql</h1><h2 id="Mysql主要存储引擎包括InnoDB-MyISAM"><a href="#Mysql主要存储引擎包括InnoDB-MyISAM" class="headerlink" title="Mysql主要存储引擎包括InnoDB. MyISAM"></a>Mysql主要存储引擎包括InnoDB. MyISAM</h2><h2 id="InnoDB和MyISAM的区别:"><a href="#InnoDB和MyISAM的区别:" class="headerlink" title="InnoDB和MyISAM的区别:"></a>InnoDB和MyISAM的区别:</h2><ol><li>MyISAM不支持事物,表锁,支持全文检索,不支持外键,表空间相对比较小,关注的主要是查询的性能。</li><li>InnoDB支持事物,行锁,不支持全文检索,支持外检,表空间相对比较大,关注的是事务。</li><li>MyISAM的读性能比InnoDB强。</li></ol><h2 id="数值类型:"><a href="#数值类型:" class="headerlink" title="数值类型:"></a>数值类型:</h2><ol><li>tinyint 1个字节</li><li>smallint 2个字节</li><li>mediumint 3个字节</li><li>int 4个字节</li><li>bigint 8个字节</li><li>float 4个字节</li><li>double 8个字节</li><li>bit 1-8个字节</li></ol><h2 id="日期类型"><a href="#日期类型" class="headerlink" title="日期类型"></a>日期类型</h2><ol><li>如果表示年月日用date</li><li>如果标示年月日时分秒,用datetime和timestamp</li><li>如果表示十分秒,用time</li><li>如果表示年,用year</li></ol><h2 id="datetime和timestamp的区别:"><a href="#datetime和timestamp的区别:" class="headerlink" title="datetime和timestamp的区别:"></a>datetime和timestamp的区别:</h2><ol><li>timestamp支持的时间范围比较小,从1970年到2038年的某个时间。</li><li>timestamp的查询和插入受当地时区的影响。</li></ol><h2 id="char-varchar-binary-varbinary-blob-text-enum和set"><a href="#char-varchar-binary-varbinary-blob-text-enum和set" class="headerlink" title="char. varchar. binary. varbinary. blob. text. enum和set"></a>char. varchar. binary. varbinary. blob. text. enum和set</h2><ol><li>char的固定长度是0-255,且会去掉末尾的空格</li><li>varchar是非固定的,会保留末尾的空格</li></ol><h2 id="数据库隔离级别"><a href="#数据库隔离级别" class="headerlink" title="数据库隔离级别"></a>数据库隔离级别</h2><ol><li>数据库隔离级别包括:读未提交. 读提交. 重复读. 序列化。</li><li>数据库各种隔离级别出现的问题:脏读. 不可重复度. 幻读</li><li>读未提交:脏读. 不可重复读. 幻读</li><li>读提交:不可重复读. 幻读</li><li>重复度:幻读</li><li>序列化:不会出现问题</li></ol><h2 id="各种隔离级别出现的问题"><a href="#各种隔离级别出现的问题" class="headerlink" title="各种隔离级别出现的问题"></a>各种隔离级别出现的问题</h2><ol><li>脏读:一个事务读取了另外一个事务未提交的数据,而这个数据有可能回滚。</li><li>不可重复读:在访问数据库时,一个事务范围内的两次查询,返回了不同的结果。这是由于查询时系统中其他事务修改的提交而引起的。</li><li>幻读:是指事务不是独立执行时发生的一种现象。,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.</li></ol><ul><li><p>小数类型为 decimal,禁止使用 float 和 double。<br>说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。</p></li><li><p>如果存储的字符串长度几乎相等,使用 char 定长字符串类型。<br>varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。</p></li><li><p>字段允许适当冗余,以提高性能,但是必须考虑数据同步的情况。冗余字段应遵循:<br>1)不是频繁修改的字段。<br>2)不是 varchar 超长字段,更不能是 text 字段。</p></li><li><p>单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。</p></li><li><p>合适的字符存储长度,不但节约数据库表空间. 节约索引存储,更重要的是提升检 索速度。</p></li><li><p>业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。<br>说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明 显的;另外,即使在应用层做了非常完善的校验和控制,只要没有唯一索引,根据墨菲定律, 必然有脏数据产生。</p></li><li><p>超过三个表禁止 join。需要 join 的字段,数据类型保持绝对一致;多表关联查询 时,保证被关联的字段需要有索引。<br>说明:即使双表 join 也要注意表索引. SQL 性能。</p></li><li><p>在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度。<br>说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分 度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度 来确定。</p></li><li><p>页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。 说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索 引。</p></li><li><p>如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合 索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。<br>正例:where a=? and b=? order by c; 索引:a_b_c 反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引 a_b 无法排序。</p></li><li><p>利用覆盖索引来进行查询操作,来避免回表操作。<br>说明:如果一本书需要知道第 11 章是什么标题,会翻开第 11 章对应的那一页吗?目录浏览 一下就好,这个目录就是起到覆盖索引的作用。<br>正例:能够建立索引的种类:主键索引. 唯一索引. 普通索引,而覆盖索引是一种查询的一种 效果,用explain的结果,extra列会出现:using index</p></li><li><p>利用延迟关联或者子查询优化超多分页场景。<br>说明:MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过 特定阈值的页数进行 SQL 改写。<br>正例:先快速定位需要获取的 id 段,然后再关联:<br>SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id</p></li><li><p>SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。<br>说明:<br>1)consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。 2)ref 指的是使用普通的索引(normal index)。<br>3)range 对索引进行范围检索。<br>反例:explain 表的结果,type=index,索引物理文件全扫描,速度非常慢,这个 index 级 别比较 range 还低,与全表扫描是小巫见大巫。</p></li><li><p>建组合索引的时候,区分度最高的在最左边。<br>正例:如果 where a=? and b=? ,a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即 可。<br>说明:存在非等号和等号混合判断条件时,在建索引时,请把等号条件的列前置。如:where a>? and b=? 那么即使 a 的区分度更高,也必须把 b 放在索引的最前列。</p></li><li><p>创建索引时避免有如下极端误解:<br>1)误认为一个查询就需要建一个索引。 2)误认为索引会消耗空间. 严重拖慢更新和新增速度。 3)误认为唯一索引一律需要在应用层通过“先查后插”方式解决。</p></li><li><p>count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行</p></li><li><p>当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为 NULL,因此使用 sum()时需注意 NPE 问题<br>正例:可以使用如下方式来避免sum的NPE问题:SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;</p></li><li><p>使用 ISNULL()来判断是否为 NULL 值。注意:NULL 与任何值的直接比较都为 NULL。 说明:</p></li></ul><ol><li>NULL<>NULL的返回结果是NULL,而不是false。 2) NULL=NULL的返回结果是NULL,而不是true。 3) NULL<>1的返回结果是NULL,而不是true。</li></ol><h1 id="netty"><a href="#netty" class="headerlink" title="netty"></a>netty</h1><h2 id="为什么使用Netty"><a href="#为什么使用Netty" class="headerlink" title="为什么使用Netty?"></a>为什么使用Netty?</h2><ol><li>Netty提供了这样的一个间接的解决方法。Netty提供了高层次的抽象来简化TCP和UDP服务器的编程,但是你仍然可以使用底层地API。</li><li>Netty成功的提供了易于开发,高性能和高稳定性,以及较强的扩展性</li></ol><h2 id="Design-设计"><a href="#Design-设计" class="headerlink" title="Design(设计)"></a>Design(设计)</h2><p>各种传输类型,阻塞和非阻塞套接字统一的API<br>使用灵活<br>简单但功能强大的线程模型<br>无连接的DatagramSocket支持<br>链逻辑,易于重用</p><h2 id="Ease-of-Use-易于使-用"><a href="#Ease-of-Use-易于使-用" class="headerlink" title="Ease of Use(易于使 用)"></a>Ease of Use(易于使 用)</h2><p>提供大量的文档和例子<br>除了依赖jdk1.6+,没有额外的依赖关系。某些功能依赖jdk1.7+,其他特性可能有相 关依赖,但都是可选的。</p><h2 id="Performance-性能"><a href="#Performance-性能" class="headerlink" title="Performance(性能)"></a>Performance(性能)</h2><p>比Java APIS更好的吞吐量和更低的延迟<br>因为线程池和重用所有消耗较少的资源<br>尽量减少不必要的内存拷贝</p><h2 id="Robustness-鲁棒性"><a href="#Robustness-鲁棒性" class="headerlink" title="Robustness(鲁棒性)"></a>Robustness(鲁棒性)</h2><p>链接快或慢或超载不会导致更多的OutOfMemoryError<br>在高速的网络程序中不会有不公平的read/write</p><h2 id="Security-安全性"><a href="#Security-安全性" class="headerlink" title="Security(安全性)"></a>Security(安全性)</h2><p>完整的SSL/TLS和StartTLS支持<br>可以在如Applet或OSGI这些受限制的环境中运行</p><h2 id="Community-社区"><a href="#Community-社区" class="headerlink" title="Community(社区)"></a>Community(社区)</h2><p>版本发布频繁<br>社区活跃</p><h1 id="network"><a href="#network" class="headerlink" title="network"></a>network</h1><h2 id="Netty-解决TCP粘包-x2F-拆包问题"><a href="#Netty-解决TCP粘包-x2F-拆包问题" class="headerlink" title="Netty 解决TCP粘包/拆包问题"></a>Netty 解决TCP粘包/拆包问题</h2><p>业务上一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。<br>对于这类问题,netty提供了LineBasedFrameDecoder和StringDecoder进行完美解决。如下是相关代码。</p><ol><li>LineBasedFrameDecoder<br>工作原理是依次遍历ByteBuf中的可读字节,判断是否有换行符,如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行。</li><li>StringDecoder<br>功能就是将接受到的对象转换为字符串,然后继续调用后面的handler。<br>LineBasedFrameDecoder+StringDecoder组合就是按行切换的文本解码器。</li><li>其他解码器<br>DelimiterBasedFrameDecoder可以自定义分隔符<br>FixedLengthFrameDecoder定长解码器。</li></ol><h1 id="nginx"><a href="#nginx" class="headerlink" title="nginx"></a>nginx</h1><h2 id="Nginx能做什么?"><a href="#Nginx能做什么?" class="headerlink" title="Nginx能做什么?"></a>Nginx能做什么?</h2><ol><li>反向代理</li><li>负载均衡</li><li>HTTP服务器(包含动静分离)</li><li>正向代理</li></ol><h2 id="反向代理"><a href="#反向代理" class="headerlink" title="反向代理"></a>反向代理</h2><p>反向代理是指代理服务器接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器得到的结果返回给internet上请求连接的客户端,此时代理服务器<br>对外表现为一个反向代理服务器。简单的说就是真是的服务器不能直接被外部网络访问,需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真是服务器在同一个网络环境。</p><figure class="highlight plaintext"><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">server { </span><br><span class="line"> listen 80; </span><br><span class="line"> server_name localhost; </span><br><span class="line"> client_max_body_size 1024M;</span><br><span class="line"> </span><br><span class="line"> location / {</span><br><span class="line"> proxy_pass http://localhost:8080;</span><br><span class="line"> proxy_set_header Host :;</span><br><span class="line"> </span><br><span class="line">}}</span><br></pre></td></tr></table></figure><p>保存配置文件后启动Nginx,这样当我们访问localhost的时候,就相当于访问localhost:8080了</p><h2 id="负载均衡"><a href="#负载均衡" class="headerlink" title="负载均衡"></a>负载均衡</h2><ol><li>RR 默认<br>每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。</li></ol><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">upstream test {</span><br><span class="line"> server localhost:8080;</span><br><span class="line"> server localhost:8081;</span><br><span class="line"> </span><br><span class="line"> server {</span><br><span class="line"> listen 81; </span><br><span class="line"> server_name localhost; </span><br><span class="line"> client_max_body_size 1024M;</span><br><span class="line"> </span><br><span class="line"> location / {</span><br><span class="line"> proxy_pass http://test;</span><br><span class="line"> proxy_set_header Host :;</span><br><span class="line"> }</span><br><span class="line">}}</span><br></pre></td></tr></table></figure><p>负载均衡的核心代码为</p><figure class="highlight plaintext"><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">upstream test {</span><br><span class="line"> server localhost:8080;</span><br><span class="line"> server localhost:8081;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>这里我配置了2台服务器,当然实际上是一台,只是端口不一样而已,而8081的服务器是不存在的,也就是说访问不到,但是我们访问<a href="http://localhost/">http://localhost</a> 的时候,也不会有问题,会默认跳转到<a href="http://localhost:8080/">http://localhost:8080</a><br>具体是因为Nginx会自动判断服务器的状态,如果服务器处于不能访问(服务器挂了),就不会跳转到这台服务器,所以也避免了一台服务器挂了影响使用的情况,由于Nginx默认是RR策略,所以我们不需要其他更多的设置。</p><ol start="2"><li>权重<br>指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 例如</li></ol><figure class="highlight plaintext"><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"></span><br><span class="line">upstream test {</span><br><span class="line"> server localhost:8080 weight=9;</span><br><span class="line"> server localhost:8081 weight=1;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>那么10次一般只会有1次会访问到8081,而有9次会访问到8080</p><ol start="3"><li>ip_hash<br>上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。</li></ol><figure class="highlight plaintext"><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">upstream test {</span><br><span class="line"> ip_hash;</span><br><span class="line"> server localhost:8080;</span><br><span class="line"> server localhost:8081;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><ol start="4"><li>fair(第三方)<br>按后端服务器的响应时间来分配请求,响应时间短的优先分配。</li></ol><figure class="highlight plaintext"><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">upstream backend {</span><br><span class="line"> fair;</span><br><span class="line"> server localhost:8080;</span><br><span class="line"> server localhost:8081;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><ol start="5"><li>url_hash(第三方)<br>按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法</li></ol><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">upstream backend {</span><br><span class="line"> hash ;</span><br><span class="line"> hash_method crc32;</span><br><span class="line"> server localhost:8080;</span><br><span class="line"> server localhost:8081;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>以上5种负载均衡各自适用不同情况下使用,所以可以根据实际情况选择使用哪种策略模式,不过fair和url_hash需要安装第三方模块才能使用,由于本文主要介绍Nginx能做的事情,所以Nginx安装第三方模块不会再本文介绍</p><h2 id="HTTP服务器"><a href="#HTTP服务器" class="headerlink" title="HTTP服务器"></a>HTTP服务器</h2><p>Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,同时现在也很流行动静分离,就可以通过Nginx来实现,<br>首先看看Nginx做静态资源服务器</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">server {</span><br><span class="line"> listen 80; </span><br><span class="line"> server_name localhost; </span><br><span class="line"> client_max_body_size 1024M;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> location / {</span><br><span class="line"> root e:wwwroot;</span><br><span class="line"> index index.html;</span><br><span class="line"> </span><br><span class="line"> }}</span><br></pre></td></tr></table></figure><p>这样如果访问<a href="http://localhost/">http://localhost</a> 就会默认访问到E盘wwwroot目录下面的index.html,如果一个网站只是静态页面的话,那么就可以通过这种方式来实现部署。</p><h2 id="动静分离"><a href="#动静分离" class="headerlink" title="动静分离"></a>动静分离</h2><p>动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">upstream test{ </span><br><span class="line"> server localhost:8080; </span><br><span class="line"> server localhost:8081; </span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> server { </span><br><span class="line"> listen 80; </span><br><span class="line"> server_name localhost; </span><br><span class="line"> </span><br><span class="line"> location / { </span><br><span class="line"> root e:wwwroot; </span><br><span class="line"> index index.html; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> # 所有静态请求都由nginx处理,存放目录为html </span><br><span class="line"> location ~ .(gif|jpg|jpeg|png|bmp|swf|css|js)$ { </span><br><span class="line"> root e:wwwroot; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> # 所有动态请求都转发给tomcat处理 </span><br><span class="line"> location ~ .(jsp|do)$ { </span><br><span class="line"> proxy_pass http://test; </span><br><span class="line"> } </span><br><span class="line"> </span><br><span class="line"> error_page 500 502 503 504 /50x.html; </span><br><span class="line"> location = /50x.html { </span><br><span class="line"> root e:wwwroot; </span><br><span class="line"> } </span><br><span class="line"> } }</span><br></pre></td></tr></table></figure><p>这样我们就可以吧HTML以及图片和css以及js放到wwwroot目录下,而tomcat只负责处理jsp和请求,例如当我们后缀为gif的时候,<br>Nginx默认会从wwwroot获取到当前请求的动态图文件返回,当然这里的静态文件跟Nginx是同一台服务器,我们也可以在另外一台服务器,然后通过反向代理和负载均衡配置过去就好了,只要搞清楚了最基本的流程,很多配置就很简单了,另外localtion后面其实是一个正则表达式,所以非常灵活</p><h2 id="正向代理"><a href="#正向代理" class="headerlink" title="正向代理"></a>正向代理</h2><p>正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。当你需要把你的服务器作为代理服务器的时候,可以用Nginx来实现正向代理,但是目前Nginx有一个问题,那么就是不支持HTTPS,虽然我百度到过配置HTTPS的正向代理,但是到最后发现还是代理不了,当然可能是我配置的不对,所以也希望有知道正确方法的同志们留言说明一下。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">resolver 114.114.114.114 8.8.8.8;</span><br><span class="line">server {</span><br><span class="line"> </span><br><span class="line"> resolver_timeout 5s;</span><br><span class="line"> </span><br><span class="line"> listen 81;</span><br><span class="line"> </span><br><span class="line"> access_log e:wwwrootproxy.access.log;</span><br><span class="line"> error_log e:wwwrootproxy.error.log;</span><br><span class="line"> </span><br><span class="line"> location / {</span><br><span class="line"> proxy_pass http://;</span><br><span class="line"> </span><br><span class="line">}}</span><br></pre></td></tr></table></figure><p>resolver是配置正向代理的DNS服务器,listen 是正向代理的端口,配置好了就可以在ie上面或者其他代理插件上面使用服务器ip+端口号进行代理了。</p><h2 id="Nginx热部署"><a href="#Nginx热部署" class="headerlink" title="Nginx热部署"></a>Nginx热部署</h2><p>Nginx是支持热启动的,也就是说当我们修改配置文件后,不用关闭Nginx,就可以实现让配置生效,当然我并不知道多少人知道这个,反正我一开始并不知道,导致经常杀死了Nginx线程再来启动。。。Nginx从新读取配置的命令是<br>nginx -s reload<br>windows下面就是<br>nginx.exe -s reload </p><h1 id="redis"><a href="#redis" class="headerlink" title="redis"></a>redis</h1><h2 id="redis数据类型"><a href="#redis数据类型" class="headerlink" title="redis数据类型"></a>redis数据类型</h2><ol><li>string. list. set. zset. hash</li><li>String是最简单的类型,一个key对应一个value</li><li>list是一个链表,主要包括push. pop,获取一定范围内的所有值,操作中key为链表的名称</li><li>set是集合,对集合的操作包括,新增. 删除. 合并求交集等,操作中的key为集合的名称。</li><li>zSet是set的一个升级版本,在set的基础上增加了顺序的功能,这个属性在添加删除的时候可以指定,每次指定后,zSet会自动重新按照<br>新的值调整顺序。</li><li>Hash数据类型允许用户使用redis对象类型,当你存储的数据对象只有很少几个key值时,数据存储的消耗会很小。</li></ol><h2 id="Redis的持久化方式:"><a href="#Redis的持久化方式:" class="headerlink" title="Redis的持久化方式:"></a>Redis的持久化方式:</h2><ol><li>RDB方式:默认redis会以快照的形式存储数据持久化到硬盘中,在配置文件中的格式是 save N M,标识在N秒的时间内,redis至少发生<br>M次修改,则将redis抓去快照到磁盘。工作原理:当redis需要做持久化时,只需要fork一个子进程,子进程将数据写入到磁盘上的一个临时<br>文件RDB中,当子进程完成后,将原来的RDB文件替换掉,这样的好处是copy-on-write。</li><li>AOF方式:append only file,文件日志追加,当开启后,redis每执行一次修改数据的命令后,都会把它添加到aof文件中,当redis<br>重启时,进行”重放”,以恢复redis关闭前的最后时刻。AOF的三中方式:每提交一个修改命令都刷新到aof中,非常慢,但是很安全。每秒中<br>刷盘一次,很快,但是可能会丢失一秒中的数据。第三种是依赖操作系统的缓存进行刷新,最快,但是安全性最差。</li></ol><h2 id="Redis各种特征的试用场景"><a href="#Redis各种特征的试用场景" class="headerlink" title="Redis各种特征的试用场景"></a>Redis各种特征的试用场景</h2><ol><li>Strings<br>Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字。<br>setnx 设置可以为对应的值为String类型的value,如果key存在返回0不覆盖,不存在返回1<br>常规key-value缓存应用。<br>常规计数: 微博数, 粉丝数</li><li>Hashs<br>在Memcached中,我们经常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值,比如用户的昵称. 年龄. 性别. 积分等,这时候在需要修改其中某一项时,<br>通常需要将所有值取出反序列化后,修改某一项的值,再序列化存储回去。这样不仅增大了开销,也不适用于一些可能并发操作的场合(比如两个并发的操作都需要修改积分)。<br>而Redis的Hash结构可以使你像在数据库中Update一个属性一样只修改某一项属性值。<br>它是一个String类型的field和value的映射表,它的添加和删除都是平均的,hash特别适合用于存储对象,对于将对象存储成字符串而言,hash会占用更少的内存,<br>并且可以更方便的存取整个对象. 它和java的HashMap完全类似<br>使用场景<br>存储部分变更数据<br>如用户信息等。</li><li>Lists<br>Lists 就是链表,略有数据结构知识的人都应该能理解其结构。使用Lists结构,我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,<br>然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作Lists中某一段的api,你可以直接查询,删除Lists中某一段的元素。<br>Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。<br>消息队列系统<br>使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。<br>比如:将Redis用作日志收集器<br>实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。<br>取最新N个数据的操作<br>记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。<br>//把当前登录人添加到链表里<br>ret = r.lpush(“login:last_login_times”, uid)<br>//保持链表只有N位<br>ret = redis.ltrim(“login:last_login_times”, 0, N-1)<br>//获得前N个最新登陆的用户Id列表<br>last_login_list = r.lrange(“login:last_login_times”, 0, N-1)<br>比如sina微博:<br>在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。<br>我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。<br>Sets<br>Sets 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Sets数据结构,可以存储一些集合性的数据。<br>案例:<br>在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集. 并集. 差集等操作,可以非常方便的实现如共同关注. 共同喜好. 二度好友等功能,对上面的所有集合操作,<br>你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。<br>Set是集合,是String类型的无序集合,set是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等,set中的元素是没有顺序的。</li></ol><p>Sorted Sets<br>和Sets相比,Sorted Sets增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如一个存储全班同学成绩的Sorted Sets,其集合value可以是同学的学号,而score就可以是其考试得分,<br>这样在数据插入集合的时候,就已经进行了天然的排序。<br>可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。<br>比如在线游戏的排行榜,根据得分你通常想要:</p><ul><li>列出前100名高分选手</li><li>列出某用户当前的全球排名</li></ul><h1 id="seckill"><a href="#seckill" class="headerlink" title="seckill"></a>seckill</h1><h2 id="典型的秒杀系统:"><a href="#典型的秒杀系统:" class="headerlink" title="典型的秒杀系统:"></a>典型的秒杀系统:</h2><ol><li>典型的秒杀系统由接入层. 逻辑服务层. 存储层与缓存构成。Proxy处理请求接入,Server承载主要的业务逻辑,Cache用于缓存库存数量. DB则用于数据持久化。</li><li>一个秒杀系统对应DB中一条库存记录,当用户秒杀商品时,系统主要逻辑在于DB中库存的操作,一般对DB操作流程主要有以下三方面,1.锁库存. 2.插入秒杀记录. 3.更新库存,锁<br>库存避免超卖情况,同时要求这三步操作需要在一个事务中完成,作为单个逻辑工作单元执行,要么全部成功,要么全部失败。</li><li>秒杀系统设计难点,就在这个事务的操作上,商品库存在DB中记为一行,大量用户同时秒杀同一商品,第一个到达DB的请求锁住了这个库存记录,在第一个事物完成之前,这个锁一直被<br>第一个请求占用,后面的所有请求需要排队等待。并发请求的用户越多,DB请求就越多,排队越严重。</li></ol><h2 id="秒杀系统解决高并发问题常用方案"><a href="#秒杀系统解决高并发问题常用方案" class="headerlink" title="秒杀系统解决高并发问题常用方案"></a>秒杀系统解决高并发问题常用方案</h2><ol><li>方案一,使用内存操作替代实时DB事务操作。将实时扣库存的行为上移到内存Cache中操作,内存Cache操作成功直接给Server返回成功,然后异步落DB持久化。<br>优点:用内存操作替换磁盘操作,提高了并发性能。<br>缺点:在内存操作成功,但是DB持久化失败,或者内存Cache故障的情况下,DB持久化会丢数据。</li><li>方案二 使用乐观锁代替悲观锁:<br>悲观锁:关系数据库管理系统中一种并发控制的方法。<br>乐观锁:它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,会检查该事务读取的数据后,有没有其他事务对数据<br>进行了修改,如果有修改,正在提交的事务会回滚。<br>商品秒杀系统中,乐观锁的具体应用方法,是在DB的库存记录中维护一个版本号,在更新库存之前,先去DB获取当前版本号,在更新库存的事务提交时,检查版本号是否已经被其他事务修改,如果没有修改,<br>则提交事务,且版本号+1,如果版本号已经被其他事务修改,那么回滚事务,并报错。<br>优点:提高了DB并发处理的能力<br>缺点:采用乐观锁的方式,会带来大数据量的无效更新,事务回滚,给DB造成不必要的压力。用户体验也十分不好。</li></ol><h2 id="秒杀系统的挑战"><a href="#秒杀系统的挑战" class="headerlink" title="秒杀系统的挑战"></a>秒杀系统的挑战</h2><ol><li>对现有网站业务造成冲击</li><li>高并发下的应用. 数据库压力</li><li>突然增加的网络及服务器宽带</li><li>直接下单,下单页面的URL,需要动态化</li></ol><h2 id="秒杀系统的应对策略"><a href="#秒杀系统的应对策略" class="headerlink" title="秒杀系统的应对策略"></a>秒杀系统的应对策略</h2><ol><li>秒杀系统独立部署</li><li>秒杀系统页面静态化,用户请求不需要经过应用服务器的业务逻辑,也不需要访问数据库。</li><li>租赁秒杀网络宽带,需要将秒杀商品网页缓存到CDN,同样需要和CDN服务商临时租赁新增的出口宽带。</li><li>动态生成下单页面的URL,为了避免用户直接访问下单页面的URL,需要将URL动态化。在下单页面的URL加入由服务端生成的随机数作为参数,在秒杀开始的时候才能得到。</li></ol><h2 id="秒杀系统架构设计"><a href="#秒杀系统架构设计" class="headerlink" title="秒杀系统架构设计"></a>秒杀系统架构设计</h2><ol><li>秒杀页面尽量设计的简单</li><li>下单页也一样,尽量简单。只有第一个提交的订单会发送到网站的订单系统,其他用户提交订单后,只能看到秒杀结束页面。</li></ol><h2 id="如何控制秒杀商品页面购买按钮的点亮"><a href="#如何控制秒杀商品页面购买按钮的点亮" class="headerlink" title="如何控制秒杀商品页面购买按钮的点亮"></a>如何控制秒杀商品页面购买按钮的点亮</h2><p>使用javascript脚本控制,在秒杀商品静态页面加入一个javaScript文件引用,该javaScript文件中加入秒杀是否开始的标志和下单页面URL的随机参数,当秒杀开始的时候,生成一个新的javaScript文件并被用户浏览器加载,控制秒杀商品页面的展示,这个javaScript文件使用随机版本号,并且不做浏览器. CDN和反向代理服务器缓存。javaScript文件非常小,及时每次浏览器刷新都访问javaScript文件服务器也不会对服务器集群和网络宽带造成太大压力。</p><h2 id="如何只允许第一个提交的订单被发送到订单子系统。"><a href="#如何只允许第一个提交的订单被发送到订单子系统。" class="headerlink" title="如何只允许第一个提交的订单被发送到订单子系统。"></a>如何只允许第一个提交的订单被发送到订单子系统。</h2><ol><li>在用户提交订单时,需要检查是否已经有订单提交了。可以控制进入下单页面的入口,只有少数用户能进入到下单页,其他用户直接进入秒杀结束页面。</li></ol><h1 id="service"><a href="#service" class="headerlink" title="service"></a>service</h1><h2 id="微服务故障"><a href="#微服务故障" class="headerlink" title="微服务故障"></a>微服务故障</h2><ol><li>分布式调用故障<br> 序列化. 反序列化故障<br> 分布式路由故障<br> 网络通信故障</li><li>第三方服务故障,微服务会依赖第三方服务,包括数据库服务. 文件存储服务. 缓存服务. 消息队列服务等<br> 网络通信类故障<br> 雪崩效应,导致的级联故障,例如服务处理缓慢导致客户端线程被阻塞<br> 第三方不可用,导致微服务处理失败</li><li>微服务之间的故障<br> 处理较慢的微服务会阻塞其他服务<br> 某个微服务故障蔓延,导致整个进程不可用OOM<br> 低优先级的微服务,抢占高优先级微服务的资源</li></ol><h2 id="服务故障隔离"><a href="#服务故障隔离" class="headerlink" title="服务故障隔离"></a>服务故障隔离</h2><ol><li>IO操作故障隔离:网络IO. 磁盘IO. 数据库</li><li>资源故障隔离<br> 通信链路隔离<br> 调度资源隔离:微服务之间隔离. 第三方依赖隔离<br> 进程级隔离:VM隔离. 进程级隔离</li><li>容错能力<br> 路由容错:失败重试. 失败回调. 快速失败<br> 服务降级:强制降级. 容错降级<br> 熔断:全部拒绝. 部分拒绝</li><li>流量控制</li></ol><h2 id="故障隔离技术"><a href="#故障隔离技术" class="headerlink" title="故障隔离技术"></a>故障隔离技术</h2><p>同步I/O主要弊端:<br>I/O操作同步阻塞, 受制于网络和第三方处理速度 I/O线程效率低,容易发生 线程数量膨胀. 通信队列积压 等问题<br>优化策略:<br>TCP私有协议:建议直接基于 Netty开发<br>HTTP/Restful/SOAP等:选择支 持非阻塞I/O的Web框架。可以选 择基于Netty构建的开源应用层 协议栈框架</p><h2 id="RPC通信链路隔离"><a href="#RPC通信链路隔离" class="headerlink" title="RPC通信链路隔离"></a>RPC通信链路隔离</h2><p>隔离策略:</p><ol><li>微服务节点之间支持配置多链路</li><li>微服务链路支持不同的隔离策略: 例如根据消息码流大小. 根据微服务的优先级等策略,实现链路级的隔离</li></ol><h2 id="微服务调度隔离"><a href="#微服务调度隔离" class="headerlink" title="微服务调度隔离"></a>微服务调度隔离</h2><p>关键技术点:</p><ol><li>微服务发布时支持指定线程池/线程组</li><li>微服务线程池支持独享和共享两种模式 微服务和线程池监控,识别故障微服务, 动态调整到故障隔离线程池中</li><li>支持按照微服务优先级调度微服务, 即微服务线程支持微服务优先级调度</li></ol><h2 id="第三方服务依赖隔离"><a href="#第三方服务依赖隔离" class="headerlink" title="第三方服务依赖隔离"></a>第三方服务依赖隔离</h2><p>关键技术点:</p><ol><li>第三方依赖隔离可以采用线程池 + 响应式编程(例如RxJava)的方式实现 </li><li>对第三方依赖进行分类,每种依赖对应一个独立的线程/线程池</li><li>微服务不直接调用第三方依赖的API,而是使用异步封装之后的API接口</li><li>异步调用第三方依赖API之后,获取Future对象。利用响应式编程框架, 可以订阅后续的事件,接收响应,针对响应进行编程</li></ol><h2 id="微服务进程隔离-Docker容器"><a href="#微服务进程隔离-Docker容器" class="headerlink" title="微服务进程隔离(Docker容器)"></a>微服务进程隔离(Docker容器)</h2><p>关键技术点:</p><ol><li>微服务独立开发. 打包和部署</li><li>基于Docker部署微服务,可以实现细粒度的资源隔离,实现微服务的高密度部署。<br>优势:</li><li>高效:微服务的启动和销毁速度非常快, 可以实现秒级弹性伸缩</li><li>高性能:Docker容器的性能接近裸的物理机, 综合性能损耗 < 5%</li><li>可移植性:“一次编写,到处运行”</li></ol><h2 id="分布式路由容错"><a href="#分布式路由容错" class="headerlink" title="分布式路由容错"></a>分布式路由容错</h2><ol><li>失败自动重试:微服务调用失败自动重试</li><li>失败自动切换:当发生服务调用异常时,重新选路,查找下一个可用的微服务提供者 </li><li>快速失败:对于一些非核心的服务,希望只调用一次,失败也不再重试</li><li>失败回调:提供异常回调接口,执行微服务消费者自定义的失败处理逻辑</li></ol><h2 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h2><ol><li>强制降级:不发起远程服务调用,执行本地降级策略,例如本地Mock方法 </li><li>容错降级:当非核心服务不可用时,可以对故障服务做业务逻辑放通,以保障核心服务的运行,降级策略包括异常转换. 本地放通方法调用</li></ol><h2 id="熔断机制"><a href="#熔断机制" class="headerlink" title="熔断机制"></a>熔断机制</h2><ol><li>熔断判断:微服务调用时, 对熔断开关状态进行判断,当熔断器开关关闭时, 请求被允许通过熔断器</li><li>熔断执行:当熔断器开关打 开时,微服务调用请求被禁止通过,执行失败回调接口</li><li>自动恢复:熔断之后,周期T 之后允许一条消息通过,如果成功,则取消熔断状态,否则继续处于熔断状态</li></ol><h1 id="spark"><a href="#spark" class="headerlink" title="spark"></a>spark</h1><h2 id="什么是Spark"><a href="#什么是Spark" class="headerlink" title="什么是Spark"></a>什么是Spark</h2><ol><li>Apache Spark是一个围绕速度. 易用性和复杂分析构建的大数据处理框架。<br>最初在2009年由加州大学伯克利分校的AMPLab开发,并于2010年成为Apache的开源项目之一。</li><li>Spark为我们提供了一个全面. 统一的框架用于管理各种有着不同性质(文本数据. 图表数据等)的数据集和数据源(批量数据或实时的流数据)的大数据处理的需求。</li><li>Spark可以将Hadoop集群中的应用在内存中的运行速度提升100倍,甚至能够将应用在磁盘上的运行速度提升10倍。</li><li>除了Map和Reduce操作之外,它还支持SQL查询,流数据,机器学习和图表数据处理。<br>开发者可以在一个数据管道用例中单独使用某一能力或者将这些能力结合在一起使用。</li></ol><h2 id="Spark特性"><a href="#Spark特性" class="headerlink" title="Spark特性"></a>Spark特性</h2><ol><li>Spark通过在数据处理过程中成本更低的洗牌(Shuffle)方式,将MapReduce提升到一个更高的层次。利用内存数据存储和接近实时的处理能力,Spark比其他的大数据处理技术的性能要快很多倍。</li><li>Spark还支持大数据查询的延迟计算,这可以帮助优化大数据处理流程中的处理步骤。Spark还提供高级的API以提升开发者的生产力,除此之外还为大数据解决方案提供一致的体系架构模型。</li><li>Spark将中间结果保存在内存中而不是将其写入磁盘,当需要多次处理同一数据集时,这一点特别实用。Spark的设计初衷就是既可以在内存中又可以在磁盘上工作的执行引擎。当内存中的数据不适用时,Spark操作符就会执行外部操作。Spark可以用于处理大于集群内存容量总和的数据集。</li><li>Spark会尝试在内存中存储尽可能多的数据然后将其写入磁盘。它可以将某个数据集的一部分存入内存而剩余部分存入磁盘。开发者需要根据数据和用例评估对内存的需求。Spark的性能优势得益于这种内存中的数据存储</li></ol><h2 id="Spark生态系统"><a href="#Spark生态系统" class="headerlink" title="Spark生态系统"></a>Spark生态系统</h2><ol><li>Spark Streaming:<br> Spark Streaming基于微批量方式的计算和处理,可以用于处理实时的流数据。它使用DStream,简单来说就是一个弹性分布式数据集(RDD)系列,处理实时数据。</li><li>Spark SQL:<br> Spark SQL可以通过JDBC API将Spark数据集暴露出去,而且还可以用传统的BI和可视化工具在Spark数据上执行类似SQL的查询。用户还可以用Spark SQL对不同格式的数据(如JSON,Parquet以及数据库等)执行ETL,将其转化,然后暴露给特定的查询。</li><li>Spark MLlib:<br> MLlib是一个可扩展的Spark机器学习库,由通用的学习算法和工具组成,包括二元分类. 线性回归. 聚类. 协同过滤. 梯度下降以及底层优化原语。</li><li>Spark GraphX:<br> GraphX是用于图计算和并行图计算的新的(alpha)Spark API。通过引入弹性分布式属性图(Resilient Distributed Property Graph),一种顶点和边都带有属性的有向多重图,扩展了Spark RDD。为了支持图计算,<br> GraphX暴露了一个基础操作符集合(如subgraph,joinVertices和aggregateMessages)和一个经过优化的Pregel API变体。此外,GraphX还包括一个持续增长的用于简化图分析任务的图算法和构建器集合。</li><li>BlinkDB是一个近似查询引擎,用于在海量数据上执行交互式SQL查询。BlinkDB可以通过牺牲数据精度来提升查询响应时间。通过在数据样本上执行查询并展示包含有意义的错误线注解的结果,操作大数据集合。</li><li>Tachyon是一个以内存为中心的分布式文件系统,能够提供内存级别速度的跨集群框架(如Spark和MapReduce)的可信文件共享。它将工作集文件缓存在内存中,从而避免到磁盘中加载需要经常读取的数据集。通过这一机制,不同的作业/查询和框架可以以内存级的速度访问缓存的文件。<br>此外,还有一些用于与其他产品集成的适配器,如Cassandra(Spark Cassandra 连接器)和R(SparkR)。Cassandra Connector可用于访问存储在Cassandra数据库中的数据并在这些数据上执行数据分析。</li></ol><h2 id="Spark体系架构"><a href="#Spark体系架构" class="headerlink" title="Spark体系架构"></a>Spark体系架构</h2><p>Spark体系架构包括如下三个主要组件:</p><ol><li><p>数据存储</p></li><li><p>API</p></li><li><p>管理框架</p></li><li><p>数据存储:<br>Spark用HDFS文件系统存储数据。它可用于存储任何兼容于Hadoop的数据源,包括HDFS,HBase,Cassandra等。</p></li><li><p>API:<br>利用API,应用开发者可以用标准的API接口创建基于Spark的应用。Spark提供Scala,Java和Python三种程序设计语言的API。<br>下面是三种语言Spark API<br>Scala API<br>Java<br>Python</p></li><li><p>资源管理:<br>Spark既可以部署在一个单独的服务器也可以部署在像Mesos或YARN这样的分布式计算框架之上。</p></li></ol><h2 id="Spark体系架构-1"><a href="#Spark体系架构-1" class="headerlink" title="Spark体系架构"></a>Spark体系架构</h2><ol><li>弹性分布式数据集:弹性分布式数据集(基于Matei的研究论文)或RDD是Spark框架中的核心概念。可以将RDD视作数据库中的一张表。其中可以保存任何类型的数据。Spark将数据存储在不同分区上的RDD之中。<br>RDD可以帮助重新安排计算并优化数据处理过程。此外,它还具有容错性,因为RDD知道如何重新创建和重新计算数据集。RDD是不可变的。你可以用变换(Transformation)修改RDD,但是这个变换所返回的是一个全新的RDD,而原有的RDD仍然保持不变。<br>RDD支持两种类型的操作:<br>变换(Transformation)<br>行动(Action)</li></ol><h2 id="变换:变换的返回值是一个新的RDD集合,而不是单个值。调用一个变换方法,不会有任何求值计算,它只获取一个RDD作为参数,然后返回一个新的RDD。"><a href="#变换:变换的返回值是一个新的RDD集合,而不是单个值。调用一个变换方法,不会有任何求值计算,它只获取一个RDD作为参数,然后返回一个新的RDD。" class="headerlink" title="变换:变换的返回值是一个新的RDD集合,而不是单个值。调用一个变换方法,不会有任何求值计算,它只获取一个RDD作为参数,然后返回一个新的RDD。"></a>变换:变换的返回值是一个新的RDD集合,而不是单个值。调用一个变换方法,不会有任何求值计算,它只获取一个RDD作为参数,然后返回一个新的RDD。</h2><p>变换函数包括:map,filter,flatMap,groupByKey,reduceByKey,aggregateByKey,pipe和coalesce。</p><h2 id="行动:行动操作计算并返回一个新的值。当在一个RDD对象上调用行动函数时,会在这一时刻计算全部的数据处理查询并返回结果值。"><a href="#行动:行动操作计算并返回一个新的值。当在一个RDD对象上调用行动函数时,会在这一时刻计算全部的数据处理查询并返回结果值。" class="headerlink" title="行动:行动操作计算并返回一个新的值。当在一个RDD对象上调用行动函数时,会在这一时刻计算全部的数据处理查询并返回结果值。"></a>行动:行动操作计算并返回一个新的值。当在一个RDD对象上调用行动函数时,会在这一时刻计算全部的数据处理查询并返回结果值。</h2><p>行动操作包括:reduce,collect,count,first,take,countByKey以及foreach。</p><h1 id="synchronized"><a href="#synchronized" class="headerlink" title="synchronized"></a>synchronized</h1><h2 id="synchronized是java的关键字,是一种同步锁"><a href="#synchronized是java的关键字,是一种同步锁" class="headerlink" title="synchronized是java的关键字,是一种同步锁"></a>synchronized是java的关键字,是一种同步锁</h2><ol><li>修饰代码块,被修饰的代码块成为同步代码块,其作用范围是大括号括起来的代码,作用的对象是调用这个代码块的对象。</li><li>修饰一个方法,被修饰的方法成为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。</li><li>修改是一个静态方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象。</li></ol><h2 id="零长度的byte数组创建起来比任何对象都经济,生成0长度的byte-对象只需要3条字节码-而创建一个Object则需要7步骤。"><a href="#零长度的byte数组创建起来比任何对象都经济,生成0长度的byte-对象只需要3条字节码-而创建一个Object则需要7步骤。" class="headerlink" title="零长度的byte数组创建起来比任何对象都经济,生成0长度的byte[]对象只需要3条字节码. 而创建一个Object则需要7步骤。"></a>零长度的byte数组创建起来比任何对象都经济,生成0长度的byte[]对象只需要3条字节码. 而创建一个Object则需要7步骤。</h2><h2 id="并发访问时需要注意事项"><a href="#并发访问时需要注意事项" class="headerlink" title="并发访问时需要注意事项"></a>并发访问时需要注意事项</h2><ol><li>当2个并发线程访问一个对象Object中的这个Synchronized同步代码块时,一个时间内只能有一个线程得到执行,另一个线程必须等待<br>当前线程执行完,才能执行。</li><li>当一个线程访问Object的Synchronized方法时,另一个线程可以访问非synchronized的同步代码块。</li><li>当一个线程访问Object的Synchronized方法时,其他线程对Object中所有其他Synchronized同步代码块的访问将阻塞。</li><li>静态方法属于类,而不属于任何一个对象,synchronized修饰的静态方法锁定这个对象的所有类。<br>总结:</li><li>无论synchronized关键字加在方法上还是对象上,如果它作用的是非静态的,则它取得的锁是对象。如果一个synchronized作用的对象<br>是一个静态方法或者一个类,则它获取的锁是对该类所有对象的同一把锁。</li></ol><h1 id="system"><a href="#system" class="headerlink" title="system"></a>system</h1><h2 id="高并发服务器建议调小-TCP-协议的-time-wait-超时时间"><a href="#高并发服务器建议调小-TCP-协议的-time-wait-超时时间" class="headerlink" title="高并发服务器建议调小 TCP 协议的 time_wait 超时时间"></a>高并发服务器建议调小 TCP 协议的 time_wait 超时时间</h2><p>说明:操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服 务器端会因为处于 time_wait 的连接数太多,可能无法建立新的连接,所以需要在服务器上 调小此等待值。<br>正例:在 linux 服务器上请通过变更/etc/sysctl.conf 文件去修改该缺省值(秒):<br>net.ipv4.tcp_fin_timeout = 30</p><h2 id="调大服务器所支持的最大文件句柄数-File-Descriptor-简写为fd"><a href="#调大服务器所支持的最大文件句柄数-File-Descriptor-简写为fd" class="headerlink" title="调大服务器所支持的最大文件句柄数(File Descriptor,简写为fd)"></a>调大服务器所支持的最大文件句柄数(File Descriptor,简写为fd)</h2><p>说明:主流操作系统的设计是将 TCP/UDP 连接采用与文件一样的方式去管理,即一个连接对 应于一个 fd。<br>主流的 linux 服务器默认所支持最大 fd 数量为 1024,当并发连接数很大时很 容易因为 fd 不足而出现“open too many files”错误,导致新的连接无法建立。<br>建议将 linux 服务器所支持的最大句柄数调高数倍(与服务器的内存数量相关)。</p><h2 id="给-JVM-设置-XX-HeapDumpOnOutOfMemoryError-参数-让-JVM-碰到-OOM-场景时输出-dump-信息"><a href="#给-JVM-设置-XX-HeapDumpOnOutOfMemoryError-参数-让-JVM-碰到-OOM-场景时输出-dump-信息" class="headerlink" title="给 JVM 设置-XX:+HeapDumpOnOutOfMemoryError 参数,让 JVM 碰到 OOM 场景时输出 dump 信息"></a>给 JVM 设置-XX:+HeapDumpOnOutOfMemoryError 参数,让 JVM 碰到 OOM 场景时输出 dump 信息</h2><p>说明:OOM 的发生是有概率的,甚至有规律地相隔数月才出现一例,出现时的现场信息对查错 非常有价值。</p><h2 id="服务器内部重定向使用-forward,外部重定向地址使用-URL-拼装工具类来生成-否则-会带来-URL-维护不一致的问题和潜在的安全风险。"><a href="#服务器内部重定向使用-forward,外部重定向地址使用-URL-拼装工具类来生成-否则-会带来-URL-维护不一致的问题和潜在的安全风险。" class="headerlink" title="服务器内部重定向使用 forward,外部重定向地址使用 URL 拼装工具类来生成,否则 会带来 URL 维护不一致的问题和潜在的安全风险。"></a>服务器内部重定向使用 forward,外部重定向地址使用 URL 拼装工具类来生成,否则 会带来 URL 维护不一致的问题和潜在的安全风险。</h2><h1 id="threadpoolexecutor"><a href="#threadpoolexecutor" class="headerlink" title="threadpoolexecutor"></a>threadpoolexecutor</h1><h2 id="参数介绍"><a href="#参数介绍" class="headerlink" title="参数介绍"></a>参数介绍</h2><ol><li>corePoolSize:线程池维护线程的最小数量。</li><li>maxinumPoolSize:线程池维护线程的最大数量。</li><li>keepAliveTime:线程池维护线程所允许的空闲时间。</li><li>unit:空闲时间对应的时间单元。</li><li>workQueue:线程池所使用的缓冲队列</li></ol><h2 id="线程池对拒绝任务的处理策略"><a href="#线程池对拒绝任务的处理策略" class="headerlink" title="线程池对拒绝任务的处理策略"></a>线程池对拒绝任务的处理策略</h2><ol><li>不使用线程池线程执行。</li><li>直接丢弃当前任务。</li><li>丢弃队列中最旧的任务。</li><li>抛出异常。<br>这四种策略是独立无关的,是对任务拒绝处理的四种表现形式。最简单的方式就是直接丢弃任务。<br>但是却有两种方式,到底是改丢弃哪一个任务,比如可以丢弃当前将要加入队列的任务本身,或者丢弃任务队列最旧任务。<br>丢弃最旧任务也不是简单的丢弃最旧的任务,而是有一些额外的处理。除了丢弃任务还可以抛出异常,这是比较简单的方式。<br>抛出异常的方式比较简单,但是会中断调用者的处理过程,除了抛出异常还可以不进入线程池执行,在这种方式中,任务将由调用者去执行。</li></ol><h1 id="transaction"><a href="#transaction" class="headerlink" title="transaction"></a>transaction</h1><h2 id="数据库事务的四个特性ACID:"><a href="#数据库事务的四个特性ACID:" class="headerlink" title="数据库事务的四个特性ACID:"></a>数据库事务的四个特性ACID:</h2><ol><li>原子性:事务是一个原子操作,由一系列动作组成,要么全部成功,要么全部失败。</li><li>一致性:事物开启到结束,数据库的完整性没有被破坏,一个事务执行之前和执行之后都必须处于一致性状态。</li><li>隔离性:事务之间相互隔离,互不影响。</li><li>持久性:事务一旦提交,影响将是永久性的。</li></ol><h1 id="weakhashmap"><a href="#weakhashmap" class="headerlink" title="weakhashmap"></a>weakhashmap</h1><h2 id="WeakHashMap"><a href="#WeakHashMap" class="headerlink" title="WeakHashMap"></a>WeakHashMap</h2><p>它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。<br>使用 WeakHashMap 时,即使没有显示的添加或删除任何元素,也可能发生如下情况:<br> 调用两次size()方法返回不同的值;<br> 两次调用isEmpty()方法,第一次返回false,第二次返回true;<br> 两次调用containsKey()方法,第一次返回true,第二次返回false,尽管两次使用的是同一个key;<br> 两次调用get()方法,第一次返回一个value,第二次返回null,尽管两次使用的是同一个对象。</p><h2 id="WeekHashMap用途:"><a href="#WeekHashMap用途:" class="headerlink" title="WeekHashMap用途:"></a>WeekHashMap用途:</h2><p>WeekHashMap 的这个特点特别适用于需要缓存的场景。在缓存场景下,由于内存是有限的,不能缓存所有对象;<br>对象缓存命中可以提高系统效率,但缓存MISS也不会造成错误,因为可以通过计算重新得到。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>要明白 WeekHashMap 的工作原理,还需要引入一个概念:弱引用(WeakReference)。我们都知道Java中内存是通过GC自动管理的,GC会在程序运行过程中自动判断哪些对象是可以被回收的,并在合适的时机进行内存释放。<br>GC判断某个对象是否可被回收的依据是,是否有有效的引用指向该对象。如果没有有效引用指向该对象(基本意味着不存在访问该对象的方式),那么该对象就是可回收的。这里的“有效引用”并不包括弱引用。<br>也就是说,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收。<br>WeakHashMap 内部是通过弱引用来管理entry的,弱引用的特性对应到 WeakHashMap 上意味着什么呢?将一对key, value放入到 WeakHashMap 里并不能避免该key值被GC回收,<br>除非在 WeakHashMap 之外还有对该key的强引用。</p><h1 id="web"><a href="#web" class="headerlink" title="web"></a>web</h1><h2 id="静态化系统的特征"><a href="#静态化系统的特征" class="headerlink" title="静态化系统的特征"></a>静态化系统的特征</h2><ol><li>一个页面对应的URL通常是固定的。不同的URL标识不同的内容。</li><li>页面中不能包含与浏览者相关的因素,例如JS动态生成的部分,还有用户的姓名. 身份等。</li><li>在页面中不能包含时间因素。</li><li>在页面中不能包含地域因素。</li><li>不能包含Cookie等私有数据。</li></ol><h2 id="为什么要进行静态化架构设计"><a href="#为什么要进行静态化架构设计" class="headerlink" title="为什么要进行静态化架构设计"></a>为什么要进行静态化架构设计</h2><ol><li>系统进行多次升级,包括架构升级,系统本身升级,代码优化,增加各种缓存,这些java系统中做的优化,不能满足要求。<br>java本身不擅长处理大量连接的请求,每个连接消耗的内存较多。</li><li>所以需要跳出java系统,在前面的web服务层直接返回。</li></ol><h2 id="静态化系统的优点:"><a href="#静态化系统的优点:" class="headerlink" title="静态化系统的优点:"></a>静态化系统的优点:</h2><ol><li>改变了缓存的方式,直接缓存HTTP连接,而不是仅仅缓存数据。web代理服务器根据请求URL直接取出对应的HTTP响应头<br>和响应提直接返回。这个响应连HTTP都不用重新组装。</li><li>改变了缓存的地方。不是在java层面做缓存,而是直接在web服务层做,屏蔽了java的一些弱点。</li></ol><h2 id="如何动态改造系统"><a href="#如何动态改造系统" class="headerlink" title="如何动态改造系统"></a>如何动态改造系统</h2><ol><li>动静分离</li><li>组装动态内容:<br>2.1 ESI,在Web代理服务器上做动态内容请求,并将请求插入到静态页面中。当用户拿到页面已经是一个完整的页面了。这种对服务器<br>性能有些影响,但是用户体验是好的。<br>2.2 CSI,这种方式就是发起一个异步JS请求单独向服务器获取动态内容。这种方式使服务器性能更佳,但是用户端页面有些延迟,体验<br>稍差。</li></ol><h1 id="zk"><a href="#zk" class="headerlink" title="zk"></a>zk</h1><h2 id="流行的应用场景"><a href="#流行的应用场景" class="headerlink" title="流行的应用场景"></a>流行的应用场景</h2><ol><li>分布式配置管理<br>发布与订阅即所谓的配置管理,顾名思义就是将数据发布到zk的节点上,供订阅者动态获取数据,实现配置信息的集中式管理和动态更新,例如全局的配置信息,地址列表等就非常的适合使用。</li><li>Name Server<br>这个主要是用作分布式命名服务,通过调用zk的create node api,能够很容易创建一个全局唯一的path,这个path就可以作为一个名称。</li><li>分布式通知/协调<br>Zookeeper中特有的watcher注册与异步通知机制,能够很好的实现分布式环境下不同系统之间的通知与协调,实现对数据变更的实时处理。使用方法通常是不同系统都对zk上同一个znode进行注册,监听znode的变化(包括znode本身内容以及子节点的),其中一个系统update了znode,那么另外一个系统能够收到通知,并作出对应的处理。</li><li>分布式锁<br>分布式锁,这个主要得益于zookeeper为我们保证了数据的强一致性,即用户只要完全相信每时每刻,zk集群中任意的借点(一个zk server)上的相同znode的数据是一定相同的。锁服务可以氛围两类,一个是保持独占,另一个是控制时序。</li><li>集群管理<br>Hbase Master 选举则是zookeeper经典的使用场景;<br>Storm集群管理。</li><li>分布式队列<br>队列方面一种是常规的先进先出队列,另外一种是要等到队列成员都聚齐之后才统一按序执行,对于第二种先进先出队列,增加分布式锁服务以控制时序场景。</li></ol>]]></content>
<summary type="html"><h1 id="annotation"><a href="#annotation" class="headerlink" title="annotation"></a>annotation</h1><h2 id="元注解:"><a href="#元注解:" class="head</summary>
<category term="JAVA" scheme="https://chengzc.club/tags/JAVA/"/>
<category term="笔记" scheme="https://chengzc.club/tags/%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>关于使用码云,GITHUB,阿里云CODE来管理代码的一些操作记录</title>
<link href="https://chengzc.club/posts/865795493/"/>
<id>https://chengzc.club/posts/865795493/</id>
<published>2019-01-21T09:18:11.000Z</published>
<updated>2023-04-14T01:38:51.000Z</updated>
<content type="html"><![CDATA[<h1 id="创建远程仓库"><a href="#创建远程仓库" class="headerlink" title="创建远程仓库"></a>创建远程仓库</h1><p>帐号申请完后,就可以新建库,比如boke。</p><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140938408.webp"></p><h1 id="本地初始化"><a href="#本地初始化" class="headerlink" title="本地初始化"></a>本地初始化</h1><p>本地得先安装git,在本地建一个文件夹,比如:web</p><p>点击:git bash here,弹出git命令窗口<br><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140940120.webp"></p><figure class="highlight plaintext"><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><br><span class="line">git init</span><br></pre></td></tr></table></figure><p>这时在web文件夹中会有一个.git的隐藏文件夹<br><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140941152.webp"></p><h1 id="配置本地的git配置信息"><a href="#配置本地的git配置信息" class="headerlink" title="配置本地的git配置信息"></a>配置本地的git配置信息</h1><figure class="highlight plaintext"><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">$ git config --global user.name "你的名字或昵称"</span><br><span class="line">$ git config --global user.email "你的邮箱"</span><br></pre></td></tr></table></figure><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140944823.webp"></p><h1 id="生成-x2F-添加SSH公钥"><a href="#生成-x2F-添加SSH公钥" class="headerlink" title="生成/添加SSH公钥"></a>生成/添加SSH公钥</h1><p>因为是第一次使用git,所以公钥是还没有的,可以使用以下方式创建公钥</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C "xxxxx@xxxxx.com"</span><br></pre></td></tr></table></figure><p>按照提示完成三次回车,即可生成 ssh key。通过查看 ~/.ssh/id_rsa.pub 文件内容,获取到你的 public key</p><figure class="highlight plaintext"><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">cat ~/.ssh/id_rsa.pub</span><br><span class="line"># ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....</span><br></pre></td></tr></table></figure><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140949053.webp"><br>公钥的后缀是.pub的,把这个里面的东西都粘到远程库的设置里</p><p>添加后,在终端中输入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -T git@gitee.com</span><br></pre></td></tr></table></figure><p>添加成功后,就可以使用SSH协议对项目进行操作了。</p><h1 id="添加远程库:origin"><a href="#添加远程库:origin" class="headerlink" title="添加远程库:origin"></a>添加远程库:origin</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git remote add origin https://gitee.com/用户个性地址/web.git</span><br></pre></td></tr></table></figure><p>查看有哪些远程库,可以用git remote -v<br>要删除远程库,可以用git remote rm 库名</p><h1 id="push文件到远程库"><a href="#push文件到远程库" class="headerlink" title="push文件到远程库"></a>push文件到远程库</h1><p>有了以上设置后,基本上就能push了,添加文件到缓存区add,提到缓存区到版本库commit,最后发布到远程push</p><figure class="highlight plaintext"><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">$ git add .</span><br><span class="line">$ git commit -m "第一次提交"</span><br><span class="line">$ git push origin master</span><br></pre></td></tr></table></figure><p>之后就可以在github或码云或阿里云code网站的项目上看到你上传的文件了</p><blockquote><p>看着上面的流程好像有点乱,其实自己一次后就简单了,至于git的一些命令,可以查阅网上的教程,很多这方面的知识,以下用文章简化下流程,用码云的:</p></blockquote><ol><li>先在码云上创建一个库,比如:python</li><li>本地新建一个文件夹用来存放代码,比如:python</li><li>初始化本地库,先cd到python,然后git init</li><li>本地生成ssh-key,查看是否有:$ cd ~/.ssh,如果没有这个文件夹,则生成:$ ssh-keygen -t rsa -C “<a href="mailto:xxx@xxx.com">xxx@xxx.com</a>“,在终端添加SSH信任:ssh -T <a href="mailto:git@gitee.com">git@gitee.com</a></li><li>复制KEY到码云个人的设置-安全设置-SSH公钥:$ cat ~/.ssh/id_rsa.pub</li><li>设置远程仓库地址:git remote add origin <a href="https://gitee.com/%E7%94%A8%E6%88%B7%E4%B8%AA%E6%80%A7%E5%9C%B0%E5%9D%80/python.git">https://gitee.com/用户个性地址/python.git</a></li><li>拉取远程仓库文件:git pull origin master</li><li>上传文件到远程仓库:git push origin master</li></ol><blockquote><p>一些常用的GIT命令</p></blockquote><ol><li>查看文件状态:git status</li><li>查看远程仓库有哪些:git remote -v</li><li>删除不要的远程仓库:git remote rm 远程仓库名</li><li>回退版本:git reset –hard 版本号</li><li>查看配置:git config –list</li><li>配置user.name :git config –global user.name “阿乞云计算”</li><li>配置user.email: git config –global user.email “<a href="mailto:xxx@xxx.com">xxx@xxx.com</a>“</li><li>查看差异:git diff</li></ol><blockquote><p>这里有个注意的,要配置SSH钥的时候,如果你重新执行ssh-keygen -t rsa -C “<a href="mailto:xxxxx@xxxxx.com">xxxxx@xxxxx.com</a>“,之前的旧KEY就不能用了,得重新到网站上添加新的KEY</p></blockquote><h1 id="使用git的一些其它补充-分支处理、SSH、多个远程库"><a href="#使用git的一些其它补充-分支处理、SSH、多个远程库" class="headerlink" title="使用git的一些其它补充 分支处理、SSH、多个远程库"></a>使用git的一些其它补充 分支处理、SSH、多个远程库</h1><h2 id="关于SSH-keys"><a href="#关于SSH-keys" class="headerlink" title="关于SSH keys"></a>关于SSH keys</h2><p>SSH key 可以让你在你的电脑和Code服务器之间建立安全的加密连接。 先执行以下语句来判断是否已经存在本地公钥:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat ~/.ssh/id_rsa.pub</span><br></pre></td></tr></table></figure><p>如果你看到一长串以 ssh-rsa或 ssh-dsa开头的字符串, 你可以跳过 ssh-keygen的步骤。</p><p>提示: 最好的情况是一个密码对应一个ssh key,但是那不是必须的。你完全可以跳过创建密码这个步骤。请记住设置的密码并不能被修改或获取。</p><p>你可以按如下命令来生成ssh key:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C “487042@qq.com”</span><br></pre></td></tr></table></figure><p>这个指令会要求你提供一个位置和文件名去存放键值对和密码,你可以点击Enter键去使用默认值。</p><p>用以下命令获取你生成的公钥:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat ~/.ssh/id_rsa.pub</span><br></pre></td></tr></table></figure><h2 id="一个本地库关联多个github库"><a href="#一个本地库关联多个github库" class="headerlink" title="一个本地库关联多个github库"></a>一个本地库关联多个github库</h2><p>使用多个远程库时,我们要注意,git给远程库起的默认名称是origin,如果有多个远程库,我们需要用不同的名称来标识不同的远程库。</p><p>仍然以python本地库为例,我们先删除已关联的名为origin的远程库:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote rm origin</span><br></pre></td></tr></table></figure><p>然后,先关联GitHub的远程库:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add github git@github.com:michaelliao/python.git</span><br></pre></td></tr></table></figure><p>注意,远程库的名称叫github,不叫origin了。</p><p>接着,再关联码云的远程库:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add gitee git@gitee.com:liaoxuefeng/python.git</span><br></pre></td></tr></table></figure><p>同样注意,远程库的名称叫gitee,不叫origin。</p><p>现在,我们用git remote -v查看远程库信息,可以看到两个远程库:</p><figure class="highlight plaintext"><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">git remote -v</span><br><span class="line">gitee git@gitee.com:liaoxuefeng/python.git (fetch)</span><br><span class="line">gitee git@gitee.com:liaoxuefeng/python.git (push)</span><br><span class="line">github git@github.com:michaelliao/python.git (fetch)</span><br><span class="line">github git@github.com:michaelliao/python.git (push)</span><br></pre></td></tr></table></figure><p>如果要推送到GitHub,使用命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push github master</span><br></pre></td></tr></table></figure><p>如果要推送到码云,使用命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push gitee master</span><br></pre></td></tr></table></figure><p>这样一来,我们的本地库就可以同时与多个远程库互相同步</p><h2 id="分支"><a href="#分支" class="headerlink" title="分支"></a>分支</h2><p>Git鼓励大量使用分支:</p><ul><li>查看分支:<code>git branch</code></li><li>创建分支:<code>git branch</code></li><li>切换分支:<code>git checkout</code></li><li>创建+切换分支:<code>git checkout -b</code></li><li>合并某分支到当前分支:<code>git merge</code></li><li>删除本地分支:<code>git branch -d</code></li><li>删除远程服务器上的分支:<code>git push origin -d BranchName</code></li><li>或删除远程服务器上的分支:<code>git branch -d origin/BranchName</code></li></ul>]]></content>
<summary type="html"><h1 id="创建远程仓库"><a href="#创建远程仓库" class="headerlink" title="创建远程仓库"></a>创建远程仓库</h1><p>帐号申请完后,就可以新建库,比如boke。</p>
<p><img src="https://czcsw-1</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="git" scheme="https://chengzc.club/tags/git/"/>
<category term="码云" scheme="https://chengzc.club/tags/%E7%A0%81%E4%BA%91/"/>
</entry>
<entry>
<title>关于win10威盛声卡前置面板没声音的问题</title>
<link href="https://chengzc.club/posts/3679620969/"/>
<id>https://chengzc.club/posts/3679620969/</id>
<published>2019-01-21T01:07:42.000Z</published>
<updated>2023-04-13T17:26:24.324Z</updated>
<content type="html"><![CDATA[<h1 id="关于win10威盛声卡前置面板没声音的问题"><a href="#关于win10威盛声卡前置面板没声音的问题" class="headerlink" title="关于win10威盛声卡前置面板没声音的问题"></a>关于win10威盛声卡前置面板没声音的问题</h1><ol><li><a href="http://bbs.pcbeta.com/viewthread-1672134-1-4.html">驱动下载</a>,下载这个里边的驱动,解压出里边的文件。然后该怎么安装就怎么安装,装完先不要重启。</li><li>然后运行HD VDeck会发现主程序是32位的,在64位系统下打不开。</li><li>然后打开你解压驱动的文件夹,照着这个路径找到这个文件夹下<strong>:\VIAHDAud\Present\VDeck64</strong><br>这里边的文件都是64位的音效控制程序</li><li>右击桌面上的HD VDeck快捷方式,点击打开文件所在的位置打开的路径是<strong>C:\Program Files (x86)\VIA\VIAudioi\VDeck</strong>(由于基本没人改驱动安装的位置,所以大部分都完全相同,你要是改了请以你那个为准)</li><li>然后把<strong>C:\Program Files (x86)\VIA\VIAudioi\VDeck</strong>里边的全部文件替换掉,换成<strong>\VIAHDAud\Present\VDeck64</strong>下的文件(一定要全部替换)</li><li>之后重启计算机,HD VDeck就可以出现在右下角了</li></ol>]]></content>
<summary type="html"><h1 id="关于win10威盛声卡前置面板没声音的问题"><a href="#关于win10威盛声卡前置面板没声音的问题" class="headerlink" title="关于win10威盛声卡前置面板没声音的问题"></a>关于win10威盛声卡前置面板没声音的问题</</summary>
<category term="声卡" scheme="https://chengzc.club/tags/%E5%A3%B0%E5%8D%A1/"/>
</entry>
<entry>
<title>Markdown基本语法</title>
<link href="https://chengzc.club/posts/1563885333/"/>
<id>https://chengzc.club/posts/1563885333/</id>
<published>2019-01-11T08:32:12.000Z</published>
<updated>2023-04-17T08:26:56.000Z</updated>
<content type="html"><</span><br><span class="line"></span><br><span class="line">图片alt就是显示在图片下面的文字,相当于对图片内容的解释。</span><br><span class="line">图片title是图片的标题,当鼠标移到图片上时显示的内容。title可加可不加</span><br></pre></td></tr></table></figure><p>示例:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><p>效果如下:</p><p><img src="https://img.chengzc.club/i/2023/04/15/64397f9e885d0.webp" alt="1681489821423-15b0252c20f5ecfdb3beb181befd77b6.webp"></p><h1 id="六、超链接"><a href="#六、超链接" class="headerlink" title="六、超链接"></a>六、超链接</h1><p>语法:</p><figure class="highlight plaintext"><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">[超链接名](超链接地址 "超链接title")</span><br><span class="line">title可加可不加</span><br></pre></td></tr></table></figure><p>示例:</p><figure class="highlight plaintext"><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">[简书](http://jianshu.com)</span><br><span class="line">[百度](http://baidu.com)</span><br></pre></td></tr></table></figure><p>效果如下:</p><p><a href="http://jianshu.com/">简书</a><br><a href="http://baidu.com/">百度</a></p><p>注:Markdown本身语法不支持链接在新页面中打开,貌似简书做了处理,是可以的。别的平台可能就不行了,如果想要在新页面中打开的话可以用html语言的a标签代替。</p><figure class="highlight plaintext"><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"><a href="超链接地址" target="_blank">超链接名</a></span><br><span class="line"></span><br><span class="line">示例</span><br><span class="line"><a href="https://www.jianshu.com/u/1f5ac0cf6a8b" target="_blank">简书</a></span><br></pre></td></tr></table></figure><h1 id="七、列表"><a href="#七、列表" class="headerlink" title="七、列表"></a>七、列表</h1><ul><li><p><strong>无序列表</strong></p><p>语法:<br>无序列表用 - + * 任何一种都可以</p></li></ul><p>示例</p><figure class="highlight plaintext"><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">- 列表内容</span><br><span class="line">+ 列表内容</span><br><span class="line">* 列表内容</span><br><span class="line"></span><br><span class="line">注意:- + * 跟内容之间都要有一个空格</span><br></pre></td></tr></table></figure><p>效果</p><ul><li>列表内容</li></ul><ul><li>列表内容</li></ul><ul><li>列表内容</li></ul><ul><li><strong>有序列表</strong></li></ul><p>语法:<br>数字加点</p><figure class="highlight plaintext"><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">1.列表内容</span><br><span class="line">2.列表内容</span><br><span class="line">3.列表内容</span><br><span class="line"></span><br><span class="line">注意:序号跟内容之间要有空格</span><br></pre></td></tr></table></figure><ol><li>列表内容</li><li>列表内容</li><li>列表内容</li></ol><ul><li><strong>列表嵌套</strong></li></ul><p>上一级和下一级之间敲三个空格即可</p><ul><li><p>一级无序列表内容(嵌套无序)</p><ul><li>列表嵌套</li><li>列表嵌套</li><li>列表嵌套</li></ul></li><li><p>一级无序列表内容(嵌套有序)</p><ol><li>列表嵌套</li><li>列表嵌套</li><li>列表嵌套</li></ol></li></ul><ol><li><p>一级有序列表内容(嵌套无序)</p><ul><li>列表嵌套</li><li>列表嵌套</li><li>列表嵌套</li></ul></li><li><p>一级有序列表内容(嵌套有序)</p><ol><li>列表嵌套</li><li>列表嵌套</li><li>列表嵌套</li></ol></li></ol><ul><li><strong>任务列表</strong></li></ul><ul><li>[任务一]</li><li>[任务二]</li><li>[任务三]</li></ul><h1 id="八、表格"><a href="#八、表格" class="headerlink" title="八、表格"></a>八、表格</h1><p>语法:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">表头|表头|表头</span><br><span class="line">---|:--:|---:</span><br><span class="line">内容|内容|内容</span><br><span class="line">内容|内容|内容</span><br><span class="line"></span><br><span class="line">第二行分割表头和内容。</span><br><span class="line">- 有一个就行,为了对齐,多加了几个</span><br><span class="line">文字默认居左</span><br><span class="line">-两边加:表示文字居中</span><br><span class="line">-右边加:表示文字居右</span><br><span class="line">注:原生的语法两边都要用 | 包起来。此处省略</span><br></pre></td></tr></table></figure><p>示例:</p><figure class="highlight plaintext"><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">姓名|技能|排行</span><br><span class="line">--|:--:|--:</span><br><span class="line">刘备|哭|大哥</span><br><span class="line">关羽|打|二哥</span><br><span class="line">张飞|骂|三弟</span><br></pre></td></tr></table></figure><p>效果</p><table><thead><tr><th>姓名</th><th align="center">技能</th><th align="right">排行</th></tr></thead><tbody><tr><td>刘备</td><td align="center">哭</td><td align="right">大哥</td></tr><tr><td>关羽</td><td align="center">打</td><td align="right">二哥</td></tr><tr><td>张飞</td><td align="center">骂</td><td align="right">三弟</td></tr></tbody></table><table><thead><tr><th align="center">姓名</th><th align="center">性别</th><th align="center">年龄</th><th align="center">身高</th><th align="center">体重</th><th align="center">爱好</th></tr></thead><tbody><tr><td align="center">小明</td><td align="center">男</td><td align="center">11</td><td align="center">153</td><td align="center">56</td><td align="center">学习</td></tr><tr><td align="center">小红</td><td align="center">女</td><td align="center">12</td><td align="center">166</td><td align="center">50</td><td align="center">读书</td></tr></tbody></table><h1 id="九、代码"><a href="#九、代码" class="headerlink" title="九、代码"></a>九、代码</h1><p>语法:<br>单行代码:代码之间分别用一个反引号包起来</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">`代码内容`</span><br></pre></td></tr></table></figure><p>代码块:代码之间分别用三个反引号包起来,且两边的反引号单独占一行</p><figure class="highlight plaintext"><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">(```)</span><br><span class="line"> 代码...</span><br><span class="line"> 代码...</span><br><span class="line"> 代码...</span><br><span class="line">(```)</span><br></pre></td></tr></table></figure><blockquote><p>注:为了防止转译,前后三个反引号处加了小括号,实际是没有的。这里只是用来演示,实际中去掉两边小括号即可。</p></blockquote><p>示例:</p><p>单行代码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">`this is linecode`</span><br></pre></td></tr></table></figure><p>多行代码</p><figure class="highlight js"><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">(<span class="string">``</span><span class="string">`)</span></span><br><span class="line"><span class="string"> function fun(){</span></span><br><span class="line"><span class="string"> echo "这是一句非常牛逼的代码";</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> fun();</span></span><br><span class="line"><span class="string">(`</span><span class="string">``</span>)</span><br></pre></td></tr></table></figure><p>效果如下:</p><p>单行代码</p><p><code>this is linecode</code></p><p>多行代码</p><figure class="highlight js"><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="keyword">function</span> <span class="title function_">fun</span>(<span class="params"></span>){</span><br><span class="line"> echo <span class="string">"这是一句非常牛逼的代码"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">fun</span>();</span><br></pre></td></tr></table></figure><h1 id="十、流程图"><a href="#十、流程图" class="headerlink" title="十、流程图"></a>十、流程图</h1><p>简单流程</p><figure class="highlight plaintext"><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">```mermaid</span><br><span class="line"> graph LR</span><br><span class="line"> A-->B</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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">```mermaid</span><br><span class="line">graph LR</span><br><span class="line">A-->B</span><br></pre></td></tr></table></figure><p>复杂流程</p><figure class="highlight plaintext"><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">```mermaid</span><br><span class="line"> classDiagram</span><br><span class="line"> BaseClass <|-- AveryLongClass : Cool</span><br><span class="line"> BaseClass : size()</span><br><span class="line"> BaseClass : int chimp</span><br><span class="line"> BaseClass : int gorilla</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">```mermaid</span><br><span class="line">classDiagram</span><br><span class="line">BaseClass <|-- AveryLongClass : Cool</span><br><span class="line">BaseClass : size()</span><br><span class="line">BaseClass : int chimp</span><br><span class="line">BaseClass : int gorilla</span><br></pre></td></tr></table></figure><h1 id="十一丶-Math函数"><a href="#十一丶-Math函数" class="headerlink" title="十一丶 Math函数"></a>十一丶 Math函数</h1><p>示例</p><figure class="highlight plaintext"><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">开根号</span><br><span class="line"> ```math</span><br><span class="line"> \sqrt{2};\sqrt[n]{3}</span><br></pre></td></tr></table></figure><p> 分数,平方<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\frac{7x+5}{1+y^2}</span><br></pre></td></tr></table></figure><br> 下标<br> <figure class="highlight plaintext"><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"> z=z_l</span><br><span class="line"> ``` </span><br><span class="line">省略号 </span><br><span class="line"> ```math</span><br><span class="line"> \cdots</span><br></pre></td></tr></table></figure><br> 行间公式(使用两个$包含公式可以独立一行)<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\frac{d}{dx}e^{ax}=ae^{ax}\quad \sum_{i=1}^{n}{(X_i - \overline{X})^2}</span><br></pre></td></tr></table></figure><br> 矢量<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\vec{a} \cdot \vec{b}=0</span><br></pre></td></tr></table></figure><br> 积分<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\int ^2_3 x^2 {\rm d}x</span><br></pre></td></tr></table></figure><br> 累加<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\sum \frac{1}{i^2}</span><br></pre></td></tr></table></figure><br> 累乘<br> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\prod \frac{1}{i^2}</span><br></pre></td></tr></table></figure></p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">~~</span><br><span class="line"></span><br><span class="line">> 注:~~积分函数~~无效,不做演示</span><br><span class="line"></span><br><span class="line">效果</span><br><span class="line"></span><br><span class="line">- **开根号**</span><br><span class="line"></span><br><span class="line">```math</span><br><span class="line">\sqrt{2};\sqrt[n]{3}</span><br></pre></td></tr></table></figure><ul><li><strong>分数,平方</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\frac{7x+5}{1+y^2}</span><br></pre></td></tr></table></figure><ul><li><strong>下标</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">z=z_l</span><br></pre></td></tr></table></figure><ul><li><strong>省略号</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\cdots</span><br></pre></td></tr></table></figure><ul><li><strong>行间公式(使用两个$包含公式可以独立一行)</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\frac{d}{dx}e^{ax}=ae^{ax}\quad \sum_{i=1}^{n}{(X_i - \overline{X})^2}</span><br></pre></td></tr></table></figure><ul><li><strong>矢量</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\vec{a} \cdot \vec{b}=0</span><br></pre></td></tr></table></figure><ul><li><strong>累加</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\sum \frac{1}{i^2}</span><br></pre></td></tr></table></figure><ul><li><strong>累乘</strong></li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">\prod \frac{1}{i^2}</span><br></pre></td></tr></table></figure><h1 id="十二丶私密博客文章"><a href="#十二丶私密博客文章" class="headerlink" title="十二丶私密博客文章"></a>十二丶私密博客文章</h1><ol><li>在主题header下加入themes->/archer/layout/_partial/->base-header.ejs 添加如下代码,编译的时候会自动加入 HTML 中,</li></ol><figure class="highlight js"><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"><script></span><br><span class="line"> (<span class="keyword">function</span>(<span class="params"></span>){</span><br><span class="line"> <span class="keyword">if</span>(<span class="string">'{{ page.password }}'</span>){</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_">prompt</span>(<span class="string">'请输入查看密码'</span>) !== <span class="string">'{{ page.password }}'</span>){</span><br><span class="line"> <span class="title function_">alert</span>(<span class="string">'密码不正确,请询问主编大大'</span>);</span><br><span class="line"> history.<span class="title function_">back</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> })();</span><br><span class="line"></script></span><br></pre></td></tr></table></figure><ol start="2"><li>在生成文件的新页面中最顶部加上,title: 标签</li></ol><p>keywords:</p><ul><li>私人</li><li>日记<br>description: 文章访问需要密码<br>password: ******(在你的 MD 文件中是明文)</li></ul><h1 id="十三丶视频"><a href="#十三丶视频" class="headerlink" title="十三丶视频"></a>十三丶视频</h1><iframe height="400" width="600" src="//player.bilibili.com/player.html?aid=49775093&cid=87150521&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>]]></content>
<summary type="html">文章访问需要密码</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="Markdown" scheme="https://chengzc.club/tags/Markdown/"/>
</entry>
<entry>
<title>spring-boot</title>
<link href="https://chengzc.club/posts/2071970418/"/>
<id>https://chengzc.club/posts/2071970418/</id>
<published>2019-01-10T16:22:59.000Z</published>
<updated>2023-04-13T17:28:01.664Z</updated>
<content type="html"><![CDATA[<h1 id="Spring-Boot基础教程"><a href="#Spring-Boot基础教程" class="headerlink" title="Spring Boot基础教程"></a>Spring Boot基础教程</h1><p>本项目内容为Spring Boot教程程序样例。如您觉得该项目对您有用,欢迎点击右上方的<strong>Star</strong>按钮,给予支持!!</p><ul><li>我的博客:<a href="http://blog.didispace.com/">http://blog.didispace.com</a></li><li><strong>我的小密圈(深度交流与问答):<a href="https://t.xiaomiquan.com/zfEiY3v">https://t.xiaomiquan.com/zfEiY3v</a></strong></li><li>GitHub:<a href="https://github.com/dyc87112/SpringBoot-Learning">https://github.com/dyc87112/SpringBoot-Learning</a></li><li>Gitee:<a href="https://gitee.com/didispace/SpringBoot-Learning">https://gitee.com/didispace/SpringBoot-Learning</a></li><li>Spring For All社区:<a href="http://spring4all.com/">http://spring4all.com/</a></li><li>Spring Boot基础教程:<a href="http://blog.didispace.com/Spring-Boot%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/">http://blog.didispace.com/Spring-Boot%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/</a></li><li>Spring Cloud基础教程:<a href="http://blog.didispace.com/Spring-Cloud%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/">http://blog.didispace.com/Spring-Cloud%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/</a></li></ul><p><strong>声明:本人已放弃”Spring Cloud中国社区”,该社区的任何行为均与本人无关。<a href="http://spring4all.com/">Spring For All社区</a>是新组建的关于Spring的纯技术交流社区(涵盖Spring Boot、Spring Cloud等内容),集诸多开源爱好者和技术大牛贡献内容和交流问题。我们不夸大、不装逼、做最纯粹的技术分享!!!</strong></p><p><strong>优惠云服务推荐</strong></p><ul><li><a href="https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=wxfqkr0o&utm_source=wxfqkr0o">阿里云:ECS云服务器2折起</a></li><li><a href="https://cloud.tencent.com/redirect.php?redirect=1027&cps_key=f6a8af1297bfac40b9d10ffa1270029a&from=console">腾讯云:轻松应对建站成本问题</a></li></ul><h2 id="Spring-Boot-2-0-新特性学习"><a href="#Spring-Boot-2-0-新特性学习" class="headerlink" title="Spring Boot 2.0 新特性学习"></a>Spring Boot 2.0 新特性学习</h2><p><strong>简介与概览</strong></p><ul><li><a href="http://blog.didispace.com/spring-boot-2-release/">Spring Boot 2.0 正式发布,升还是不升呢?</a></li><li><a href="http://blog.didispace.com/Spring-Boot-2-0-%E6%96%B0%E7%89%B9%E6%80%A7%E5%92%8C%E5%8F%91%E5%B1%95%E6%96%B9%E5%90%91/">Spring Boot 2.0 新特性和发展方向</a></li><li><a href="http://blog.didispace.com/Spring-Boot-2.0%E4%B8%8EJava-9/">Spring Boot 2.0 与 Java 9</a></li></ul><p><strong>新特性详解</strong></p><ul><li><a href="http://blog.didispace.com/Spring-Boot-2-0-feature-1-relaxed-binding-2/">Spring Boot 2.0 新特性(一):配置绑定 2.0 全解析</a></li><li><a href="http://blog.didispace.com/Spring-Boot-2-0-feature-2-ApplicationStartedEvent/">Spring Boot 2.0 新特性(二):新增事件ApplicationStartedEvent</a></li></ul><h2 id="Spring-Boot-基础教程(基于1-3-x-1-5-x)"><a href="#Spring-Boot-基础教程(基于1-3-x-1-5-x)" class="headerlink" title="Spring Boot 基础教程(基于1.3.x-1.5.x)"></a>Spring Boot 基础教程(基于1.3.x-1.5.x)</h2><h4 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h4><ul><li>chapter1:<a href="http://blog.didispace.com/spring-boot-learning-1/">基本项目构建(可作为工程脚手架),引入web模块,完成一个简单的RESTful API</a></li><li><a href="http://blog.didispace.com/spring-initializr-in-intellij/">使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程</a></li></ul><h4 id="工程配置"><a href="#工程配置" class="headerlink" title="工程配置"></a>工程配置</h4><ul><li>chapter2-1-1:<a href="http://blog.didispace.com/springbootproperties/">配置文件详解:自定义属性、随机数、多环境配置等</a></li><li>chapter2-1-2:<a href="http://blog.didispace.com/Spring-Boot-2-0-feature-1-relaxed-binding-2/">2.0 新特性(一):配置绑定全解析</a></li><li>chapter2-2-1:<a href="http://blog.didispace.com/Spring-Boot-2-0-feature-2-ApplicationStartedEvent/">2.0 新特性(二):新增事件ApplicationStartedEvent</a></li></ul><h4 id="Web开发"><a href="#Web开发" class="headerlink" title="Web开发"></a>Web开发</h4><ul><li>chapter3-1-1:<a href="http://blog.didispace.com/springbootrestfulapi/">构建一个较为复杂的RESTful API以及单元测试</a></li><li>chapter3-1-2:<a href="http://blog.didispace.com/springbootweb/">使用Thymeleaf模板引擎渲染web视图</a></li><li>chapter3-1-3:<a href="http://blog.didispace.com/springbootweb/">使用Freemarker模板引擎渲染web视图</a></li><li>chapter3-1-4:<a href="http://blog.didispace.com/springbootweb/">使用Velocity模板引擎渲染web视图</a></li><li>chapter3-1-5:<a href="http://blog.didispace.com/springbootswagger2/">使用Swagger2构建RESTful API</a></li><li>chapter3-1-6:<a href="http://blog.didispace.com/springbootexception/">统一异常处理</a></li><li>chapter3-1-7:<a href="http://blog.didispace.com/Spring-Boot-And-Feign-Use-localdate/">使用Java 8中LocalDate等时间日期类的问题解决</a></li><li>chapter3-1-8:<a href="http://blog.didispace.com/spring-boot-xml-httpmessageconverter">扩展XML请求和响应的支持</a></li></ul><h4 id="数据访问"><a href="#数据访问" class="headerlink" title="数据访问"></a>数据访问</h4><ul><li>chapter3-2-1:<a href="http://blog.didispace.com/springbootdata1/">使用JdbcTemplate</a></li><li>chapter3-2-2:<a href="http://blog.didispace.com/springbootdata2/">使用Spring-data-jpa简化数据访问层(推荐)</a></li><li>chapter3-2-3:<a href="http://blog.didispace.com/springbootmultidatasource/">多数据源配置(一):JdbcTemplate</a></li><li>chapter3-2-4:<a href="http://blog.didispace.com/springbootmultidatasource/">多数据源配置(二):Spring-data-jpa</a></li><li>chapter3-2-5:<a href="http://blog.didispace.com/springbootredis/">使用NoSQL数据库(一):Redis</a></li><li>chapter3-2-6:<a href="http://blog.didispace.com/springbootmongodb/">使用NoSQL数据库(二):MongoDB</a></li><li>chapter3-2-7:<a href="http://blog.didispace.com/springbootmybatis/">整合MyBatis</a></li><li>chapter3-2-8:<a href="http://blog.didispace.com/mybatisinfo/">MyBatis注解配置详解</a></li><li>chapter3-2-9:<a href="http://blog.didispace.com/spring-boot-flyway-db-version/">使用Flyway来管理数据库版本</a></li><li>chapter3-2-10:<a href="http://blog.didispace.com/spring-boot-ldap-user/">使用LDAP来统一管理用户信息</a></li><li>chapter3-2-11:<a href="http://blog.didispace.com/springbootmongodb-plus/">Spring Boot中增强对MongoDB的配置(连接池等)</a></li></ul><h4 id="事务管理"><a href="#事务管理" class="headerlink" title="事务管理"></a>事务管理</h4><ul><li>chapter3-3-1:<a href="http://blog.didispace.com/springboottransactional/">使用事务管理</a></li><li>chapter3-3-2:[分布式事务(未完成)]</li></ul><h4 id="其他内容"><a href="#其他内容" class="headerlink" title="其他内容"></a>其他内容</h4><ul><li>chapter4-1-1:<a href="http://blog.didispace.com/springbootscheduled/">使用@Scheduled创建定时任务</a></li><li>chapter4-1-2:<a href="http://blog.didispace.com/springbootasync/">使用@Async实现异步调用</a></li><li>chapter4-1-3:<a href="http://blog.didispace.com/springbootasync-2/">使用@Async实现异步调用:自定义线程池</a></li><li>chapter4-1-4:<a href="http://blog.didispace.com/springbootasync-3/">使用@Async实现异步调用:资源优雅关闭</a></li><li>chapter4-1-5:<a href="http://blog.didispace.com/springbootasync-4/">使用@Async实现异步调用:使用Future以及定义超时</a></li></ul><h4 id="日志管理"><a href="#日志管理" class="headerlink" title="日志管理"></a>日志管理</h4><ul><li>chapter4-2-1:<a href="http://blog.didispace.com/springbootlog/">默认日志的配置</a></li><li>chapter4-2-2:<a href="http://blog.didispace.com/springbootlog4j/">使用log4j记录日志</a></li><li>chapter4-2-3:<a href="http://blog.didispace.com/springbootlog4jmuilt/">对log4j进行多环境不同日志级别的控制</a></li><li>chapter4-2-4:<a href="http://blog.didispace.com/springbootaoplog/">使用AOP统一处理Web请求日志</a></li><li>chapter4-2-5:<a href="http://blog.didispace.com/springbootlog4jmongodb/">使用log4j记录日志到MongoDB</a></li><li>chapter4-2-6:<a href="http://blog.didispace.com/spring-boot-1-5-x-feature-1/">Spring Boot 1.5.x新特性:动态修改日志级别</a>]</li></ul><h4 id="安全管理"><a href="#安全管理" class="headerlink" title="安全管理"></a>安全管理</h4><ul><li>chapter4-3-1:<a href="http://blog.didispace.com/springbootsecurity/">使用Spring Security</a></li><li>chapter4-3-2:[使用Spring Session(未完成)]</li></ul><h4 id="缓存支持"><a href="#缓存支持" class="headerlink" title="缓存支持"></a>缓存支持</h4><ul><li>chapter4-4-1:<a href="http://blog.didispace.com/springbootcache1/">注解配置与EhCache使用</a></li><li>chapter4-4-2:<a href="http://blog.didispace.com/springbootcache2/">使用Redis做集中式缓存</a></li></ul><h4 id="邮件发送"><a href="#邮件发送" class="headerlink" title="邮件发送"></a>邮件发送</h4><ul><li>chapter4-5-1:<a href="http://blog.didispace.com/springbootmailsender/">实现邮件发送:简单邮件、附件邮件、嵌入资源的邮件、模板邮件</a></li></ul><h4 id="消息服务"><a href="#消息服务" class="headerlink" title="消息服务"></a>消息服务</h4><ul><li>chapter5-1-1:[JMS(未完成)]</li><li>chapter5-2-1:<a href="http://blog.didispace.com/spring-boot-rabbitmq/">Spring Boot中使用RabbitMQ</a></li></ul><h4 id="其他功能"><a href="#其他功能" class="headerlink" title="其他功能"></a>其他功能</h4><ul><li>chapter6-1-1:<a href="http://blog.didispace.com/spring-statemachine/">使用Spring StateMachine框架实现状态机</a></li><li><a href="http://blog.didispace.com/spring-boot-actuator-1/">Spring Boot Actuator监控端点小结</a></li><li><a href="http://blog.didispace.com/spring-boot-actuator-without-boot/">在传统Spring应用中使用spring-boot-actuator模块提供监控端点</a></li><li><a href="http://blog.didispace.com/spring-boot-run-backend/">Spring Boot应用的后台运行配置</a></li><li><a href="http://blog.didispace.com/spring-boot-banner/">Spring Boot自定义Banner</a></li></ul><h4 id="Dubbo进行服务治理"><a href="#Dubbo进行服务治理" class="headerlink" title="Dubbo进行服务治理"></a>Dubbo进行服务治理</h4><ul><li>chapter9-2-1:<a href="https://gitee.com/didispace/SpringBoot-Learning/tree/master/Chapter9-2-1">Spring Boot中使用Dubbo进行服务治理</a></li><li>chapter9-2-2:<a href="https://gitee.com/didispace/SpringBoot-Learning/tree/master/Chapter9-2-2">Spring Boot与Dubbo中管理服务依赖</a></li></ul><h2 id="开源项目推荐"><a href="#开源项目推荐" class="headerlink" title="开源项目推荐"></a>开源项目推荐</h2><ul><li>我的《Spring Cloud基础教程》:<a href="https://github.com/dyc87112/SpringCloud-Learning">https://github.com/dyc87112/SpringCloud-Learning</a></li><li>泥瓦匠Spring Boot学习案例:<a href="https://git.oschina.net/jeff1993/springboot-learning-example">https://git.oschina.net/jeff1993/springboot-learning-example</a></li></ul><h2 id="其他推荐"><a href="#其他推荐" class="headerlink" title="其他推荐"></a>其他推荐</h2><ul><li>Spring Boot Reference Guide:<a href="http://blog.didispace.com/books/spring-boot-reference/">http://blog.didispace.com/books/spring-boot-reference/</a></li></ul>]]></content>
<summary type="html"><h1 id="Spring-Boot基础教程"><a href="#Spring-Boot基础教程" class="headerlink" title="Spring Boot基础教程"></a>Spring Boot基础教程</h1><p>本项目内容为Spring Boot教</summary>
<category term="转载" scheme="https://chengzc.club/categories/%E8%BD%AC%E8%BD%BD/"/>
<category term="spring-boot" scheme="https://chengzc.club/tags/spring-boot/"/>
<category term="java" scheme="https://chengzc.club/tags/java/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="https://chengzc.club/posts/1243066710/"/>
<id>https://chengzc.club/posts/1243066710/</id>
<published>2019-01-10T08:32:12.000Z</published>
<updated>2019-04-14T02:04:01.000Z</updated>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><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 new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><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 server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><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>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><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 deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
<summary type="html"><p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for</summary>
</entry>
<entry>
<title>如何快速搭建hexo博客</title>
<link href="https://chengzc.club/posts/3402318135/"/>
<id>https://chengzc.club/posts/3402318135/</id>
<published>2018-10-18T06:47:02.000Z</published>
<updated>2023-04-14T01:19:18.000Z</updated>
<content type="html"><![CDATA[<p>hexo 是一个快速、简洁且高效的博客框架。hexo 使用 Markdown解析文章,在几秒内,即可利用靓丽的主题生成静态网页。hexo是一款基于Node.js的静态博客框架,依赖少易于安装使用,可以方便的生成静态网页托管在GitHub Page、COS(腾讯云对象存储)等支持静态网站的系统上,是搭建博客的首选框架。</p><p>本文将简介如何自己的服务器、腾讯云COS及Github Page上部署hexo博客。先说结论,如果你在国内使用博客的话,本文推荐你在COS上部署,首先是不用自己搭建<a href="https://cloud.tencent.com/developer/article/1354850">静态网站服务器</a>,其次是免费,这里的<strong>免费</strong>额度优惠很大,每月50G免费空间,10G CDN下行流量,每月100万次读写请求。对于一个静态网站或者个人博客来说,非常够用了。当然,你也可以使用Github Page和自己的服务器,但是这里会遇到一些问题,比如使用Github Page国内访问速度慢甚至无法加载报错456的情况。而使用自己的服务器,撰写部署又成为一大难题。</p><h1 id="本地部署hexo开发环境"><a href="#本地部署hexo开发环境" class="headerlink" title="本地部署hexo开发环境"></a>本地部署hexo开发环境</h1><p>安装之前,需要你电脑安装好<a href="">Node.js</a>和<a href="https://git-scm.com/">Git</a>,由于系统花样繁多,本文将仅介绍Windows、Mac、Ubuntu(linux)安装方法,其他系统请自行摸索。</p><h2 id="Node-js及git的安装"><a href="#Node-js及git的安装" class="headerlink" title="Node.js及git的安装"></a>Node.js及git的安装</h2><h3 id="windows中Node-js及Git的安装中Node-js及Git的安装"><a href="#windows中Node-js及Git的安装中Node-js及Git的安装" class="headerlink" title="windows中Node.js及Git的安装中Node-js及Git的安装)"></a>windows中Node.js及Git的安装中Node-js及Git的安装)</h3><ul><li><em><strong>Node.js</strong></em></li></ul><p>打开<a href="https://nodejs.org/en/">Node.js</a>的官网,点击8.12.0 LTS绿色按钮(本文撰写时的版本),下载好后一路下一步安装即可。</p><ul><li><em><strong>Git</strong></em></li></ul><p>打开<a href="https://git-scm.com/">Git</a>官网,点击Download 2.19.1 for Windows(本文撰写时的版本)按钮,下载好后一路下一步安装即可。</p><h3 id="Mac中Node-js及Git的安装"><a href="#Mac中Node-js及Git的安装" class="headerlink" title="Mac中Node.js及Git的安装"></a>Mac中Node.js及Git的安装</h3><ul><li><em><strong>Node.js</strong></em></li></ul><p>打开<a href="https://nodejs.org/en/">Node.js</a>的官网,点击8.9.4 LTS绿色按钮(本文撰写时的版本),下载好后一路下一步安装即可。</p><ul><li><em><strong>Git</strong></em></li></ul><p>Mac默认自带Git,若您系统版本过低,请打开<a href="https://git-scm.com/">Git</a>官网下载安装。</p><h3 id="Ubuntu中Node-js及Git的安装"><a href="#Ubuntu中Node-js及Git的安装" class="headerlink" title="Ubuntu中Node-js及Git的安装"></a>Ubuntu中Node-js及Git的安装</h3><ul><li><em><strong>Node.js</strong></em></li></ul><p>命令窗口输入以下命令</p><figure class="highlight shell"><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">sudo apt-get update</span><br><span class="line">sudo apt-get install -y python-software-properties software-properties-common</span><br><span class="line">sudo add-apt-repository ppa:chris-lea/node.js</span><br><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install nodejs</span><br><span class="line">sudo apt install nodejs-legacy</span><br><span class="line">sudo apt install npm</span><br><span class="line">sudo npm install n -g</span><br><span class="line">sudo n stable</span><br><span class="line">sudo node -v</span><br></pre></td></tr></table></figure><p>如遇到安装错误或其他问题,请使用编译安装。</p><blockquote><p>为保证nodejs版本及稳定性,下面安装是下载nodejs进行编译安装,可能耗时较长,请耐心等待。如您上面执行<code>sudo node -v</code>已经正常显示版本,则不用执行下面的代码。</p></blockquote><figure class="highlight shell"><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">sudo git clone https://github.com/nodejs/node.git</span><br><span class="line">sudo chmod -R 755 node</span><br><span class="line">cd node</span><br><span class="line">sudo ./configure</span><br><span class="line">sudo make</span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure><ul><li><em><strong>Git</strong></em></li></ul><p>Ubuntu安装git,执行以下命令即可安装</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install git</span><br></pre></td></tr></table></figure><h2 id="hexo的安装"><a href="#hexo的安装" class="headerlink" title="hexo的安装"></a>hexo的安装</h2><p>接下来,我们需要在本地安装hexo,hexo安装命令非常简单,只需要一步即可安装完成,具体命令窗口输入以下命令:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo npm install -g hexo-cli</span><br></pre></td></tr></table></figure><blockquote><p>但是值得注意的是,<strong>Windows</strong>必须去掉<code>sudo</code>命令即<code>npm install -g hexo-cli</code>,windows如何打开命令窗口请点击<a href="https://jingyan.baidu.com/article/f3e34a12c284e8f5eb653517.html">这里</a>学习。Ubuntu和Mac仍使用上述命令安装即可。</p></blockquote><h2 id="如何建站"><a href="#如何建站" class="headerlink" title="如何建站"></a>如何建站</h2><p>安装完Hexo等相关依赖后,请执行以下命令创建您的网站</p><figure class="highlight shell"><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">sudo hexo init <folder></span><br><span class="line">cd <folder></span><br><span class="line">sudo npm install</span><br></pre></td></tr></table></figure><blockquote><p>同上,<strong>Windows</strong>须去掉<code>sudo</code>命令,Ubuntu和Mac仍使用上述命令安装即可。其中<code>&lt;folder&gt;</code>为你需要创建的网站的文件夹名称,名称无硬性要求,如我创建自己的网站,则可写为<code>sudo hexo init techeek</code></p></blockquote><p>没错,这样就完了,你的网站已经搭建完成。更多相关的命令解释请点击<a href="https://hexo.io/zh-cn/docs/commands.html">这里</a>查看。</p><h2 id="如何写文章"><a href="#如何写文章" class="headerlink" title="如何写文章"></a>如何写文章</h2><p>首先我们需要创建一个新的文章,默认Hexo已经为我们写了一篇为Hello Word的文章,但是为了熟悉撰写文章的过程,我们还是重头撰写一遍。</p><p>首先在您的命令窗口输入以下命令</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo hexo new <title></span><br></pre></td></tr></table></figure><blockquote><p>同上,<strong>Windows</strong>须去掉<code>sudo</code>命令,Ubuntu和Mac仍使用上述命令安装即可。其中<code>&lt;title&gt;</code>为你需要创建的文章的名称,名称无硬性要求,如我创建自己的文章,则可写为<code>sudo hexo init hexo-tutorial</code></p></blockquote><p>这时,找到你创建的网站目录中创建markdown源文件的地方,位置在<code>你创建网站的名称\source\_posts</code>下,双击编辑该文件,打开后markdown格式如下:</p><figure class="highlight shell"><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">---</span><br><span class="line">title: 这块写你文章的名称</span><br><span class="line">date: 这块为创建文章的时间,可修改,格式为:年-月-日 时:分:秒</span><br><span class="line">tags: [这块写你文章的标签,使用“,”隔开(注意去掉引号须包含中括号)]</span><br><span class="line">---</span><br><span class="line">这块写你的正文</span><br></pre></td></tr></table></figure><p>如本文格式</p><figure class="highlight shell"><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">---</span><br><span class="line">title: 如何快速搭建hexo博客</span><br><span class="line">date: 2018-10-18 14:47:02</span><br><span class="line">tags: [hexo,git,同步]</span><br><span class="line">---</span><br><span class="line">hexo 是一个快速、简洁且高效的博客框架。hexo 使用 Markdown解析文章,在几秒内,即可利用靓丽的主题生成静态网页。hexo是一款基于Node.js的静态博客框架,依赖少易……</span><br></pre></td></tr></table></figure><h1 id="部署hexo到腾讯云COS"><a href="#部署hexo到腾讯云COS" class="headerlink" title="部署hexo到腾讯云COS"></a>部署hexo到腾讯云COS</h1><p>既然比较推荐部署到腾讯云COS,那么我们就先看看如何将hexo部署在腾讯云的COS上。在开始之前,我们要做一些准备,要在腾讯云COS上创建存储桶,并设置好静态网站环境,这里可以参考**<a href="https://cloud.tencent.com/developer/article/1355233">如何通过 cos 托管静态网站</a>**这个教程。</p><p>创建并设置好环境后,还需要获取腾讯云COS相关密钥才能部署,这里我们需要获取<code>APPID</code>,<code>SecretId</code>,<code>SecretKey</code>,<code>Bucket</code>,<code>Region</code>这五个参数,具体如下:</p><table><thead><tr><th align="left">名称</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">APPID</td><td align="left">开发者访问 COS 服务时拥有的用户维度唯一资源标识,用以标识资源</td></tr><tr><td align="left">SecretId</td><td align="left">开发者拥有的项目身份识别 ID,用以身份认证</td></tr><tr><td align="left">SecretKey</td><td align="left">开发者拥有的项目身份密钥</td></tr><tr><td align="left">Bucket</td><td align="left">COS 中用于存储数据的容器,本文创建以www为例</td></tr><tr><td align="left">Region</td><td align="left">域名中的地域信息。枚举值参见<a href="https://cloud.tencent.com/document/product/436/6224">可用地域</a> 文档,如:ap-beijing, ap-hongkong, eu-frankfurt 等</td></tr></tbody></table><p>获取这些值后,我们需要安装能将HEXO部署在COS上的插件,这里我们选择安装<code>hexo-deployer-cos</code>,安装比较简单,只需要执行<code>npm install hexo-deployer-cos --save</code>即可,具体如下。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-cos --save</span><br></pre></td></tr></table></figure><p>](http://)</p><p>接下面我们配置hexo的配置文件,首先打开根目录的<code>_config.yml</code>配置文件,将原来的<code>deploy</code>替换为下面的内容:</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">deploy: </span><br><span class="line"> type: cos</span><br><span class="line"> appId: yourAPPID</span><br><span class="line"> secretId: yourSecretId</span><br><span class="line"> secretKey: yourSecretKey</span><br><span class="line"> bucket: yourBucketName-yourAPPID</span><br><span class="line"> region: yourRegion</span><br></pre></td></tr></table></figure><p>细心的同学发现我的配置与<code>hexo-deployer-cos</code>的Github项目页面给出的配置不同,为什么呢?该插件作者更新了插件,但是没更新Readme文档,用原作者的配置文件会报错。所以请用我给出的配置。那么具体配置如下。</p><p>假如说我的<code>APPID</code>是<code>1251234567</code>,<code>secretId</code>是<code>ABCDEFGHIGKLMNOPQRSTUVWXYZ</code>,<code>secretKey</code>是<code>abcdefghijklmnopqrstuvwxyz</code>,创建的<code>bucket</code>是<code>www</code>,<code>region</code>可用地区是成都,也就是<code>ap-chengdu</code>,这个详见准备的表格。</p><p>那么我的<code>_config.yml</code>中<code>deploy</code>配置为:</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">......</span><br><span class="line">deploy: </span><br><span class="line"> type: cos</span><br><span class="line"> appId: 1251234567</span><br><span class="line"> secretId: ABCDEFGHIGKLMNOPQRSTUVWXYZ</span><br><span class="line"> secretKey: abcdefghijklmnopqrstuvwxyz</span><br><span class="line"> bucket: www-1251234567</span><br><span class="line"> region: ap-chengdu</span><br><span class="line">......</span><br></pre></td></tr></table></figure><p>现在你已经完成了最后的设置,最后一步就是需要部署项目到COS了,输入我们熟悉的部署命:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo g -d</span><br></pre></td></tr></table></figure><p>你会看到如下输出:</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">INFO Start processing</span><br><span class="line">INFO Generating Baidu urls for last 1 posts</span><br><span class="line">INFO Posts urls generated in baidu_urls.txt</span><br><span class="line">https://www.techeek.cn/2018/08/14/Ubuntu-DTS-translation/</span><br><span class="line">INFO Files loaded in 1.24 s</span><br><span class="line">INFO Generated: sitemap.xml</span><br><span class="line">......</span><br><span class="line">INFO 成功上传:E:\Desktop\临时\git\www.test.com\public\2016\06\05\Workerman-Tcp\index.html</span><br><span class="line">INFO 成功上传:E:\Desktop\临时\git\www.test.com\public\2017\03\09\docker-lnmp-typecho\index.html</span><br><span class="line">INFO 成功上传:E:\Desktop\临时\git\www.test.com\public\2016\09\28\dontstarve-server\index.html</span><br><span class="line">......</span><br></pre></td></tr></table></figure><p>好了,现在我们访问你的域名看看是否上传成功了?在浏览器打开<code>https://www.test.com</code></p><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140859285.webp"></p><p>我们看到项目已经上传,我们在打开COS的Bucket,看看是不是网站真的在Bucket上。</p><p><img src="https://czcsw-1256525464.cos.ap-chengdu.myqcloud.com/images/blog/202304140900400.webp"></p><p>我们看到,服务器在COS运行成功了。</p><h1 id="部署在Github-Page"><a href="#部署在Github-Page" class="headerlink" title="部署在Github Page"></a>部署在Github Page</h1><h2 id="创建Github仓库"><a href="#创建Github仓库" class="headerlink" title="创建Github仓库"></a>创建Github仓库</h2><p>首先你需要创建并登录Github账户,点击<a href="github.com">这里</a>注册,然后点击GitHub中的New repository创建新仓库。仓库名称必须命名为<code>你的GitHub用户名.github.io</code>,其中“你的GitHub用户名”使用你的github账户代替,比如我的仓库名称为<code>techeek.github.io</code>,这样,你就创建好你的Github Pages仓库了。</p><h2 id="生成ssh密钥文件"><a href="#生成ssh密钥文件" class="headerlink" title="生成ssh密钥文件"></a>生成ssh密钥文件</h2><p>接下需要创建ssh密钥文件,为什么要创建呢,因为Hexo部署在github上是通过密钥配对上传的,所以我们需要创建公钥和私钥,什么是公钥和私钥请点<a href="https://www.alibabacloud.com/help/zh/faq-detail/42216.htm">这里</a>。我们首先依然打开命令提示符,Windows请搜索打开Git Bash。然后输入如下命令配置git</p><figure class="highlight shell"><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">git config --global user.name "你的GitHub用户名"</span><br><span class="line">git config --global user.email "你的GitHub注册邮箱"</span><br></pre></td></tr></table></figure><p>配置完成后,输入如下命令生成ssh密钥文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C "你的GitHub注册邮箱"</span><br></pre></td></tr></table></figure><p>接下来按三下回车就行,不创建密码,然后我们使用</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cd ~/.ssh</span><br></pre></td></tr></table></figure><p>命令打开ssh生成的密钥文件,Windows密钥文件在<code>C:/Users/你的用户名/.ssh</code>目录下。接下来打开<a href="https://github.com/settings/keys">GitHub_Settings_keys</a> 页面,新建new SSH Key。Title为标题,任意填写。将刚刚复制的id_rsa.pub内容粘贴到key,最后点击Add SSH key。</p><h2 id="部署网站"><a href="#部署网站" class="headerlink" title="部署网站"></a>部署网站</h2><p>部署前需要修改Hexo的配置文件,这里先放出<a href="https://hexo.io/zh-cn/docs/configuration.html">官方</a>的配置方法,大家可以参考。我这里只讲如何配置git<br>修改_config.yml内容如下</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">......</span><br><span class="line"> eployment</span><br><span class="line"> Docs: https://hexo.io/docs/deployment.html</span><br><span class="line"> ......</span><br><span class="line"> deploy: </span><br><span class="line"> type: git</span><br><span class="line"> repo: git@github.com:你的GitHub用户名/你的GitHub用户名.github.io.git</span><br><span class="line"> branch: master</span><br></pre></td></tr></table></figure><p>很多教程都将<code>repo:</code>写为<code>https://github.com/你的GitHub用户名/你的GitHub用户名.github.io.git</code>但是我个人不推荐这样写,因为有时候会因为BUG无法上传,所以我建议按照我上面的格式写。</p><p>这是执行如下命令,就可部署你的网站了</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo hexo deploy</span><br></pre></td></tr></table></figure><p>部署完成后,打开<a href="https://你的github用户名.github.io.git/">https://你的GitHub用户名.github.io.git</a>看看是不是能正常访问啦?</p><h1 id="部署在自己的服务器"><a href="#部署在自己的服务器" class="headerlink" title="部署在自己的服务器"></a>部署在自己的服务器</h1><p>可以按照第一步的步骤在自己的服务器上提前安装好<a href="https://nodejs.org/en/">Node.js</a>和<a href="https://git-scm.com/">Git</a>,接下来在本地部署好hexo博客,撰写好文章。最后生成静态文件。当静态文件生成好之后我们需要使用如下命令部署网站,命令如下</p><figure class="highlight shell"><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">sudo hexo deploy</span><br><span class="line">sudo hexo server</span><br></pre></td></tr></table></figure><p>启动服务器。默认情况下,访问网址为: <a href="http://localhost:4000/">http://localhost:4000/</a>,或访问你的服务器地址 <a href="http://你的服务器ip:4000/">http://你的服务器IP:4000/</a>。如果使用的是腾讯云的服务器,请打开安全组的4000端口。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>部署hexo网站很简单,推荐在Windows部署完成后部署在COS上,因为有cdn的加持,访问速度会快很多,况且有那么多免费流量,个人博客使用足矣。建议将hexo的项目文件同步到Git上,这里我推荐<a href="https://cloud.tencent.com/product/TGit">腾讯Git代码托管(工蜂</a>),为开发者提供基于 Git 的在线代码托管工具,包含代码提交/存储/下载/复刻/分支/历史/比对/合并等功能。可一站式完成对代码及代码质量管理,项目及项目人员管理,大大提升研发效率。而且支持免费的私有仓库,将hexo项目同步上去,后续哪怕是更换电脑也能快速更新博客并控制版本。</p><h2 id="Usage-hexo"><a href="#Usage-hexo" class="headerlink" title="Usage: hexo"></a>Usage: hexo</h2><blockquote><p>Commands:</p></blockquote><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">clean Remove generated files and cache.</span><br><span class="line"> config Get or set configurations.</span><br><span class="line"> deploy Deploy your website.</span><br><span class="line"> generate Generate static files.</span><br><span class="line"> help Get help on a command.</span><br><span class="line"> init Create a new Hexo folder.</span><br><span class="line"> list List the information of the site</span><br><span class="line"> migrate Migrate your site from other system to Hexo.</span><br><span class="line"> new Create a new post.</span><br><span class="line"> publish Moves a draft post from _drafts to _posts folder.</span><br><span class="line"> render Render files with renderer plugins.</span><br><span class="line"> server Start the server.</span><br><span class="line"> version Display version information.</span><br></pre></td></tr></table></figure><blockquote><p>Global Options:</p></blockquote><figure class="highlight shell"><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">--config Specify config file instead of using _config.yml</span><br><span class="line"> --cwd Specify the CWD</span><br><span class="line"> --debug Display all verbose messages in the terminal</span><br><span class="line"> --draft Display draft posts</span><br><span class="line"> --safe Disable all plugins and scripts</span><br><span class="line"> --silent Hide output on console</span><br></pre></td></tr></table></figure><blockquote><p>For more help, you can use ‘hexo help [command]’ for the detailed information or you can check the docs: <a href="http://hexo.io/docs/">hexo</a></p></blockquote>]]></content>
<summary type="html"><p>hexo 是一个快速、简洁且高效的博客框架。hexo 使用 Markdown解析文章,在几秒内,即可利用靓丽的主题生成静态网页。hexo是一款基于Node.js的静态博客框架,依赖少易于安装使用,可以方便的生成静态网页托管在GitHub Page、COS(腾讯云对象存储)等</summary>
<category term="git" scheme="https://chengzc.club/tags/git/"/>
<category term="hexo" scheme="https://chengzc.club/tags/hexo/"/>
<category term="同步" scheme="https://chengzc.club/tags/%E5%90%8C%E6%AD%A5/"/>
</entry>
</feed>