-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
1292 lines (1292 loc) · 220 KB
/
Copy pathsearch.xml
File metadata and controls
1292 lines (1292 loc) · 220 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
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>随笔</title>
<url>/post/4151840936.html</url>
<content><![CDATA[<p>刚考研结束,其他三门还行,数学感觉要炸了。</p>
<p>毕设也懒得做,把以前的网站重新搭建起来,现在差不多就这样吧。</p>
<p>考研结束真觉得是个废人了。</p>
<p>最后坐等Switch到。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>随笔</title>
<url>/post/4151840937.html</url>
<content><![CDATA[<p>今天又赖床到10点了,emmm。</p>
<p>起来看一会视频,吃个饭去拿风扇和我等了七天的switch,开心😊。</p>
<p>风扇这东西,好像是我这台电脑的通病,总是在闭合情况下打开电脑时,风扇总会发出间断性的噪声,本来以为我是以为是风扇能够检测外侧震动,从而保护自己的一种措施,没想这玩意失控,噪声相当难忍受。</p>
<p>拆机图:<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/2019-12-29-mi-pro.jpg" alt=""></p>
<p>风扇:<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/2019-12-29-fan.jpg" alt=""></p>
<p>switch到了,等待更新中:<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/2019-12-29-switch.jpg" alt=""></p>
<p>这是我是PDD,2279(港版主机加塞尔达),真的太香了。可惜只有单独主机,转接头、闪存、保护包还要另外买。</p>
<p>其他东西还在路上,不知道还要不要买个pro手柄。</p>
<p>今天就先这样了吧。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>2019冬季PAT考试</title>
<url>/post/3855630166.html</url>
<content><![CDATA[<h3 id="感想"><a href="#感想" class="headerlink" title="感想"></a>感想</h3><p>第一次拿100,留个纪念。</p>
<p>这是第二次考了, 第一次9月份考的,准备作为考研机试。考前准备复习了十几个小时就上考场了</p>
<p>第一考的时候心态不太好,看到第一题,心态崩了,搞了好久一个半小时一分没拿,后来心态回了点,把后面三题写完了, 最后没时间写第一题了。</p>
<p>第二次考的时候,心态稍微好了一点,看到第一题,没看懂,心态有点微崩。 直接做后面三题,还是比较简单的。回过来做第一个,其实也就是个格式控制,半小时写完出考场了。</p>
<p>本来以为会考AVL和最短路径或者集合的,结果没考,紧张死了。</p>
<h3 id="7-1-Good-in-C-20分"><a href="#7-1-Good-in-C-20分" class="headerlink" title="7-1 Good in C (20分)"></a>7-1 Good in C (20分)</h3><p>When your interviewer asks you to write “Hello World” using C, can you do as the following figure shows?</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/2019-winter-PAT-advanced-HWC.jpg" alt="HWC.jpg"></p>
<h4 id="Input-Specification"><a href="#Input-Specification" class="headerlink" title="Input Specification:"></a>Input Specification:</h4><p>Each input file contains one test case. For each case, the first part gives the 26 capital English letters A-Z, each in a 7×5 matrix of C’s and .’s. Then a sentence is given in a line, ended by a return. The sentence is formed by several words (no more than 10 continuous capital English letters each), and the words are separated by any characters other than capital English letters.</p>
<p>It is guaranteed that there is at least one word given.</p>
<h4 id="Output-Specification"><a href="#Output-Specification" class="headerlink" title="Output Specification:"></a>Output Specification:</h4><p>For each word, print the matrix form of each of its letters in a line, and the letters must be separated by exactly one column of space. There must be no extra space at the beginning or the end of the word.</p>
<p>Between two adjacent words, there must be a single empty line to separate them. There must be no extra line at the beginning or the end of the output.</p>
<h4 id="Sample-Input"><a href="#Sample-Input" class="headerlink" title="Sample Input:"></a>Sample Input:</h4><a id="more"></a>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">..C..</span><br><span class="line">.C.C.</span><br><span class="line">C...C</span><br><span class="line">CCCCC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">CCCCC</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">CCCC.</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">CCCCC</span><br><span class="line">CCCCC</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">CCCC.</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C....</span><br><span class="line">C.CCC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCCC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCCC</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">CCCCC</span><br><span class="line">CCCCC</span><br><span class="line">....C</span><br><span class="line">....C</span><br><span class="line">....C</span><br><span class="line">....C</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C..C.</span><br><span class="line">C.C..</span><br><span class="line">CC...</span><br><span class="line">C.C..</span><br><span class="line">C..C.</span><br><span class="line">C...C</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">CCCCC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CC.CC</span><br><span class="line">C.C.C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CC..C</span><br><span class="line">C.C.C</span><br><span class="line">C..CC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">C....</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C.C.C</span><br><span class="line">C..CC</span><br><span class="line">.CCC.</span><br><span class="line">CCCC.</span><br><span class="line">C...C</span><br><span class="line">CCCC.</span><br><span class="line">CC...</span><br><span class="line">C.C..</span><br><span class="line">C..C.</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C....</span><br><span class="line">.CCC.</span><br><span class="line">....C</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">CCCCC</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.CCC.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.C.C.</span><br><span class="line">..C..</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C.C.C</span><br><span class="line">CC.CC</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.C.C.</span><br><span class="line">..C..</span><br><span class="line">.C.C.</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">C...C</span><br><span class="line">.C.C.</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">..C..</span><br><span class="line">CCCCC</span><br><span class="line">....C</span><br><span class="line">...C.</span><br><span class="line">..C..</span><br><span class="line">.C...</span><br><span class="line">C....</span><br><span class="line">CCCCC</span><br><span class="line">HELLO~WORLD!</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">C...C CCCCC C.... C.... .CCC.</span><br><span class="line">C...C C.... C.... C.... C...C</span><br><span class="line">C...C C.... C.... C.... C...C</span><br><span class="line">CCCCC CCCC. C.... C.... C...C</span><br><span class="line">C...C C.... C.... C.... C...C</span><br><span class="line">C...C C.... C.... C.... C...C</span><br><span class="line">C...C CCCCC CCCCC CCCCC .CCC.</span><br><span class="line"></span><br><span class="line">C...C .CCC. CCCC. C.... CCCC.</span><br><span class="line">C...C C...C C...C C.... C...C</span><br><span class="line">C...C C...C CCCC. C.... C...C</span><br><span class="line">C.C.C C...C CC... C.... C...C</span><br><span class="line">CC.CC C...C C.C.. C.... C...C</span><br><span class="line">C...C C...C C..C. C.... C...C</span><br><span class="line">C...C .CCC. C...C CCCCC CCCC.</span><br></pre></td></tr></table></figure>
<h4 id="解析"><a href="#解析" class="headerlink" title="解析"></a>解析</h4><p>这题,它给了26个单词的7×5矩阵的字符表示形式,要求把把最后的字符串的大写单词分别表出来。 </p>
<p>这题坑点就是严格的格式。首先很自然的会用一个数组储存单词的表示形式,所以我用了一个<code>data[26][7][5]</code>数组存,注意不要将结尾的回车存入。使用<code>getline</code>获得一整行字符串,然后将字符串遍历,将小于10个字符长度的全大写连续的单词存起来,用作结果输出。然后按行输出,可以看出每一个单词都是七行,然后根据每个单词,输出对应行,就可以了,格式注意一下就好了。</p>
<h4 id="Solution:"><a href="#Solution:" class="headerlink" title="Solution:"></a>Solution:</h4><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><string></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">char</span> data[<span class="number">26</span>][<span class="number">7</span>][<span class="number">5</span>], ch;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">26</span>; ++i) { <span class="comment">//存数据</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < <span class="number">7</span>; ++j) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> k = <span class="number">0</span>; k < <span class="number">5</span>; ++k) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%c"</span>, &ch);</span><br><span class="line"> <span class="keyword">if</span>(ch == <span class="string">'\n'</span>) k--; <span class="comment">//跳过回车</span></span><br><span class="line"> <span class="keyword">else</span> data[i][j][k] = ch; </span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> getchar(); <span class="comment">// 字符串处理</span></span><br><span class="line"> <span class="built_in">string</span> s, s1 = <span class="string">""</span>;</span><br><span class="line"> getline(<span class="built_in">cin</span>, s);</span><br><span class="line"> <span class="built_in">vector</span><<span class="built_in">string</span>> result;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < s.<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="keyword">if</span>(<span class="string">'A'</span> <= s[i] && s[i] <= <span class="string">'Z'</span>) {</span><br><span class="line"> s1 += s[i];</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span>(s1 != <span class="string">""</span> && s1.length() <= <span class="number">10</span>)</span><br><span class="line"> result.push_back(s1);</span><br><span class="line"> s1 = <span class="string">""</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(s1 != <span class="string">""</span>) result.push_back(s1);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < result.<span class="built_in">size</span>(); ++i) { <span class="comment">// 输出模块</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j < <span class="number">7</span>; ++j) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> k = <span class="number">0</span>; k < result[i].<span class="built_in">size</span>(); ++k) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> l = <span class="number">0</span>; l < <span class="number">5</span>; ++l) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%c"</span>, data[result[i][k]- <span class="string">'A'</span>][j][l]);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(k != result[i].<span class="built_in">size</span>() - <span class="number">1</span>) <span class="built_in">printf</span>(<span class="string">" "</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(i != result.<span class="built_in">size</span>() - <span class="number">1</span>) <span class="built_in">printf</span>(<span class="string">"\n"</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="7-2-Block-Reversing-25分"><a href="#7-2-Block-Reversing-25分" class="headerlink" title="7-2 Block Reversing (25分)"></a>7-2 Block Reversing (25分)</h3><p>Given a singly linked list L. Let us consider every K nodes as a <code>block</code> (if there are less than K nodes at the end of the list, the rest of the nodes are still considered as a block). Your job is to reverse all the blocks in L. For example, given L as 1→2→3→4→5→6→7→8 and K as 3, your output must be 7→8→4→5→6→1→2→3.</p>
<h4 id="Input-Specification-1"><a href="#Input-Specification-1" class="headerlink" title="Input Specification:"></a>Input Specification:</h4><p>Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤$10^5$) which is the total number of nodes, and a positive K (≤N) which is the size of a block. The address of a node is a 5-digit nonnegative integer, and NULL is represented by −1.</p>
<p>Then N lines follow, each describes a node in the format:</p>
<blockquote>
<p>Address Data Next</p>
</blockquote>
<p>where Address is the position of the node, Data is an integer, and Next is the position of the next node.</p>
<h4 id="Output-Specification-1"><a href="#Output-Specification-1" class="headerlink" title="Output Specification:"></a>Output Specification:</h4><p>For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.</p>
<h4 id="Sample-Input-1"><a href="#Sample-Input-1" class="headerlink" title="Sample Input:"></a>Sample Input:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">00100 8 3</span><br><span class="line">71120 7 88666</span><br><span class="line">00000 4 99999</span><br><span class="line">00100 1 12309</span><br><span class="line">68237 6 71120</span><br><span class="line">33218 3 00000</span><br><span class="line">99999 5 68237</span><br><span class="line">88666 8 -1</span><br><span class="line">12309 2 33218</span><br></pre></td></tr></table></figure>
<h4 id="Sample-Output"><a href="#Sample-Output" class="headerlink" title="Sample Output:"></a>Sample Output:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">71120 7 88666</span><br><span class="line">88666 8 00000</span><br><span class="line">00000 4 99999</span><br><span class="line">99999 5 68237</span><br><span class="line">68237 6 00100</span><br><span class="line">00100 1 12309</span><br><span class="line">12309 2 33218</span><br><span class="line">33218 3 -1</span><br></pre></td></tr></table></figure>
<h4 id="解析-1"><a href="#解析-1" class="headerlink" title="解析"></a>解析</h4><p>常规的链表题,就是将每K个数据编成一组,然后将这几个组逆置。为了稳妥起见,使用结构体数组存链式关系,然后从开头遍历,每k个存入同一个<code>vecotr<node></code>,再将这个<code>vector<node></code>存入<code>vector<vector<node>></code>,然后拼接成一个<code>vector<node></code>,然后遍历重新改写next就好了,最后在注意一下格式就行了。</p>
<h4 id="Solution"><a href="#Solution" class="headerlink" title="Solution:"></a>Solution:</h4><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">node</span> {</span></span><br><span class="line"> <span class="keyword">int</span> address;</span><br><span class="line"> <span class="keyword">int</span> key;</span><br><span class="line"> <span class="keyword">int</span> next;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">node <span class="built_in">list</span>[<span class="number">100100</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> start, n, k;</span><br><span class="line"> <span class="built_in">cin</span> >> start >> n >> k;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> s, key, ne;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &s);</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d %d"</span>, &<span class="built_in">list</span>[s].key, &<span class="built_in">list</span>[s].next);</span><br><span class="line"> <span class="built_in">list</span>[s].address = s;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">vector</span><<span class="built_in">vector</span><node>> data;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">while</span>(start != <span class="number">-1</span>) {</span><br><span class="line"> <span class="keyword">int</span> count = k;</span><br><span class="line"> <span class="built_in">vector</span><node> tmp;</span><br><span class="line"> <span class="keyword">while</span>(count-- && start != <span class="number">-1</span>) {</span><br><span class="line"> tmp.push_back(<span class="built_in">list</span>[start]);</span><br><span class="line"> start = <span class="built_in">list</span>[start].next;</span><br><span class="line"> }</span><br><span class="line"> data.push_back(tmp);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">vector</span><node> result;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = data.<span class="built_in">size</span>() - <span class="number">1</span>; i >= <span class="number">0</span>; --i) {</span><br><span class="line"> result.insert(result.<span class="built_in">end</span>(), data[i].<span class="built_in">begin</span>(), data[i].<span class="built_in">end</span>());</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < result.<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="keyword">if</span>(i == result.<span class="built_in">size</span>() - <span class="number">1</span>) result[i].next = <span class="number">-1</span>;</span><br><span class="line"> <span class="keyword">else</span> result[i].next = result[i+<span class="number">1</span>].address;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < result.<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="keyword">if</span>(i == result.<span class="built_in">size</span>() - <span class="number">1</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%05d %d -1\n"</span>, result[i].address, result[i].key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%05d %d %05d\n"</span>, result[i].address, result[i].key, result[i].next);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="7-3-Summit-25分"><a href="#7-3-Summit-25分" class="headerlink" title="7-3 Summit (25分)"></a>7-3 Summit (25分)</h3><p>A summit (峰会) is a meeting of heads of state or government. Arranging the rest areas for the summit is not a simple job. The ideal arrangement of one area is to invite those heads so that everyone is a direct friend of everyone.</p>
<p>Now given a set of tentative arrangements, your job is to tell the organizers whether or not each area is all set.</p>
<h4 id="Input-Specification-2"><a href="#Input-Specification-2" class="headerlink" title="Input Specification:"></a>Input Specification:</h4><p>Each input file contains one test case. For each case, the first line gives two positive integers N (≤ 200), the number of heads in the summit, and M, the number of friendship relations. Then M lines follow, each gives a pair of indices of the heads who are friends to each other. The heads are indexed from 1 to N.</p>
<p>Then there is another positive integer K (≤ 100), and K lines of tentative arrangement of rest areas follow, each first gives a positive number L (≤ N), then followed by a sequence of L distinct indices of the heads. All the numbers in a line are separated by a space.</p>
<h4 id="Output-Specification-2"><a href="#Output-Specification-2" class="headerlink" title="Output Specification:"></a>Output Specification:</h4><p>For each of the K areas, print in a line your advice in the following format:</p>
<p>if in this area everyone is a direct friend of everyone, and no friend is missing (that is, no one else is a direct friend of everyone in this area), print Area X is OK..</p>
<p>if in this area everyone is a direct friend of everyone, yet there are some other heads who may also be invited without breaking the ideal arrangement, print Area X may invite more people, such as H. where H is the smallest index of the head who may be invited.</p>
<p>if in this area the arrangement is not an ideal one, then print Area X needs help. so the host can provide some special service to help the heads get to know each other.</p>
<p>Here X is the index of an area, starting from 1 to K.</p>
<h4 id="解析-2"><a href="#解析-2" class="headerlink" title="解析"></a>解析</h4><p><a href="https://pintia.cn/problem-sets/994805342720868352/problems/994805343979159552" target="_blank" rel="noopener">pat1142</a>原题考过,不难,就是判断给出的这几个人是否互为朋友,如果为朋友,是否存在一个人不在其中,缺与其他人都是朋友关系。这题可以设置两个判断。第一个判断,判断人是否相互为朋友,暴力搜两个人之间是否有关系。第二个判断,判断是否有这样的一个人,暴力搜不在其中的人的人际关系。</p>
<h4 id="Sample-Input-2"><a href="#Sample-Input-2" class="headerlink" title="Sample Input:"></a>Sample Input:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">8 10</span><br><span class="line">5 6</span><br><span class="line">7 8</span><br><span class="line">6 4</span><br><span class="line">3 6</span><br><span class="line">4 5</span><br><span class="line">2 3</span><br><span class="line">8 2</span><br><span class="line">2 7</span><br><span class="line">5 3</span><br><span class="line">3 4</span><br><span class="line">6</span><br><span class="line">4 5 4 3 6</span><br><span class="line">3 2 8 7</span><br><span class="line">2 2 3</span><br><span class="line">1 1</span><br><span class="line">2 4 6</span><br><span class="line">3 3 2 1</span><br></pre></td></tr></table></figure>
<h4 id="Sample-Output-1"><a href="#Sample-Output-1" class="headerlink" title="Sample Output:"></a>Sample Output:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">Area 1 is OK.</span><br><span class="line">Area 2 is OK.</span><br><span class="line">Area 3 is OK.</span><br><span class="line">Area 4 is OK.</span><br><span class="line">Area 5 may invite more people, such as 3.</span><br><span class="line">Area 6 needs help.</span><br></pre></td></tr></table></figure>
<h4 id="Solution-1"><a href="#Solution-1" class="headerlink" title="Solution:"></a>Solution:</h4><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><algorithm></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> e[<span class="number">210</span>][<span class="number">210</span>];</span><br><span class="line"><span class="keyword">bool</span> vis[<span class="number">210</span>];</span><br><span class="line"><span class="keyword">int</span> person = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">int</span> n, m, a, b;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">judge1</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &data)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < data.<span class="built_in">size</span>(); ++i) {</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j = i + <span class="number">1</span>; j < data.<span class="built_in">size</span>(); ++j) {</span><br><span class="line"> <span class="keyword">if</span>(!e[data[i]][data[j]]) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">judge2</span><span class="params">(<span class="built_in">vector</span><<span class="keyword">int</span>> &data)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i <= n; ++i) {</span><br><span class="line"> <span class="keyword">if</span>(!vis[i]) {</span><br><span class="line"> <span class="keyword">int</span> j = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(; j < data.<span class="built_in">size</span>(); ++j) {</span><br><span class="line"> <span class="keyword">if</span>(!e[i][data[j]]) <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(j == data.<span class="built_in">size</span>()) {</span><br><span class="line"> person = i;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">cin</span> >> n >> m;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < m; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d %d"</span>, &a, &b);</span><br><span class="line"> e[a][b] = <span class="number">1</span>;</span><br><span class="line"> e[b][a] = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> k;</span><br><span class="line"> <span class="built_in">cin</span> >> k;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j <= k; ++j) {</span><br><span class="line"> <span class="keyword">int</span> l;</span><br><span class="line"> <span class="built_in">cin</span> >> l;</span><br><span class="line"> <span class="built_in">vector</span><<span class="keyword">int</span>> data;</span><br><span class="line"> <span class="built_in">fill</span>(vis, vis + <span class="number">210</span>, <span class="literal">false</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < l; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &a);</span><br><span class="line"> data.push_back(a);</span><br><span class="line"> vis[a] = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(!judge1(data)) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Area %d needs help.\n"</span>, j);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span>(judge2(data)){</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Area %d is OK.\n"</span>, j);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Area %d may invite more people, such as %d.\n"</span>, j, person);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="7-4-Cartesian-Tree-30分"><a href="#7-4-Cartesian-Tree-30分" class="headerlink" title="7-4 Cartesian Tree (30分)"></a>7-4 Cartesian Tree (30分)</h3><p>A Cartesian tree is a binary tree constructed from a sequence of distinct numbers. The tree is heap-ordered, and an inorder traversal returns the original sequence. For example, given the sequence { 8, 15, 3, 4, 1, 5, 12, 10, 18, 6 }, the min-heap Cartesian tree is shown by the figure.</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/2019-winter-PAT-advanced-CTree.jpg" alt="CTree.jpg"></p>
<p>Your job is to output the level-order traversal sequence of the min-heap Cartesian tree.</p>
<h4 id="Input-Specification-3"><a href="#Input-Specification-3" class="headerlink" title="Input Specification:"></a>Input Specification:</h4><p>Each input file contains one test case. Each case starts from giving a positive integer N (≤30), and then N distinct numbers in the next line, separated by a space. All the numbers are in the range of int.</p>
<h4 id="Output-Specification-3"><a href="#Output-Specification-3" class="headerlink" title="Output Specification:"></a>Output Specification:</h4><p>For each test case, print in a line the level-order traversal sequence of the min-heap Cartesian tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the beginning or the end of the line.</p>
<h4 id="Sample-Input-3"><a href="#Sample-Input-3" class="headerlink" title="Sample Input:"></a>Sample Input:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">10</span><br><span class="line">8 15 3 4 1 5 12 10 18 6</span><br></pre></td></tr></table></figure>
<h4 id="Sample-Output-2"><a href="#Sample-Output-2" class="headerlink" title="Sample Output:"></a>Sample Output:</h4><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">1 3 5 8 4 6 15 10 12 18</span><br></pre></td></tr></table></figure>
<h4 id="解析-3"><a href="#解析-3" class="headerlink" title="解析"></a>解析</h4><p>这题是利用堆的一个中序,生成堆,并且输出它的层序遍历结果。<br>这题也不难,其实和前序中序生成树或者中序后序生成树差不多。为了防止爆数组,我是用map充当数组的作用,递归建树。</p>
<h4 id="Solution-2"><a href="#Solution-2" class="headerlink" title="Solution"></a>Solution</h4><figure class="highlight c++"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><map></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"><span class="built_in">vector</span><<span class="keyword">int</span>> in;</span><br><span class="line"><span class="built_in">map</span><<span class="keyword">int</span>,<span class="keyword">int</span>> tree;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">createTree</span><span class="params">(<span class="keyword">int</span> ind, <span class="keyword">int</span> start, <span class="keyword">int</span> <span class="built_in">end</span>)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span>(start > <span class="built_in">end</span>) <span class="keyword">return</span> ;</span><br><span class="line"> <span class="keyword">int</span> index = start;</span><br><span class="line"> <span class="keyword">int</span> key = in[start];</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = start; i <= <span class="built_in">end</span>; ++i) {</span><br><span class="line"> <span class="keyword">if</span>(key > in[i]) {</span><br><span class="line"> key = in[i];</span><br><span class="line"> index = i;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> tree[ind] = key;</span><br><span class="line"> createTree(ind * <span class="number">2</span>, start, index - <span class="number">1</span>);</span><br><span class="line"> createTree(ind * <span class="number">2</span> + <span class="number">1</span>, index + <span class="number">1</span>, <span class="built_in">end</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> n, num;</span><br><span class="line"> <span class="built_in">cin</span> >> n;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i < n; ++i) {</span><br><span class="line"> <span class="built_in">scanf</span>(<span class="string">"%d"</span>, &num);</span><br><span class="line"> in.push_back(num);</span><br><span class="line"> }</span><br><span class="line"> createTree(<span class="number">1</span>, <span class="number">0</span>, n - <span class="number">1</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">auto</span> a = tree.<span class="built_in">begin</span>();</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d"</span>, a->second);</span><br><span class="line"> a++;</span><br><span class="line"> <span class="keyword">for</span>(; a != tree.<span class="built_in">end</span>(); ++a) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %d"</span>, a->second);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>diary</category>
</categories>
<tags>
<tag>PAT</tag>
<tag>C++</tag>
</tags>
</entry>
<entry>
<title>随笔</title>
<url>/post/4151840938.html</url>
<content><![CDATA[<p>忙了一星期,准备在年前完成实习生工作的寻找,现在已经入职两天了。这还是很紧要的,毕竟我们学校有4个实习的必修学分,实习期必须满3个月。</p>
<p>找工作唯一的感觉,就是感觉学的不够深入,虽然接触了大部分东西,但大部分都是浅尝辄止。都说今年是互联网企业的寒冬,但是这样也得硬着头皮上了。如果实在找不到的话,就在老师的手下做实习生吧。</p>
<p>忘了说我的进的是虹软科技,测试开发实习生,可惜没有开发岗位了。</p>
<p>已经实习两天了,感觉还不错,公司氛围挺好的,其他的以后再说说吧。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>随笔</title>
<url>/post/4151840940.html</url>
<content><![CDATA[<p>大家新年快乐。</p>
<p>19号坐的的动车回来,还好没赶上疫情爆发的时候。</p>
<p>这几天舆论发酵的厉害,其实也没必要过度惊慌,武汉1000多万人,就算实际感染的人数有几千人,其实中奖几率也就是万分之一。但是也不能过度放松。必要的带带口罩,勤洗手其实就够了。</p>
<p>希望一切都会好起来。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
<tags>
<tag>新年</tag>
</tags>
</entry>
<entry>
<title>随笔</title>
<url>/post/4151840941.html</url>
<content><![CDATA[<p>不好意思,差不多一个多月没有更新了。</p>
<p>因为疫情,没法回杭州了。当然我这边已经开始远程办公了,从2月初就开始了,开始了差不都三星期了。</p>
<p>基本上每天早上9点起来,吃个早餐,开始工作。晚上打麻将,然后switch 1-2小时。毕设根本不想动……</p>
<p>考研成绩也已经出了,考的比较一般吧,还是有机会进复试的,现在好好准备复试吧。之后等复试结束,录取名单出了,再总结一下考研历程吧。</p>
<p>写这篇随笔的目的,主要是准备转换生活方式了。</p>
<p>今年上半年的的三座大山:</p>
<ul>
<li>研究生复试</li>
<li>毕设</li>
<li>实习</li>
</ul>
<p>希望这三个都能好好的完成。</p>
<p>就到这里吧。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>随笔</title>
<url>/post/4151840939.html</url>
<content><![CDATA[<p>不好意思好久没更新了。</p>
<p>我三月七号回的杭州,在自如上,在公司旁边租了小房子,自我隔离了七天。</p>
<p>还算是比较贵,6.4平、公共厨房、公共卫生间,一天60。不过也没办法短租不太好找,一个月工资全拿来交房租了(难受</p>
<p>三月十六号开始真正回公司上班。</p>
<p>工作的同时还伴随着完成毕设.. 每天都很焦躁. (疯狂拖延症),拖着拖着一天就结束了,啥事都没做成(难受。</p>
<p>复试大概是要拖到五月了,应该还有时间吧。</p>
<p>今天就到这里吧,尽量每个月都更新一点。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>2021-辞旧迎新</title>
<url>/post/635688087.html</url>
<content><![CDATA[<p>这篇文章本来应该是在寒假在家的时候写的,可惜因为某些原因拖到现在,才不是因为拖延症(滑稽</p>
<p>寒假在家基本上打通了 Hades(通关80多次) 和 空洞骑士(switch)。</p>
<p>不得不说空洞骑士是我买过最值的游戏了,它的游戏体量、内容、完成度和游戏体验不逊色一些3A大作,就是新人不太友好。坐等丝之歌。</p>
<p>hades这游戏也不错作为一个rougelike游戏,虽然只有四关,但是本身剧情非常不错,重复可玩性非常高。一共6种武器,每种武器4种形态。也就是说有24种武器可以切换。难度本身并不低,特别是开了热度。我觉得可以再出一个DLC,本身的内容还可以再充实一下,价格中规中矩。音乐非常不错,这游戏反正买了不亏。</p>
<p>在家期间,主动去学习一些关于健身的知识,我也想改变一下十年吃啥都不长肉的体型了。去B站搜到了卓叔,扫除了我之前很多的健身误区,又恰逢我家社区建设了新的免费的健身房。最终踏上了健身之旅,前几天测了一下体重,涨了10斤(狂喜)</p>
<p>前面简单介绍了一下我在家的事情。</p>
<p>2020年是一个对我有重大影响的一年:</p>
<p>考研结束->摸着疫情,一人在外第一次租房实习->摸着实习写毕设->研究生复试->毕设答辩->简单毕业->研究生生活</p>
<p>这大概是每个大学生都要经历的过程吧。</p>
<p>其实看起来还好,只有当自己回顾起自己的经历的才会感慨自己当时是怎么样边实习边把毕设完成的。</p>
<p>感叹留给过去,着眼未来大概才是我不会停止脚步的原因吧。</p>
<p>新的一年希望自己能在专业领域别再迷茫,能有明确的努力方向。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title>2020年考研感想&一些其他的</title>
<url>/post/1996876469.html</url>
<content><![CDATA[<h2 id="总述"><a href="#总述" class="headerlink" title="总述"></a>总述</h2><p>好久没更新了,前阵子忙着考研复试,学校开放之后,便从公司请假,回到学校封闭式管理了。</p>
<p>复试在5月16日,录取名单5月17日就出了,不得不说我浙这个效率真的高。</p>
<p>本人一战,双非一本本专业,报考的是<code>浙江大学软件学院</code>,运气较好,因为疫情扩招,最终录取到软件工程全日制。分数360+,按未扩招时算的在复试边缘。</p>
<p>这几天忙着毕设和找导师,更新的较迟,这是一个阶段性总结,等之后生活平稳了才会稳定更新。</p>
<a id="more"></a>
<h2 id="学校简介"><a href="#学校简介" class="headerlink" title="学校简介"></a>学校简介</h2><p>浙大计算机还是很强的,全国第三。浙大计算机主要在:CAD/CG、区块链、机器学习方面较为突出。报考浙大的计算机/电子信息主要有三个分院:计算机学院(计算机科学与技术(<code>学硕</code>)、软件工程(<code>学硕</code>)、网络空间安全(<code>学硕</code>)、计算机技术(<code>专硕</code>))、软件学院(软件工程(<code>专硕</code>))、工程师学院(物联网(<code>专硕</code>))</p>
<p>这三个学院考研科目公共课相同,专业课上:计院、工院都是408、软院878(c+数据结构)</p>
<p>计院录取人数:<a href="http://www.cs.zju.edu.cn/csen/2020/0430/c27006a2092231/page.htm" target="_blank" rel="noopener">http://www.cs.zju.edu.cn/csen/2020/0430/c27006a2092231/page.htm</a></p>
<p>软院录取人数:<a href="http://www.cst.zju.edu.cn/2020/0502/c32178a2092359/page.htm" target="_blank" rel="noopener">http://www.cst.zju.edu.cn/2020/0502/c32178a2092359/page.htm</a></p>
<p>工院录取人数:<a href="http://pi.zju.edu.cn/index.php?c=Index&a=news_detail&id=3308" target="_blank" rel="noopener">http://pi.zju.edu.cn/index.php?c=Index&a=news_detail&id=3308</a></p>
<p>浙大招得人算是非常多了,相对来说难度比招人数个位数的学校好多了,但是同样会吸引大量大佬来竞争。所以难度不太好评估。</p>
<p>浙大的复试较为公平,也是相对来说没那么繁杂的。</p>
<p>总分成绩 = (初试/5) x 0.7 + 复试 x 0.3</p>
<p>相当于:1分复试=2.1分初试,所以初试不高逆袭也不是不可能</p>
<p>其他的考研信息最好请关注分院官网,以及研究生招生网。</p>
<h2 id="个人情况"><a href="#个人情况" class="headerlink" title="个人情况"></a>个人情况</h2><p>我是从7月正式开始复习的,之前断断续续背了一些英语单词就不算进去了。</p>
<p>7月我觉考浙大可能有点迟了,因为我的高数基础和英语底子可能不算太好,所以在早期我数学一天6个小时,英语一天4个小时,因为我考的是软件学院,专业课最后三个月准备就可以了。所以最好在考研前评估自己的基础怎么样。</p>
<p>复习方法我就不说了,毕竟考得不高..</p>
<p>最难受的就是最用心复习的数学和英语并没有考起来,反而没怎复习的政治考得还不错。(难受)</p>
<p>我主要侧重于对于时间的把握。</p>
<p>今年因为疫情的关系,取消了上机考试。按照往年,上机也是复试的内容之一,当然pat可以代替上机复试。</p>
<p>换算公式:2分pat = 1分初试</p>
<p>可以看到pat还是相当重要的,同时pat和上机成绩只能2选1,就意味着如果你参加了上机考试,pat成绩作废,成绩只能算上机的,同时pat就只有当年的pat成绩有效。比如我考2020的研究生,只有2019年3月、9月、12月的有效。</p>
<p>这边推荐PAT考试尽量早开始,在3月份拿到高分最后,后面每天可以多出2、3时来复习。</p>
<p>我七月开始,pat也没考,后面花了比较多的时间复习pat,这部分其实可以提早结束。</p>
<p>我也写了一个,有兴趣的可以看看</p>
<p>其他就没什么好说的了</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>考研选择比努力重要,今年软院ai上线就可以录取,相比隔壁的软件工程均分都到了390.</p>
<p>考985、211或者强势专业请早点开始。</p>
<p>尽早地评估自己地水平,对症下药。</p>
<p>我地一个同学因为数学低了2分,补了25分,最终无缘软院。补足短板十分重要。</p>
<p>最近忙着各种各样的荣誉,有点烦。感觉拿到浙大的录取通知书反而没有特别开心,身上的压力更大了。真是令人头秃。</p>
<p>过段时间离校,又得找个地方租,跟着导师做项目去了。</p>
<p>祝愿大家以后前程似锦。</p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>PAT真题目录</title>
<url>/post/1337061191.html</url>
<content><![CDATA[<h2 id="PAT甲级真题目录(按题型整理)"><a href="#PAT甲级真题目录(按题型整理)" class="headerlink" title="PAT甲级真题目录(按题型整理)"></a>PAT甲级真题目录(按题型整理)</h2><blockquote>
<p>来自<a href="https://www.liuchuo.net/archives/2502?tdsourcetag=s_pcqq_aiomsg" target="_blank" rel="noopener">柳婼 の blog</a></p>
</blockquote>
<h3 id="最短路径"><a href="#最短路径" class="headerlink" title="最短路径"></a>最短路径</h3><p><a href="http://www.liuchuo.net/archives/2359" target="_blank" rel="noopener">1003. Emergency (25)-PAT甲级真题(Dijkstra算法)</a><br><a href="http://www.liuchuo.net/archives/2373" target="_blank" rel="noopener">1018. Public Bike Management (30)-PAT甲级真题(Dijkstra + DFS)</a><br><a href="http://www.liuchuo.net/archives/2369" target="_blank" rel="noopener">1030. Travel Plan (30)-PAT甲级真题(Dijkstra + DFS,输出路径,边权)</a><br><a href="http://www.liuchuo.net/archives/2399" target="_blank" rel="noopener">1087. All Roads Lead to Rome (30)-PAT甲级真题-Dijkstra + DFS</a><br><a href="http://www.liuchuo.net/archives/2407" target="_blank" rel="noopener">1111. Online Map (30)-PAT甲级真题(Dijkstra + DFS)树的遍历</a> </p>
<h3 id="树的遍历"><a href="#树的遍历" class="headerlink" title="树的遍历"></a>树的遍历</h3><p><a href="http://www.liuchuo.net/archives/2229" target="_blank" rel="noopener">1004. Counting Leaves (30)-PAT甲级真题(bfs,dfs,树的遍历,层序遍历)</a><br><a href="http://www.liuchuo.net/archives/2100" target="_blank" rel="noopener">1020. Tree Traversals (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2285" target="_blank" rel="noopener">1053. Path of Equal Weight (30)-PAT甲级真题(树的遍历) </a><br><a href="http://www.liuchuo.net/archives/2212" target="_blank" rel="noopener">1079. Total Sales of Supply Chain (25)-PAT甲级真题(dfs,bfs,树的遍历)</a><br><a href="http://www.liuchuo.net/archives/2168" target="_blank" rel="noopener">1086. Tree Traversals Again (25)-PAT甲级真题 </a><br><a href="http://www.liuchuo.net/archives/2465" target="_blank" rel="noopener">1090. Highest Price in Supply Chain (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2223" target="_blank" rel="noopener">1094. The Largest Generation (25)-PAT甲级真题(bfs,dfs,树的遍历)</a><br><a href="http://www.liuchuo.net/archives/2166" target="_blank" rel="noopener">1102. Invert a Binary Tree (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2226" target="_blank" rel="noopener">1106. Lowest Price in Supply Chain (25)-PAT甲级真题(dfs,bfs,树的遍历)</a><br><a href="http://www.liuchuo.net/archives/2235" target="_blank" rel="noopener">1115. Counting Nodes in a BST (30)-PAT甲级真题(二叉树的遍历,dfs)</a><br><a href="http://www.liuchuo.net/archives/2484" target="_blank" rel="noopener">1119. Pre- and Post-order Traversals (30)-PAT甲级真题(前序后序转中序)</a></p>
<h3 id="图的遍历"><a href="#图的遍历" class="headerlink" title="图的遍历"></a>图的遍历</h3><p><a href="http://www.liuchuo.net/archives/2346" target="_blank" rel="noopener">1013. Battle Over Cities (25)-PAT甲级真题(图的遍历,统计强连通分量的个数,dfs)</a><br><a href="http://www.liuchuo.net/archives/2348" target="_blank" rel="noopener">1021. Deepest Root (25)-PAT甲级真题(图的遍历,dfs,连通分量的个数)</a><br><a href="http://www.liuchuo.net/archives/2331" target="_blank" rel="noopener">1034. Head of a Gang (30)-PAT甲级真题(图的遍历dfs)</a><br><a href="http://www.liuchuo.net/archives/2376" target="_blank" rel="noopener">1072. Gas Station (30)-PAT甲级真题(Dijkstra)</a><br><a href="http://www.liuchuo.net/archives/2334" target="_blank" rel="noopener">1076. Forwards on Weibo (30)-PAT甲级真题(图的遍历bfs)</a> </p>
<h3 id="深度优先搜索"><a href="#深度优先搜索" class="headerlink" title="深度优先搜索"></a>深度优先搜索</h3><p><a href="http://www.liuchuo.net/archives/2451" target="_blank" rel="noopener">1103. Integer Factorization (30)-PAT甲级真题(dfs深度优先)</a> </p>
<h3 id="广度优先搜索"><a href="#广度优先搜索" class="headerlink" title="广度优先搜索"></a>广度优先搜索</h3><p><a href="http://www.liuchuo.net/archives/2307" target="_blank" rel="noopener">1091. Acute Stroke (30)-PAT甲级真题(广度优先搜索)</a> </p>
<h3 id="哈希、散列"><a href="#哈希、散列" class="headerlink" title="哈希、散列"></a>哈希、散列</h3><p><a href="http://www.liuchuo.net/archives/2142" target="_blank" rel="noopener">1048. Find Coins (25)-PAT甲级真题(Hash散列)</a><br><a href="http://www.liuchuo.net/archives/2130" target="_blank" rel="noopener">1050. String Subtraction (20)-PAT甲级真题(哈希)</a><br><a href="http://www.liuchuo.net/archives/1898" target="_blank" rel="noopener">1092. To Buy or Not to Buy (20)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/452" target="_blank" rel="noopener">1084. Broken Keyboard (20)-PAT甲级试题</a> </p>
<h3 id="排序"><a href="#排序" class="headerlink" title="排序"></a>排序</h3><p><a href="http://www.liuchuo.net/archives/2207" target="_blank" rel="noopener">1012. The Best Rank (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2350" target="_blank" rel="noopener">1016. Phone Bills (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2180" target="_blank" rel="noopener">1025. PAT Ranking (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2120" target="_blank" rel="noopener">1028. List Sorting (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2255" target="_blank" rel="noopener">1055. The World’s Richest (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2068" target="_blank" rel="noopener">1062. Talent and Virtue (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2260" target="_blank" rel="noopener">1075. PAT Judge (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2453" target="_blank" rel="noopener">1080. Graduate Admission (30)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2128" target="_blank" rel="noopener">1083. List Grades (25)-PAT甲级真题</a> </p>
<h3 id="STL的使用"><a href="#STL的使用" class="headerlink" title="STL的使用"></a>STL的使用</h3><p><a href="http://www.liuchuo.net/archives/2295" target="_blank" rel="noopener">1022. Digital Library (30)-PAT甲级真题(map映射)</a><br><a href="http://www.liuchuo.net/archives/2145" target="_blank" rel="noopener">1039. Course List for Student (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2147" target="_blank" rel="noopener">1047. Student List for Course (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2048" target="_blank" rel="noopener">1054. The Dominant Color (20)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2106" target="_blank" rel="noopener">1063. Set Similarity (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2257" target="_blank" rel="noopener">1071. Speech Patterns (25)-PAT甲级真题(map应用)</a><br><a href="http://www.liuchuo.net/archives/1892" target="_blank" rel="noopener">1100. Mars Numbers (20)-PAT甲级真题</a> </p>
<h3 id="链表处理"><a href="#链表处理" class="headerlink" title="链表处理"></a>链表处理</h3><p><a href="http://www.liuchuo.net/archives/2113" target="_blank" rel="noopener">1032. Sharing (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2116" target="_blank" rel="noopener">1052. Linked List Sorting (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/1910" target="_blank" rel="noopener">1074. Reversing Linked List (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2118" target="_blank" rel="noopener">1097. Deduplication on a Linked List (25)-PAT甲级真题</a></p>
<h3 id="二叉搜索树"><a href="#二叉搜索树" class="headerlink" title="二叉搜索树"></a>二叉搜索树</h3><p><a href="http://www.liuchuo.net/archives/2153" target="_blank" rel="noopener">1043. Is It a Binary Search Tree (25)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2161" target="_blank" rel="noopener">Complete Binary Search Tree (30)-PAT甲级真题</a><br><a href="http://www.liuchuo.net/archives/2173" target="_blank" rel="noopener">1099. Build A Binary Search Tree (30)-PAT甲级真题</a> </p>
<h3 id="平衡二叉树"><a href="#平衡二叉树" class="headerlink" title="平衡二叉树"></a>平衡二叉树</h3><p><a href="http://www.liuchuo.net/archives/2178" target="_blank" rel="noopener">1066. Root of AVL Tree (25)-PAT甲级真题</a></p>
<h3 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a>堆排序</h3><p><a href="http://www.liuchuo.net/archives/2273" target="_blank" rel="noopener">1098. Insertion or Heap Sort (25)-PAT甲级真题(堆排序)</a></p>
<h3 id="并查集"><a href="#并查集" class="headerlink" title="并查集"></a>并查集</h3><p><a href="http://www.liuchuo.net/archives/2183" target="_blank" rel="noopener">1107. Social Clusters (30)-PAT甲级真题(并查集)</a><br><a href="http://www.liuchuo.net/archives/2201" target="_blank" rel="noopener">1114. Family Property (25)-PAT甲级真题(并查集)</a><br><a href="http://www.liuchuo.net/archives/2482" target="_blank" rel="noopener">1118. Birds in Forest (25)-PAT甲级真题(并查集)</a></p>
<h3 id="树状数组"><a href="#树状数组" class="headerlink" title="树状数组"></a>树状数组</h3><p><a href="http://www.liuchuo.net/archives/2265" target="_blank" rel="noopener">1057. Stack (30)-PAT甲级真题(树状数组)</a></p>
]]></content>
<categories>
<category>diary</category>
</categories>
</entry>
<entry>
<title>virtualenvwarpper安装与配置</title>
<url>/post/1999622911.html</url>
<content><![CDATA[<h1 id="Virtualenvwrapper"><a href="#Virtualenvwrapper" class="headerlink" title="Virtualenvwrapper"></a>Virtualenvwrapper</h1><p><code>virtualenvwarpper</code>一般用作<code>python</code>管理不同的env。把<code>virtualenv</code>拓展之后,用起来更加简单方便</p>
<ol>
<li>可以将所有虚拟环境环境放在一个目录下,方便管理</li>
<li>切换虚拟环境较为方便</li>
<li>管理虚拟环境比较方便</li>
</ol>
<h1 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h1><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pip3 install virtualenvwrapper</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建目录用来存放虚拟环境</span></span><br><span class="line">mkdir ~/.virtualenvs</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在.bashrc中添加</span></span><br><span class="line"><span class="comment">## 指定PYTHON 版本</span></span><br><span class="line">VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3</span><br><span class="line"><span class="built_in">export</span> WORKON_HOME=~/.virtualenvs</span><br><span class="line"><span class="built_in">source</span> /usr/<span class="built_in">local</span>/bin/virtualenvwrapper.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行</span></span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure>
<ul>
<li>workon [虚拟环境名称]:切换虚拟环境</li>
<li>lsvirtualenv:列出已有的虚拟环境列表</li>
<li>mkvirtualenv :新建虚拟环境</li>
<li>rmvirtualenv :删除虚拟环境</li>
<li>deactivate: 离开已进入的虚拟环境</li>
</ul>
]]></content>
<categories>
<category>tool</category>
</categories>
<tags>
<tag>virtualenv</tag>
</tags>
</entry>
<entry>
<title>wsl2环境配置+docker+wt+vscode</title>
<url>/post/4258143485.html</url>
<content><![CDATA[<h2 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h2><p>最近新换的电脑又坏了,拿回来还得重新配置环境,还得挨个找教程进行配置。这次就简单地全写一起吧。</p>
<p>作为<code>wsl</code>的忠实爱好者,我已经使用了<code>wsl</code>两年了,相比虚拟机来说,实在是不要方便太多了,而且配置要求也没这么高。</p>
<p>之前<code>windows</code> 商店也发布了<code>wt</code>(<code>windows terminal</code>),相比<code>cmd</code>和<code>powershell</code>以及原本<code>bash</code>漂亮太多了,而且集成了多个窗口,切换很方便。</p>
<p>这是我现在的界面,大家可以自己定义其他的外观等等。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-overview.png" alt="overview"></p>
<p>最近看了一下,居然<code>wsl2</code>已经出好久了,还支持<code>docker</code>。我居然才知道,我想了想那时我应该在准备考研,emmm 。好了,废话不多说我们开始配置。</p>
<p>另外说一句,<code>wsl2</code>还没有推送到正式版的<code>windows 10</code>中,目前还是在<code>windows</code>的测试版中。</p>
<a id="more"></a>
<h3 id="对比"><a href="#对比" class="headerlink" title="对比"></a>对比</h3><p><a href="https://docs.microsoft.com/zh-cn/windows/wsl/compare-versions" target="_blank" rel="noopener">比较 WSL 2 和 WSL 1</a></p>
<p><code>wsl1</code>和<code>wsl2</code>底层架构不同,所以<code>wsl2</code>能相比<code>wsl1</code>更多的实现一些<code>linux</code>内的功能。包括这次的<code>docker</code>,同时在<code>windows 10</code>最新的测试版中已经提供了GPU计算,有兴趣的可以自己升到最新的版本使用。</p>
<h2 id="开始配置"><a href="#开始配置" class="headerlink" title="开始配置"></a>开始配置</h2><h3 id="更新windows-10"><a href="#更新windows-10" class="headerlink" title="更新windows 10"></a>更新windows 10</h3><p><code>wsl2</code>只有在<code>windows 10</code>版本2004的内部版本19041或者更高的版本中有提供 </p>
<ul>
<li>你可以<code>win+R</code>中输入<code>winver</code>中查看windows的版本<ul>
<li><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-winver.png" alt="winver"></li>
</ul>
</li>
<li>如果你的版本没有达到要求的话,你可以先试图通过windows 10的系统更新。</li>
<li>如果依旧没达到版本要求的话:<ul>
<li>加入微软的<code>windows 预览体院计划</code>,并选择Beta渠道</li>
<li><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-preview.png" alt="preview"></li>
<li>进行windows 10的系统更新</li>
</ul>
</li>
</ul>
<h3 id="系统设置"><a href="#系统设置" class="headerlink" title="系统设置"></a>系统设置</h3><h4 id="如果你没有安装过wsl"><a href="#如果你没有安装过wsl" class="headerlink" title="如果你没有安装过wsl"></a>如果你没有安装过wsl</h4><p>那么,你必须先启用<code>适用于 Linux 的 Windows 子系统</code>功能。</p>
<p>以管理员身份打开 PowerShell 并运行:</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">dism.exe /online /<span class="built_in">enable-feature</span> /featurename:Microsoft<span class="literal">-Windows</span><span class="literal">-Subsystem</span><span class="literal">-Linux</span> /all /norestart</span><br></pre></td></tr></table></figure>
<p>并重启电脑</p>
<h4 id="如果你安装过wsl"><a href="#如果你安装过wsl" class="headerlink" title="如果你安装过wsl"></a>如果你安装过wsl</h4><p>安装 WSL 2 之前,必须启用<code>虚拟机平台</code>功能。</p>
<p>以管理员身份打开 PowerShell 并运行:</p>
<figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">dism.exe /online /<span class="built_in">enable-feature</span> /featurename:VirtualMachinePlatform /all /norestart</span><br></pre></td></tr></table></figure>
<p>重新启动计算机,以完成 WSL 安装并更新到 WSL 2。</p>
<h4 id="将wsl2设置为默认版本"><a href="#将wsl2设置为默认版本" class="headerlink" title="将wsl2设置为默认版本"></a>将wsl2设置为默认版本</h4><p>在powershell中输入:<br><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">wsl -<span class="literal">-set</span><span class="literal">-default</span><span class="literal">-version</span> <span class="number">2</span></span><br></pre></td></tr></table></figure></p>
<p>你可能会遇到错误信息:<code>WSL 2 requires an update to its kernel component. For information please visit https://aka.ms/wsl2kernel</code><br>请安装<a href="https://aka.ms/wsl2kernel" target="_blank" rel="noopener">wsl2kernel</a>。</p>
<h4 id="wsl1-to-wsl2"><a href="#wsl1-to-wsl2" class="headerlink" title="wsl1 to wsl2"></a>wsl1 to wsl2</h4><p>先查看wsl的版本信息<br><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">wsl -<span class="literal">-list</span> -<span class="literal">-verbose</span></span><br><span class="line"><span class="comment"># or</span></span><br><span class="line">wsl <span class="literal">-l</span> <span class="literal">-v</span></span><br></pre></td></tr></table></figure></p>
<p>如果你是版本1的话,切换至版本2<br><figure class="highlight powershell"><table><tr><td class="code"><pre><span class="line">wsl -<span class="literal">-set</span><span class="literal">-version</span> <distro<span class="literal">-name</span>> <span class="number">2</span></span><br><span class="line"><span class="comment"># in my case</span></span><br><span class="line">wsl -<span class="literal">-set</span><span class="literal">-version</span> Ubuntu <span class="number">2</span></span><br></pre></td></tr></table></figure></p>
<p>从wsl1切换到wsl2可能会有错误,可能这能够解决<a href="https://docs.microsoft.com/zh-cn/windows/wsl/install-legacy#uninstallingremoving-the-legacy-distro" target="_blank" rel="noopener">卸载并删除任何旧分发</a></p>
<h3 id="安装-linux-发行版与-windows-terminal"><a href="#安装-linux-发行版与-windows-terminal" class="headerlink" title="安装 linux 发行版与 windows terminal"></a>安装 linux 发行版与 windows terminal</h3><p>在<code>Microsoft Store</code>搜索<code>windows terminal</code>与想要的<code>linux</code> 发行版</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-windows-terminal.png" alt="windows-ternimal"></p>
<p>你可以搜索你想要的 linux 发行版,基本上都有<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-disto.png" alt="disto"></p>
<ul>
<li>Ubuntu 16.04 LTS</li>
<li>Ubuntu 18.04 LTS</li>
<li>Ubuntu 20.04 LTS</li>
<li>openSUSE Leap 15.1</li>
<li>SUSE Linux Enterprise Server 12 SP5</li>
<li>SUSE Linux Enterprise Server 15 SP1</li>
<li>Kali Linux</li>
<li>Debian GNU/Linux</li>
<li>Fedora Remix for WSL</li>
<li>Pengwin</li>
<li>Pengwin Enterprise</li>
<li>Alpine WSL</li>
</ul>
<h3 id="linux环境配置"><a href="#linux环境配置" class="headerlink" title="linux环境配置"></a>linux环境配置</h3><p>我安装的是<code>ubuntu18.04</code>,所以接下来的流程都在该发行版下进行。</p>
<p>在使用<code>wt</code>中使用发行版时,先启动该发行版完成预安装和预配置。完成安装之后便可以通过<code>win+r</code>输入<code>wt</code>,打开<code>windows ternimal</code>点击<code>+</code>号选择你安装的发行版,就可以了,<code>wt</code>的配置我会在后面贴出。</p>
<h4 id="换源"><a href="#换源" class="headerlink" title="换源"></a>换源</h4><figure class="highlight shell"><table><tr><td class="code"><pre><span class="line">sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak</span><br><span class="line">sudo vim /etc/apt/sources.list</span><br></pre></td></tr></table></figure>
<p>清空里面所有内容,换入国内源。</p>
<p>例如阿里源:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br></pre></td></tr></table></figure>
<p>更新source包,安装更新,开发基础内容包<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get upgrade</span><br><span class="line">sudo apt-get install build-essential</span><br></pre></td></tr></table></figure></p>
<h4 id="zsh"><a href="#zsh" class="headerlink" title="zsh"></a>zsh</h4><p>将zsh替代bash<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt install zsh <span class="comment"># 安装zsh</span></span><br></pre></td></tr></table></figure></p>
<p>更改默认的shell<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">chsh -s $(<span class="built_in">which</span> zsh)</span><br></pre></td></tr></table></figure></p>
<p>下次再打开分发版时默认就是zsh</p>
<h4 id="Oh-My-ZSH"><a href="#Oh-My-ZSH" class="headerlink" title="Oh My ZSH"></a>Oh My ZSH</h4><p><code>oh my zsh</code>是一个开源的社区驱动的框架,用于管理zsh配置。</p>
<p>下载安装:<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"</span><br></pre></td></tr></table></figure></p>
<p>zsh的配置文件在<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">vim ~/.zshrc</span><br></pre></td></tr></table></figure></p>
<p>可以更改主题</p>
<figure class="highlight zsh"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 默认主题</span></span><br><span class="line">ZSH_THEME=<span class="string">"robbyrussell"</span></span><br><span class="line"><span class="comment"># 新主题</span></span><br><span class="line">ZSH_THEME=<span class="string">"agnoster"</span></span><br></pre></td></tr></table></figure>
<p>可以安装插件<code>Syntax Highlighting</code>, <code>Auto Suggestions</code><br>分别是语法高亮和自动补齐</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mkdir ~/.zsh</span><br><span class="line"><span class="built_in">cd</span> ~/.zsh</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/zsh-users/zsh-syntax-highlighting.git</span><br><span class="line">git <span class="built_in">clone</span> https://github.com/zsh-users/zsh-autosuggestions.git</span><br></pre></td></tr></table></figure>
<p>同时<code>wt</code>里面文件夹名比较丑,下载<code>dircolors</code></p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">curl https://raw.githubusercontent.com/seebi/dircolors-solarized/master/dircolors.ansi-dark --output ~/.dircolors</span><br></pre></td></tr></table></figure>
<p>然后<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vim ~/.zshrc</span><br></pre></td></tr></table></figure></p>
<p>在末尾加上<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh</span><br><span class="line"><span class="built_in">source</span> ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh </span><br><span class="line"><span class="built_in">eval</span> `dircolors ~/.dircolors`</span><br></pre></td></tr></table></figure><br>这样的话在每一次开启终端,都会启用插件</p>
<h4 id="proxychains"><a href="#proxychains" class="headerlink" title="proxychains"></a>proxychains</h4><p>在wsl2中的网络有了新的变化,系统会生成一个虚拟网卡,也就是说,在windows上会多一个网卡,且Ip是变化的。</p>
<p>所以在linux中它的<code>hosts</code>是自动生成的、沿袭原本windows内容的<code>hosts</code>,<code>nameserver</code>也是一样的。</p>
<p>所以window上的小飞机是无法直接给<code>wsl2</code>使用的,但是小飞机可以走本地端口代理。</p>
<p>而proxychains就是这样以一个工具可以利用http协议,走1080端口本地代理。</p>
<figure class="highlight zsh"><table><tr><td class="code"><pre><span class="line">sudo apt-get install proxychains</span><br></pre></td></tr></table></figure>
<p>它的配置文件在<br><figure class="highlight zsh"><table><tr><td class="code"><pre><span class="line">cat /etc/proxychains.conf</span><br></pre></td></tr></table></figure></p>
<p>因为wsl2的ip是变化的,host的ip也是变化的<br>所以要让<code>proxychains.conf</code>的代理信息自动变化</p>
<figure class="highlight zsh"><table><tr><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/.zsh</span><br><span class="line">mkdir proxy</span><br><span class="line"><span class="built_in">cd</span> proxy</span><br><span class="line">vim proxy.sh</span><br></pre></td></tr></table></figure>
<p>输入以下内容</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="built_in">export</span> HOSTIP=$(cat /etc/resolv.conf | grep <span class="string">'nameserver'</span> | cut -f 2 -d <span class="string">' '</span>)</span><br><span class="line"><span class="built_in">export</span> WSLIP=$(ip addr show eth0 | grep <span class="string">'inet '</span> | cut -f 6 -d <span class="string">' '</span> | cut -f 1 -d <span class="string">'/'</span>)</span><br><span class="line"><span class="built_in">echo</span> HOSTIP <span class="variable">$HOSTIP</span></span><br><span class="line"><span class="built_in">echo</span> WSLIP <span class="variable">$WSLIP</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> Your password | sudo -S sed -i <span class="string">"/http/c http\t<span class="variable">$HOSTIP</span> 1080"</span> /etc/proxychains.conf</span><br></pre></td></tr></table></figure>
<p>保存退出后</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">vim ~/.zshrc</span><br></pre></td></tr></table></figure>
<p>输入<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.zsh/proxy/proxy.sh</span><br></pre></td></tr></table></figure></p>
<p>以后只要想要下载某些外网内容就可以直接在前面加<code>proxychains</code></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 例如</span></span><br><span class="line">sudo proxychains apt-get update</span><br><span class="line">sudo proxychains apt-get upgrade </span><br><span class="line">proxychian git <span class="built_in">clone</span> ......</span><br></pre></td></tr></table></figure>
<h4 id="Nodejs"><a href="#Nodejs" class="headerlink" title="Nodejs"></a>Nodejs</h4><p>方法一:利用n安装nodejs<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt-get install nodejs</span><br><span class="line">sudo apt-get install npm</span><br><span class="line">sudo npm install -g npm</span><br><span class="line">sudo npm install -g n</span><br><span class="line">sudo n stable //稳定版</span><br></pre></td></tr></table></figure></p>
<p>方法二:利用nvm管理nodejs</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash</span><br></pre></td></tr></table></figure>
<p>之后重启<code>wt</code></p>
<p>输入<br><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="built_in">command</span> -v nvm</span><br><span class="line"><span class="comment"># return nvm</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装node</span></span><br><span class="line">nvm install node <span class="comment"># 最新版本</span></span><br><span class="line">nvm use node</span><br></pre></td></tr></table></figure></p>
<h4 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a>Docker</h4><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 更新索引包依赖</span></span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt install apt-transport-https ca-certificates curl software-properties-common</span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加官方的GPG-key</span></span><br><span class="line">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 验证</span></span><br><span class="line">sudo apt-key fingerprint 0EBFCD88</span><br><span class="line"><span class="comment"># 答案 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加 Docker repository </span></span><br><span class="line">sudo add-apt-repository <span class="string">"deb [arch=amd64] https://download.docker.com/linux/ubuntu <span class="variable">$(lsb_release -cs)</span> stable"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装</span></span><br><span class="line">sudo apt update</span><br><span class="line">sudo apt install docker-ce</span><br><span class="line"></span><br><span class="line"><span class="comment"># 启动docker</span></span><br><span class="line">sudo service docker start</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试docker</span></span><br><span class="line">sudo docker run hello-world</span><br></pre></td></tr></table></figure>
<h4 id="Docker-Compose"><a href="#Docker-Compose" class="headerlink" title="Docker Compose"></a>Docker Compose</h4><p>docker容器的管理工具。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># 下载当前的稳定发行版并将其放在/usr/local/bin下。</span></span><br><span class="line">sudo curl -L <span class="string">"https://github.com/docker/compose/releases/download/1.24.0/docker-compose-<span class="variable">$(uname -s)</span>-<span class="variable">$(uname -m)</span>"</span> -o /usr/<span class="built_in">local</span>/bin/docker-compose</span><br><span class="line"></span><br><span class="line"><span class="comment"># 修改权限</span></span><br><span class="line">sudo chmod +x /usr/<span class="built_in">local</span>/bin/docker-compose</span><br><span class="line"></span><br><span class="line"><span class="comment"># 测试</span></span><br><span class="line">docker-compose --version</span><br></pre></td></tr></table></figure>
<h4 id="Docker-Desktop"><a href="#Docker-Desktop" class="headerlink" title="Docker Desktop"></a>Docker Desktop</h4><p>在windows上下载<br><a href="https://www.docker.com/products/docker-desktop" target="_blank" rel="noopener">Docker Desktop</a></p>
<p>提供了docker的gui</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-docker-desktop.png" alt="docker-desktop"></p>
<h3 id="连接vscode"><a href="#连接vscode" class="headerlink" title="连接vscode"></a>连接vscode</h3><p>请先下载vscode安装插件:<code>remote-wsl</code>和<code>terminal</code>。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-remote-wsl.png" alt="remote-wsl"><br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-terminal-plugin.png" alt="terminal-plugin"></p>
<p>这样你就可以通过点击<img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-connection.png" alt="">连接wsl</p>
<p>通过<code>ctrl+p</code>输入terminal,选择打开一个内部的teriminal。就可以了。<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/wsl2-wt-zsh-docker-vscode-shell.png" alt=""></p>
<p>修改默认的shell为zsh。</p>
<h4 id="字体问题"><a href="#字体问题" class="headerlink" title="字体问题"></a>字体问题</h4><p>你可能会遇到某些字无法正常显示。</p>
<p>下载<a href="https://github.com/powerline/fonts/blob/master/DejaVuSansMono/DejaVu%20Sans%20Mono%20for%20Powerline.ttf" target="_blank" rel="noopener">DejaVuSansMono</a>,并安装。</p>
<p>同时在vscode的设置中,将terminal的字体选择为这个名字。</p>
<h3 id="windows-terminal"><a href="#windows-terminal" class="headerlink" title="windows terminal"></a>windows terminal</h3><p>这个是我的配置,不做过多介绍了<br><figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="comment">// This file was initially generated by Windows Terminal 1.0.1401.0</span></span><br><span class="line"><span class="comment">// It should still be usable in newer versions, but newer versions might have additional</span></span><br><span class="line"><span class="comment">// settings, help text, or changes that you will not see unless you clear this file</span></span><br><span class="line"><span class="comment">// and let us generate a new one for you.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// To view the default settings, hold "alt" while clicking on the "Settings" button.</span></span><br><span class="line"><span class="comment">// For documentation on these settings, see: https://aka.ms/terminal-documentation</span></span><br><span class="line">{</span><br><span class="line"> <span class="attr">"$schema"</span>: <span class="string">"https://aka.ms/terminal-profiles-schema"</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="attr">"defaultProfile"</span>: <span class="string">"{c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40}"</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// You can add more global application settings here.</span></span><br><span class="line"> <span class="comment">// To learn more about global settings, visit https://aka.ms/terminal-global-settings</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// If enabled, selections are automatically copied to your clipboard.</span></span><br><span class="line"> <span class="attr">"copyOnSelect"</span>: <span class="literal">false</span>,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// If enabled, formatted data is also copied to your clipboard</span></span><br><span class="line"> <span class="attr">"copyFormatting"</span>: <span class="literal">false</span>,</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// A profile specifies a command to execute paired with information about how it should look and feel.</span></span><br><span class="line"> <span class="comment">// Each one of them will appear in the 'New Tab' dropdown,</span></span><br><span class="line"> <span class="comment">// and can be invoked from the commandline with `wt.exe -p xxx`</span></span><br><span class="line"> <span class="comment">// To learn more about profiles, visit https://aka.ms/terminal-profile-settings</span></span><br><span class="line"> <span class="attr">"profiles"</span>:</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"defaults"</span>:</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"fontFace"</span>: <span class="string">"DejaVu Sans Mono for Powerline"</span>,</span><br><span class="line"> <span class="attr">"acrylicOpacity"</span>: <span class="number">0.8</span>, <span class="comment">//背景透明度</span></span><br><span class="line"> <span class="attr">"useAcrylic"</span>: <span class="literal">true</span>, <span class="comment">// 启用毛玻璃</span></span><br><span class="line"> <span class="comment">// "backgroundImage": "D:\\OneDrive\\图片\\stack.jpg", //背景图片</span></span><br><span class="line"> <span class="comment">// "backgroundImageOpacity": 0.5, //图片透明度</span></span><br><span class="line"> <span class="comment">// "backgroundImageStretchMode": "fill", //填充模式</span></span><br><span class="line"> <span class="comment">// "icon": "ms-appx:///ProfileIcons/{9acb9455-ca41-5af7-950f-6bca1bc9722f}.png", //图标</span></span><br><span class="line"> <span class="attr">"fontSize"</span>: <span class="number">10</span>, <span class="comment">//文字大小</span></span><br><span class="line"> <span class="attr">"colorScheme"</span>: <span class="string">"Solarized Dark"</span>, <span class="comment">//主题</span></span><br><span class="line"> <span class="attr">"cursorColor"</span>: <span class="string">"#FFFFFF"</span>, <span class="comment">//光标颜色</span></span><br><span class="line"> <span class="attr">"cursorShape"</span>: <span class="string">"bar"</span> <span class="comment">//光标形状</span></span><br><span class="line"> <span class="comment">// "startingDirectory":"D://Projects//" //起始目录</span></span><br><span class="line"> <span class="comment">// Put settings here that you want to apply to all profiles.</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"list"</span>:</span><br><span class="line"> [</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// Make changes here to the powershell.exe profile.</span></span><br><span class="line"> <span class="attr">"guid"</span>: <span class="string">"{61c54bbd-c2c6-5271-96e7-009a87ff44bf}"</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Windows PowerShell"</span>,</span><br><span class="line"> <span class="attr">"commandline"</span>: <span class="string">"powershell.exe"</span>,</span><br><span class="line"> <span class="attr">"hidden"</span>: <span class="literal">false</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// Make changes here to the cmd.exe profile.</span></span><br><span class="line"> <span class="attr">"guid"</span>: <span class="string">"{0caa0dad-35be-5f56-a8ff-afceeeaa6101}"</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"命令提示符"</span>,</span><br><span class="line"> <span class="attr">"commandline"</span>: <span class="string">"cmd.exe"</span>,</span><br><span class="line"> <span class="attr">"hidden"</span>: <span class="literal">false</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"guid"</span>: <span class="string">"{c6eaf9f4-32a7-5fdc-b5cf-066e8a4b1e40}"</span>,</span><br><span class="line"> <span class="attr">"hidden"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Ubuntu-18.04"</span>,</span><br><span class="line"> <span class="attr">"source"</span>: <span class="string">"Windows.Terminal.Wsl"</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"guid"</span>: <span class="string">"{b453ae62-4e3d-5e58-b989-0a998ec441b8}"</span>,</span><br><span class="line"> <span class="attr">"hidden"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Azure Cloud Shell"</span>,</span><br><span class="line"> <span class="attr">"source"</span>: <span class="string">"Windows.Terminal.Azure"</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"guid"</span>: <span class="string">"{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}"</span>,</span><br><span class="line"> <span class="attr">"hidden"</span>: <span class="literal">false</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Ubuntu-20.04"</span>,</span><br><span class="line"> <span class="attr">"source"</span>: <span class="string">"Windows.Terminal.Wsl"</span></span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Add custom color schemes to this array.</span></span><br><span class="line"> <span class="comment">// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes</span></span><br><span class="line"> <span class="attr">"schemes"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Solarized Dark"</span>,</span><br><span class="line"> <span class="attr">"black"</span>: <span class="string">"#002831"</span>,</span><br><span class="line"> <span class="attr">"red"</span>: <span class="string">"#d11c24"</span>,</span><br><span class="line"> <span class="attr">"green"</span>: <span class="string">"#738a05"</span>,</span><br><span class="line"> <span class="attr">"yellow"</span>: <span class="string">"#a57706"</span>,</span><br><span class="line"> <span class="attr">"blue"</span>: <span class="string">"#2176c7"</span>,</span><br><span class="line"> <span class="attr">"purple"</span>: <span class="string">"#c61c6f"</span>,</span><br><span class="line"> <span class="attr">"cyan"</span>: <span class="string">"#259286"</span>,</span><br><span class="line"> <span class="attr">"white"</span>: <span class="string">"#eae3cb"</span>,</span><br><span class="line"> <span class="attr">"brightBlack"</span>: <span class="string">"#475b62"</span>,</span><br><span class="line"> <span class="attr">"brightRed"</span>: <span class="string">"#bd3613"</span>,</span><br><span class="line"> <span class="attr">"brightGreen"</span>: <span class="string">"#475b62"</span>,</span><br><span class="line"> <span class="attr">"brightYellow"</span>: <span class="string">"#536870"</span>,</span><br><span class="line"> <span class="attr">"brightBlue"</span>: <span class="string">"#708284"</span>,</span><br><span class="line"> <span class="attr">"brightPurple"</span>: <span class="string">"#5956ba"</span>,</span><br><span class="line"> <span class="attr">"brightCyan"</span>: <span class="string">"#819090"</span>,</span><br><span class="line"> <span class="attr">"brightWhite"</span>: <span class="string">"#fcf4dc"</span>,</span><br><span class="line"> <span class="attr">"background"</span>: <span class="string">"#001e27"</span>,</span><br><span class="line"> <span class="attr">"foreground"</span>: <span class="string">"#708284"</span></span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Solarized Darcula"</span>,</span><br><span class="line"> <span class="attr">"black"</span>: <span class="string">"#25292a"</span>,</span><br><span class="line"> <span class="attr">"red"</span>: <span class="string">"#f24840"</span>,</span><br><span class="line"> <span class="attr">"green"</span>: <span class="string">"#629655"</span>,</span><br><span class="line"> <span class="attr">"yellow"</span>: <span class="string">"#b68800"</span>,</span><br><span class="line"> <span class="attr">"blue"</span>: <span class="string">"#2075c7"</span>,</span><br><span class="line"> <span class="attr">"purple"</span>: <span class="string">"#797fd4"</span>,</span><br><span class="line"> <span class="attr">"cyan"</span>: <span class="string">"#15968d"</span>,</span><br><span class="line"> <span class="attr">"white"</span>: <span class="string">"#d2d8d9"</span>,</span><br><span class="line"> <span class="attr">"brightBlack"</span>: <span class="string">"#25292a"</span>,</span><br><span class="line"> <span class="attr">"brightRed"</span>: <span class="string">"#f24840"</span>,</span><br><span class="line"> <span class="attr">"brightGreen"</span>: <span class="string">"#629655"</span>,</span><br><span class="line"> <span class="attr">"brightYellow"</span>: <span class="string">"#b68800"</span>,</span><br><span class="line"> <span class="attr">"brightBlue"</span>: <span class="string">"#2075c7"</span>,</span><br><span class="line"> <span class="attr">"brightPurple"</span>: <span class="string">"#797fd4"</span>,</span><br><span class="line"> <span class="attr">"brightCyan"</span>: <span class="string">"#15968d"</span>,</span><br><span class="line"> <span class="attr">"brightWhite"</span>: <span class="string">"#d2d8d9"</span>,</span><br><span class="line"> <span class="attr">"background"</span>: <span class="string">"#3d3f41"</span>,</span><br><span class="line"> <span class="attr">"foreground"</span>: <span class="string">"#d2d8d9"</span></span><br><span class="line"> } </span><br><span class="line"> ],</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Add custom keybindings to this array.</span></span><br><span class="line"> <span class="comment">// To unbind a key combination from your defaults.json, set the command to "unbound".</span></span><br><span class="line"> <span class="comment">// To learn more about keybindings, visit https://aka.ms/terminal-keybindings</span></span><br><span class="line"> <span class="attr">"keybindings"</span>:</span><br><span class="line"> [</span><br><span class="line"> <span class="comment">// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.</span></span><br><span class="line"> <span class="comment">// These two lines additionally bind them to Ctrl+C and Ctrl+V.</span></span><br><span class="line"> <span class="comment">// To learn more about selection, visit https://aka.ms/terminal-selection</span></span><br><span class="line"> { <span class="attr">"command"</span>: {<span class="attr">"action"</span>: <span class="string">"copy"</span>, <span class="attr">"singleLine"</span>: <span class="literal">false</span> }, <span class="attr">"keys"</span>: <span class="string">"ctrl+c"</span> },</span><br><span class="line"> { <span class="attr">"command"</span>: <span class="string">"paste"</span>, <span class="attr">"keys"</span>: <span class="string">"ctrl+v"</span> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Press Ctrl+Shift+F to open the search box</span></span><br><span class="line"> { <span class="attr">"command"</span>: <span class="string">"find"</span>, <span class="attr">"keys"</span>: <span class="string">"ctrl+shift+f"</span> },</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Press Alt+Shift+D to open a new pane.</span></span><br><span class="line"> <span class="comment">// - "split": "auto" makes this pane open in the direction that provides the most surface area.</span></span><br><span class="line"> <span class="comment">// - "splitMode": "duplicate" makes the new pane use the focused pane's profile.</span></span><br><span class="line"> <span class="comment">// To learn more about panes, visit https://aka.ms/terminal-panes</span></span><br><span class="line"> { <span class="attr">"command"</span>: { <span class="attr">"action"</span>: <span class="string">"splitPane"</span>, <span class="attr">"split"</span>: <span class="string">"auto"</span>, <span class="attr">"splitMode"</span>: <span class="string">"duplicate"</span> }, <span class="attr">"keys"</span>: <span class="string">"alt+shift+d"</span> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://nickymeuleman.netlify.app/blog/linux-on-windows-wsl2-zsh-docker#powerline-fonts" target="_blank" rel="noopener">WSL2, zsh, and docker. Linux through Windows.</a><br><a href="https://www.oyohyee.com/post/note_wsl2_net" target="_blank" rel="noopener">WSL2中自动配置Windows IP地址</a><br><a href="https://docs.microsoft.com/zh-cn/windows/wsl/install-win10#update-to-wsl-2" target="_blank" rel="noopener">适用于 Linux 的 Windows 子系统安装指南 (Windows 10)</a></p>
]]></content>
<categories>
<category>tool</category>
</categories>
<tags>
<tag>docker</tag>
<tag>wsl2</tag>
<tag>zsh</tag>
<tag>wt</tag>
</tags>
</entry>
<entry>
<title>[DDIA][第一章]:可靠性、可拓展性、可维护性</title>
<url>/post/3372083996.html</url>
<content><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>久仰DDIA大名,刚把<code>MIT 6.824</code>做完,之后应该会把DDIA的内容做一个摘录,其中也会夹杂着<code>6.824</code>的论文翻译和<code>lab</code>记录的整理</p>
<p>原书链接: <a href="https://vonng.gitbooks.io/ddia-cn/content/ch1.html" target="_blank" rel="noopener">Designing Data-Intensive Application</a></p>
<h1 id="第一章"><a href="#第一章" class="headerlink" title="第一章"></a>第一章</h1><h2 id="数据系统"><a href="#数据系统" class="headerlink" title="数据系统"></a>数据系统</h2><p>现今很多应用属于数据密集型 (data-intensive),而非计算密集型(compute-intensive)。主要的问题来自数据量、数据的复杂性以及数据的变更速度。</p>
<p>数据密集型应用通常都需要:</p>
<ul>
<li>存储数据,以便自己或其他应用程序之后能再次找到 (<code>数据库(database)</code>)</li>
<li>记住开销昂贵操作的结果,加快读取速度(<code>缓存(cache)</code>)</li>
<li>允许用户按关键字搜索数据,或以各种方式对数据进行过滤(<code>搜索索引(search indexes)</code>)</li>
<li>向其他进程发送消息,进行异步处理(<code>流处理(stream processing)</code>)</li>
<li>定期处理累积的大批量数据(<code>批处理(batch processing)</code>)</li>
</ul>
<p>这些都属于数据系统(data-system)。</p>
<p>其中三个在大多数软件种都非常重要的问题:</p>
<ul>
<li><p>可靠性(Reliability)</p>
<ul>
<li>系统在困境(adversity)(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功能,并能达到期望的性能水准)。</li>
</ul>
</li>
<li><p>可扩展性(Scalability)<br>有合理的办法应对系统的增长(数据量、流量、复杂性)</p>
</li>
<li><p>可维护性(Maintainability)</p>
<ul>
<li>许多不同的人(工程师、运维)在不同的生命周期,都能高效地在系统上工作(使系统保持现有行为,并适应新的应用场景)。</li>
</ul>
</li>
</ul>
<h2 id="可靠性"><a href="#可靠性" class="headerlink" title="可靠性"></a>可靠性</h2><p>人们对可靠软件的典型期望包括:</p>
<ul>
<li>应用程序表现出用户所期望的功能。 </li>
<li>允许用户犯错,允许用户以出乎意料的方式使用软件。 </li>
<li>在预期的负载和数据量下,性能满足要求。 </li>
<li>系统能防止未经授权的访问和滥用。 </li>
</ul>
<p>简单的说可以认为是“即使出现问题,系统也能继续正确工作”</p>
<p><code>故障</code>(fault):造成错误的原因<br><code>容错</code>(fault-tolerant):能预料并对应故障的系统特性,它是一定范围内的容忍</p>
<p><code>故障</code>(fault)不同于<code>失效</code>(failure)<br><code>故障</code>通常定义为系统的一部分状态偏离其标准,而<code>失效</code>则是系统作为一个整体停止向用户提供服务。<code>故障</code>的概率不可能降到零,因此最好设计容错机制以防因<code>故障</code>而导致<code>失效</code></p>
<p>现在会通过提高触发故障来提高保障率,因为可以通过故意引发故障来确保容错机制的正常运行。</p>
<p>同时相比组织错误,通常倾向与容忍错误。但是在某些环境下,不容忍错误更好。例:银行系统中的出错不能容忍,多种错误累计将对账号造成不可逆的伤害,这时候应该选择直接停止服务。</p>
<h3 id="硬件故障"><a href="#硬件故障" class="headerlink" title="硬件故障"></a>硬件故障</h3><p>硬盘的<code>平均无故障时间</code>(MTTF mean time to failure)约为10-50年</p>
<p>通常是增加单个硬件的冗余度,比如RAID,双路电源,热插拔CPU等</p>
<p>云平台的设计优先考虑<code>灵活性</code>和<code>弹性</code> ,因为云平台有大量的机器,一旦一个主机失效,那么一般是移动其他机器上运行。</p>
<h3 id="软件错误"><a href="#软件错误" class="headerlink" title="软件错误"></a>软件错误</h3><p>系统性错误:</p>
<ul>
<li>接受特定的错误输入,便导致所有应用服务器实例崩溃的BUG。例如2012年6月30日的闰秒,由于Linux内核中的一个错误,许多应用同时挂掉了。</li>
<li>失控进程会占用一些共享资源,包括CPU时间、内存、磁盘空间或网络带宽。</li>
<li>系统依赖的服务变慢,没有响应,或者开始返回错误的响应。</li>
<li>级联故障,一个组件中的小故障触发另一个组件中的故障,进而触发更多的故障。</li>
</ul>
<p>需要系统不断自检,出现差异时报警</p>
<h3 id="人为错误"><a href="#人为错误" class="headerlink" title="人为错误"></a>人为错误</h3><ul>
<li>以最小化犯错机会的方式设计系统。例如,精心设计的抽象、API和管理后台</li>
<li>将人们最容易犯错的地方与可能导致失效的地方解耦(decouple)。</li>
<li>在各个层次进行彻底的测试,从单元测试、全系统集成测试到手动测试。</li>
<li>允许从人为错误中简单快速地恢复,以最大限度地减少失效情况带来的影响。</li>
<li>配置详细和明确的监控,比如性能指标和错误率。</li>
<li>良好的管理实践与充分的培训—</li>
</ul>
<h2 id="可拓展性"><a href="#可拓展性" class="headerlink" title="可拓展性"></a>可拓展性</h2><p> 可扩展性(Scalability) 是用来描述系统应对负载增长能力的术语。</p>
<ul>
<li>说“X可扩展”或“Y不可扩展”. <code>X</code></li>
<li>“如果系统以特定方式增长,有什么选项可以应对增长?”<code>√</code></li>
<li>“如何增加计算资源来处理额外的负载?”等问题。<code>√</code></li>
</ul>
<h3 id="描述负载"><a href="#描述负载" class="headerlink" title="描述负载"></a>描述负载</h3><p>负载参数:例如:参数的最佳选择取决于系统架构,它可能是每秒向Web服务器发出的请求、数据库中的读写比率、聊天室中同时活跃的用户数量、缓存命中率或其他东西</p>
<p><code>fan-out</code>: 扇出:从电子工程学中借用的术语,它描述了输入连接到另一个门输出的逻辑门数量。 输出需要提供足够的电流来驱动所有连接的输入。 在事务处理系统中,我们使用它来描述为了服务一个传入请求而需要执行其他服务的请求数量</p>
<h3 id="描述性能"><a href="#描述性能" class="headerlink" title="描述性能"></a>描述性能</h3><p><code>吞吐量(throughput)</code>即每秒可以处理的记录数量,或者在特定规模数据集上运行作业的总时间</p>
<p><code>响应时间(response time)</code>即客户端发送请求到接收响应之间的时间。</p>
<blockquote>
<p><code>延迟(latency)</code> 和 <code>响应时间(response time)</code> 经常用作同义词,但实际上它们并不一样。响应时间是客户所看到的,除了实际处理请求的时间( <code>服务时间(service time)</code> )之外,还包括网络延迟和排队延迟。延迟是某个请求等待处理的<code>持续时长</code>,在此期间它处于 <code>休眠(latent)</code> 状态,并等待服务。</p>
</blockquote>
<p>百分位点:<br>如果想知道典型场景下用户需要等待多长时间,那么中位数是一个好的度量标准:一半用户请求的响应时间少于响应时间的中位数,另一半服务时间比中位数长。中位数也被称为第50百分位点,有时缩写为p50。注意中位数是关于单个请求的;如果用户同时发出几个请求(在一个会话过程中,或者由于一个页面中包含了多个资源),则至少一个请求比中位数慢的概率远大于50%。</p>
<p> 百分位点通常用于<code>服务级别目标(SLO, service level objectives)</code>和<code>服务级别协议(SLA, service level agreements)</code>,即定义服务预期性能和可用性的合同。 SLA可能会声明,如果服务响应时间的中位数小于200毫秒,且99.9百分位点低于1秒,则认为服务工作正常(如果响应时间更长,就认为服务不达标)。这些指标为客户设定了期望值,并允许客户在SLA未达标的情况下要求退款。</p>
<p>在多重调用的后端服务里,高百分位数变得特别重要。即使并行调用,最终用户请求仍然需要等待最慢的并行调用完成。只需要一个缓慢的调用就可以使整个最终用户请求变慢。即使只有一小部分后端调用速度较慢,如果最终用户请求需要多个后端调用,则获得较慢调用的机会也会增加,因此较高比例的最终用户请求速度会变慢(效果称为尾部延迟放大)。 </p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-chap1-reliability-scalability-maintainability-fig1-5.png" alt="fig1-5"></p>
<h3 id="应对负载的方法"><a href="#应对负载的方法" class="headerlink" title="应对负载的方法"></a>应对负载的方法</h3><p><code>纵向扩展(scaling up)</code>(<code>垂直扩展(vertical scaling)</code>): 转向更强大的机器</p>
<p><code>横向扩展(scaling out)</code> (<code>水平扩展(horizontal scaling)</code>):将负载分布到多台小机器上之间的对立</p>
<p><code>弹性(elastic)</code> 意味着可以在检测到负载增加时自动增加计算资源,而其他系统则是手动扩展(人工分析容量并决定向系统添加更多的机器)。如果负载极难预测(highly unpredictable),则弹性系统可能很有用,但手动扩展系统更简单,并且意外操作可能会更少</p>
<h2 id="可维护性"><a href="#可维护性" class="headerlink" title="可维护性"></a>可维护性</h2><p><code>可操作性(Operability)</code></p>
<p> 便于运维团队保持系统平稳运行。</p>
<p><code>简单性(Simplicity)</code></p>
<p> 从系统中消除尽可能多的复杂度(complexity),使新工程师也能轻松理解系统。(注意这和用户接口的简单性不一样。)</p>
<p><code>可演化性(evolability)</code></p>
<p> 使工程师在未来能轻松地对系统进行更改,当需求变化时为新应用场景做适配。也称为<code>可扩展性(extensibility)</code>,<code>可修改性(modifiability)</code>或<code>可塑性(plasticity)</code>。</p>
<h3 id="可操作性"><a href="#可操作性" class="headerlink" title="可操作性"></a>可操作性</h3><ul>
<li>通过良好的监控,提供对系统内部状态和运行时行为的可见性(visibility)</li>
<li>为自动化提供良好支持,将系统与标准化工具相集成</li>
<li>避免依赖单台机器(在整个系统继续不间断运行的情况下允许机器停机维护)</li>
<li>提供良好的文档和易于理解的操作模型(“如果做X,会发生Y”)</li>
<li>提供良好的默认行为,但需要时也允许管理员自由覆盖默认值</li>
<li>有条件时进行自我修复,但需要时也允许管理员手动控制系统状态</li>
<li>行为可预测,最大限度减少意外</li>
</ul>
<h3 id="简单性:管理复杂度"><a href="#简单性:管理复杂度" class="headerlink" title="简单性:管理复杂度"></a>简单性:管理复杂度</h3><p><code>复杂度(complexity)</code> 有各种可能的症状,例如:状态空间激增、模块间紧密耦合、纠结的依赖关系、不一致的命名和术语、解决性能问题的Hack、需要绕开的特例等等</p>
<p> 简化系统并不一定意味着减少功能;它也可以意味着消除额外的(accidental)的复杂度。</p>
<p>用于消除额外复杂度的最好工具之一是抽象(abstraction)。</p>
<h3 id="可演化性:拥抱变化"><a href="#可演化性:拥抱变化" class="headerlink" title="可演化性:拥抱变化"></a>可演化性:拥抱变化</h3><p>敏捷(agile) 工作模式为适应变化提供了一个框架</p>
<p>敏捷社区还开发了对在频繁变化的环境中开发软件很有帮助的技术工具和模式,如 测试驱动开发(TDD, test-driven development) 和 重构(refactoring) 。</p>
]]></content>
<categories>
<category>book</category>
<category>DDIA</category>
</categories>
<tags>
<tag>分布式</tag>
<tag>可靠性</tag>
<tag>可拓展性</tag>
<tag>可维护性</tag>
</tags>
</entry>
<entry>
<title>[DDIA][第二章]:数据模型与查询语言</title>
<url>/post/3286644706.html</url>
<content><![CDATA[<h1 id="第二章"><a href="#第二章" class="headerlink" title="第二章"></a>第二章</h1><h2 id="关系模型与文档模型"><a href="#关系模型与文档模型" class="headerlink" title="关系模型与文档模型"></a>关系模型与文档模型</h2><p>NoSQL(Not Only SQL),出现的原因:</p>
<ul>
<li>需要比关系数据库更好的可扩展性,包括非常大的数据集或非常高的写入吞吐量</li>
<li>相比商业数据库产品,免费和开源软件更受偏爱。</li>
<li>关系模型不能很好地支持一些特殊的查询操作</li>
<li>受挫于关系模型的限制性,渴望一种更具多动态性与表现力的数据模型。</li>
</ul>
<p>关系型数据库会与各种非关系型数据库一起使用被称作<code>混合持久化</code>。</p>
<h2 id="对象关系不匹配"><a href="#对象关系不匹配" class="headerlink" title="对象关系不匹配"></a>对象关系不匹配</h2><p>如果数据存储在关系表中,那么需要一个笨拙的转换层,处于应用程序代码中的对象和表,行,列的数据库模型之间。模型之间的不连贯有时被称为阻抗不匹配(impedance mismatch)。</p>
<blockquote>
<p>一个从电子学借用的术语。每个电路的输入和输出都有一定的阻抗(交流电阻)。当你将一个电路的输出连接到另一个电路的输入时,如果两个电路的输出和输入阻抗匹配,则连接上的功率传输将被最大化。阻抗不匹配会导致信号反射及其他问题。</p>
</blockquote>
<p><code>对象关系映射</code>(ORM object-relational mapping) 框架可以减少这个转换层所需的样板代码的数量,但是它们不能完全隐藏这两个模型之间的差异。</p>
<h2 id="多对一和多对多"><a href="#多对一和多对多" class="headerlink" title="多对一和多对多"></a>多对一和多对多</h2><p>region_id和industry_id是以ID,而不是纯字符串“Greater Seattle Area”和“Philanthropy”的形式给出的。为什么?</p>
<p>如果用户界面用一个自由文本字段来输入区域和行业,那么将他们存储为纯文本字符串是合理的。另一方式是给出地理区域和行业的标准化的列表,并让用户从下拉列表或自动填充器中进行选择,其优势如下:</p>
<ul>
<li>各个简介之间样式和拼写统一</li>
<li>避免歧义(例如,如果有几个同名的城市)</li>
<li>易于更新——名称只存储在一个地方,如果需要更改(例如,由于政治事件而改变城市名称),很容易进行全面更新。</li>
<li>本地化支持——当网站翻译成其他语言时,标准化的列表可以被本地化,使得地区和行业可以使用用户的语言来显示</li>
<li>更好的搜索——例如,搜索华盛顿州的慈善家就会匹配这份简介,因为地区列表可以编码记录西雅图在华盛顿这一事实</li>
</ul>
<p>使用ID的好处是,ID对人类没有任何意义,因而永远不需要改变:ID可以保持不变,即使它标识的信息发生变化。任何对人类有意义的东西都可能需要在将来某个时候改变——如果这些信息被复制,所有的冗余副本都需要更新。这会导致写入开销,也存在不一致的风险(一些副本被更新了,还有些副本没有被更新)。去除此类重复是数据库 <code>规范化(normalization)</code> 的关键思想。</p>
<blockquote>
<p>关于关系模型的文献区分了几种不同的规范形式,但这些区别几乎没有实际意义。一个经验法则是,如果重复存储了可以存储在一个地方的值,则模式就不是规范化(normalized)的。</p>
</blockquote>
<h2 id="文档数据库是否在重蹈覆辙?"><a href="#文档数据库是否在重蹈覆辙?" class="headerlink" title="文档数据库是否在重蹈覆辙?"></a>文档数据库是否在重蹈覆辙?</h2><h3 id="层次模型"><a href="#层次模型" class="headerlink" title="层次模型"></a>层次模型</h3><ul>
<li>(1)有且只有一个结点没有双亲结点,这个结点称为根结点;</li>
<li>(2)根以外的其他结点有且只有一个双亲结点两个条件的记录以及它们之间联系的集合为层次模型</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch2-data-model-and-search-language-hierarchical-model.png" alt=""></p>
<p>层次模型它与文档数据库使用的JSON模型有相似之处。能良好处理好一对多的关系,但是很难应对多对多的关系,并且不支持连接。</p>
<p>为了解决层次模型的局限性,推出两个<code>关系模型(relational model)</code>和<code>网络模型(network model)</code></p>
<h3 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h3><p>网络模型由一个称为数据系统语言会议(CODASYL)的委员会进行了标准化,并被数个不同的数据库商实现;它也被称为CODASYL模型。</p>
<p>CODASYL模型是层次模型的推广。在层次模型的树结构中,每条记录只有一个父节点;在网络模式中,每条记录可能有多个父节点。</p>
<p>网络模型中记录之间的链接不是外键,而更像编程语言中的指针(同时仍然存储在磁盘上)。访问记录的唯一方法是跟随从根记录起沿这些链路所形成的路径。这被称为<code>访问路径(access path)</code>。</p>
<ul>
<li>查询和更新数据库的代码变得复杂不灵活</li>
<li>必须浏览大量手写数据库查询代码,并重写来处理新的访问路径。</li>
<li>更改应用程序的数据模型是很难的。</li>
</ul>
<h3 id="关系模型"><a href="#关系模型" class="headerlink" title="关系模型"></a>关系模型</h3><p>一个 <code>关系(表)</code> 只是一个 <code>元组(行)</code> 的集合</p>
<p>在关系数据库中,查询优化器自动决定查询的哪些部分以哪个顺序执行,以及使用哪些索引</p>
<h2 id="关系型数据库与文档数据库对比"><a href="#关系型数据库与文档数据库对比" class="headerlink" title="关系型数据库与文档数据库对比"></a>关系型数据库与文档数据库对比</h2><ul>
<li>示多对一和多对多的关系时,关系数据库和文档数据库并没有根本的不同</li>
<li>支持文档数据模型的主要论据是架构灵活性,因局部性而拥有更好的性能,以及对于某些应用程序而言更接近于应用程序使用的数据结构。</li>
<li>关系模型通过为连接提供更好的支持以及支持多对一和多对多的关系来反击。</li>
</ul>
<p>如果应用程序中的数据具有类似文档的结构(即,一对多关系树,通常一次性加载整个树),那么使用文档模型可能是一个好主意</p>
<p>文档模型有一定的局限性:例如,不能直接引用文档中的嵌套的项目,而是需要说“用户251的位置列表中的第二项”(很像分层模型中的访问路径)</p>
<h3 id="文档模型的架构灵活性"><a href="#文档模型的架构灵活性" class="headerlink" title="文档模型的架构灵活性"></a>文档模型的架构灵活性</h3><p>大多数文档数据库以及关系数据库中的JSON支持都不会强制文档中的数据采用何种模式。关系数据库的XML支持通常带有可选的模式验证。没有模式意味着可以将任意的键和值添加到文档中,并且当读取时,客户端对无法保证文档可能包含的字段。</p>
<p>文档数据库有时称为<code>无模式(schemaless)</code>,但这具有误导性,因为读取数据的代码通常假定某种结构——即存在隐式模式,但不由数据库强制执行【20】。一个更精确的术语是<code>读时模式(schema-on-read)</code>(数据的结构是隐含的,只有在数据被读取时才被解释),相应的是<code>写时模式(schema-on-write)</code>(传统的关系数据库方法中,模式明确,且数据库确保所有的数据都符合其模式)。</p>
<p>大多数关系数据库系统可在几毫秒内执行ALTER TABLE语句。MySQL是一个值得注意的例外,它执行ALTER TABLE时会复制整个表,这可能意味着在更改一个大型表时会花费几分钟甚至几个小时的停机时间</p>
<p>大型表上运行UPDATE语句在任何数据库上都可能会很慢,因为每一行都需要重写。要是不可接受的话,应用程序可以将first_name设置为默认值NULL,并在读取时再填充,就像使用文档数据库一样。</p>
<h2 id="数据查询语言"><a href="#数据查询语言" class="headerlink" title="数据查询语言"></a>数据查询语言</h2><p>SQL是一种 <code>声明式</code> 查询语言,而IMS和CODASYL使用 <code>命令式</code> 代码来查询数据库。</p>
<p>命令式语言告诉计算机以特定顺序执行某些操作。可以想象一下,逐行地遍历代码,评估条件,更新变量,并决定是否再循环一遍。</p>
<p>在声明式查询语言(如SQL或关系代数)中,你只需指定所需数据的模式 - 结果必须符合哪些条件,以及如何将数据转换(例如,排序,分组和集合) - 但不是如何实现这一目标。</p>
<p>声明式语言更具有并行执行的潜力。</p>
<h3 id="MapReduce"><a href="#MapReduce" class="headerlink" title="MapReduce"></a>MapReduce</h3><p>map和reduce函数在功能上有所限制:它们必须是纯函数,这意味着它们只使用传递给它们的数据作为输入,它们不能执行额外的数据库查询,也不能有任何副作用。这些限制允许数据库以任何顺序运行任何功能,并在失败时重新运行它们。然而,map和reduce函数仍然是强大的:它们可以解析字符串,调用库函数,执行计算等等。</p>
<p>MapReduce是一个相当底层的编程模型,用于计算机集群上的分布式执行。像SQL这样的更高级的查询语言可以用一系列的MapReduce操作来实现(见第10章),但是也有很多不使用MapReduce的分布式SQL实现。请注意,SQL中没有任何内容限制它在单个机器上运行,而MapReduce在分布式查询执行上没有垄断权。</p>
<h2 id="图数据库"><a href="#图数据库" class="headerlink" title="图数据库"></a>图数据库</h2><p>图数据库用来处理多对多关系</p>
<p>一个图由两种对象组成:<code>顶点(vertices)</code>(也称为<code>节点(nodes)</code> 或<code>实体(entities)</code>),和<code>边(edges)</code>( 也称为<code>关系(relationships)</code>或<code>弧 (arcs)</code> )。多种数据可以被建模为一个图形。</p>
<h3 id="属性图"><a href="#属性图" class="headerlink" title="属性图"></a>属性图</h3><p>每个顶点(vertex)包括:</p>
<ul>
<li>唯一的标识符</li>
<li>一组 <code>出边(outgoing edges)</code></li>
<li>一组 <code>入边(ingoing edges)</code></li>
<li>一组属性(键值对)</li>
</ul>
<p>每条 边(edge) 包括:</p>
<ul>
<li>唯一标识符</li>
<li>边的起点/尾部顶点(tail vertex)</li>
<li>边的终点/头部顶点(head vertex)</li>
<li>描述两个顶点之间关系类型的标签</li>
<li>一组属性(键值对)</li>
</ul>
<h3 id="Cypher-查询语言"><a href="#Cypher-查询语言" class="headerlink" title="Cypher 查询语言"></a>Cypher 查询语言</h3><p>Cypher是属性图的声明式查询语言,为Neo4j图形数据库而发明</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">CREATE</span><br><span class="line"> (NAmerica:Location {name:'North America', type:'continent'}),</span><br><span class="line"> (USA:Location {name:'United States', type:'country' }),</span><br><span class="line"> (Idaho:Location {name:'Idaho', type:'state' }),</span><br><span class="line"> (Lucy:Person {name:'Lucy' }),</span><br><span class="line"> (Idaho) -[:WITHIN]-> (USA) -[:WITHIN]-> (NAmerica),</span><br><span class="line"> (Lucy) -[:BORN_IN]-> (Idaho)</span><br></pre></td></tr></table></figure>
<p>(Idaho) - [:WITHIN] ->(USA)创建一条标记为WITHIN的边,Idaho为尾节点,USA为头节点。</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">// 查找所有从美国移民到欧洲的人的Cypher查询</span><br><span class="line">MATCH</span><br><span class="line"> (person) -[:BORN_IN]-> () -[:WITHIN*0..]-> (us:Location {name:'United States'}),</span><br><span class="line"> (person) -[:LIVES_IN]-> () -[:WITHIN*0..]-> (eu:Location {name:'Europe'})</span><br><span class="line">RETURN person.name</span><br></pre></td></tr></table></figure>
<p>上面的例子的意思是,<br>找到满足以下两个条件的所有顶点(称之为person顶点):</p>
<ol>
<li><p>person顶点拥有一条到某个顶点的BORN_IN出边。从那个顶点开始,沿着一系列WITHIN出边最终到达一个类型为Location,name属性为United States的顶点。</p>
</li>
<li><p>person顶点还拥有一条LIVES_IN出边。沿着这条边,可以通过一系列WITHIN出边最终到达一个类型为Location,name属性为Europe的顶点。</p>
</li>
</ol>
<p>对于这样的Person顶点,返回其name属性。</p>
<h2 id="三元组存储和SPARQL"><a href="#三元组存储和SPARQL" class="headerlink" title="三元组存储和SPARQL"></a>三元组存储和SPARQL</h2><p>三元组存储中,所有信息都以非常简单的三部分表示形式存储(主语,谓语,宾语)。例如,三元组 (吉姆, 喜欢 ,香蕉) 中,吉姆 是主语,喜欢 是谓语(动词),香蕉 是对象。</p>
<ul>
<li>原始数据类型中的值,例如字符串或数字。在这种情况下,三元组的谓语和宾语相当于主语顶点上的属性的键和值。例如,(lucy, age, 33)就像属性{“age”:33}的顶点lucy。</li>
<li>图中的另一个顶点。在这种情况下,谓语是图中的一条边,主语是其尾部顶点,而宾语是其头部顶点。例如,在(lucy, marriedTo, alain)中主语和宾语lucy和alain都是顶点,并且谓语marriedTo是连接他们的边的标签。</li>
</ul>
<h3 id="RDF数据模型"><a href="#RDF数据模型" class="headerlink" title="RDF数据模型"></a>RDF数据模型</h3><h3 id="SPARQL查询语言"><a href="#SPARQL查询语言" class="headerlink" title="SPARQL查询语言"></a>SPARQL查询语言</h3><p>SPARQL是一种用于三元组存储的面向RDF数据模型的查询语言。</p>
<h3 id="Datalog"><a href="#Datalog" class="headerlink" title="Datalog"></a>Datalog</h3><p>Datalog是比SPARQL或Cypher更古老的语言</p>
<p>Datalog的数据模型类似于三元组模式,但进行了一点泛化。把三元组写成谓语(主语,宾语),而不是写三元语(主语,谓语,宾语)</p>
]]></content>
<categories>
<category>book</category>
<category>DDIA</category>
</categories>
<tags>
<tag>分布式</tag>
<tag>数据库</tag>
<tag>查询语言</tag>
</tags>
</entry>
<entry>
<title>[DDIA][第三章]:存储与检索</title>
<url>/post/2372247431.html</url>
<content><![CDATA[<h1 id="第三章"><a href="#第三章" class="headerlink" title="第三章"></a>第三章</h1><p>这里将会研究两大类存储引擎:<code>日志结构(log-structred)</code>的存储引擎,以及<code>面向页面(page-oriented)</code>的存储引擎(例如B树)。</p>
<h2 id="驱动数据库的数据结构"><a href="#驱动数据库的数据结构" class="headerlink" title="驱动数据库的数据结构"></a>驱动数据库的数据结构</h2><p>世界上最简单的数据库</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="function"><span class="title">db_set</span></span> () {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$1</span>,<span class="variable">$2</span>"</span> >> database</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">db_get</span></span> () {</span><br><span class="line"> grep <span class="string">"^<span class="variable">$1</span>,"</span> database | sed -e <span class="string">"s/^<span class="variable">$1</span>,//"</span> | tail -n 1</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>执行<code>db_set key value</code>,会将key和value存储在数据库中。<br>调用<code>db_get key</code>,查询该key关联的value</p>
<p>在文件尾部追加写入通常是非常高效的</p>
<p>如果该数据库中有大量的记录,那么<code>db_get</code>的效率会非常低,查找的开销为<code>O(n)</code>。所以为了提高查找效率增加了一个新的数据结构:<code>索引(index)</code>。</p>
<p>索引的大致思想就是:保存一些额外的元数据作为路标,帮助你找到想要的数据。</p>
<p>索引是从主数据衍生的<code>附加(additional)</code>结构。许多数据库允许添加与删除索引,这不会影响数据的内容,它只影响查询的性能。任何类型的索引通常都会减慢写入速度,因为每次写入数据时都需要更新索引。</p>
<p>这是存储系统中一个重要的权衡:<code>精心选择的索引加快了读查询的速度,但是每个索引都会拖慢写入速度</code>。因为这个原因,数据库默认并不会索引所有的内容,而需要你(程序员或DBA)通过对应用查询模式的了解来手动选择索引。</p>
<h3 id="哈希索引"><a href="#哈希索引" class="headerlink" title="哈希索引"></a>哈希索引</h3><p>最简单的索引策略就是:保留一个内存中的哈希映射,其中每个键都映射到一个数据文件中的字节偏移量,指明了可以找到对应值的位置</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-1.png" alt="3-1"></p>
<p><a href="https://github.com/basho/bitcask" target="_blank" rel="noopener">Bitcask</a>提供高性能的读取和写入操作,但所有键必须能放入可用内存中,因为哈希映射完全保留在内存中。这些值可以使用比可用内存更多的空间,因为可以从磁盘上通过一次seek加载所需部分,如果数据文件的那部分已经在文件系统缓存中,则读取根本不需要任何磁盘I/O。</p>
<p>避免最终用完磁盘空间:将日志分为特定大小的段,当日志增长到特定尺寸时关闭当前段文件,并开始写入一个新的段文件。然后,就可以对这些段进行<code>压缩(compaction)</code>压缩意味着在日志中丢弃重复的键,只保留每个键的最近更新。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-2.png" alt="3-2"></p>
<p>而且,由于压缩经常会使得段变得很小(假设在一个段内键被平均重写了好几次),也可以在执行压缩的同时将多个段合并在一起,冻结段的合并和压缩可以在后台线程中完成,在进行时,仍然可以继续使用旧的段文件来正常提供读写请求。合并过程完成后,我们将读取请求转换为使用新的合并段,然后可以删除旧的段文件。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-3.png" alt="3-3"></p>
<p>每个段现在都有自己的内存散列表,将键映射到文件偏移量。为了找到一个键的值,我们首先检查最近段的哈希映射;如果键不存在,我们检查第二个最近的段,依此类推。不过其中有一些问题:</p>
<h4 id="文件格式"><a href="#文件格式" class="headerlink" title="文件格式"></a>文件格式</h4><p>CSV不是日志的最佳格式。使用二进制格式更快,更简单,首先以字节为单位对字符串的长度进行编码,然后使用原始字符串(不需要转义)。</p>
<h4 id="删除记录"><a href="#删除记录" class="headerlink" title="删除记录"></a>删除记录</h4><p>如果要删除一个键及其关联的值,则必须在数据文件(有时称为逻辑删除)中附加一个特殊的删除记录。当日志段被合并时,逻辑删除告诉合并过程放弃删除键的任何以前的值。</p>
<h4 id="崩溃记录"><a href="#崩溃记录" class="headerlink" title="崩溃记录"></a>崩溃记录</h4><p>如果数据库重新启动,则内存散列映射将丢失。原则上,您可以通过从头到尾读取整个段文件并在每次按键时注意每个键的最近值的偏移量来恢复每个段的哈希映射。但是,如果段文件很大,这可能需要很长时间,这将使服务器重新启动痛苦。 Bitcask通过存储加速恢复磁盘上每个段的哈希映射的快照,可以更快地加载到内存中。</p>
<h4 id="部分写入记录"><a href="#部分写入记录" class="headerlink" title="部分写入记录"></a>部分写入记录</h4><p>数据库可能随时崩溃,包括将记录附加到日志中途。 Bitcask文件包含校验和,允许检测和忽略日志的这些损坏部分。</p>
<h4 id="并发控制"><a href="#并发控制" class="headerlink" title="并发控制"></a>并发控制</h4><p>由于写操作是以严格顺序的顺序附加到日志中的,所以常见的实现选择是只有一个写入器线程。数据文件段是附加的,或者是不可变的,所以它们可以被多个线程同时读取。</p>
<p>乍一看,只有追加日志看起来很浪费:为什么不更新文件,用新值覆盖旧值?但是只能追加设计的原因有几个:</p>
<ul>
<li>追加和分段合并是顺序写入操作,通常比随机写入快得多,尤其是在磁盘旋转硬盘上。在某种程度上,顺序写入在基于闪存的 固态硬盘(SSD) 上也是优选的</li>
<li>如果段文件是附加的或不可变的,并发和崩溃恢复就简单多了。例如,您不必担心在覆盖值时发生崩溃的情况,而将包含旧值和新值的一部分的文件保留在一起。</li>
<li>合并旧段可以避免数据文件随着时间的推移而分散的问题。</li>
</ul>
<p>但是,哈希表索引也有局限性:</p>
<ul>
<li>散列表必须能放进内存</li>
<li>如果你有非常多的键,那真是倒霉。原则上可以在磁盘上保留一个哈希映射,不幸的是磁盘哈希映射很难表现优秀。它需要大量的随机访问I/O,当它变满时增长是很昂贵的,并且散列冲突需要很多的逻辑。</li>
<li>范围查询效率不高。例如,无法轻松扫描kitty00000和kitty99999之间的所有键——您必须在散列映射中单独查找每个键。</li>
</ul>
<h3 id="SSTables和LSM树"><a href="#SSTables和LSM树" class="headerlink" title="SSTables和LSM树"></a>SSTables和LSM树</h3><p>之前的<code>Bitcask</code>之类的,每个日志结构存储段都是一系列键值对。这些对按照它们写入的顺序出现,日志中稍后的值优先于日志中较早的相同键的值。除此之外,文件中键值对的顺序并不重要。</p>
<p>SSTable,排序字符串表(Sorted String Table):键值对的序列按键排序</p>
<p>LSM树,日志结构合并树(Log-Structured Merge-Tree)</p>
<p>SSTables优势:</p>
<ul>
<li><p>合并段是简单而高效的,即使文件大于可用内存。这种方法就像归并排序算法中使用的方法一样,并排读取输入文件,查看每个文件中的第一个键,复制最低键(根据排序顺序)到输出文件,并重复。这产生一个新的合并段文件,也按键排序。<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-4.png" alt="3-4"><br>当多个段包含相同的键时,我们可以保留最近段的值,并丢弃旧段中的值。</p>
</li>
<li><p>为了在文件中找到一个特定的键,你不再需要保存内存中所有键的索引。假设你正在内存中寻找键 handiwork,但是你不知道段文件中该关键字的确切偏移量。然而,你知道 handbag 和 handsome 的偏移,而且由于排序特性,你知道 handiwork 必须出现在这两者之间。这意味着您可以跳到 handbag 的偏移位置并从那里扫描,直到您找到 handiwork(或没找到,如果该文件中没有该键)。<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-5.png" alt=""><br>仍然需要一个内存中索引来告诉您一些键的偏移量,但它可能很稀疏:每几千字节的段文件就有一个键就足够了,因为几千字节可以很快被扫描。</p>
</li>
<li><p>由于读取请求无论如何都需要扫描所请求范围内的多个键值对,因此可以将这些记录分组到块中,并在将其写入磁盘之前对其进行压缩(如上图阴影)。稀疏内存中索引的每个条目都指向压缩块的开始处。除了节省磁盘空间之外,压缩还可以减少IO带宽的使用。</p>
</li>
</ul>
<h3 id="构建和维护SSTables"><a href="#构建和维护SSTables" class="headerlink" title="构建和维护SSTables"></a>构建和维护SSTables</h3><p>如何让数据首先被按键排序?</p>
<p>可以使用红黑树或AVL树等,可以以任何顺序插入键,并按照排序顺序读取他们。</p>
<p>当前存储引擎工作方式:</p>
<ul>
<li>写入时,将其添加到内存中的平衡树数据结构(例如,红黑树)。这个内存树有时被称为内存表(memtable)。</li>
<li>当内存表大于某个阈值(通常为几兆字节)时,将其作为SSTable文件写入磁盘。这可以高效地完成,因为树已经维护了按键排序的键值对。新的SSTable文件成为数据库的最新部分。当SSTable被写入磁盘时,写入可以继续到一个新的内存表实例。</li>
<li>为了提供读取请求,首先尝试在内存表中找到关键字,然后在最近的磁盘段中,然后在下一个较旧的段中找到该关键字。</li>
<li>有时会在后台运行合并和压缩过程以组合段文件并丢弃覆盖或删除的值。</li>
</ul>
<p>但是,如果数据库崩溃,则最近的写入(在内存表中,但尚未写入磁盘)将丢失。</p>
<p>我们可以在磁盘上保存一个单独的日志,每个写入都会立即被附加到磁盘上,就像在前一节中一样。该日志不是按排序顺序,但这并不重要,因为它的唯一目的是在崩溃后恢复内存表。每当内存表写出到SSTable时,相应的日志都可以被丢弃。</p>
<h3 id="使用SSTables生成LSM树"><a href="#使用SSTables生成LSM树" class="headerlink" title="使用SSTables生成LSM树"></a>使用SSTables生成LSM树</h3><p>这里描述的算法本质上是LevelDB和RocksDB中使用的关键值存储引擎库,被设计嵌入到其他应用程序中。除此之外,LevelDB可以在Riak中用作Bitcask的替代品。在Cassandra和HBase中使用了类似的存储引擎,这两种引擎都受到了Google的Bigtable文档(引入了SSTable和memtable)的启发。</p>
<p>最初这种索引结构是由Patrick O’Neil等人描述的。在日志结构合并树(或LSM树)的基础上,建立在以前的工作上日志结构的文件系统。基于这种合并和压缩排序文件原理的存储引擎通常被称为LSM存储引擎。</p>
<p>Lucene是Elasticsearch和Solr使用的一种全文搜索的索引引擎,它使用类似的方法来存储它的词典。全文索引比键值索引复杂得多,但是基于类似的想法:在搜索查询中给出一个单词,找到提及单词的所有文档(网页,产品描述等)。这是通过键值结构实现的,其中键是单词(关键词(term)),值是包含单词(文章列表)的所有文档的ID的列表。在Lucene中,从术语到发布列表的这种映射保存在SSTable类的有序文件中,根据需要在后台合并。</p>
<h3 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h3><p>与往常一样,大量的细节使得存储引擎在实践中表现良好。例如,当查找数据库中不存在的键时,LSM树算法可能会很慢:您必须检查内存表,然后将这些段一直回到最老的(可能必须从磁盘读取每一个),然后才能确定键不存在。为了优化这种访问,存储引擎通常使用额外的<code>Bloom过滤器</code>。 (布隆过滤器是用于近似集合内容的内存高效数据结构,它可以告诉您数据库中是否出现键,从而为不存在的键节省许多不必要的磁盘读取操作。</p>
<p>还有不同的策略来确定SSTables如何被压缩和合并的顺序和时间。最常见的选择是大小分层压实。 LevelDB和RocksDB使用平坦压缩(LevelDB因此得名),HBase使用大小分层,Cassandra同时支持。在规模级别的调整中,更新和更小的SSTables先后被合并到更老的和更大的SSTable中。在水平压实中,关键范围被拆分成更小的SSTables,而较旧的数据被移动到单独的“水平”,这使得压缩能够更加递增地进行,并且使用更少的磁盘空间。</p>
<p><code>LSM树的基本思想</code>:保存一系列在后台合并的SSTables。即使数据集比可用内存大得多,它仍能继续正常工作。由于数据按排序顺序存储,因此可以高效地执行范围查询(扫描所有高于某些最小值和最高值的所有键),并且因为磁盘写入是连续的,所以LSM树可以支持非常高的写入吞吐量。</p>
<h2 id="B树"><a href="#B树" class="headerlink" title="B树"></a>B树</h2><p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-6.png" alt=""></p>
<p>一个页面会被指定为B树的根;在索引中查找一个键时,就从这里开始。该页面包含几个键和对子页面的引用。每个子页面负责一段连续范围的键,引用之间的键,指明了引用子页面的键范围。</p>
<p>在图3-6的例子中,我们正在寻找关键字 251 ,所以我们知道我们需要遵循边界 200 和 300 之间的页面引用。这将我们带到一个类似的页面,进一步打破了200 - 300到子范围。</p>
<p>最后,我们可以看到包含单个键(叶页)的页面,该页面包含每个键的内联值,或者包含对可以找到值的页面的引用。</p>
<p>在B树的一个页面中对子页面的引用的数量称为分支因子。例如,在图3-6中,分支因子是 6 。在实践中,分支因子取决于存储页面参考和范围边界所需的空间量,但通常是几百个。</p>
<p>如果要更新B树中现有键的值,则搜索包含该键的叶页,更改该页中的值,并将该页写回到磁盘(对该页的任何引用保持有效) 。如果你想添加一个新的键,你需要找到其范围包含新键的页面,并将其添加到该页面。如果页面中没有足够的可用空间容纳新键,则将其分成两个半满页面,并更新父页面以解释键范围的新分区</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-7.png" alt=""></p>
<p>该算法确保树保持平衡:具有 n 个键的B树总是具有 $O(log n)$ 的深度。大多数数据库可以放入一个三到四层的B树,所以你不需要遵追踪多页面引用来找到你正在查找的页面。 (分支因子为 500 的 4KB 页面的四级树可以存储多达 256TB 。)</p>
<h3 id="让B树更可靠"><a href="#让B树更可靠" class="headerlink" title="让B树更可靠"></a>让B树更可靠</h3><p>B树的基本底层写操作是用新数据覆盖磁盘上的页面。假定覆盖不改变页面的位置;即,当页面被覆盖时,对该页面的所有引用保持完整。这与日志结构索引(如LSM树)形成鲜明对比,后者只附加到文件(并最终删除过时的文件),但从不修改文件。</p>
<p>B树实现通常会带有一个额外的磁盘数据结构:<code>预写式日志(WAL, write-ahead-log)</code>(也称为重做日志(redo log))。这是一个仅追加的文件,每个B树修改都可以应用到树本身的页面上。当数据库在崩溃后恢复时,这个日志被用来使B树恢复到一致的状态</p>
<p>更新页面的一个额外的复杂情况是,如果多个线程要同时访问B树,则需要仔细的并发控制 —— 否则线程可能会看到树处于不一致的状态。这通常通过使用<code>锁存器(latches)</code>(轻量级锁)保护树的数据结构来完成。日志结构化的方法在这方面更简单,因为它们在后台进行所有的合并,而不会干扰传入的查询,并且不时地将旧的分段原子交换为新的分段。</p>
<h3 id="B树优化"><a href="#B树优化" class="headerlink" title="B树优化"></a>B树优化</h3><ul>
<li>写时复制</li>
<li>不存储整个键</li>
<li>布局树</li>
<li>队兄弟页面的引用</li>
<li>分形树</li>
</ul>
<h2 id="B树与LSM树优缺点比较"><a href="#B树与LSM树优缺点比较" class="headerlink" title="B树与LSM树优缺点比较"></a>B树与LSM树优缺点比较</h2><h3 id="LSM树优点"><a href="#LSM树优点" class="headerlink" title="LSM树优点"></a>LSM树优点</h3><p>B树索引必须至少两次写入每一段数据:一次写入预先写入日志,一次写入树页面本身(也许再次分页)。即使在该页面中只有几个字节发生了变化,也需要一次编写整个页面的开销。有些存储引擎甚至会覆盖同一个页面两次,以免在电源故障的情况下导致页面部分更新。</p>
<p>由于反复压缩和合并SSTables,日志结构索引也会重写数据。这种影响在数据库的生命周期中写入数据库导致对磁盘的多次写入被称为写放大(write amplification)。需要特别注意的是固态硬盘,固态硬盘的闪存寿命在覆写有限次数后就会耗尽。</p>
<p>在写入繁重的应用程序中,性能瓶颈可能是数据库可以写入磁盘的速度。在这种情况下,写放大会导致直接的性能代价:存储引擎写入磁盘的次数越多,可用磁盘带宽内的每秒写入次数越少。</p>
<p>而且,LSM树通常能够比B树支持更高的写入吞吐量,部分原因是它们有时具有较低的写放大(尽管这取决于存储引擎配置和工作负载),部分是因为它们顺序地写入紧凑的SSTable文件而不是必须覆盖树中的几个页面。这种差异在磁性硬盘驱动器上尤其重要,顺序写入比随机写入快得多。</p>
<p>LSM树可以被压缩得更好,因此经常比B树在磁盘上产生更小的文件。 B树存储引擎会由于分割而留下一些未使用的磁盘空间:当页面被拆分或某行不能放入现有页面时,页面中的某些空间仍未被使用。由于LSM树不是面向页面的,并且定期重写SSTables以去除碎片,所以它们具有较低的存储开销,特别是当使用平坦压缩时。</p>
<p>在许多固态硬盘上,固件内部使用日志结构化算法,将随机写入转变为顺序写入底层存储芯片,因此存储引擎写入模式的影响不太明显。但是,较低的写入放大率和减少的碎片对SSD仍然有利:更紧凑地表示数据可在可用的I/O带宽内提供更多的读取和写入请求。</p>
<h3 id="LSM缺点"><a href="#LSM缺点" class="headerlink" title="LSM缺点"></a>LSM缺点</h3><p>日志结构存储的缺点是压缩过程有时会干扰正在进行的读写操作。尽管存储引擎尝试逐步执行压缩而不影响并发访问,但是磁盘资源有限,所以很容易发生请求需要等待而磁盘完成昂贵的压缩操作。对吞吐量和平均响应时间的影响通常很小,但是在更高百分比的情况下(参阅“描述性能”),对日志结构化存储引擎的查询响应时间有时会相当长,而B树的行为则相对更具可预测性。</p>
<p>压缩的另一个问题出现在高写入吞吐量:磁盘的有限写入带宽需要在初始写入(记录和刷新内存表到磁盘)和在后台运行的压缩线程之间共享。写入空数据库时,可以使用全磁盘带宽进行初始写入,但数据库越大,压缩所需的磁盘带宽就越多。</p>
<p>如果写入吞吐量很高,并且压缩没有仔细配置,压缩跟不上写入速率。在这种情况下,磁盘上未合并段的数量不断增加,直到磁盘空间用完,读取速度也会减慢,因为它们需要检查更多段文件。通常情况下,即使压缩无法跟上,基于SSTable的存储引擎也不会限制传入写入的速率,所以您需要进行明确的监控来检测这种情况。</p>
<p>B树的一个优点是每个键只存在于索引中的一个位置,而日志结构化的存储引擎可能在不同的段中有相同键的多个副本。这个方面使得B树在想要提供强大的事务语义的数据库中很有吸引力:在许多关系数据库中,事务隔离是通过在键范围上使用锁来实现的,在B树索引中,这些锁可以直接连接到树。</p>
<hr>
<h2 id="事务处理还是分析?"><a href="#事务处理还是分析?" class="headerlink" title="事务处理还是分析?"></a>事务处理还是分析?</h2><p>在线事务处理(OLTP,Online Transcation Processing)。</p>
<p>在线分析处理(OLAP,Online Analytice Processing)。</p>
<div class="table-container">
<table>
<thead>
<tr>
<th>属性</th>
<th>事务处理 OLTP</th>
<th>分析系统 OLAP</th>
</tr>
</thead>
<tbody>
<tr>
<td>主要读取模式</td>
<td>查询少量记录,按键读取</td>
<td>在大批量记录上聚合</td>
</tr>
<tr>
<td>主要写入模式</td>
<td>随机访问,写入要求低延时</td>
<td>批量导入(ETL),事件流</td>
</tr>
<tr>
<td>主要用户</td>
<td>终端用户,通过Web应用</td>
<td>内部数据分析师,决策支持</td>
</tr>
<tr>
<td>处理的数据</td>
<td>数据的最新状态(当前时间点)</td>
<td>随时间推移的历史事件</td>
</tr>
<tr>
<td>数据集尺寸</td>
<td>GB ~ TB</td>
<td>TB ~ PB</td>
</tr>
</tbody>
</table>
</div>
<p><code>数据仓库</code>:用作数据分析</p>
<p>从OLTP数据库中提取数据(使用定期的数据转储或连续的更新流),转换成适合分析的模式,清理并加载到数据仓库中。将数据存入仓库的过程称为<code>抽取-转换-加载(ETL)</code><br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-8.png" alt=""></p>
<h3 id="OLTP数据库和数据仓库之间的分歧"><a href="#OLTP数据库和数据仓库之间的分歧" class="headerlink" title="OLTP数据库和数据仓库之间的分歧"></a>OLTP数据库和数据仓库之间的分歧</h3><p>表面上,一个数据仓库和一个关系OLTP数据库看起来很相似,因为它们都有一个SQL查询接口。然而,系统的内部看起来可能完全不同,因为它们针对非常不同的查询模式进行了优化。现在许多数据库供应商都将重点放在支持事务处理或分析工作负载上,而不是两者都支持。</p>
<h2 id="列存储"><a href="#列存储" class="headerlink" title="列存储"></a>列存储</h2><p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-10.png" alt=""></p>
<h2 id="列压缩"><a href="#列压缩" class="headerlink" title="列压缩"></a>列压缩</h2><p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-11.png" alt=""></p>
<h2 id="数据立方体"><a href="#数据立方体" class="headerlink" title="数据立方体"></a>数据立方体</h2><p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch3-3-12.png" alt=""></p>
]]></content>
<categories>
<category>book</category>
<category>DDIA</category>
</categories>
<tags>
<tag>存储</tag>
<tag>检索</tag>
</tags>
</entry>
<entry>
<title>[DDIA][第四章]:编码与演化</title>
<url>/post/1123594605.html</url>
<content><![CDATA[<h1 id="第四章"><a href="#第四章" class="headerlink" title="第四章"></a>第四章</h1><p>当数据格式(format)或模式(schema)发生变化时,通常需要对应用程序代码进行相应的更改(例如,为记录添加新字段,然后修改程序开始读写该字段)。但在大型应用程序中,代码变更通常不会立即完成。</p>
<p>这意味着,新旧版本的代码,以及新旧数据格式可能会在系统中同时共处。系统想要继续顺利运行,就需要保持<code>双向兼容性</code>:</p>
<p><em>向后兼容 (backward compatibility)</em></p>
<p> 新代码可以读旧数据。</p>
<p><em>向前兼容 (forward compatibility)</em></p>
<p> 旧代码可以读新数据。</p>
<p>本章中将介绍几种编码数据的格式,包括 JSON,XML,Protocol Buffers,Thrift和Avro。然后将讨论如何使用这些格式进行数据存储和通信:在Web服务中,<code>具象状态传输(REST)</code>和<code>远程过程调用(RPC)</code>,以及<code>消息传递系统</code>(如Actor和消息队列)。</p>
<h2 id="编码数据的格式"><a href="#编码数据的格式" class="headerlink" title="编码数据的格式"></a>编码数据的格式</h2><p>如果要将数据写入文件,或通过网络发送,则必须将其 编码(encode) 为某种自包含的字节序列(例如,JSON文档)</p>
<p>从内存中表示到字节序列的转换称为 <code>编码(Encoding)</code> (也称为<code>序列化(serialization)</code>或<code>编组(marshalling)</code>),反过来称为<code>解码(Decoding)</code>(解析(Parsing),<code>反序列化(deserialization)</code>,<code>反编组( unmarshalling)</code>)</p>
<p>许多编程语言都内建了将内存对象编码为字节序列的支持:<br>Java有<code>java.io.Serializable</code> ,Ruby有<code>Marshal</code>,Python有<code>pickle</code>等等。</p>
<h3 id="JSON,XML和二进制变体"><a href="#JSON,XML和二进制变体" class="headerlink" title="JSON,XML和二进制变体"></a>JSON,XML和二进制变体</h3><ul>
<li>数字的编码多有歧义之处。XML和CSV不能区分数字和字符串(除非引用外部模式)。 JSON虽然区分字符串和数字,但不区分整数和浮点数,而且不能指定精度。</li>
<li>当处理大量数据时,这个问题更严重了。例如,大于$2^{53}$的整数不能在IEEE 754双精度浮点数中精确表示,因此在使用浮点数(例如JavaScript)的语言进行分析时,这些数字会变得不准确。 Twitter上有一个大于$2^{53}$的数字的例子,它使用一个64位的数字来标识每条推文。 Twitter API返回的JSON包含了两种推特ID,一个JSON数字,另一个是十进制字符串,以此避免JavaScript程序无法正确解析数字的问题。</li>
<li>JSON和XML对Unicode字符串(即人类可读的文本)有很好的支持,但是它们不支持二进制数据(不带字符编码(character encoding)的字节序列)。二进制串是很实用的功能,所以人们通过使用Base64将二进制数据编码为文本来绕开这个限制。模式然后用于表示该值应该被解释为Base64编码。这个工作,但它有点hacky,并增加了33%的数据大小。 XML和JSON都有可选的模式支持。这些模式语言相当强大,所以学习和实现起来相当复杂。 XML模式的使用相当普遍,但许多基于JSON的工具嫌麻烦才不会使用模式。由于数据的正确解释(例如数字和二进制字符串)取决于模式中的信息,因此不使用XML/JSON模式的应用程序可能需要对相应的编码/解码逻辑进行硬编码。</li>
<li>CSV没有任何模式,因此应用程序需要定义每行和每列的含义。如果应用程序更改添加新的行或列,则必须手动处理该变更。 CSV也是一个相当模糊的格式(如果一个值包含逗号或换行符,会发生什么?)。尽管其转义规则已经被正式指定,但并不是所有的解析器都正确的实现了标准。</li>
</ul>
<h3 id="二进制编码"><a href="#二进制编码" class="headerlink" title="二进制编码"></a>二进制编码</h3><p>JSON比XML简洁,但与二进制格式一比,还是太占地方。这一事实导致大量二进制编码版本JSON & XML的出现,JSON(MessagePack,BSON,BJSON,UBJSON,BISON和Smile等)(例如WBXML和Fast Infoset)。这些格式已经被各种各样的领域所采用,但是没有一个像JSON和XML的文本版本那样被广泛采用。</p>
<p>81个字节<br><figure class="highlight json"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"userName"</span>: <span class="string">"Martin"</span>,</span><br><span class="line"> <span class="attr">"favoriteNumber"</span>: <span class="number">1337</span>,</span><br><span class="line"> <span class="attr">"interests"</span>: [<span class="string">"daydreaming"</span>, <span class="string">"hacking"</span>]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>66个字节<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-1.png" alt=""></p>
<ol>
<li>第一个字节0x83表示接下来是3个字段(低四位=<code>0x03</code>)的对象 object(高四位=<code>0x80</code>)。 (如果想知道如果一个对象有15个以上的字段会发生什么情况,字段的数量塞不进4个bit里,那么它会用另一个不同的类型标识符,字段的数量被编码两个或四个字节)。</li>
<li>第二个字节<code>0xa8</code>表示接下来是8字节长的字符串(最高四位=<code>0x08</code>)。</li>
<li>接下来八个字节是ASCII字符串形式的字段名称userName。由于之前已经指明长度,不需要任何标记来标识字符串的结束位置(或者任何转义)。</li>
<li>接下来的七个字节对前缀为0xa6的六个字母的字符串值Martin进行编码,依此类推。</li>
</ol>
<h3 id="Thrift与Protocol-Buffers"><a href="#Thrift与Protocol-Buffers" class="headerlink" title="Thrift与Protocol Buffers"></a>Thrift与Protocol Buffers</h3><p>接口定义语言(IDL)</p>
<p><em>Thrift</em><br><figure class="highlight thrift"><table><tr><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Person</span> </span>{</span><br><span class="line"> <span class="number">1</span>: <span class="keyword">required</span> <span class="built_in">string</span> userName,</span><br><span class="line"> <span class="number">2</span>: <span class="keyword">optional</span> <span class="built_in">i64</span> favoriteNumber,</span><br><span class="line"> <span class="number">3</span>: <span class="keyword">optional</span> list<<span class="keyword">string</span>> interests</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p><em>Protocol Buffers</em><br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">message Person {</span><br><span class="line"> required string user_name = 1;</span><br><span class="line"> optional int64 favorite_number = 2;</span><br><span class="line"> repeated string interests = 3;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>Thrift有两种不同的二进制编码格式,分别称为BinaryProtocol和CompactProtocol</p>
<p>59个字节<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-2.png" alt=""></p>
<p>与上面相比,最大的区别是没有字段名(userName, favoriteNumber, interest)。相反,编码数据包含字段标签,它们是数字(1, 2和3)。这些是模式定义中出现的数字</p>
<p>34个字节<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-3.png" alt=""></p>
<p>数字1337不是使用全部八个字节,而是用两个字节编码,每个字节的最高位用来指示是否还有更多的字节来</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-4.png" alt=""></p>
<h3 id="字段标签和模式演变"><a href="#字段标签和模式演变" class="headerlink" title="字段标签和模式演变"></a>字段标签和模式演变</h3><p>每个字段由其标签号码(样本模式中的数字1,2,3)标识,并用数据类型(例如字符串或整数)注释。如果没有设置字段值,则简单地从编码记录中省略。从中可以看到,字段标记对编码数据的含义至关重要。可以更改架构中字段的名称,因为编码的数据永远不会引用字段名称,但不能更改字段的标记,因为这会使所有现有的编码数据无效。</p>
<p>您可以添加新的字段到架构,只要您给每个字段一个新的标签号码。如果旧的代码(不知道你添加的新的标签号码)试图读取新代码写入的数据,包括一个新的字段,其标签号码不能识别,它可以简单地忽略该字段。数据类型注释允许解析器确定需要跳过的字节数。这保持了前向兼容性:旧代码可以读取由新代码编写的记录。</p>
<p>向后兼容性呢?只要每个字段都有一个唯一的标签号码,新的代码总是可以读取旧的数据,因为标签号码仍然具有相同的含义。唯一的细节是,如果你添加一个新的领域,你不能要求,如果您要添加一个字段并将其设置为必需,那么如果新代码读取旧代码写入的数据,则该检查将失败,因为旧代码不会写入您添加的新字段。因此,为了保持向后兼容性,在模式的初始部署之后 <code>添加的每个字段必须是可选的或具有默认值</code>。</p>
<h3 id="数据类型和模式演变"><a href="#数据类型和模式演变" class="headerlink" title="数据类型和模式演变"></a>数据类型和模式演变</h3><p>Protobuf的一个奇怪的细节是,它没有列表或数组数据类型,而是有一个字段的重复标记,读取旧数据的新代码会看到一个包含零个或一个元素的列表(取决于该字段是否存在)。读取新数据的旧代码只能看到列表的最后一个元素。</p>
<p>Thrift有一个专用的列表数据类型,它使用列表元素的数据类型进行参数化。这不允许Protocol Buffers所做的从单值到多值的相同演变,但是它具有支持嵌套列表的优点。</p>
<h3 id="Avro"><a href="#Avro" class="headerlink" title="Avro"></a>Avro</h3><p>IDL</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">record Person {</span><br><span class="line"> string userName;</span><br><span class="line"> union { null, long } favoriteNumber = null;</span><br><span class="line"> array<string> interests;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>等价的JSON</p>
<figure class="highlight json"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"record"</span>,</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Person"</span>,</span><br><span class="line"> <span class="attr">"fields"</span>: [</span><br><span class="line"> {<span class="attr">"name"</span>: <span class="string">"userName"</span>, <span class="attr">"type"</span>: <span class="string">"string"</span>},</span><br><span class="line"> {<span class="attr">"name"</span>: <span class="string">"favoriteNumber"</span>, <span class="attr">"type"</span>: [<span class="string">"null"</span>, <span class="string">"long"</span>], <span class="attr">"default"</span>: <span class="literal">null</span>},</span><br><span class="line"> {<span class="attr">"name"</span>: <span class="string">"interests"</span>, <span class="attr">"type"</span>: {<span class="attr">"type"</span>: <span class="string">"array"</span>, <span class="attr">"items"</span>: <span class="string">"string"</span>}</span><br><span class="line"> ] </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>32个字节<br><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-5.png" alt=""></p>
<p>整数使用可变长度编码(与Thrift的CompactProtocol相同)进行编码。</p>
<p>为了解析二进制数据,您按照它们出现在架构中的顺序遍历这些字段,并使用架构来告诉每个字段的数据类型。这意味着如果读取数据的代码使用与写入数据的代码完全相同的模式,则只能正确解码二进制数据。读者和作者之间的模式不匹配意味着错误地解码数据。</p>
<h3 id="作者模式与读者模式"><a href="#作者模式与读者模式" class="headerlink" title="作者模式与读者模式"></a>作者模式与读者模式</h3><p>当应用程序想要编码一些数据(将其写入文件或数据库,通过网络发送等)时,它使用它知道的任何版本的模式编码数据,例如,架构可能被编译到应用程序中。这被称为作者的模式。</p>
<p>当一个应用程序想要解码一些数据(从一个文件或数据库读取数据,从网络接收数据等)时,它希望数据在某个模式中,这就是读者的模式。</p>
<p>Avro的关键思想是作者的模式和读者的模式不必是相同的 - 他们只需要兼容。当数据解码(读取)时,Avro库通过并排查看作者的模式和读者的模式并将数据从作者的模式转换到读者的模式来解决差异。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-6.png" alt=""></p>
<h3 id="模式演变规则"><a href="#模式演变规则" class="headerlink" title="模式演变规则"></a>模式演变规则</h3><p>为了保持兼容性,您只能添加或删除具有默认值的字段。</p>
<p>如果要允许一个字段为null,则必须使用联合类型。例如,union {null,long,string}字段;表示该字段可以是数字或字符串,也可以是null。如果它是union的分支之一,那么只能使用null作为默认值。这比默认情况下可以为null是更加冗长的,但是通过明确什么可以和不可以是什么,有助于防止错误的null</p>
<p>只要Avro可以转换类型,就可以改变字段的数据类型。更改字段的名称是可能的,但有点棘手:读者的模式可以包含字段名称的别名,所以它可以匹配旧作家的模式字段名称与别名。这意味着更改字段名称是向后兼容的,但不能向前兼容。同样,向联合类型添加分支也是向后兼容的,但不能向前兼容。</p>
<h3 id="动态生成的模式"><a href="#动态生成的模式" class="headerlink" title="动态生成的模式"></a>动态生成的模式</h3><p>Avro方法的一个优点是架构不包含任何标签号码。</p>
<p>如果数据库模式发生变化(例如,一个表中添加了一列,删除了一列),则可以从更新的数据库模式生成新的Avro模式,并在新的Avro模式中导出数据。数据导出过程不需要注意模式的改变 - 每次运行时都可以简单地进行模式转换。</p>
<p>使用Thrift或Protocol Buffers,则字段标记可能必须手动分配:每次数据库模式更改时,管理员都必须手动更新从数据库列名到字段标签。</p>
<h3 id="模式的优点"><a href="#模式的优点" class="headerlink" title="模式的优点"></a>模式的优点</h3><p>Protocol Buffers,Thrift和Avro都使用模式来描述二进制编码格式。他们的模式语言比XML模式或者JSON模式简单得多,它支持更详细的验证规则。</p>
<p>所以,我们可以看到,尽管JSON,XML和CSV等文本数据格式非常普遍,但基于模式的二进制编码也是一个可行的选择。他们有一些很好的属性:</p>
<ul>
<li>它们可以比各种“二进制JSON”变体更紧凑,因为它们可以省略编码数据中的字段名称。</li>
<li>模式是一种有价值的文档形式,因为模式是解码所必需的,所以可以确定它是最新的(而手动维护的文档可能很容易偏离现实)。</li>
<li>保留模式数据库允许您在部署任何内容之前检查模式更改的向前和向后兼容性。</li>
<li>对于静态类型编程语言的用户来说,从模式生成代码的能力是有用的,因为它可以在编译时进行类型检查。<br>总而言之,模式进化允许与JSON数据库提供的无模式/模式读取相同的灵活性,同时还可以更好地保证数据和更好的工具。</li>
</ul>
<h2 id="数据流的类型"><a href="#数据流的类型" class="headerlink" title="数据流的类型"></a>数据流的类型</h2><p>如果将数据库值解码为应用程序中的模型对象,稍后重新编码这些模型对象,那么未知字段可能会在该翻译过程中丢失。</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/DDIA-ch4-4-7.png" alt=""></p>
<h3 id="REST与RPC"><a href="#REST与RPC" class="headerlink" title="REST与RPC"></a>REST与RPC</h3><p>服务器本身可以是另一个服务的客户端(例如,典型的Web应用服务器充当数据库的客户端)。这种方法通常用于将大型应用程序按照功能区域分解为较小的服务,这样当一个服务需要来自另一个服务的某些功能或数据时,就会向另一个服务发出请求。这种构建应用程序的方式传统上被称为 <code>面向服务的体系结构(service-oriented architecture,SOA)</code> ,最近被改进和更名为 <code>微服务架构</code>。</p>
<h4 id="Web服务"><a href="#Web服务" class="headerlink" title="Web服务"></a>Web服务</h4><p>当服务使用HTTP作为底层通信协议时,可称之为Web服务。</p>
<p>有两种流行的Web服务方法:REST和SOAP。他们在哲学方面几乎是截然相反的,往往是各自支持者之间的激烈辩论。</p>
<p>REST不是一个协议,而是一个基于HTTP原则的设计哲学。它强调简单的数据格式,使用URL来标识资源,并使用HTTP功能进行缓存控制,身份验证和内容类型协商。与SOAP相比,REST已经越来越受欢迎,至少在跨组织服务集成的背景下,并经常与微服务相关。根据REST原则设计的API称为RESTful。</p>
<p>SOAP是用于制作网络API请求的基于XML的协议( 尽管首字母缩写词相似,SOAP并不是SOA的要求。 SOAP是一种特殊的技术,而SOA是构建系统的一般方法。)。虽然它最常用于HTTP,但其目的是独立于HTTP,并避免使用大多数HTTP功能。相反,它带有庞大而复杂的多种相关标准(Web服务框架,称为WS-*),它们增加了各种功能。</p>
<p>SOAP Web服务的API使用称为Web服务描述语言(WSDL)的基于XML的语言来描述。 WSDL支持代码生成,客户端可以使用本地类和方法调用(编码为XML消息并由框架再次解码)访问远程服务。这在静态类型编程语言中非常有用,但在动态类型编程语言中很少。</p>
<p>由于WSDL的设计不是人类可读的,而且由于SOAP消息通常是手动构建的过于复杂,所以SOAP的用户在很大程度上依赖于工具支持,代码生成和IDE。</p>
<h4 id="RPC"><a href="#RPC" class="headerlink" title="RPC"></a>RPC</h4><p>Enterprise JavaBeans(EJB)和Java的<code>远程方法调用(RMI)</code>仅限于Java。<code>分布式组件对象模型(DCOM)</code>仅限于Microsoft平台。<code>公共对象请求代理体系结构(CORBA)</code>过于复杂,不提供前向或后向兼容性。<br>所有这些都是基于 远程过程调用(RPC) 的思想,网络请求与本地函数调用非常不同:</p>
<ul>
<li>本地函数调用是可预测的,并且成功或失败,这仅取决于受您控制的参数。网络请求是不可预知的:由于网络问题,请求或响应可能会丢失,或者远程计算机可能很慢或不可用,这些问题完全不在您的控制范围之内。网络问题是常见的,所以你必须预测他们,例如通过重试失败的请求。</li>
<li>本地函数调用要么返回结果,要么抛出异常,或者永远不返回(因为进入无限循环或进程崩溃)。网络请求有另一个可能的结果:由于超时,它可能会返回没有结果。在这种情况下,你根本不知道发生了什么:如果你没有得到来自远程服务的响应,你无法知道请求是否通过。 (我们将在第8章更详细地讨论这个问题。)</li>
<li>如果您重试失败的网络请求,可能会发生请求实际上正在通过,只有响应丢失。在这种情况下,重试将导致该操作被执行多次,除非您在协议中引入除重( 幂等(idempotence))机制。本地函数调用没有这个问题。 (在第十一章更详细地讨论幂等性)</li>
<li>每次调用本地功能时,通常需要大致相同的时间来执行。网络请求比函数调用要慢得多,而且其延迟也是非常可变的:在不到一毫秒的时间内它可能会完成,但是当网络拥塞或者远程服务超载时,可能需要几秒钟的时间完全一样的东西。</li>
<li>调用本地函数时,可以高效地将引用(指针)传递给本地内存中的对象。当你发出一个网络请求时,所有这些参数都需要被编码成可以通过网络发送的一系列字节。没关系,如果参数是像数字或字符串这样的基本类型,但是对于较大的对象很快就会变成问题。</li>
</ul>
<h4 id="RPC的当前方向"><a href="#RPC的当前方向" class="headerlink" title="RPC的当前方向"></a>RPC的当前方向</h4><p>使用二进制编码格式的自定义RPC协议可以实现比通用的JSON over REST更好的性能。但是,RESTful API还有其他一些显著的优点:对于实验和调试(只需使用Web浏览器或命令行工具curl,无需任何代码生成或软件安装即可向其请求),它是受支持的所有的主流编程语言和平台,还有大量可用的工具(服务器,缓存,负载平衡器,代理,防火墙,监控,调试工具,测试工具等)的生态系统。由于这些原因,REST似乎是公共API的主要风格。 RPC框架的主要重点在于同一组织拥有的服务之间的请求,通常在同一数据中心内。</p>
<h3 id="消息传递中的数据流"><a href="#消息传递中的数据流" class="headerlink" title="消息传递中的数据流"></a>消息传递中的数据流</h3><p>简要介绍一下RPC和数据库之间的异步消息传递系统。它们与RPC类似,因为客户端的请求(通常称为消息)以低延迟传送到另一个进程。它们与数据库类似,不是通过直接的网络连接发送消息,而是通过称为消息代理(也称为消息队列或面向消息的中间件)的中介来临时存储消息。</p>
<p>与直接RPC相比,使用消息代理有几个优点:</p>
<ul>
<li>如果收件人不可用或过载,可以充当缓冲区,从而提高系统的可靠性。</li>
<li>它可以自动将消息重新发送到已经崩溃的进程,从而防止消息丢失。</li>
<li>避免发件人需要知道收件人的IP地址和端口号(这在虚拟机经常出入的云部署中特别有用)。</li>
<li>它允许将一条消息发送给多个收件人。</li>
<li>将发件人与收件人逻辑分离(发件人只是发布邮件,不关心使用者)。<br>然而,与RPC相比,差异在于消息传递通信通常是单向的:发送者通常不期望收到其消息的回复。一个进程可能发送一个响应,但这通常是在一个单独的通道上完成的。这种通信模式是异步的:发送者不会等待消息被传递,而只是发送它,然后忘记它。</li>
</ul>
<h4 id="消息掮客"><a href="#消息掮客" class="headerlink" title="消息掮客"></a>消息掮客</h4><p>RabbitMQ,ActiveMQ,HornetQ,NATS和Apache Kafka。</p>
<p>消息代理的使用方式如下:一个进程将消息发送到指定的队列或主题,代理确保将消息传递给一个或多个消费者或订阅者到那个队列或主题。在同一主题上可以有许多生产者和许多消费者。</p>
<p>一个主题只提供单向数据流。但是,消费者本身可能会将消息发布到另一个主题上,或者发送给原始消息的发送者使用的回复队列(允许请求/响应数据流,类似于RPC)。</p>
<p>消息代理通常不会执行任何特定的数据模型 - 消息只是包含一些元数据的字节序列,因此您可以使用任何编码格式。如果编码是向后兼容的,则您可以灵活地更改发行商和消费者的独立编码,并以任意顺序进行部署。</p>
<h4 id="分布式Actor框架"><a href="#分布式Actor框架" class="headerlink" title="分布式Actor框架"></a>分布式Actor框架</h4><p>Actor模型是单个进程中并发的编程模型。逻辑被封装在角色中,而不是直接处理线程(以及竞争条件,锁定和死锁的相关问题)。每个角色通常代表一个客户或实体,它可能有一些本地状态(不与其他任何角色共享),它通过发送和接收异步消息与其他角色通信。消息传送不保证:在某些错误情况下,消息将丢失。由于每个角色一次只能处理一条消息,因此不需要担心线程,每个角色可以由框架独立调度。</p>
<p>在分布式的行为者框架中,这个编程模型被用来跨越多个节点来扩展应用程序。不管发送方和接收方是在同一个节点上还是在不同的节点上,都使用相同的消息传递机制。如果它们在不同的节点上,则该消息被透明地编码成字节序列,通过网络发送,并在另一侧解码。</p>
<p>位置透明在actor模型中比在RPC中效果更好,因为actor模型已经假定消息可能会丢失,即使在单个进程中也是如此。尽管网络上的延迟可能比同一个进程中的延迟更高,但是在使用参与者模型时,本地和远程通信之间的基本不匹配是较少的。</p>
<p>分布式的Actor框架实质上是将消息代理和角色编程模型集成到一个框架中。但是,如果要执行基于角色的应用程序的滚动升级,则仍然需要担心向前和向后兼容性问题,因为消息可能会从运行新版本的节点发送到运行旧版本的节点,反之亦然。</p>
]]></content>
<categories>
<category>book</category>
<category>DDIA</category>
</categories>
</entry>
<entry>
<title>设计原则</title>
<url>/post/2706491890.html</url>
<content><![CDATA[<h2 id="设计模式:设计原则"><a href="#设计模式:设计原则" class="headerlink" title="设计模式:设计原则"></a>设计模式:设计原则</h2><ol>
<li><p>找出应用中可能需要变化指出,把它们独立出来,不要和那些不需要变化的代码混在一起。</p>
</li>
<li><p>针对接口编程,而不是针对实现编程。</p>
</li>
<li><p>多用组合,少用继承。</p>
<blockquote>
<p>针对接口编程,即针对超类型编程,也就是使用多态。</p>
</blockquote>
</li>
<li><p>为了交互对象之间的松耦合设计而努力。</p>
</li>
<li><p>开放-关闭原则:类应该对拓展开放,对修改关闭。</p>
</li>
<li><p>依赖倒置原则:要依赖抽象,不要依赖具体类。</p>
<blockquote>
<p>变量不可以持有具体类的引用。<br>不要让类派生自具体类。<br>不要覆盖基类中已实现的方法。</p>
</blockquote>
</li>
</ol>
]]></content>
<categories>
<category>book</category>
<category>design-pattern</category>
</categories>
<tags>
<tag>设计模式</tag>
</tags>
</entry>
<entry>
<title>PAT攻略</title>
<url>/post/2386101702.html</url>
<content><![CDATA[<p>其实我pat准备得很迟,七月中旬才开始准备PAT。</p>
<p>就刷了甲级100来道题,就去考场了,其他都ac了。可能太过于紧张,第一题就留了半小时,没做出来,拿了80 …… </p>
<p>第二次把乙级题都刷了一遍,甲级中的20分题以及对照刷题目录把甲级中的经典题型也都重新刷一遍。</p>
<p>其实pat不需要全刷,有些题是真的恶心,早期各种各样恶心的模拟题,比如臭名昭著的<code>Table tennis</code>。</p>
<p>我就刷了120多题。<br><a id="more"></a><br>我感觉我这个路线应该可以2个月速成PAT甲级。我的路线:PAT乙级全刷-><a href="/post/1337061191.html" title="真题目录">真题目录</a>->甲级1101题往后所有题->还有有时间的话把甲级20分题都做一下(第一题有时候挺难的)</p>
<p>IDE: DEV C++(一般这个都有,刷题最好用c++)</p>
<p>书籍:《算法笔记》俗称晴神宝典</p>
<p>代码参考:<a href="https://www.liuchuo.net/" target="_blank" rel="noopener">柳神博客</a></p>
<p>PAT乙级,是帮助你熟悉C++/C,掌握字符串的处理的开始</p>
<p><a href="/post/1337061191.html" title="真题目录">真题目录</a>:题型分类,里面的题都是非常经典的,值得多做几次。可以从易到难,二点论结合:STL(熟悉stl)->链表->排序->树->图->广度、深度->最短路径->搜索树、平衡树->堆->并查集。其他就不用怎么用看了,基本不考。</p>
<p>差不多这样就行了吧,一天三个小时,两个月90分没有问题,100分还是需要点实力和运气的。</p>
]]></content>
<categories>
<category>book</category>
<category>design-pattern</category>
</categories>
<tags>
<tag>PAT</tag>
</tags>
</entry>
<entry>
<title>八方旅人完结</title>
<url>/post/2574678648.html</url>
<content><![CDATA[<p>八方旅人,一方五十</p>
<p>第一次全通关一款JRPG,断断续续打了一个月,将近80小时全收集。</p>
<p>这个主线剧情最终Boss和隐藏Boss难度跨度有点大。</p>
<p>全角色第四章通关之后,花了5、6天准备升级和职业搭配准备打最后的隐藏Boss(PS:不愧是非酋之舞,不然也不会刷5天的级)</p>
<p>打完隐藏Boss之后整一个八方旅人的八个零散的主线就可以织起来了,总的剧情中规中矩。</p>
<p>游戏机制在老式传统回合制上有创新,玩起来有功有防,很有节奏感。同时音乐出色,不过价格偏贵,switch版玩完还可以回血。</p>
<p>推荐程度8/10</p>
<a id="more"></a>
<p>最后收藏了一些图:</p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-alfyn.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-cyrus.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-haannit.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-olberic.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-ophilia.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-primrose.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-therion.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-tressa.jpg" alt=""></p>
<p><img src="https://cdn.jsdelivr.net/gh/charstal/images/hexo/octopath-traveler-boss.jpg" alt=""></p>
]]></content>
<categories>
<category>game</category>
<category>octopath-traveler</category>
</categories>
<tags>
<tag>八方旅人</tag>
<tag>SE</tag>
</tags>
</entry>
<entry>
<title>Talent plan Tinykv | project1 | Standalone KV</title>
<url>/post/1319254865.html</url>
<content><![CDATA[<p><a href="https://asktug.com/t/topic/242996" target="_blank" rel="noopener">Talent Plan 2021 KV 学习营信息总览</a></p>
<p>前一阵子看见P社在微信群推了这个活动,前一阵子刚学了6.824并写完了lab3,所以兴冲冲想去试试,在群里拉了一个小伙伴去试试。</p>
<p>总体收获还是挺大的,tinykv也是挺难的,主要难在文档其实描述并没有那么清楚,很多地方都需要自己淌坑。同时debug比较痛苦。但是确实是一个比较好的工程项目。</p>
<hr>
<h1 id="Project1"><a href="#Project1" class="headerlink" title="Project1"></a>Project1</h1><h2 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h2><ol>
<li>实现standaloneKV</li>
<li>实现raw_api,完成测试</li>
</ol>
<h2 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h2><h3 id="standalone-storage"><a href="#standalone-storage" class="headerlink" title="standalone_storage"></a>standalone_storage</h3><p>需要实现的代码放在<code>kv/storage/standalone_storage/standalone_storage.go</code>,需要实现<code>StandAloneStorage</code>结构体,方法都已经定义好了,仅需要实现。这其实是一个简化的<code>raft_storage</code>,只要取其中一部分就行了,其余不懂的api参考<code>engine_util</code>就行了。</p>
<ul>
<li>对于<code>StandAloneStorage</code>结构体来说,其实一个<code>engines</code>就足够了,调用一个包装好的<code>badger</code>数据库。</li>
<li><code>Start</code>方法,没有需要实现的内容</li>
<li><code>Stop</code>关闭数据库</li>
<li><code>Write</code>可以参考<code>engine_util.write_batch.go</code>,它其实就是把<code>batch</code>数组转化为一个<code>WriteBatch</code>,可以进行批处理写入数据库</li>
<li><code>Reader</code>可以参考<code>raft_storage</code>,需要一个<code>badger.txn</code>处理一致性,对于<code>Reader</code>来说需要返回一个对象实现<code>StorageReader</code>,这里新建一个对象文件<code>reader.go</code>可以参考<code>region_reader.go</code>。这里需要产生一个迭代器,我们这个迭代器比较简单直接使用<code>cf_iterator.go</code>就可以了。</li>
</ul>
<h3 id="raw-api"><a href="#raw-api" class="headerlink" title="raw_api"></a>raw_api</h3><p>需要实现的代码放在<code>kv/server/raw_api.go</code>,我们需要实现4个api,RawGet/ RawScan/ RawPut/ RawDelete</p>
<ul>
<li>RawGet, 比较简单,注意返回类型,空值需要额外标注</li>
<li>RawPut,比较简单,利用<code>Storage.Modify</code>包装原有request中的(key,value)即可</li>
<li>RawDelete,和RawPut类似</li>
<li>RawScan,这个基于我们已经写的<code>reader.go</code>,特别注意,当得到迭代器的时候,需要<code>seek</code>到对应的<code>start_key</code>,不然找不到值。需要注意,limit的大小</li>
</ul>
]]></content>
<categories>
<category>project</category>
<category>tinykv</category>
</categories>
<tags>
<tag>tinykv</tag>
<tag>raft</tag>
</tags>