-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
1264 lines (609 loc) · 461 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
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>(十八)MariaDB简单的复制(replication)使用示例</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/</url>
<content type="html"><![CDATA[<p>简单的做一个标准模式复写的示例。</p><p>为了方便建立多个 MariaDB 的实例,使用 MariaDB docker 镜像做 replication。</p><p><strong>会创建 3 个安装 MariaDB 的 docker 容器,分别命名为 mariadb1(设为 Master)、mariadb2 和 mariadb3(Slave1 和 Slave2)。端口映射依次 3307、3308、3309。</strong></p><h1 id="简单的-replication-前置准备"><a href="#简单的-replication-前置准备" class="headerlink" title="简单的 replication 前置准备"></a>简单的 replication 前置准备</h1><h2 id="1、MariaDB-docker-准备与配置"><a href="#1、MariaDB-docker-准备与配置" class="headerlink" title="1、MariaDB docker 准备与配置"></a>1、MariaDB docker 准备与配置</h2><p>快速安装 docker:</p><pre><code class="sh">sudo sh -c "$(curl -fsSL https://get.docker.com)"sudo usermod -aG docker $USER</code></pre><p>第一行用 docker 官方提供的 script 快速安装。<br>第二行将现有的使用者加入 docker 群组,否则会没有权限操作 docker 命令。<br>记得注销账号重登,以获取 docker 操作权限。</p><p>拉取 MariaDB 镜像:</p><pre><code>docker pull mariadb/server:10.4</code></pre><p>创建 3 个用于安装 mariadb 的容器,命名为 mariadb1、mariadb2、mariadb3:</p><pre><code>sudo docker run -it -p 3307:3306 --name mariadb1 -e MYSQL_ROOT_PASSWORD=root -d mariadb/server:10.4</code></pre><p><img alt="创建3个mariadb容器" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/1.png" class="lazyload"></p><h2 id="2、基准文件的准备"><a href="#2、基准文件的准备" class="headerlink" title="2、基准文件的准备"></a>2、基准文件的准备</h2><p><strong>拷贝一份同样的数据库结构文件到 3 个容器中,并导入各自数据库</strong></p><p>准备一份 sql script。</p><p>我这份示例是一个名为 test_replication 的数据库,以下有一个名为 call_record 的表,结构如下:</p><pre><code class="sql">CREATE TABLE `call_record` ( `start_time` char(19) DEFAULT NULL, `dial_out_number` varchar(12) DEFAULT NULL, `dial_out_name` varchar(20) DEFAULT NULL, `dial_out_department` varchar(20) DEFAULT NULL, `call_duration` char(19) DEFAULT NULL, `uuid` varchar(36) NOT NULL, `create_time` char(19) NOT NULL, `create_user` varchar(20) NOT NULL, `update_time` char(19) DEFAULT NULL, `update_user` varchar(20) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;</code></pre><p>同时插入了 10w 条测试数据。</p><p>将示例 sql 脚本,复制到 3 个容器中</p><pre><code>sudo docker cp /home/sanotsu/Dump20200303.sql mariadb1:/home/Dump20200303.sql</code></pre><p><img alt="示例sql脚本复制到3个容器" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/2.png" class="lazyload"></p><p>为了方面修改配置文件,给 3 个容器中安装 vim。</p><pre><code>sudo docker exec -it mariadb1 bashapt updateapt install vim</code></pre><p><img alt="docker容器中安装vim" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/3.png" class="lazyload"></p><p><strong>导入数据库</strong></p><p>就在刚刚的容器的交互界面,继续执行:</p><pre><code>mysql -uroot -p < /home/Dump20200303.sqlmysql_upgrade -uroot -p</code></pre><p>root 账号的密码就是之前创建容器时指定的 MYSQL_ROOT_PASSWORD 参数的值。<br>mysql_upgrade 用于更新表格到最新的版本。</p><p><img alt="容器中mariadb导入数据库" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/4.png" class="lazyload"></p><h2 id="3、Master-Slaves-设置-主从服务器设定"><a href="#3、Master-Slaves-设置-主从服务器设定" class="headerlink" title="3、Master-Slaves 设置(主从服务器设定)"></a>3、Master-Slaves 设置(主从服务器设定)</h2><p>配置 3 个容器中的 MariaDB server-id 分别为 1、2、3,log-basename 分别为 master01、slave01、slave02,并建立 relication 用账号。</p><p><strong>修改配置文件:</strong></p><p>使用 vim 打开容器中 mariadb 的配置文件,在容器的终端运行</p><pre><code>vim /etc/mysql/my.cnf</code></pre><p>修改或添加以下参数:</p><pre><code>server-id = 1log_bin = /var/log/mysql/mariadb-binlog_basename = master01binlog_format=mixed</code></pre><p>示例的设定是,mariadb1(master)容器如下:</p><p><img alt="mariadb1的相关配置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/4.png" class="lazyload"></p><p>mariadb2(slave1)容器如下:</p><p><img alt="mariadb2的相关配置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/6.png" class="lazyload"></p><p>mariadb3(slave2)容器如下:</p><p><img alt="mariadb3的相关配置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/7.png" class="lazyload"></p><p><strong>建立 replication 用账号:</strong></p><p>在容器中,进入到 MariaDB 的命令窗口,创建一个用于备份的账号和赋予复制权限,记得要刷新权限。</p><pre><code class="sql">CREATE USER 'reptest'@'%' IDENTIFIED BY '123456';GRANT REPLICATION SLAVE ON *.* TO 'reptest'@'%' WITH GRANT OPTION;FLUSH PRIVILEGES;</code></pre><p><img alt="创建用于备份复制使用的账号" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/8.png" class="lazyload"></p><p>设定完权限后,重启 docker 容器来重启 MariaDB 。</p><p><img alt="重启docker容器使配置等生效" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/9.png" class="lazyload"></p><p>重启之后,查看下 master01 binarylog 状态,后续将 master01 作为 MASTER 主机,slave01 和 slave02 作为 SLAVE 主机。</p><p><strong>mariadb1 会作为 master</strong>,查看状态如下</p><p><img alt="master状态" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/10.png" class="lazyload"></p><p>mariadb2 和 mariadb3 要作为 slave,需要在 mariadb 命令窗口 执行以下配置:</p><pre><code class="sql">CHANGE MASTER TO MASTER_HOST='192.168.28.93', MASTER_USER='reptest', MASTER_PASSWORD='123456', MASTER_PORT=3307, MASTER_LOG_FILE='master01-bin.000001', MASTER_LOG_POS= 331, MASTER_CONNECT_RETRY=6;</code></pre><p>注意配置的属性都要与 master 的状态一致。</p><p><img alt="配置slave" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/11.png" class="lazyload"></p><p>配置完之后在启动 slave,然后查看下 slave 状态:</p><pre><code>START SLAVE;SHOW SLAVE STATUS\G;</code></pre><p>两台 slave 实例应该会现实如下</p><p><img alt="两台slave状态" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/12.png" class="lazyload"></p><p>到这里,简单的 master-slave 的设定就完成了,可以测试一下。</p><h1 id="简单的-replication-测试示例"><a href="#简单的-replication-测试示例" class="headerlink" title="简单的 replication 测试示例"></a>简单的 replication 测试示例</h1><h2 id="1、master-的修改是否会同步到-slave-去"><a href="#1、master-的修改是否会同步到-slave-去" class="headerlink" title="1、master 的修改是否会同步到 slave 去"></a>1、master 的修改是否会同步到 slave 去</h2><p>先查看目前 3 个 MariaDB 的测试数据,可见 master 和两个 slave 在 test_replication.call_record 测试数据都是 10w 条。</p><p><img alt="查看测试数据" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/13.png" class="lazyload"></p><p>对 MASTER 进行删除操作:</p><pre><code>delete from test_replication.call_record limit <X>;</code></pre><p><img alt="查看测试数据" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/14.png" class="lazyload"></p><p>注意:如果想马上看到级联更新的效果,建议对一条数据进行修改删除插入的操作。如果如示例一样进行了 5w 条的删除,可能需要等待一段时间才能完成同步到 Slaves。</p><p>一般情况下,同步都是实时的,如果上述的操作是删除 1 条数据或者修改 1 条数据可以更加清晰地看到。(没有截图,有实际删除 1 条看效果,目前 3 个表中数据还有 49999 条)</p><p>但是也有可能需求,master 更新之后,要延迟一点时间,再同步到 slave。</p><p>只需简单设定如下:</p><p><strong>在需要被延迟更新的 SLAVE 中,设定延迟时间</strong>:</p><pre><code>STOP SLAVE;CHANGE MASTER TO master_delay= 60;START SLAVE;</code></pre><p>再次测试结果(3 个表分表有 49999 条数据)<br>选取 SLAVE02,设定 60s 延迟更新:</p><p><img alt="salve2设定60s更新延迟" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/15.png" class="lazyload"></p><p>查看两个 slave 的状态可见 SQL_Delay 的数值变化:</p><pre><code>show slave status\G;</code></pre><p><img alt="查看更新延迟设定" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/16.png" class="lazyload"></p><p>在 master 表删除 1 条数据,从下图可以看出,slave01 是很快就同步了,二 slave02 是延迟时间到达之前,是没有更新的。</p><p><img alt="查看更新延迟设定效果" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/17.png" class="lazyload"></p><h2 id="2、SLAVE-取代-MASTER"><a href="#2、SLAVE-取代-MASTER" class="headerlink" title="2、SLAVE 取代 MASTER"></a>2、SLAVE 取代 MASTER</h2><p>在 master 主机因为一些情况不能继续使用的时候,可以快速地升级某一台 SLAVE 机器替换 master,避免相关业务中断。</p><p>基本步骤如下:</p><p><strong>1> 停止 master 写入</strong></p><p>设置 mater 读锁定</p><pre><code>FLUSH TABLES WITH READ LOCK ;</code></pre><p>检查 master、slave 数据是否同步完成</p><p>master:</p><pre><code>SHOW MASTER STATUS;</code></pre><p>slave:</p><pre><code>SHOW SLAVE STATUS\G;</code></pre><p><img alt="停止master写入" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/18.png" class="lazyload"><br>(注意红框中参数)</p><p><strong>2> 设置 slave02 主机为 MASTER</strong></p><pre><code>STOP ALL SLAVES;RESET SLAVE ALL;SHOW MASTER STATUS;SELECT @@global.gtid_binlog_pos;SET @@global.read_only=0;</code></pre><p><img alt="设置slave02主机为MASTER" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/19.png" class="lazyload"></p><p><strong>3 更改 slave01 主机连接配置</strong></p><p>之前 slave01 连接的主服务器是 master01,现在要为 slave02。在原 salve01 中执行:</p><pre><code class="sql">STOP SLAVE;RESET SLAVE;CHANGE MASTER TO MASTER_HOST='192.168.28.93', MASTER_USER='reptest', MASTER_PASSWORD='123456', MASTER_PORT=3309, MASTER_LOG_FILE='slave02-bin.000002', MASTER_LOG_POS= 331, MASTER_CONNECT_RETRY=6;START SLAVE;SHOW SLAVE STATUS\G;</code></pre><p><img alt="更改slave01主机连接配置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/20.png" class="lazyload"></p><p><strong>4 更改原 master 主机配置,修改为 slave 主机</strong></p><p>原来的主服务器,现在是从服务器了,修改主服务器连接为原 slave02。</p><pre><code class="sql">UNLOCK TABLES;SET @@global.read_only=1;STOP ALL SLAVES;RESET MASTER;RESET SLAVE ALL;CHANGE MASTER TO MASTER_HOST='192.168.28.93', MASTER_USER='reptest', MASTER_PASSWORD='123456', MASTER_PORT=3309, MASTER_LOG_FILE='slave02-bin.000002', MASTER_LOG_POS= 330, MASTER_CONNECT_RETRY=6;START SLAVE;SHOW SLAVE STATUS\G;</code></pre><p><img alt="更改原master主机配置,修改为slave2主机" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/21.png" class="lazyload"></p><p>完成之后,可以测试一下,在新 master 删除两条数据,然后可以看到新的两个 salve 中数据少了两条:</p><p><img alt="设置完成测试delete语句" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/22.png" class="lazyload"></p><p>当然,除了 delete 其它语句可以自行测试。</p><h2 id="3、设定并行复制-Parallel-Replication"><a href="#3、设定并行复制-Parallel-Replication" class="headerlink" title="3、设定并行复制 Parallel Replication"></a>3、设定并行复制 Parallel Replication</h2><p>可以在从属服务器上并行(同时)执行从主服务器复制的某些写入操作。</p><p>将 slave01 设置并行复制:</p><pre><code>STOP SLAVE SQL_THREAD;SET GLOBAL slave_parallel_threads = 4;SET GLOBAL slave_parallel_max_queued=67108864;START SLAVE SQL_THREAD;SELECT @@slave_parallel_threads;show processlist;</code></pre><p>有看到进程列表中有 4 个 slave_worker</p><p><img alt="进程列表中有4个slave_worker" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/23.png" class="lazyload"></p><pre><code>STOP SLAVE;Change master to master_use_gtid =slave_pos;START SLAVE;</code></pre><p>使用 gitd 位置:</p><p><img alt="使用gitd位置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/24.png" class="lazyload"></p><p>查看 slave 状态:</p><p>master 主机查看:</p><pre><code>select @@gloabl.gtid_binlog_pos;</code></pre><p>slave server 查看 slave 状态:</p><pre><code>SHOW SLAVE STATUS\G;</code></pre><p><img alt="使用gitd位置" data-src="/../images/TechnicalEssays/MariaDBSeries/18mariadb-replication-example/25.png" class="lazyload"></p><p>设定 salve01 可并行复制完成。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十七)MariaDB的复制(replication)简介</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/17mariadb-replication/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/17mariadb-replication/</url>
<content type="html"><![CDATA[<p>注意区分:在一开始的时候,有讲到备份和还原,有详细提到两个命令 mysqldump 和 mariabackup,用于<strong>备份(Backing Up)</strong>。</p><h1 id="repelication-基础简介"><a href="#repelication-基础简介" class="headerlink" title="repelication 基础简介"></a>repelication 基础简介</h1><h2 id="replication-概述"><a href="#replication-概述" class="headerlink" title="replication 概述"></a>replication 概述</h2><p><strong>复制(Replication)是一个允许一个或多个主(master)服务器的内容镜像复制到一个或多个从(slave)服务器上的特性。</strong></p><blockquote><p>可以控制要复制的数据:所有数据库、一个或多个数据库或数据库中的表。</p></blockquote><blockquote><p>复制中使用的主要机制是二进制日志(binary log)。如果启用了二进制日志记录,则数据库的所有更新(数据操作和数据定义)都将作为 binlog 事件写入二进制日志。从服务器(Slaves)从每个主机(each master)读取二进制日志,以便访问要复制的数据。中继日志(relay log)是在从属服务器上创建的,使用与二进制日志相同的格式,用于执行复制。旧的中继日志文件将在不再需要时被删除。</p></blockquote><blockquote><p>从服务器保持轨迹(track)在主服务器的 binlog 中记录的最后一次应用到从服务器的事件的位置。这就可以允许从服务器重新连接,并从临时停止后中断的位置恢复复制操作。它还允许从服务器断开连接、克隆,然后从同一主服务器恢复新的从服务器复制。</p><p>主从服务器之间不需要持续通讯(constant communication)。服务器脱机或断开与网络的连接情况很常见,但当它们重连时,复制将在中断的地方继续执行。</p></blockquote><h2 id="replication-用途"><a href="#replication-用途" class="headerlink" title="replication 用途"></a>replication 用途</h2><blockquote><p><strong>可扩展性(Scalability)</strong>。通过拥有一个或多个从属服务器,可以将读取分散到多个服务器上,从而减少主服务器上的负载。对于高读、低写环境,最常见的情况是有一个主节点,所有的写操作都在其中进行,复制到多个从节点,这些从节点处理大部分的读操作。</p><p><strong>数据分析(Data analysis)</strong>。分析数据可能会对主服务器产生太大的影响,这同样可以在从属服务器上处理,而主服务器继续不受额外负载的影响。</p><p><strong>备援(Backup assistance)</strong>。如果服务器不主动更改数据,备份(Backups)可以更轻松地运行。一个常见的场景是将数据复制到从属服务器,然后在数据处于稳定状态时从主服务器断开连接。然后从该服务器执行备份。</p><p><strong>数据分发(Distribution of data)</strong>。与其连接到远程主机,还可以在本地复制数据,并从该数据开始工作。</p></blockquote><h2 id="通用的复制设定-Common-Replication-Setups"><a href="#通用的复制设定-Common-Replication-Setups" class="headerlink" title="通用的复制设定 Common Replication Setups"></a>通用的复制设定 Common Replication Setups</h2><h3 id="标准复制-Standard-Replication"><a href="#标准复制-Standard-Replication" class="headerlink" title="标准复制 Standard Replication"></a>标准复制 Standard Replication</h3><p><strong>特点:</strong></p><ul><li>提供无限的读取横向扩展。</li><li>通过将从机(Slave)升级为主机(Master)来提供高可用性。</li></ul><p><img alt="标准复制示意图" data-src="/../images/TechnicalEssays/MariaDBSeries/17mariadb-replication/1.png" class="lazyload"></p><h3 id="环状复制-Ring-Replication"><a href="#环状复制-Ring-Replication" class="headerlink" title="环状复制 Ring Replication"></a>环状复制 Ring Replication</h3><p><strong>特点:</strong></p><ul><li>提供读写缩放(scaling)。</li><li>不处理冲突。</li><li>如果一个主服务器发生故障,复制将停止。</li></ul><p><img alt="环状复制示意图" data-src="/../images/TechnicalEssays/MariaDBSeries/17mariadb-replication/2.png" class="lazyload"></p><h3 id="星状复制-Star-Replication"><a href="#星状复制-Star-Replication" class="headerlink" title="星状复制 Star Replication"></a>星状复制 Star Replication</h3><p><strong>特点:</strong></p><ul><li>提供读写缩放。</li><li>不处理冲突。</li><li>必须使用复制过滤器以避免重复数据。</li></ul><p><img alt="星状复制示意图" data-src="/../images/TechnicalEssays/MariaDBSeries/17mariadb-replication/3.png" class="lazyload"></p><h3 id="多源复制-Multi-Source-Replication"><a href="#多源复制-Multi-Source-Replication" class="headerlink" title="多源复制 Multi-Source Replication"></a>多源复制 Multi-Source Replication</h3><p><strong>特点:</strong></p><ul><li>允许合并来自不同来源的数据。</li><li>在所有的从服务器上,不同域独立并行执行。</li></ul><p><img alt="多源复制示意图" data-src="/../images/TechnicalEssays/MariaDBSeries/17mariadb-replication/4.png" class="lazyload"></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十六)MariaDB部分内置JSON函数简介</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/16mariadb-json-function/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/16mariadb-json-function/</url>
<content type="html"><![CDATA[<p>如今,越来越多的 IOT 设备被推广使用,收集到的数据,习惯性的,都会是 nosql 类型的,例如 JSON。</p><p>MariaDB 10.2.7 加入了 JSON 的数据类型,用于处理该格式的数据,但在 MariaDB 10.2.3 已加入多个 JSON 用途 functions,支持所有文字型别字段 ( char, varchar, text …)。</p><p>此处简单介绍下常用的 MariaDB 内建的 JSON 相关的函数。</p><p>示例直接复制 MariaDB 命令窗口测试执行语句及结果。</p><h1 id="JSON-VALID"><a href="#JSON-VALID" class="headerlink" title="JSON_VALID"></a>JSON_VALID</h1><p><strong>语法:</strong></p><pre><code>JSON_VALID(value)</code></pre><p><strong>说明:</strong></p><blockquote><p>显示给定值是否为有效的 JSON 文档(JSON document)。如果有效,则返回 1;如果无效,则返回 0;如果参数为空,则返回 NULL。</p></blockquote><blockquote><p>在 MariaDB 10.4.3 中,JSON_VALID 函数自动用作 JSON 数据类型别名的检查约束,以确保插入有效的 JSON 文档。即字段是 JSON 类型,则会自动检查值是否为 JSON 格式。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> set @json1='{"id": 1, "name": "David"}';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_VALID(@json1);+--------------------+| JSON_VALID(@json1) |+--------------------+| 1 |+--------------------+1 row in set (0.000 sec)</code></pre><p>或简单写成一句:</p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_VALID('{"id": 1, "name": " David "}');+--------------------------------------------+| JSON_VALID('{"id": 1, "name": " David "}') |+--------------------------------------------+| 1 |+--------------------------------------------+1 row in set (0.000 sec)</code></pre><p>json 数据类型自动检查:</p><pre><code class="sql">-- 建表CREATE TABLE test200222.jsont ( uid INTEGER UNSIGNED auto_increment NOT NULL, uattr json NULL, PRIMARY KEY (uid))-- 插入测试INSERT INTO jsont VALUES(1,NULL); -- Query OK, 1 row affected (0.01 sec)INSERT INTO jsont VALUES(2,'{"size": 42, "colour": "white"}'); -- Query OK, 1 row affected (0.01 sec)INSERT INTO jsont VALUES(3,'{"colour": "white}'); -- SQL 错误 [4025] [23000]: (conn=82) CONSTRAINT `jsont.uattr` failed for `test200222`.`jsont`</code></pre><h1 id="JSON-CONTAINS-PATH"><a href="#JSON-CONTAINS-PATH" class="headerlink" title="JSON_CONTAINS_PATH"></a>JSON_CONTAINS_PATH</h1><p><strong>语法:</strong></p><pre><code>JSON_CONTAINS_PATH(json_doc, return_arg, path[, path] ...)</code></pre><p><strong>说明:</strong></p><blockquote><p>显示给定的 JSON 文档是否包含指定路径处的数据。如果是,则返回 1;如果不是,则返回 0;如果任何参数为空,则返回 NULL。</p><p>返回参数可以是一个或全部:</p></blockquote><ul><li>one-如果 JSON 文档中至少存在一个路径,则返回 1。</li><li>all-仅当 JSON 文档中存在所有路径时返回 1。</li><li></li></ul><blockquote><p>Path 路径表示</p></blockquote><ul><li>$. -> 起始</li><li>$.Key -> $.id —> { “id”: 5 }</li><li>$.key.subkey -> $.data.subject -> { “data”: { “subject”:”h”} }</li></ul><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SET @json = '{"A": 1, "B": [2], "C": [3, 4]}';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D');+------------------------------------------------+| JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D') |+------------------------------------------------+| 1 |+------------------------------------------------+1 row in set (0.001 sec)MariaDB [(none)]> SELECT JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D');+------------------------------------------------+| JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D') |+------------------------------------------------+| 0 |+------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-EXISTS"><a href="#JSON-EXISTS" class="headerlink" title="JSON_EXISTS"></a>JSON_EXISTS</h1><p><strong>语法:</strong></p><pre><code>JSON_EXISTS(<given data>,<json value>)</code></pre><p><strong>说明</strong></p><p>确定给定数据中是否存在指定的 JSON 值。如果找到,则返回 1;如果没有,则返回 0;如果任何输入为空,则返回 NULL。</p><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2");+------------------------------------------------------------+| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2") |+------------------------------------------------------------+| 1 |+------------------------------------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");+---------------------------------------------------------------+| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]") |+---------------------------------------------------------------+| 1 |+---------------------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-CONTAINS"><a href="#JSON-CONTAINS" class="headerlink" title="JSON_CONTAINS"></a>JSON_CONTAINS</h1><p><strong>语法:</strong></p><pre><code>JSON_CONTAINS(json_doc, val[, path])</code></pre><p><strong>说明:</strong></p><blockquote><p>返回指定的值是否在给定的 JSON 文档中找到,或者是否在文档中的指定路径(可选)处找到。</p></blockquote><ul><li>如果是,则返回 1;如果不是,则返回 0;如果任何参数为空,则返回 NULL。</li><li>如果文档或路径无效,或包含*或**通配符,则会发生错误。</li></ul><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SET @json = '{"A": 0, "B": {"C": 1}, "D": 2}';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_CONTAINS(@json, '2', '$.A');+----------------------------------+| JSON_CONTAINS(@json, '2', '$.A') |+----------------------------------+| 0 |+----------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_CONTAINS(@json, '2', '$.D');+----------------------------------+| JSON_CONTAINS(@json, '2', '$.D') |+----------------------------------+| 1 |+----------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_CONTAINS(@json, '{"C": 1}', '$.A');+-----------------------------------------+| JSON_CONTAINS(@json, '{"C": 1}', '$.A') |+-----------------------------------------+| 0 |+-----------------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_CONTAINS(@json, '{"C": 1}', '$.B');+-----------------------------------------+| JSON_CONTAINS(@json, '{"C": 1}', '$.B') |+-----------------------------------------+| 1 |+-----------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-DEPTH"><a href="#JSON-DEPTH" class="headerlink" title="JSON_DEPTH"></a>JSON_DEPTH</h1><p><strong>语法:</strong></p><pre><code>JSON_DEPTH(json_doc)</code></pre><p><strong>说明:</strong></p><blockquote><p>返回给定 JSON 文档的最大深度,如果参数为 NULL,则返回 NULL。如果参数是无效的 JSON 文档,则会发生错误。</p><p>标量值(scalar values)或空数组或对象的深度为 1。</p><p>非空但仅包含深度为 1 的元素或成员值的数组或对象的深度为 2。</p><p>在其它情况下,深度将大于 2。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_DEPTH('[]'), JSON_DEPTH('true'), JSON_DEPTH('{}');+------------------+--------------------+------------------+| JSON_DEPTH('[]') | JSON_DEPTH('true') | JSON_DEPTH('{}') |+------------------+--------------------+------------------+| 1 | 1 | 1 |+------------------+--------------------+------------------+1 row in set (0.043 sec)MariaDB [(none)]> SELECT JSON_DEPTH('[1, 2, 3]'), JSON_DEPTH('[[], {}, []]');+-------------------------+----------------------------+| JSON_DEPTH('[1, 2, 3]') | JSON_DEPTH('[[], {}, []]') |+-------------------------+----------------------------+| 2 | 2 |+-------------------------+----------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]');+---------------------------------------+| JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]') |+---------------------------------------+| 3 |+---------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-OBJECT"><a href="#JSON-OBJECT" class="headerlink" title="JSON_OBJECT"></a>JSON_OBJECT</h1><p><strong>语法:</strong></p><pre><code>JSON_OBJECT([key, value[, key, value] ...])</code></pre><p><strong>说明:</strong></p><blockquote><p>返回包含给定键/值对的 JSON 对象。键/值列表可以为空。</p><p>如果参数的数目为奇数,或者任何键名为空,则将发生错误。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_OBJECT("id", 1, "name", "David");+---------------------------------------+| JSON_OBJECT("id", 1, "name", "David") |+---------------------------------------+| {"id": 1, "name": "David"} |+---------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-KEYS"><a href="#JSON-KEYS" class="headerlink" title="JSON_KEYS"></a>JSON_KEYS</h1><p><strong>语法:</strong></p><pre><code>JSON_KEYS(json_doc[, path])</code></pre><p><strong>说明:</strong></p><blockquote><p>从 JSON 对象的顶层值(top-level value)以 JSON 数组的形式返回键,如果提供了可选的 path 参数,则从 path 返回顶层键(top-level keys)。</p><p>从顶层值中的嵌套子对象中排除关键帧。如果所选对象为空,则生成的数组将为空。</p><p>如果任何参数为空、给定路径未找到对象或 json_doc 参数不是对象,则返回 NULL。</p><p>如果 JSON 文档无效、路径无效或路径包含*或**通配符,则会发生错误。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_KEYS('{"A": 1, "B": {"C": 2}}');+--------------------------------------+| JSON_KEYS('{"A": 1, "B": {"C": 2}}') |+--------------------------------------+| ["A", "B"] |+--------------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C');+-----------------------------------------------------+| JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C') |+-----------------------------------------------------+| ["D"] |+-----------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-VALUE"><a href="#JSON-VALUE" class="headerlink" title="JSON_VALUE"></a>JSON_VALUE</h1><p><strong>语法:</strong></p><pre><code>JSON_VALUE(json_doc, path)</code></pre><p><strong>说明:</strong></p><blockquote><p>给定一个 JSON 文档,返回路径指定的标量(scalar)。如果没有给出有效的 JSON 文档,或者没有匹配项,则返回 NULL。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> select json_value('{"key1":123}', '$.key1');+--------------------------------------+| json_value('{"key1":123}', '$.key1') |+--------------------------------------+| 123 |+--------------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> select json_value('{"key1": [1,2,3], "key1":123}', '$.key1');+-------------------------------------------------------+| json_value('{"key1": [1,2,3], "key1":123}', '$.key1') |+-------------------------------------------------------+| 123 |+-------------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-INSERT"><a href="#JSON-INSERT" class="headerlink" title="JSON_INSERT"></a>JSON_INSERT</h1><p><strong>语法:</strong></p><pre><code>JSON_INSERT(json_doc, path, val[, path, val] ...)</code></pre><p><strong>说明:</strong></p><blockquote><p>将数据插入到 JSON 文档中,如果任何参数为 NULL,则返回结果文档或 NULL。</p><p>如果 JSON 文档不是无效的,或者如果任何路径无效或包含*或**通配符,则会发生错误。</p><p>JSON_INSERT 只能插入数据,而 JSON_REPLACE 只能更新。JSON_SET 可以更新或插入数据。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SET @json = '{ "A": 0, "B": [1, 2]}';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_INSERT(@json, '$.C', '[3, 4]');+--------------------------------------+| JSON_INSERT(@json, '$.C', '[3, 4]') |+--------------------------------------+| {"A": 0, "B": [1, 2], "C": "[3, 4]"} |+--------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-REPLACE"><a href="#JSON-REPLACE" class="headerlink" title="JSON_REPLACE"></a>JSON_REPLACE</h1><p><strong>语法:</strong></p><pre><code>JSON_REPLACE(json_doc, path, val[, path, val] ...)</code></pre><p><strong>说明:</strong></p><blockquote><p>替换 JSON 文档中的现有值,返回结果;如果任何参数为空,则为空。</p><p>如果 JSON 文档无效、路径无效或路径包含*或**通配符,则会发生错误。</p><p>路径和值是从左到右计算的,前面的计算结果将用作下一个的值</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SELECT JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4);+-----------------------------------------------------+| JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4) |+-----------------------------------------------------+| {"A": 1, "B": [2, 4]} |+-----------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-SET"><a href="#JSON-SET" class="headerlink" title="JSON_SET"></a>JSON_SET</h1><p><strong>语法:</strong></p><pre><code>JSON_SET(json_doc, path, val[, path, val] ...)</code></pre><p><strong>说明:</strong></p><blockquote><p>在 JSON 文档中更新或插入数据,返回结果;如果任何参数为 NULL 或可选路径找不到对象,则返回 NULL。</p><p>如果 JSON 文档无效、路径无效或路径包含*或通配符,则会发生错误。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SET @json = '{"A": 0, "B": "hello", "C": {"msg": "check"} }';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_VALID(@json);+-------------------+| JSON_VALID(@json) |+-------------------+| 1 |+-------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_SET(@json , '$.B' , '"WORLD"');+---------------------------------------------------+| JSON_SET(@json , '$.B' , '"WORLD"') |+---------------------------------------------------+| {"A": 0, "B": "\"WORLD\"", "C": {"msg": "check"}} |+---------------------------------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_SET(@json , '$.D' , '"INSERT"');+------------------------------------------------------------------+| JSON_SET(@json , '$.D' , '"INSERT"') |+------------------------------------------------------------------+| {"A": 0, "B": "hello", "C": {"msg": "check"}, "D": "\"INSERT\""} |+------------------------------------------------------------------+1 row in set (0.000 sec)</code></pre><h1 id="JSON-EXTRACT"><a href="#JSON-EXTRACT" class="headerlink" title="JSON_EXTRACT"></a>JSON_EXTRACT</h1><p><strong>语法:</strong></p><pre><code>JSON_EXTRACT(json_doc, path[, path] ...)</code></pre><p><strong>说明:</strong></p><blockquote><p>从 JSON 文档中提取数据。从与路径参数匹配的部分中选择提取的数据。返回所有匹配的值。要么作为单个匹配的值,要么在参数可以返回多个值的情况下,则结果将自动包装为匹配顺序的数组。</p><p>如果没有匹配的路径或任何参数为空,则返回 NULL。</p><p>如果任何 path 参数不是有效的 path,或者 json_doc 参数不是有效的 json 文档,则会发生错误。</p></blockquote><p><strong>示例:</strong></p><pre><code class="sql">MariaDB [(none)]> SET @json = '[1, 2, [3, 4]]';Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> SELECT JSON_EXTRACT(@json, '$[1]');+-----------------------------+| JSON_EXTRACT(@json, '$[1]') |+-----------------------------+| 2 |+-----------------------------+1 row in set (0.000 sec)MariaDB [(none)]> SELECT JSON_EXTRACT(@json, '$[2]');+-----------------------------+| JSON_EXTRACT(@json, '$[2]') |+-----------------------------+| [3, 4] |+-----------------------------+1 row in set (0.001 sec)MariaDB [(none)]> SELECT JSON_EXTRACT(@json, '$[2][1]');+--------------------------------+| JSON_EXTRACT(@json, '$[2][1]') |+--------------------------------+| 4 |+--------------------------------+1 row in set (0.000 sec)</code></pre><p>更多 MariaDB 内建 JSON 函数,可参看官网:<a href="https://mariadb.com/kb/en/json-functions/" target="_blank" rel="noopener">https://mariadb.com/kb/en/json-functions/</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十五)Spider功能函数说明</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/</url>
<content type="html"><![CDATA[<h1 id="Spider-Functions"><a href="#Spider-Functions" class="headerlink" title="Spider Functions"></a>Spider Functions</h1><p>Spider 存储引擎提供了以下 4 个 UDF 函数,是与 Spider 存储引擎一起安装的 UDF:</p><p><strong>SPIDER_DIRECT_SQL</strong>:在远程服务器中执行 sql(Execute SQL on the remote server)<br><strong>SPIDER_BG_DIRECT_SQL</strong>:后台 SQL 执行(Background SQL execution)<br><strong>SPIDER_COPY_TABLES</strong>:(复制表数据)Copy table data<br><strong>SPIDER_FLUSH_TABLE_MON_CACHE</strong>:(刷新 Spider 监视服务器信息)Refreshing Spider monitoring server information</p><p>(UDF:User-Defined Functions,用户定义函数,随着 Spider 存储引擎的安装一并安装,是一种用新函数扩展 MariaDB 的方式,该新函数的工作方式类似于本机(内置)MariaDB 函数)</p><p>本节中,没有特殊说明,一般都是在 spider server 中执行的语句</p><h2 id="SPIDER-DIRECT-SQL"><a href="#SPIDER-DIRECT-SQL" class="headerlink" title="SPIDER_DIRECT_SQL"></a>SPIDER_DIRECT_SQL</h2><p>语法:</p><pre><code>SPIDER_DIRECT_SQL('sql', 'tmp_table_list', 'parameters')</code></pre><p>说明:</p><blockquote><p>一个与 Spider Storage Engine 一起安装的 UDF,此功能用于在远程服务器上执行 SQL 字符串 sql,如参数中所定义。 如果返回任何结果集,它们将存储在 tmp_table_list 中。</p></blockquote><blockquote><p>如果 SQL 成功执行,则该函数返回 1;如果失败,则返回 0。</p></blockquote><p>示例:</p><pre><code class="sql">-- 创建一个临时表CREATE TEMPORARY TABLE test.res( id int(10) unsigned NOT NULL, accountName varchar(20) NOT NULL DEFAULT '', name varchar(128) NOT NULL DEFAULT '') ENGINE=MEMORY;</code></pre><pre><code class="sql">-- 执行SPIDER_DIRECT_SQL语句SELECT SPIDER_DIRECT_SQL('SELECT * FROM test.opportunities', 'res', 'srv "backend1", port "3306"');</code></pre><p><img alt="执行SPIDER_DIRECT_SQL" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/1.png" class="lazyload"></p><pre><code class="sql">-- 查询执行结果SELECT * FROM test.res;</code></pre><p><img alt="执行SPIDER_DIRECT_SQL结果" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/2.png" class="lazyload"></p><h2 id="SPIDER-BG-DIRECT-SQL"><a href="#SPIDER-BG-DIRECT-SQL" class="headerlink" title="SPIDER_BG_DIRECT_SQL"></a>SPIDER_BG_DIRECT_SQL</h2><p>语法:</p><pre><code>SPIDER_BG_DIRECT_SQL('sql', 'tmp_table_list', 'parameters')</code></pre><p>描述:</p><blockquote><p>在远程服务器上后台执行给定的, 如参数列表中所定义的 SQL 语句;</p></blockquote><blockquote><p>如果查询返回结果集,则将结果存储在给定的临时表中。</p></blockquote><blockquote><p>当给定的 SQL 语句执行成功时,此函数返回被调用的 UDF 的数目。当给定的 SQL 语句失败时,它返回 0。</p></blockquote><p>示例:</p><p>准备操作,在 backend2 的远程主机 MariaDB 上,给 test.opportunities 表添加一条数据:</p><pre><code class="sql">INSERT INTO test.opportunities(id, accountName, name, owner, amount, closeDate, stageName)VALUES(1, 'ubut18test', 'spider', 'spider', 30, '2020-02-28', 'halo');</code></pre><p>在 spider server 本机的 MariaDB 的 test 数据库新建一个临时表 res2:</p><pre><code class="sql">-- 创建一个临时表CREATE TEMPORARY TABLE if not exists test.res2( id int(10) unsigned NOT NULL, accountName varchar(20) NOT NULL DEFAULT '', name varchar(128) NOT NULL DEFAULT '') ENGINE=MEMORY;</code></pre><p>执行 SPIDER_BG_DIRECT_SQL 示例语句:</p><pre><code class="sql">SELECT SPIDER_BG_DIRECT_SQL('SELECT * FROM test.opportunities', 'test.res2', 'srv "backend2", port "3307"')AS "Direct Query";</code></pre><p><img alt="执行 SPIDER_BG_DIRECT_SQL示例语句" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/3.png" class="lazyload"></p><p>查看结果,就是刚刚 backend2 新加的那条数据:</p><pre><code class="sql">SELECT * FROM test.res2;</code></pre><p><img alt="SPIDER_BG_DIRECT_SQL执行结果" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/4.png" class="lazyload"></p><h2 id="SPIDER-COPY-TABLES-无果"><a href="#SPIDER-COPY-TABLES-无果" class="headerlink" title="SPIDER_COPY_TABLES(无果)"></a>SPIDER_COPY_TABLES(无果)</h2><p>语法:</p><pre><code>SPIDER_COPY_TABLES(spider_table_name, source_link_id, destination_link_id_list [,parameters])</code></pre><p>说明:</p><blockquote><p>此函数可以在不停止 MariaDB service 的情况下,把表数据从<code>source_link_id</code>复制到<code>destination_link_id_list</code>。</p></blockquote><blockquote><p>如果 spider 表已被分区,那么表名就需要是<code>table_name#P#partition_name</code>格式。</p></blockquote><p><strong>(to be honest,这两个 id 还没有研究透彻,测试示例会报错,可以协助指出以下示例无法执行的原因,谢谢。)</strong></p><p><del>示例:</del></p><p><del>例如有执行之前的按 List 分区操作,那么执行<code>SELECT table_name FROM mysql.spider_tables;</code>语句,可以看到类似的数据:</del></p><p><del><img alt="sprider list分区" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/5.png" class="lazyload"></del></p><p><del>而此时该表的数据应该是:</del></p><p><del><img alt="opportunitiesByList表数据" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/6.png" class="lazyload"></del></p><p><del>为了方便查看分区的效果,按照 bylist 建立分区的规则,向 opportunitiesByList 表插入一些数据:</del></p><pre><code class="sql">INSERT INTO test.opportunitiesByList (id, accountName, name, owner, amount, closeDate, stageName)VALUES(4, 'spiderserver', 'spiderserver', 'Bill', 30, '2020-02-28', 'hall'),(5, 'spiderserver', 'spiderserver', 'Bob', 30, '2020-02-28', 'hall'),(6, 'spiderserver', 'spiderserver', 'Chris', 30, '2020-02-28', 'hall'),(7, 'spiderserver', 'spiderserver', 'Maria', 30, '2020-02-28', 'hall'),(8,'spiderserver', 'spiderserver', 'Olivier', 30, '2020-02-28', 'hall');SELECT * FROM test.opportunitiesByList;</code></pre><p><del>结果如下:</del></p><p><del><img alt="向 opportunitiesByList 表插入一些数据" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/7.png" class="lazyload"></del></p><p><del>而 pt1 分区的值:</del></p><p><img alt="pt1 分区的值" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/8.png" class="lazyload"></p><p><del>所以,如果要复制 opportunitiesByList 表数据,就例如:opportunitiesByList#P#pt1 的数据复制到 opportunitiesByList#P#px 中去:</del></p><pre><code>select spider_copy_tables('test.opportunities','1','2');select spider_copy_tables('test.opportunitiesByList#P#pt1','1','0');</code></pre><p>#############</p><p><del>这个实际的用法,还是没有搞清楚,这两个< source_link_id > <destination_link_id_list>到底是什么意思,执行上述语句,报错 SQL 错误 [12704][hy000]: (conn=74) Source table is not found,暂时没有找到相关资料。</destination_link_id_list></del></p><p>#############</p><h2 id="SPIDER-FLUSH-TABLE-MON-CACHE"><a href="#SPIDER-FLUSH-TABLE-MON-CACHE" class="headerlink" title="SPIDER_FLUSH_TABLE_MON_CACHE"></a>SPIDER_FLUSH_TABLE_MON_CACHE</h2><p>语法:</p><pre><code>SPIDER_FLUSH_TABLE_MON_CACHE()</code></pre><p>描述:</p><blockquote><p>此函数用于刷新监控服务器(monitoring server)的信息。返回 1。</p></blockquote><p>示例:</p><pre><code>SELECT SPIDER_FLUSH_TABLE_MON_CACHE();</code></pre><p><img alt="SPIDER_FLUSH_TABLE_MON_CACHE执行结果" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/9.png" class="lazyload"></p><p>到这里就简单说完 spider 存储引擎的使用了,主要特点就是处理不同的 MariaDB 实例就像在处理同一个实例一样。</p><p>更多的内容,可以去官网学习了解:<br><a href="https://mariadb.com/kb/en/spider/" target="_blank" rel="noopener">https://mariadb.com/kb/en/spider/</a></p><h1 id="补充:查看-MariaDB-使用硬盘空间情况"><a href="#补充:查看-MariaDB-使用硬盘空间情况" class="headerlink" title="补充:查看 MariaDB 使用硬盘空间情况"></a>补充:查看 MariaDB 使用硬盘空间情况</h1><p>安装 DISKS 插件:</p><pre><code>INSTALL SONAME 'disks'</code></pre><p>使用:</p><pre><code>SELECT * FROM Information_Schema.DISKS</code></pre><p><img alt="使用disks插件查看mariadb硬盘占用" data-src="/../images/TechnicalEssays/MariaDBSeries/15mariadb-spider-function/10.png" class="lazyload"></p><p>限制:</p><ul><li>MariaDB 10.1.32 加入;</li><li>从 MariaDB 10.4.7,MariaDB 10.3.17,MariaDB 10.2.26 和 MariaDB 10.1.41 开始,它需要 FILE 权限;</li><li>该插件仅适用于 Linux。</li></ul>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十四)Spider使用示例</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/</url>
<content type="html"><![CDATA[<h1 id="Spider-使用簡單示例:"><a href="#Spider-使用簡單示例:" class="headerlink" title="Spider 使用簡單示例:"></a>Spider 使用簡單示例:</h1><h2 id="準備工作"><a href="#準備工作" class="headerlink" title="準備工作"></a>準備工作</h2><p>有三個設備安裝 MariaDB</p><p>簡單的架構一個 spider server,兩個后端 server:backend1 和 backend2;</p><p>在我的例子里,對應的主機名和 IP 分別是:<br>spider server(ubt18) :主機名:<code>sanotsu</code>,ip:192.168.28.93;<br>backend1(ubt18):主機名:<code>david</code>,,ip:192.168.28.72;<br>backend2(win7):主機名:<code>davidsu</code>,,ip:192.168.28.80。</p><h2 id="1、spider-server-安裝-Spider"><a href="#1、spider-server-安裝-Spider" class="headerlink" title="1、spider server 安裝 Spider"></a>1、spider server 安裝 Spider</h2><p>MariaDB package 並無相關套件,需要終端安裝</p><pre><code>sudo apt install mariadb-plugin-spider</code></pre><p>確認是否安裝成功</p><p>使用任一指令:<br><code>show plugins;</code>,<code>show engines;</code>或<code>show tables from mysql like '%spider%';</code>.</p><p>有看到 spider 相關值或變量就說明成功。</p><h2 id="2、backend-MariaDB-建立-spider-使用的賬戶"><a href="#2、backend-MariaDB-建立-spider-使用的賬戶" class="headerlink" title="2、backend MariaDB 建立 spider 使用的賬戶"></a>2、backend MariaDB 建立 spider 使用的賬戶</h2><p>分別在兩個 backend 創建 spider server 可訪問的賬戶:</p><pre><code>grant all on test.* to spider@'192.168.28.93' identified by 'spider';</code></pre><p>創建完之後,在 spider server 測試能否連接到兩個 backend:</p><p>只用終端輸入指令:<code>mysql -uspider -p -h 192.168.28.72</code>,或者直接用工具 dbeaver 通過 spider 帳號連接到 backend。</p><p><img alt="測試連接到backend" data-src="/../images/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/1.png" class="lazyload"><br><img alt="測試連接到backend" data-src="/../images/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/2.png" class="lazyload"></p><h2 id="3、在-backend-創建示例表"><a href="#3、在-backend-創建示例表" class="headerlink" title="3、在 backend 創建示例表"></a>3、在 backend 創建示例表</h2><p>在 backend1 和 backend2 設備的 MariaDB 創建 test 數據庫(如果沒有的話),再創建一個示例表,如下:</p><pre><code class="sql">create table opportunities ( id int, accountName varchar(20), name varchar(128), owner varchar(7), amount decimal(10,2), closeDate date, stageName varchar(11), primary key (id), key (accountName)) engine=InnoDB;</code></pre><h2 id="4、在-spider-server-上創建服務器條目-server-entries"><a href="#4、在-spider-server-上創建服務器條目-server-entries" class="headerlink" title="4、在 spider server 上創建服務器條目(server entries)"></a>4、在 spider server 上創建服務器條目(server entries)</h2><p>虽然连接信息也可以在注释中内联指定,但是定义一个代表每个远程后端服务器连接的服务器对象更简洁。語句如下:</p><pre><code class="sql">create server backend1 foreign data wrapper mysql options(host '192.168.28.72', database 'test', user 'spider', password 'spider', port 3306);create server backend2 foreign data wrapper mysql options(host '192.168.28.80', database 'test', user 'spider', password 'spider', port 3307);flush tables;</code></pre><p>端口不同是因為 win7 主機上有安裝 mysql 和 MariaDB,區分了端口,注意遠端 MariaDB server 主機的 IP 地址正確。</p><p>注意:</p><p>请记住,如果出于任何原因需要删除、重新创建或以其他方式修改服务器定义,则还需要执行<code>FLUSH TABLES语句</code>。 否则,Spider 会继续使用旧的服务器定义,这可能导致查询引发错误:<code>Error 1429: Unable to connect to foreign data source</code></p><h2 id="5、spider-用例:"><a href="#5、spider-用例:" class="headerlink" title="5、spider 用例:"></a>5、spider 用例:</h2><h3 id="5-1-處理遠端表"><a href="#5-1-處理遠端表" class="headerlink" title="5.1 處理遠端表"></a>5.1 處理遠端表</h3><p>在这种情况下,将创建一个 spider 表,以允许远程访问 backend1 上托管的机会表。 然后,这将允许从 spider server 向 backend1 服务器執行查询和远程 DML 操作.</p><p>在 spider server 創建一個 spider table,連接到遠端主機 backend1:</p><pre><code class="sql">create table test.opportunities ( id int, accountName varchar(20), name varchar(128), owner varchar(7), amount decimal(10,2), closeDate date, stageName varchar(11), primary key (id), key (accountName)) engine=spider comment='wrapper "mysql", srv "backend1" , table "opportunities"';</code></pre><p>此時,在 spider server 的 test 數據庫中,建立了一個直接關聯到了 backend 主機上的 test.opportunities 表。</p><p><strong>在 spider server 對該表做 DML 都會對 backend1 中關聯表生效,執行查詢也是對該表數據的查詢</strong>。</p><p>演示:在 backend1 中 test.opportunities 插入一條數據</p><pre><code class="sql">INSERT INTO test.opportunities (id, accountName, name, owner, amount, closeDate, stageName) VALUES(1, 'backend1', 'backend1', 'back1', 30, '2020-02-28', 'halo');</code></pre><p><img alt="在backend1中test.opportunities插入一條數據" data-src="/../images/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/3.png" class="lazyload"></p><p>再在 spider server 中查詢該表,可以得到該數據:</p><pre><code class="sql">SELECT id, accountName, name, owner, amount, closeDate, stageName FROM test.opportunities;</code></pre><p>因為有設定 id 為主鍵,所以在 spider server 對該表新加一條已存在值的 id,會報錯:</p><pre><code class="sql">INSERT INTO test.opportunities (id, accountName, name, owner, amount, closeDate, stageName) VALUES(1, 'spiderserver', 'spiderserver', 'test', 30, '2020-02-28', 'hall');</code></pre><p>不過正確插入值之後,執行成功,然后可以查詢到新增的值</p><p><img alt="在 spider server 中查詢該表已有數據,並再插入一條數據" data-src="/../images/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/4.png" class="lazyload"></p><p>再回到 backend1,查看該 test.opportunities 表,雖然未在 backend1 中新增,但已有新增的值:</p><p><img alt="backend1中對應表可見server新插入的數據" data-src="/../images/TechnicalEssays/MariaDBSeries/14mariadb-spider-example/5.png" class="lazyload"></p><h3 id="5-2-數據分片-sharding"><a href="#5-2-數據分片-sharding" class="headerlink" title="5.2 數據分片(sharding)"></a>5.2 數據分片(sharding)</h3><h4 id="按-hash-分区"><a href="#按-hash-分区" class="headerlink" title="按 hash 分区"></a>按 hash 分区</h4><p>在本例中,通过对 id 进行散列(hashing)处理,创建了一个 spider 表,以便在 backend1 和 backend2 之间分布(distribute )数据。</p><p>如果 id 是一个自增的值,散列處理將可以确保值在 2 个节点之间均匀分布。</p><pre><code class="sql">create table test.opportunitiesByHash ( id int, accountName varchar(20), name varchar(128), owner varchar(7), amount decimal(10,2), closeDate date, stageName varchar(11), primary key (id), key (accountName)) engine=spider COMMENT='wrapper "mysql", table "opportunities"' PARTITION BY HASH (id)( PARTITION pt1 COMMENT = 'srv "backend1"', PARTITION pt2 COMMENT = 'srv "backend2"') ;</code></pre><h4 id="按-range-分区"><a href="#按-range-分区" class="headerlink" title="按 range 分区"></a>按 range 分区</h4><p>示例使用 accountName 來進行 range 分區,那么依照 MariaDB 的規范,需要將 accountName 欄位加入到主鍵中去。具體分區條件見示例:</p><pre><code class="sql">create table test.opportunitiesByRange ( id int, accountName varchar(20), name varchar(128), owner varchar(7), amount decimal(10,2), closeDate date, stageName varchar(11), primary key (id, accountName), key(accountName)) engine=spider COMMENT='wrapper "mysql", table "opportunities"' PARTITION BY range columns (accountName)( PARTITION pt1 values less than ('M') COMMENT = 'srv "backend1"', PARTITION pt2 values less than (maxvalue) COMMENT = 'srv "backend2"') ;</code></pre><h4 id="按-list-分区"><a href="#按-list-分区" class="headerlink" title="按 list 分区"></a>按 list 分区</h4><p>示例使用 owner 來進行 list 分區,那么依照 MariaDB 的規范,需要將 owner 欄位加入到主鍵中去。具體分區條件見示例:</p><pre><code class="sql">create table test.opportunitiesByList ( id int, accountName varchar(20), name varchar(128), owner varchar(7), amount decimal(10,2), closeDate date, stageName varchar(11), primary key (id, owner), key(accountName)) engine=spider COMMENT='wrapper "mysql", table "opportunities"' PARTITION BY list columns (owner)( PARTITION pt1 values in ('Bill', 'Bob', 'Chris') COMMENT = 'srv "backend1"', PARTITION pt2 values in ('Maria', 'Olivier') COMMENT = 'srv "backend2"') ;</code></pre><p>根據之前的說明,list 分區還可以加<code>DEFAULT</code>收納所有不滿足的值。</p><p>ref:(沒用到,后續可以用來補充)<br><a href="https://mariadb.com/resources/blog/uses-for-mariadb-and-the-spider-storage-engine/" target="_blank" rel="noopener">https://mariadb.com/resources/blog/uses-for-mariadb-and-the-spider-storage-engine/</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十三)MariaDB存储引擎Spider简介</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/</url>
<content type="html"><![CDATA[<p>新的问题:</p><p>若数据量即使使用 Partition,都不是单一台主机有办法处理;<br>存放要分散,但存取要集中。</p><p>这个时候,就可以考虑 Spider 存储引擎。</p><p>事实上,<strong>对于数据驱动的功能,都可能面临类似的问题,数据库日益膨大,单表、单数据库、单机器已经不能存储和处理数据了。</strong> 所以会有上述说明的分片设计。</p><p>针对不同程度的数据,会选择到不同的具体分片实现,这也是上述说明的各种单表的分区作业。</p><p>不过基于有些引擎的限制或者功能不够强大,可能在数据库分片上无法实现跨设备的作业。</p><p>但是 Spider 引擎可能提供了一个比较好的解决方案。</p><h1 id="Spider-是什么?"><a href="#Spider-是什么?" class="headerlink" title="Spider 是什么?"></a>Spider 是什么?</h1><p>Spider 是 MariaDB 内置的一个可插拔用于 MariaDB/MySQL 数据库分片的存储引擎,充当应用服务器和远程后端 DB 之间的代理(中间件),它可以轻松实现 MariaDB/MySQL 的横向和纵向扩展,突破单台 MariaDB/MySQL 的限制,支持范围分区、列表分区、哈希分区,支持 XA 分布式事务,支持跨库 join。完成数据库跨越多组实例(instances)。</p><blockquote><p>使用 Spider 存储引擎创建表后,该表将链接到远程服务器上的表。远程表可以是任何存储引擎。通过建立从本地 MariaDB 服务器到远程 MariaDB 服务器的连接,可以具体实现表链接。该链接对于属于同一事务的所有表共享。</p></blockquote><p><img alt="图源 MariaDB 博客" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/1.png" class="lazyload"></p><p><img alt="图源 MariaDB 官网" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/2.png" class="lazyload"></p><p>简单说起来:</p><blockquote><p><strong>Spider 首先提供的是从另一个 MariaDB 服务器访问一个 MariaDB 服务器(也可以是其它类型数据库服务器)上的表的方法。</strong></p></blockquote><p>保存实际表数据的 MariaDB 服务器上根本没有任何特定的 Spider 代码,它是一个普通的 MariaDB 服务器。MariaDB 服务器被配置为访问该数据,然后使用 Spider 存储引擎使用通常的 MariaDB 协议访问另一台服务器上的数据。</p><p><img alt="MariaDB spider 图示" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/3.png" class="lazyload"><br>图源 mariadb 博客(<a href="https://mariadb.com/resources/blog/uses-for-mariadb-and-the-spider-storage-engine/" target="_blank" rel="noopener">https://mariadb.com/resources/blog/uses-for-mariadb-and-the-spider-storage-engine/</a>)</p><blockquote><p>可以看到,Spider 只在引用节点上处于活动状态,目标节点不需要安装 Spider。创建“spider 表”意味着我们定义一个表,该表包含目标表中相同列或列的子集,并引用目标服务器。</p></blockquote><blockquote><p>还要注意,“spider 节点”上没有这些表的数据,也没有重复的数据,所有数据都驻留在目标节点上。</p></blockquote><h1 id="Spider-存储引起核心概念"><a href="#Spider-存储引起核心概念" class="headerlink" title="Spider 存储引起核心概念"></a>Spider 存储引起核心概念</h1><p>这是几乎每一篇介绍 Spider 的文章都会提到的东西。</p><blockquote><p>典型的 Spider 部署有一个<strong>无共享的集群架构(shared-nothing clustered architecture)</strong>。这个系统可以使用任何满足对硬件或软件有最低的特定要求的硬件。它由一组运行有一个或多个称为节点(node)的 MariaDB 进程的主机(computers)组成。</p></blockquote><blockquote><p>存储数据的节点将被设计为后端节点(Backend Nodes),可以是使用后端中可用的任何存储引擎的任何 MariaDB、MySQL、Oracle 服务器实例。</p></blockquote><blockquote><p>Spider 代理节点(Spider Proxy Nodes)是至少运行 MariaDB 10 版本上,用于向后端节点声明每个表的附件(attachment)。此外,还可以设置 Spider 代理节点,以便将表拆分并镜像到多个后端节点。</p></blockquote><p>Spider 常见用例:</p><p><img alt="MariaDB spider 常见用例1" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/4-1.png" class="lazyload"><br><img alt="MariaDB spider 常见用例2" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/4-2.png" class="lazyload"></p><p>图源官网(<a href="https://mariadb.com/kb/en/spider-storage-engine-core-concepts/" target="_blank" rel="noopener">https://mariadb.com/kb/en/spider-storage-engine-core-concepts/</a>)</p><p>此外 Spider 引擎的底层架构和优化设计还是比较复杂的,有兴趣可以查看官网了解,或者从下图中窥见一二:</p><p><img alt="MariaDB spider 底层架构和优化设计" data-src="/../images/TechnicalEssays/MariaDBSeries/13mariadb-spider-storage-engine/6.png" class="lazyload"></p><p>图源官网(<a href="https://mariadb.com/kb/en/spider-storage-engine-core-concepts/" target="_blank" rel="noopener">https://mariadb.com/kb/en/spider-storage-engine-core-concepts/</a>)</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十二)MariaDB中的分区操作</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/</url>
<content type="html"><![CDATA[<p><strong>数据量不大的中小型规模 size 的 Table 原则是还是采用 Table+Index 设计为最佳化的思考重点。</strong></p><p>在大数据考虑数据分片的时候,有两点也是重点:</p><p>一是空间,数据存放的存储空间是否足够,易于扩展。<br>二是时间,对于数据存取是否有限制,能否优化。</p><p>此外就是:</p><ul><li>基本的数据与索引区隔无法满足 Big Data 所需的数据分片</li><li>高达数百 TB 的数据表毫无疑问将导致 DML 语法执行缺乏效率</li><li>海量型数据建议采用 分区(Partition) 机制分离储存数据</li><li>数据分区存放可以有效提升数据查询与异动操作</li></ul><p>对于 MyISAM 引擎,可以设计分离数据文件和索引文件来加快数据存取。例如:</p><pre><code class="sql">CREATE TABLE X ( …)ENGINE=MyISAM,DATA DIRECTORY = '/var/p1',INDEX DIRECTORY = '/var/p2';</code></pre><p>当然,InnoDB 采用 System TableSpace 集中存放,无法支持此种方式,需要通过设定去转换成一个 table 一个 file。</p><h1 id="MariaDB-表分区(Table-Partition)"><a href="#MariaDB-表分区(Table-Partition)" class="headerlink" title="MariaDB 表分区(Table Partition)"></a>MariaDB 表分区(Table Partition)</h1><p>MariaDB 10 提供 Table 分区储存功能,大量数据切割成不同储存区域(Partition),Partiton 底层的档案可再切成多档方式储存(Sub-Partition)。</p><p>使用 Plugin 方式扩充</p><p>由 Storage Engine 自行实作,MariaDB 已支持的包括 InnoDB, TokuDB , Memory, Aria, Spider、MyISAM, Archive, BLACKHOLE</p><p>MySQL 仅支援 InnoDB</p><p><strong>MariaDB 透过内建的 Partiton Storage Engine 提供此项分区服务</strong>。</p><p>查看是否有安装此引擎:</p><pre><code class="sql">SELECT * FROM information_schema.PLUGINS WHERE PLUGIN_NAME like "%part%";</code></pre><p><img alt="查看是否启用分区插件" data-src="/../images/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/1.png" class="lazyload"></p><p>系统管理方式与一般 tables 相同,System Partition 提供元数据(Metadata): <code>Informaton_Schema.PARTITIONS</code>。</p><p>分区作业时,有些东西还需要特别考虑,例如分区类型、分区计算、目标表的形态、分区前后的应用等等。</p><h1 id="MariaDB-的分区类型使用示例"><a href="#MariaDB-的分区类型使用示例" class="headerlink" title="MariaDB 的分区类型使用示例"></a>MariaDB 的分区类型使用示例</h1><p>MariaDB 的分区类型主要有:</p><ul><li>RANGE ( 单一字段)</li><li>LIST ( 单一字段)</li><li>RANGE COLUMNS and LIST COLUMNS, HASH COLUMNS(多栏)</li><li>HASH ( 单一字段)</li><li>KEY ( 单一字段 )</li><li>LINEAR HASH, LINEAR KEY</li><li>SYSTEM_TIME</li></ul><h2 id="RANGE-分区类型"><a href="#RANGE-分区类型" class="headerlink" title="RANGE 分区类型"></a>RANGE 分区类型</h2><blockquote><p>RANGE 分区类型用于为每个分区分配由分区表达式生成的值的范围。<strong>范围必须是有序的,连续的且不重叠的</strong>。最小值始终包含在第一个范围内。最高值可以包含在最后一个范围内,也可以不包含在最后一个范围内。</p></blockquote><blockquote><p>这种分区方法的一种变体 RANGE COLUMNS 允许我们使用多列和更多数据类型。</p></blockquote><p>语法:</p><p>CREATE TABLE 语句的最后一部分可以是新表分区的定义。对于 RANGE 分区</p><pre><code class="sql">PARTITION BY RANGE (partitioning_expression)( PARTITION partition_name VALUES LESS THAN (value), [ PARTITION partition_name VALUES LESS THAN (value), ... ])</code></pre><p>说明:</p><ul><li>partitioning_expression 是一个 SQL 表达式,从每行返回一个值,最简单的就是一个字段名(column name),用于确定哪个分区需要包含一行数据( which partition should contain a row)。</li><li>partition_name 是分区的名称。</li><li><strong>value 指示该分区的上限,表达式必须回传 deterministic / nonconstant 值(Integer 或 NULL)</strong></li><li>不支持 stored functions 以及 user-defined functions</li><li>不支持 / 除法运算子( DIV , MOD 可 ) ( / 回传的是 Float 10/3 = 3.3 )</li><li>表达式不可消耗过多资源/时间</li><li>使用针对 Partition 最佳化过的分区函数(partitioning function),例如 YEAR() , TO_DAYS(), TO_SECONDS() 。</li><li>如果存在问题,可以将 MAXVALUE 指定为最后一个分区的值。但是请注意,不能拆分现有 RANGE 分区表的分区。可以附加新的分区,但是如果最后一个分区的上限为 MAXVALUE,则将无法添加新分区。</li></ul><p>示例:</p><p>通过年份对日志表进行分区</p><pre><code class="sql">CREATE TABLE test200221.log( id INT UNSIGNED NOT NULL AUTO_INCREMENT, timestamp DATETIME NOT NULL, user INT UNSIGNED, ip BINARY(16), action VARCHAR(20), PRIMARY KEY (id,timestamp)) ENGINE = InnoDBPARTITION BY RANGE (YEAR(timestamp))( PARTITION p0 VALUES LESS THAN (2013), PARTITION p1 VALUES LESS THAN (2014), PARTITION p2 VALUES LESS THAN (2015), PARTITION p3 VALUES LESS THAN (2016));</code></pre><p>注意:</p><ul><li>1、partitioning_expression 表达式中所引用的字段必须是 Primary key 中的成员</li><li>2、Primary key 包含了表达式中所有字段的组合,限缩 Unique keys 的使用</li></ul><p>如果 partitioning_expression 表达式引用的字段不是,就会出现以下错误:</p><pre><code>SQL 错误 [1503] [HY000]: (conn=51) A PRIMARY KEY must include all columns in the table's partitioning function</code></pre><ul><li>3、一般情况下,不支持的分区字段类型有 TEXT,LongText,BLOB,CLOB …(前面有提到,返回值需要是 Integer 或 NULL)</li><li>4、此外,在使用分区函数(partitioning function)时,要注意函数和字段的正确性,否则可能会出现类似的问题:</li></ul><pre><code>SQL 错误 [1486] [HY000]: (conn=51) Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed</code></pre><ul><li>5、注意插入的数据是否有对应的分区。例如示例中分区有 4 个,对应 2013~2016 年的日志,如果此时插入的有是 2020 年的日志,没有该分区,可能出现类似的错误:</li></ul><p><img alt="无对应分区报错" data-src="/../images/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/2.png" class="lazyload"></p><pre><code>但可以添加 IGNORE 关键词去去除不符合的值。上述就会插入 2015 年的那条:</code></pre><p><img alt="去除不符合分区的值" data-src="/../images/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/3.png" class="lazyload"></p><ul><li>6、部分 Partition 语法 需要对 Partition 进行命名,MariaDB 可自行命名( pN , N(0~N ) ),人工编码最长长度 61 字符,推荐有意义的命名。</li></ul><h2 id="LIST-分区类型"><a href="#LIST-分区类型" class="headerlink" title="LIST 分区类型"></a>LIST 分区类型</h2><blockquote><p>LIST 分区在概念上类似于 RANGE 分区。在这两种情况下,都需要确定一个分区表达式(一个字段(column),或者稍微复杂一些的计算),然后使用它来确定哪些分区将包含每一行。但是,对于 RANGE 类型,分区是通过为每个分区分配一个值范围来完成的。对于 LIST 类型,将会为每个分区分配一组值。如果分区表达式可以返回一组有限的值(a limited set of values),则通常是首选方法。</p></blockquote><blockquote><p>这种分区方法的一种变体 LIST COLUMNS 允许使用多列和更多数据类型。</p></blockquote><p>语法:</p><pre><code class="sql">PARTITION BY LIST (partitioning_expression)( PARTITION partition_name VALUES IN (value_list), [ PARTITION partition_name VALUES IN (value_list), ... ] [ PARTITION partition_name DEFAULT ])</code></pre><p>说明:</p><ul><li>依据数据类型,符合指定项目则存入指定 Partition</li><li>partitioning_expression 是一个 SQL 表达式,从每行返回一个值,最简单的就是一个字段名(column name),用于确定哪个分区需要包含一行数据( which partition should contain a row)。</li><li>partition_name 是分区的名称。</li><li>value 是一系列值(a list of values),表达式返回这些值,就能存入该分区</li><li>EXPRESSION 表达式 必须是 Integer 回传值</li><li>搭配 DEFAULT 收纳所有不符合其它分区条件的数据( 10.2 之后 加入),但也只能有一个 DEFUILT 分区。可设定超出范围的处理: NULL</li></ul><p>示例:</p><p>依据文章语言分类,所有可能的筛选值必须判断,Language 事实上是 Foreign key 对应到 Language Table(所以用 id 表示),Partition table 不支持 Fkey,Language 必须是 正整数或 null。</p><pre><code class="sql">DROP table if exists test200221.article;CREATE TABLE test200221.article( id integer unsigned not null auto_increment, date date not null, author varchar(100), language tinyint unsigned, text text, primary key(id,language))ENGINE=InnoDBpartition by LIST (language)( PARTITION p0 VALUES IN (1), PARTITION p1 VALUES IN (2,3), PARTITION p2 VALUES IN (4,5,6,7,8,9), PARTITION px VALUES IN (NULL ) -- 或 PARTITION px DEFAULT)</code></pre><h2 id="RANGE-COLUMNS-和-LIST-COLUMNS-分区类型"><a href="#RANGE-COLUMNS-和-LIST-COLUMNS-分区类型" class="headerlink" title="RANGE COLUMNS 和 LIST COLUMNS 分区类型"></a>RANGE COLUMNS 和 LIST COLUMNS 分区类型</h2><blockquote><p>RANGE COLUMNS 和 LIST COLUMNS 分别是 RANGE 和 LIST 的变体。对于这些分区类型,不是一个分区表达式(partitioning _expression)。而是接受一个或多个字段(columns)。适用以下规则:</p><ul><li>该列表可以包含一个或多个字段(columns)。</li><li>字段(columns)可以是任何 integer,string,DATE 和 DATETIME 类型。</li><li>仅允许使用纯字段(bare columns),不能加表达式。<br>将所有指定的列与指定的值进行比较,以确定哪个分区应包含特定的行。</li></ul></blockquote><p>字段型别:<br>Integer ( 不可产生负数 )、Date, DateTime、CHAR, VARCHAR, BINARY , VARBINARY、不可使用任何 functions, 运算子符号 (只能单纯使用字段…)</p><p>语法:</p><p>RANGE COLUMNS 分区类型:</p><pre><code class="sql">PARTITION BY RANGE COLUMNS (col1, col2, ...)( PARTITION partition_name VALUES LESS THAN (value1, value2, ...), [ PARTITION partition_name VALUES LESS THAN (value1, value2, ...), ... ])</code></pre><p>LIST COLUMNS 分区类型:</p><pre><code class="sql">PARTITION BY LIST COLUMNS (partitioning_expression)( PARTITION partition_name VALUES IN (value1, value2, ...), [ PARTITION partition_name VALUES IN (value1, value2, ...), ... ] [ PARTITION partititon_name DEFAULT ])</code></pre><p>两者的区别:</p><p>RANGE COLUMNS 是返回的值小于指定的值,第一个匹配条件的分区将包含该值;<br>LIST COLUMNS 返回的值包含在给定的值里面,同样允许且仅运行一个 DEFAULT 分区。</p><p>示例,修改上述 article 表,新加 year 字段:</p><pre><code class="sql">DROP table if exists test200221.article2;CREATE TABLE test200221.article2 ( id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, date DATE NOT NULL, year CHAR(4) NOT NULL, author VARCHAR(100), language TINYINT UNSIGNED, text TEXT, PRIMARY KEY (id, language, year)) ENGINE = InnoDBPARTITION BY RANGE COLUMNS (language, year) ( PARTITION p0 VALUES LESS THAN (1, '2010'), PARTITION p1 VALUES LESS THAN (1, '2020'), PARTITION p2 VALUES LESS THAN (100, '2010'), PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE));</code></pre><h2 id="MariaDB-的分区的限制-Partitioning-Limitations"><a href="#MariaDB-的分区的限制-Partitioning-Limitations" class="headerlink" title="MariaDB 的分区的限制(Partitioning Limitations)"></a>MariaDB 的分区的限制(Partitioning Limitations)</h2><blockquote><p>每个表最多可包含 8192 个分区(自 MariaDB 10.0.4)。在 MariaDB 5.5 和 10.0.3 中,限制是 1024。</p></blockquote><blockquote><p>目前,查询永远不会并行化,即使它们涉及多个分区。</p></blockquote><blockquote><p>只有当存储引擎支持分区时,才能对表进行分区。</p></blockquote><blockquote><p>所有分区必须使用相同的存储引擎。</p></blockquote><blockquote><p>分区表不能包含外键,也不能被外键引用。</p></blockquote><blockquote><p>查询缓存(query cache)不知道分区和分区修剪(partitioning and partition pruning)。修改分区将使与整个表相关的条目失效。</p></blockquote><blockquote><p>当 binlog_format=ROW 且分区表被更新(update)时,更新的速度可能比等效的非分区表更慢。</p></blockquote><blockquote><p>分区表的分区表达式中使用的所有字段(column)必须是必须是 unique 结果( PRIMARY, UNIQUE_KEY 可支持)。</p></blockquote><h2 id="分区文件"><a href="#分区文件" class="headerlink" title="分区文件"></a>分区文件</h2><p>分割后的 Table 将产生多个个别档案</p><p>文件名编码: table_name#P#partition_name.ext</p><p>在 InnoDB 下,会有以下 3 类:</p><ul><li>table_name.frm</li><li>table_name.par</li><li>table_name#P#partition_name.ibd</li></ul><p><img alt="分区文件示例" data-src="/../images/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/4.png" class="lazyload"></p><h2 id="分区修剪-Partition-Pruning-和分区选择-partition-selection"><a href="#分区修剪-Partition-Pruning-和分区选择-partition-selection" class="headerlink" title="分区修剪(Partition Pruning)和分区选择(partition selection)"></a>分区修剪(Partition Pruning)和分区选择(partition selection)</h2><blockquote><p>当 WHERE 子句与分区表达式有关联时,优化器知道哪些分区与查询相关。其它分区将不会被读取。这种优化称为<strong>分区修剪</strong>。</p></blockquote><blockquote><p>可以使用 EXPLAIN 分区来了解将为给定的查询读取哪些分区。名为 partitions 的列将包含以逗号分隔的被访问分区列表。</p></blockquote><p>以之前的 article 表为例,回顾一下创建语言:</p><pre><code class="sql">CREATE TABLE test200221.article( id integer unsigned not null auto_increment, publish_date date not null, author varchar(100), language tinyint unsigned, text text, primary key(id,language))ENGINE=InnoDBpartition by LIST (language)( PARTITION p0 VALUES IN (1), PARTITION p1 VALUES IN (2,3), PARTITION p2 VALUES IN (4,5,6,7,8,9), PARTITION px VALUES IN (NULL ) -- PARTITION px DEFAULT)</code></pre><p>使用<code>EXPLAIN PARTITIONS</code>来查看哪些分区会被使用到:</p><pre><code class="sql">EXPLAIN PARTITIONS SELECT * FROM article WHERE language < 4;</code></pre><p><img alt="使用EXPLAIN查看被使用分区" data-src="/../images/TechnicalEssays/MariaDBSeries/12mariadb-partitioning/5.png" class="lazyload"></p><p>从结果来看,的确在<code>WHERE language < 4;</code>的条件下,只有 p0 和 p1 分区会有访问到。</p><p>如果优化器不知道或无法推断出哪些分区会被使用到,可以通过 PARTITION 子句强制 MariaDB 仅访问给定分区(MariaDB 10.0 开始),这也被称为<strong>分区选择</strong>。</p><p>例如:</p><pre><code class="sql">SELECT * FROM article PARTITION (p2) WHERE language = 5;</code></pre><p>所有 DML 语句均支持 PARTITION 子句:SELECT、INSERT、UPDATE、DELETE、REPLACE、LOAD DATA 等。</p><p>通常情况下,分区修剪会用在触发器(triggers)语句中。</p><p>但是如果在表上定义了 BEFORE INSERT 或者 BEFORE UPDATE 的触发器,则 MariaDB 不会预先知道分区表达式中使用的字段(column)是否会更改。因此,被迫锁定所有分区。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十一)数据分片(Sharding)和数据分区(PARTITIONing)简述</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/11data-sharing-and-partitioning/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/11data-sharing-and-partitioning/</url>
<content type="html"><![CDATA[<p>即便是 MariaDB,也有一个想要处理大数据的心。虽然可能跟其它的例如 HBase、Hive 之类的比有些差异和不足,但并不影响壮志。</p><p>简单列举两个要处理大量数据的例子:</p><ul><li>1、IoT Sensor Networks<ul><li>存取特性: 很少大量写入,但多大量读取</li><li>事务需求: 少</li><li>资料量: 累积数量庞大</li></ul></li><li>2、AI Machine Learning 领域<ul><li>搜集大量数据进行分析</li></ul></li></ul><p>使用 MariaDB 处理大量数据,先来了解一下这两点。</p><h1 id="DATA-Sharding-数据分片-和-Data-Partition-数据分区"><a href="#DATA-Sharding-数据分片-和-Data-Partition-数据分区" class="headerlink" title="DATA Sharding (数据分片)和 Data Partition(数据分区)"></a>DATA Sharding (数据分片)和 Data Partition(数据分区)</h1><p>数据分片简述</p><ul><li>单一数据库系统已无法处理 Big Data 服务需求</li><li>大部分数据库瓶颈皆处于 I/O 效能问题</li><li>提供数据分片技术将数据分散储存于多个数据库实例中</li><li>提供水平式,垂直档案分布于不同的 I/O 系统,加速数据存取</li><li>可横跨多种不同功能数据库系统</li><li>相关技术或引擎:FEDERATEDX , CONNECT , SPIDER , MAXSCALE</li></ul><p>关于数据分片,这里有一篇 2019 年 2 月发布的文章,到今天(2020/06/18)一年多,有 169.9k 的浏览量,讲解说明还不错,推荐阅读:</p><p><a href="https://www.digitalocean.com/community/tutorials/understanding-database-sharding" target="_blank" rel="noopener">Understanding Database Sharding</a></p><p>个人理解来说:</p><p><strong>分片(Sharding)</strong> 是一种与水平切分(horizontal partitioning)相关的数据库架构模式,用于在特定的 SQL 操作中减少数据读写的总量以缩减响应时间。——例如将一个表里面的行(row),分成多个不同的表的。</p><p><strong>分区(PARTITIONing)</strong> 是分片的具体做法实现,例如水平分区、垂直分区。</p><blockquote><p>分片(Sharding)将一个数据分成两个或多个较小的块,称为逻辑分片(logical shards)。然后,逻辑分片(logical shards)分布在单独的数据库节点上,称为物理分片(physical shards)。物理分片(physical shards)可以容纳多个逻辑分片(logical shards)。尽管如此,所有分片中保存的数据,共同代表整个逻辑数据集。</p></blockquote><blockquote><p>数据库分片(Database shards)是无共享架构( shared-nothing architecture)的一个例子。这意味着分片是自治的:分片间不共享任何相同的数据或服务器资源。但是在某些情况下,将某些表复制到每个分片中作为参考表是有意义的。例如,假设某个应用程序的数据库依赖于重量测量的固定转换率。通过将包含必要转换率数据的表复制到每个分片中,有助于确保查询所需的所有数据都保存在每个分片中。</p></blockquote><blockquote><p>通常,分片(Sharding)在应用程序级别进行实现。这意味着应用程序包含“要向哪个分片发送读和写”的代码。但是,某些数据库管理系统内置了分片功能,允许您直接在数据库级别实现分片。</p></blockquote><p>分片的优点:</p><blockquote><p><strong>高可用性(High Availability)</strong>:对于分片数据库,如果一个数据库分片出现故障,则仅会使部分用户无法使用应用程序或网站的一部分,而其它分片可以继续运行而不会出现任何问题。如果数据库未分片,则中断可能会导致整个应用程序不可用。</p></blockquote><blockquote><p><strong>更快的查询响应(Faster queries response)</strong>:对尚未分片的数据库提交查询时,它可能必须搜索查询表中的每一行,才能找到您要查找的结果集。对于具有大型整体数据库的应用程序,查询会变得异常缓慢。但是,通过将一个表拆分为多个表,查询必须遍历更少的行,并且其结果集可以更快地返回。</p></blockquote><blockquote><p><strong>更多的写带宽(More write bandwidth)</strong>:无需主数据库序列化写操作,就可以并行写操作,从而提高了写吞吐量。写作是许多网站的主要瓶颈。</p></blockquote><blockquote><p><strong>向外扩展(Scaling out)</strong>:对数据库进行分片可以帮助促进水平扩展(称为向外扩展)。</p></blockquote><p>分片的缺点:</p><blockquote><p><strong>增加系统的复杂性(Adds complexity in the system)</strong>:恰当地实现分片数据库体系结构是一项复杂的任务。如果处理不正确,则存在很大的风险,即分片过程可能导致数据丢失或表损坏。分片对团队的工作流程也有重大影响。用户必须从多个入口位置管理数据,而不是从单个入口点管理和访问数据,这可能对某些团队具有潜在地破坏性。</p></blockquote><blockquote><p><strong>重新平衡数据(Rebalancing data)</strong>:在分片数据库体系结构中,有时分片会超出其它分片而变得不平衡,这也称为数据库热点(database hotspot)。在这种情况下,分片数据库的任何好处都会被抵消。数据库可能需要重新分片以允许更均匀的数据分发。必须从一开始就建立重新平衡,否则在重新分片时,将数据从一个分片移动到另一个分片需要大量的停机时间。</p></blockquote><blockquote><p><strong>从多个分片连接数据(Joining data from multiple shards)</strong>:要实现一些复杂的功能,我们可能需要从分布在多个分片中的不同来源提取大量数据。我们无法发出查询并从多个分片获取数据。我们需要对不同的分片发出多个查询,获取所有响应并将其合并。</p></blockquote><blockquote><p><strong>没有原生支持(No Native Support)</strong>:并非每个数据库引擎都原生支持分片。因此,分片通常需要自己实现。这意味着通常很难找到有关分片的文档或解决问题的技巧。</p></blockquote><p>ref: <a href="https://medium.com/system-design-blog/database-sharding-69f3f4bd96db" target="_blank" rel="noopener">https://medium.com/system-design-blog/database-sharding-69f3f4bd96db</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十)MariaDB存储引擎CONNECT使用介绍</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/</url>
<content type="html"><![CDATA[<p>事实上,采用 MariaDB 作为数据库,一般是两种情况:<br>1 是觉得 MySQL 被 Oracle 收购之后,继续使用 MySQL 心里不踏实(license 和发展前景等)。<br>2 是想另外找一个生命力比较旺盛、小区比较丰富的关系型数据库。</p><p>所以一般默认的 InnoDB 和 Aria 就足够满足大部分的需求了。</p><p>不过连接处理到其它数据库,或者加载到 MariaDB 中的需求还是比较多的。例如将一份 json 文件 存在大量需要加载到 MariaDB 数据库中的数据时,这个时候就比较需要使用 CONNECT 引擎了。</p><p>注意:<strong>CONNECT 是连接到远程数据,并没有转存到 MariaDB 中。所以远程数据源的异动,MariaDB 处理查德德询得到的也是异动后的数据</strong>。</p><p>在官网(<a href="https://mariadb.com/kb/en/introduction-to-the-connect-engine/)可以看到" target="_blank" rel="noopener">https://mariadb.com/kb/en/introduction-to-the-connect-engine/)可以看到</a> CONNECT 更多特性。</p><h1 id="CONNECT-的安装与卸载"><a href="#CONNECT-的安装与卸载" class="headerlink" title="CONNECT 的安装与卸载"></a>CONNECT 的安装与卸载</h1><p>Connect Storage Engine 并未封装于 MariaDB Package 内,需要透过 Repository 安装:</p><pre><code>sudo apt install mariadb-plugin-connect</code></pre><p>会同时安装依赖库 libodbc1</p><p>然后再安装插件(我测试时已有默认安装上并启用,如果没有默热安装启用,执行此句)</p><pre><code>install soname 'ha_connect'</code></pre><p>此次,查看引擎可以看到新装的 CONNECT:</p><p><img alt="查看CONNETC已安装" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/1.png" class="lazyload"></p><p>卸载,执行<code>UNINSTALL SONAME 'ha_connect';</code>即可。</p><h1 id="使用-CONNECT-连接处理-json-文件"><a href="#使用-CONNECT-连接处理-json-文件" class="headerlink" title="使用 CONNECT 连接处理 json 文件"></a>使用 CONNECT 连接处理 json 文件</h1><p>有两点要做:1 是指定表的类型,2 是指定要连接的文件(远程表)的类型和文件名。</p><p>前者是创建表时要指定<code>engine=CONNECT</code>,后者是要针对需要访问的不同类型的文件,指定 table_type 参数为指定类型。</p><p>目前,table_type 的类型有很多种,除了常见的 json、csv、xml,还有例如<br>BIN, DBF, DIR, DOS, FIX, ZIP, JDBC, ODBC, MONGO, MYSQL, WMI, MAC 等。</p><p>以 json 为例</p><h2 id="1、准备一份JsonDemo-json文件如下-官网示例"><a href="#1、准备一份JsonDemo-json文件如下-官网示例" class="headerlink" title="1、准备一份JsonDemo.json文件如下(官网示例)"></a>1、准备一份<code>JsonDemo.json</code>文件如下(官网示例)</h2><pre><code class="json">[ { "ISBN": "9782212090819", "LANG": "fr", "SUBJECT": "applications", "AUTHOR": [ { "FIRSTNAME": "Jean-Christophe", "LASTNAME": "Bernadac" }, { "FIRSTNAME": "François", "LASTNAME": "Knab" } ], "TITLE": "Construire une application XML", "PUBLISHER": { "NAME": "Eyrolles", "PLACE": "Paris" }, "DATEPUB": 1999 }, { "ISBN": "9782840825685", "LANG": "fr", "SUBJECT": "applications", "AUTHOR": [ { "FIRSTNAME": "William J.", "LASTNAME": "Pardi" } ], "TITLE": "XML en Action", "TRANSLATED": { "PREFIX": "adapté de l'anglais par", "TRANSLATOR": { "FIRSTNAME": "James", "LASTNAME": "Guerin" } }, "PUBLISHER": { "NAME": "Microsoft Press", "PLACE": "Paris" }, "DATEPUB": 1999 }]</code></pre><h2 id="2、放到一个-MariaDB-可以访问的路径"><a href="#2、放到一个-MariaDB-可以访问的路径" class="headerlink" title="2、放到一个 MariaDB 可以访问的路径"></a>2、放到一个 MariaDB 可以访问的路径</h2><p>这一点很重要,否则可能报错:</p><pre><code>SQL 错误 [1296] [HY000]: (conn=65) Got error 174 'Open(map) error 13 on /<path>/JsonDemo.json' from CONNECT</code></pre><p>例如本例放到了/tmp 活页夹下</p><p><img alt="json文件放在可以访问的路径" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/2.png" class="lazyload"></p><h2 id="3、MariaDB-命令窗口执行测试"><a href="#3、MariaDB-命令窗口执行测试" class="headerlink" title="3、MariaDB 命令窗口执行测试"></a>3、MariaDB 命令窗口执行测试</h2><p>语句及说明如下:</p><pre><code class="sql">-- 创建一个数据库CREATE DATABASE test200222;-- 在数据库中新建一张表,并制定engine为CONNECT,-- table_type为JSON,File_name为json文件存放位置DROP table if exists test200222.jsample;create table test200222.jsample ( ISBN char(15), LANG char(2), SUBJECT char(32), AUTHOR char(128), TITLE char(32), TRANSLATED char(80), PUBLISHER char(20), DATEPUB int(4))engine=CONNECT table_type=JSONFile_name='/tmp/JsonDemo.json';-- 条件查询,查看是否有数据select isbn, author, title, publisher from test200222.jsample;</code></pre><p>查询结果应当如下</p><p><img alt="通过CONNECT查询json文件数据" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/3.png" class="lazyload"></p><p>问题说明:<br>从查询的结果可以看出,在 JSON 中,isbn 为 9782212*的书的作者,是两个人,读入的存储结果只有一个人。<br>这是因为,默认情况下,遇到数组时,它只会读取数组的第一个值。<br>事实上,json 文件大部分情况下,都不可能只有一层,值是数据应该常见。</p><p><strong>因此 CONNECT 启用一个特殊的字段<code>field_format</code>选项 Jpath,用来描述如何显示和处理数组</strong>。</p><p>新建 jsample2 表,指定 field_format 字段:</p><pre><code class="sql">DROP table if exists test200222.jsample2;create table test200222.jsample2 ( ISBN char(15), Language char(2) field_format='LANG', Subject char(32) field_format='SUBJECT', Author char(128) field_format='AUTHOR.[" and "]', Title char(32) field_format='TITLE', Translation char(32) field_format='TRANSLATOR.PREFIX', Translator char(80) field_format='TRANSLATOR', Publisher char(20) field_format='PUBLISHER.NAME', Location char(16) field_format='PUBLISHER.PLACE', Year int(4) field_format='DATEPUB')engine=CONNECT table_type=JSONFile_name='/tmp/JsonDemo.json';</code></pre><p>注意,<strong>在 Connect 1.5,json 对象取值用的是”:”,Connect 1.6 使用”.”。</strong></p><p>同样查询一次:</p><pre><code>select isbn, author, title, publisher from jsample2;</code></pre><p><img alt="json文件放在可以访问的路径" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/4.png" class="lazyload"></p><p>当然,除了把数组的值合并到一起,还可以<strong>根据数组的值将数据拆成 2 条</strong>。</p><p>新建 jsample3 表如下:</p><pre><code class="sql">DROP table if exists test200222.jsample3;create table test200222.jsample3 ( ISBN char(15), Title char(32) field_format='TITLE', AuthorFN char(128) field_format='AUTHOR.[*].FIRSTNAME', AuthorLN char(128) field_format='AUTHOR.[*].LASTNAME', Year int(4) field_format='DATEPUB')engine=CONNECT table_type=JSONFile_name='/tmp/JsonDemo.json';</code></pre><p>注意,<strong>在 Connect 1.5,1.6,json 对象拓展符用的是”X”,Connect 1.06.006:使用”*“。</strong></p><p>查看结果:</p><pre><code class="sql">SELECT * FROM test200222.jsample3;</code></pre><p><img alt="json查看结果" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/5.png" class="lazyload"></p><p>从上可以简单窥见,’:’已被’.’取代,’[*]’已用来表示扩展,而’[X]’表示乘法。</p><p>更多 Jpath 数组规范可见下表:<br><a href="https://mariadb.com/kb/en/connect-json-table-type/#the-jpath-specification" target="_blank" rel="noopener">Jpath 规范</a></p><p><img alt=" Jpath 数组规范" data-src="/../images/TechnicalEssays/MariaDBSeries/10mariadb-connect-storage-engine/6.png" class="lazyload"></p><p>更多 CONNECT 对 json 文件的处理,可参看官网:<a href="https://mariadb.com/kb/en/connect-json-table-type/" target="_blank" rel="noopener">https://mariadb.com/kb/en/connect-json-table-type/</a></p><p>此外,除了对 JSON 文件,还有对其它常见文件的处理例如 csv、xml,都可以到官网<a href="https://mariadb.com/kb/en/connect-table-types/查看对应的table_type了解实践。" target="_blank" rel="noopener">https://mariadb.com/kb/en/connect-table-types/查看对应的table_type了解实践。</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(九)MariaDB存储引擎简介</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/09mariadb-storage-engine/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/09mariadb-storage-engine/</url>
<content type="html"><![CDATA[<h1 id="存储引擎简述"><a href="#存储引擎简述" class="headerlink" title="存储引擎简述"></a>存储引擎简述</h1><ul><li>简单说来,存储引擎是数据库管理系统用来从数据库创建、读取、更新数据的软件模块。</li><li>负责提供数据实体储存的算法</li><li>提供数据文件与索引档案的管理</li><li>MariaDB 采用 Plugin 方式动态加载/卸载 引擎模块</li><li>可透过外部安装的方式添加新的 Storage Engine</li></ul><p>查询指令:</p><p>查看所有的已启用的存储引擎:<code>show engines;</code></p><p>查询预设引擎:<code>select @@global.storage_engine;</code></p><p><img alt="查看所有的已启用的存储引擎" data-src="/../images/TechnicalEssays/MariaDBSeries/09mariadb-storage-engine/1.png" class="lazyload"></p><h1 id="简单介绍几个-MariaDB-的存储引擎"><a href="#简单介绍几个-MariaDB-的存储引擎" class="headerlink" title="简单介绍几个 MariaDB 的存储引擎"></a>简单介绍几个 MariaDB 的存储引擎</h1><h2 id="1、InnoDB-XtraDB"><a href="#1、InnoDB-XtraDB" class="headerlink" title="1、InnoDB/XtraDB"></a>1、InnoDB/XtraDB</h2><ul><li>XtraDB 属于 InnoDB 分支( Percona 负责维护),针对“效能与监控”进行强化,兼容 InnoDB 引擎。MariaDB 10.1 采用 (MariaDB 10.1),但在 MariaDB 10.2 回归 MySQL InnoDB 。</li><li>支持 Trasaction/Savepoints 以及 XA Transaction。</li><li>现代 IoT/BigData: 大量数据与快速写入上出现瓶颈。</li></ul><h2 id="2、MyISAM"><a href="#2、MyISAM" class="headerlink" title="2、MyISAM"></a>2、MyISAM</h2><ul><li>MySQL/MariaDB 最早的预设引擎</li><li>轻量化设计不支持交易(Trasaction)处理</li><li>适合 read-heavy workload</li><li>无事务无日志,因此档案容易因其它因素而损毁</li><li>过渡时期的 Big Data 处理方式</li></ul><h2 id="3、Aria"><a href="#3、Aria" class="headerlink" title="3、Aria"></a>3、Aria</h2><ul><li>原名 Maria,MariaDB 5.1 导入</li><li>MariaDB 10.4 后 System Tables 全面改用 Aria</li><li>Crash Safe ,采用 log 进行 数据还原(data recovery)</li><li>采用 page 提供更快速 不易产生 Fragment 的储存算法</li><li>建议改用 Aria 取代 MyISAM</li></ul><h2 id="4、TokuDB"><a href="#4、TokuDB" class="headerlink" title="4、TokuDB"></a>4、TokuDB</h2><ul><li>由 Tokutek 负责开发,MariaDB 5.5 纳入此引擎模块</li><li>支持数据压缩(data compression)</li><li>支持大型数据处理,速度快于 InnoDB</li><li>适合高效能与写密集型(write-intensive) 需求的应用环境</li></ul><h2 id="5、MyRocks"><a href="#5、MyRocks" class="headerlink" title="5、MyRocks"></a>5、MyRocks</h2><ul><li>Facebook 所发展的数据储存技术</li><li>MyRocks 是将 RocksDB 数据库添加到 MariaDB 的存储引擎。RocksDB 是一个 LSM 数据库,具有很大的压缩率,已针对闪存进行了优化</li><li>提供高效能的压缩与 I/O 效能</li><li>降低数据空间需求</li></ul><h2 id="6、Connect"><a href="#6、Connect" class="headerlink" title="6、Connect"></a>6、Connect</h2><ul><li>MariaDB 10.0 导入,透过 Connect Plugin 让 MariaDB 连接不同的数据来源, 提供外部数据(MED: Management External Data)给 MariaDB Client</li><li>标准规范: SQL/MED</li><li>提供多种类型的数据连接服务</li><li>定义 Wrapper Table 提供 Client 存取</li></ul><h1 id="按用途选择存储引擎"><a href="#按用途选择存储引擎" class="headerlink" title="按用途选择存储引擎"></a>按用途选择存储引擎</h1><p>MariaDB 有几十种存储引擎,但并不一定都是最佳。官网有简单针对各种用于,建议使用不同的引擎。大概如下:</p><h2 id="一般用途:"><a href="#一般用途:" class="headerlink" title="一般用途:"></a>一般用途:</h2><ul><li>在 MariaDB 10.1 之前,XtraDB 是大多数情况下的最佳选择。它是 InnoDB 增强性能的分支,并且是 MariaDB 10.1 之前的默认引擎。</li><li>InnoDB 是一个很好的常规事务存储引擎。它是 MariaDB 10.2(以及 MySQL)的默认存储引擎。对于早期版本,XtraDB 是 InnoDB 的性能增强分支,通常是首选。</li><li>Aria 是 MariaDB 基于 MyISAM 上的更加现代改进,占用空间小,并且让系统之间相互复制很简单。</li><li>MyISAM 占用空间小,也可轻松在系统之间进行复制。MyISAM 是 MySQL 最古老的存储引擎。但是除了解决遗留问题用途,通常没有其它理由使用它。Aria 是 MariaDB 的更现代改进。</li></ul><h2 id="缩放,分区-Scaling-Partitioning"><a href="#缩放,分区-Scaling-Partitioning" class="headerlink" title="缩放,分区(Scaling, Partitioning):"></a>缩放,分区(Scaling, Partitioning):</h2><p>如果想要拆分数据库并加载在几个服务器上,或者优化缩放,建议使用 Galera(一个同步多主集群)。</p><ul><li>TokuDB 是一个事务性存储引擎,它针对不适合内存的工作负载进行了优化,并提供了良好的压缩比。</li><li>Spider 使用分区(partitioning)通过多个服务器提供数据分片(data sharding)。</li><li>ColumnStore 采用大规模并行分布式数据体系结构,专为大数据扩展而设计,可处理 PB 级别的数据。</li><li>MERGE 存储引擎是一个相同 MyISAM 表的集合,所有表具有相同的列和索引信息。</li></ul><h2 id="压缩-归档-Compression-Archive"><a href="#压缩-归档-Compression-Archive" class="headerlink" title="压缩/归档(Compression / Archive)"></a>压缩/归档(Compression / Archive)</h2><ul><li>MyRocks 相比与 InnoDB,可以实现更大的压缩,更小的写入放大率(write amplification),从而可以更好地承受闪存存储并提高整体吞吐量。</li><li>TokuDB 是一个事务性存储引擎,它针对不适合内存的工作负载进行了优化,并提供了良好的压缩比。</li><li>Archive 存储引擎,勿庸置疑,最适合用于归档。</li></ul><h2 id="连接到其它数据源"><a href="#连接到其它数据源" class="headerlink" title="连接到其它数据源"></a>连接到其它数据源</h2><p>如果要使用的数据没有存放到 MariaDB 数据库,但可以通过以下的数据引擎去连接访问。</p><ul><li>CONNECT 允许访问不同类型的文本文件和远程资源,就像它们是常规的 MariaDB 表一样。</li><li>CSV 存储引擎可以读取并附加到以 CSV(逗号分隔值)格式存储的文件。然而,自从 MariaDB 10.0 以来,CONNECT 是一个更好的选择,并且能够更灵活地读写这样的文件。</li><li>FederatedX 使用 libmysql 与远程 RDBMS 数据源沟通。目前,由于 FederatedX 只使用 libmysql,它只能与另一个 MySQL RDBMS 通信。</li><li>CassandraSE 是一个允许访问旧版本的 Apache Cassandra NoSQL DBMS 的存储引擎。不过它是相对实验性的,并且不再被积极开发。</li></ul><h2 id="搜索优化"><a href="#搜索优化" class="headerlink" title="搜索优化"></a>搜索优化</h2><ul><li>SphinxSE 用作在远程 Sphinx 数据库服务器上运行语句的代理(主要用于高级全文搜索)。</li><li>Mroonga 使用列存储提供快速的 CJK 就绪全文搜索。</li></ul><h2 id="缓存,只读"><a href="#缓存,只读" class="headerlink" title="缓存,只读"></a>缓存,只读</h2><ul><li>MEMORY 不会在磁盘上写数据(崩溃时所有行都会丢失),并且最适合用于其它表中数据的只读缓存或临时工作区。借助默认的 XtraDB 和其它具有良好缓存的存储引擎,与过去相比,对该引擎的需求减少了。</li></ul><h2 id="其它专用引擎"><a href="#其它专用引擎" class="headerlink" title="其它专用引擎"></a>其它专用引擎</h2><ul><li>S3 存储引擎是一个只读存储引擎,它将数据存储在 amazons3 中。</li><li>Sequence 允许使用给定的起始值、结束值和增量创建数字(正整数)的升序或降序序列,并在需要时自动创建虚拟的临时表。</li><li>BLACKHOLE 存储引擎接受数据,但不存储数据,并始终返回空结果。这在复制环境中非常有用,例如,如果您希望在从机上运行复杂的筛选规则,而不会在主机上产生任何开销。</li><li>OQGRAPH 允许处理层次结构(树结构)和复杂图(在多个方向上有多个连接的节点)。</li></ul><h1 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h1><p>关于 MariaDB 存储引擎的一般性常规选择(先不考虑拓展和集群),其实大体看来只有以下几个</p><ul><li>一般使用:InnoDB</li><li>快速存取,不使用事务:Aria</li><li>高压缩和吞吐,需要降低数据空间占比:MyRocks 或 TokuDB</li><li>归档专用:Archive</li><li>连接到其它文本或远程数据源:CONNECT</li></ul><p>更多 MariaDB 的存储引擎详细,可参看官网<a href="https://mariadb.com/kb/en/storage-engines/" target="_blank" rel="noopener">https://mariadb.com/kb/en/storage-engines/</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(八)MariaDB的备份还原(mysqldump及mariabackup)</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/</url>
<content type="html"><![CDATA[<h1 id="备份简介"><a href="#备份简介" class="headerlink" title="备份简介"></a>备份简介</h1><p>备份一般分为逻辑备份 Logical Backup ( Hot Backup )和物理备份 Physical Backup ( Cold Backup )。</p><p><strong>逻辑备份</strong> 由恢复数据所需的 SQL 语句组成,例如 CREATE DATABASE,CREATE TABLE 和 INSERT。</p><p><strong>逻辑备份的特点:</strong></p><ul><li>无需停机作业</li><li>还原弹性较佳</li><li>硬件无关,可任意还原到指定的数据库</li><li>档案较大, 备份与还原时间较长</li><li>无法备份 log 与配置文件</li><li>无事务的表(Non-transaction table) 必须被锁定</li><li>可能影响联机操作处理效能</li></ul><p><strong>物理备份</strong> 是通过复制单个数据文件或目录来执行的。</p><p><strong>物理备份的特点:</strong></p><ul><li>需停机作业( MariaDB 10 可执行 Hot Physical Backup )</li><li>目录/文件(Directories/Files) 操作</li><li>执行速度较快</li><li>档案 size 较小</li><li>可备份日志和配置文件</li></ul><p>因此,<strong>逻辑备份和物理备份主要区别如下</strong>:</p><blockquote><p>逻辑备份更加灵活,因为可以在其它不同的硬件配置、MariaDB 版本甚至其它 DBMS 上恢复数据,而物理备份不能在明显不同的硬件、不同的 DBMS 或可能甚至不同的 MariaDB 版本上导入。</p></blockquote><blockquote><p>逻辑备份可以在数据库和表级别执行,而物理数据库是目录和文件级别。在 MyISAM 和 InnoDB 存储引擎中,每个表都有一组等效的文件。(在 MariaDB 5.5 之前的版本中,默认情况下,多个 InnoDB 表存储在同一文件中,在这种情况下,无法按表进行备份。)</p></blockquote><blockquote><p>逻辑备份的大小 <strong>大于</strong> 等效物理备份的大小。</p></blockquote><blockquote><p>与等效的物理备份相比,逻辑备份花费更多的时间进行备份和还原。</p></blockquote><blockquote><p>日志文件和配置文件不是逻辑备份的一部分</p></blockquote><p>备份工具:mysqldump 和 Mariabackup</p><h1 id="mysqldump"><a href="#mysqldump" class="headerlink" title="mysqldump"></a>mysqldump</h1><h2 id="mysqldump-简述"><a href="#mysqldump-简述" class="headerlink" title="mysqldump 简述"></a>mysqldump 简述</h2><blockquote><p>mysqldump 执行逻辑备份。这是执行备份和还原的最灵活的方法,并且是当数据量较小时的理想选择。</p></blockquote><blockquote><p>对于大型数据集,备份文件可能很大,并且恢复时间很长。</p></blockquote><blockquote><p>mysqldump 将数据转储为 SQL 格式(它也可以转储为其它格式,例如 CSV 或 XML),然后可以轻松地将其导入另一个数据库。假设转储中没有版本或特定于 DBMS 的语句,则可以将数据导入到其它版本的 MariaDB,MySQL 甚至是其它 DBMS 中。</p></blockquote><blockquote><p>mysqldump 将触发器(triggers)与表一起转储,因为它们是表定义的一部分。但是,存储过程,视图和事件(stored procedures, views, and events)不是,并且需要额外的参数来显式地重新创建(例如–routines 和–events)。 但是,过程和函数也是系统表的一部分。</p></blockquote><h2 id="使用语法"><a href="#使用语法" class="headerlink" title="使用语法"></a>使用语法</h2><p><strong>备份语法</strong></p><pre><code>mysqldump db_name > backup-file.sql</code></pre><p>具体例如:</p><pre><code class="sh">shell> mysqldump [options] db_name [tbl_name ...] > backup-file.sql # 指定数据库的某些表shell> mysqldump [options] --databases db_name ... > backup-file.sql # 指定某几个数据库shell> mysqldump [options] --all-databases > backup-file.sql # 备份所有数据库</code></pre><p><strong>还原语法</strong></p><pre><code>mysql db_name < backup-file.sql</code></pre><h2 id="mysqldump-使用实例"><a href="#mysqldump-使用实例" class="headerlink" title="mysqldump 使用实例"></a>mysqldump 使用实例</h2><p>(实际 demo 使用说明,<strong>后续一些指令说明可能会接续使用此演示。若不感兴趣可略过</strong>)</p><p>在 MariaDB 的命令窗口执行以下语句(创建示例表及其数据):</p><pre><code class="sql">CREATE DATABASE testbak;CREATE TABLE testbak.tablebak ( `create_time` char(19) NOT NULL, `create_user` varchar(20) NOT NULL, `update_time` char(19) DEFAULT NULL, `update_user` varchar(20) DEFAULT NULL)ENGINE=InnoDBDEFAULT CHARSET=utf8COLLATE=utf8_general_ci;INSERT INTO testbak.tablebak(`create_time`,`create_user`,`update_time`,`update_user`)VALUES('2020/02/21 15:41:20','david','2020/02/21 15:43:20','david'),('2020/02/21 15:41:20','david','2020/02/21 15:43:20','david'),('2020/02/21 15:41:20','david','2020/02/21 15:43:20','david'),('2020/02/21 15:41:20','david','2020/02/21 15:43:20','david'),('2020/02/21 15:41:20','david','2020/02/21 15:43:20','david');CREATE DATABASE testbres;</code></pre><p>作用时创建一个名为 testbak 的数据库,里面一个名为 tablebak 的表,添加了 5 条数据。并创建了一个空的数据库 testres,用于测试还原。</p><p>完成之后在终端中,使用 mysqldump 备份该数据库。</p><pre><code class="sql">mysqldump -u test -p testbak > backup-testbak.sql -- >后是备份路径和文件名,此处就在用户名根目录下。</code></pre><p><img alt="mysqldump备份数据库" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/1.png" class="lazyload"></p><p>还原的话需要指定还原的数据库名称。否则会报错类似<code>ERROR 1049 (42000): Unknown database 'testres'</code></p><p>还原语句:</p><p>在终端中执行</p><pre><code>mysql -u test -p testres< backup-testbak.sql</code></pre><p><img alt="mysqldump还原数据库" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/2.png" class="lazyload"></p><p>更多 mysqldump 的使用,可访问官网<a href="https://mariadb.com/kb/en/mysqldump/了解。" target="_blank" rel="noopener">https://mariadb.com/kb/en/mysqldump/了解。</a></p><h1 id="Mariabackup"><a href="#Mariabackup" class="headerlink" title="Mariabackup"></a>Mariabackup</h1><h2 id="Mariabackup-简介:"><a href="#Mariabackup-简介:" class="headerlink" title="Mariabackup 简介:"></a>Mariabackup 简介:</h2><p>Mariabackup 是 MariaDB 提供的开源工具,用于执行 InnoDB,Aria 和 MyISAM 表的物理在线备份。对于 InnoDB,可以进行“热在线”备份。</p><p>当然,mariabackup 同样适用于 MySQL。</p><p>支持的功能</p><blockquote><p>MariaDB 一开始使用 Percona 的 XtraBackup (因为采用 Xtra Storage)<br>衍生自/并取代 Percona XtraBackup</p></blockquote><blockquote><p>内建于 MariaDB 10.1.23 版之后</p></blockquote><blockquote><p>使用静态数据加密备份/还原表。</p></blockquote><blockquote><p>使用 InnoDB 页面压缩备份/恢复表。</p></blockquote><blockquote><p>支持 Galera Cluster(MariaDB Galera Cluster 是仅在 Linux 上运行的同步多主群集(synchronous multi-master cluster)。)</p></blockquote><blockquote><p>Microsoft Windows 支持。</p></blockquote><blockquote><p>从 MariaDB 10.2.16 和 MariaDB 10.3.8 开始,使用 MyRocks 存储引擎备份/还原表。</p></blockquote><p>使用前先安装</p><p>ubuntu 下,终端执行:</p><pre><code>sudo apt-get install mariadb-backup</code></pre><p>其它系统可去官网<a href="https://mariadb.com/kb/en/mariabackup-overview/#installing-mariabackup" target="_blank" rel="noopener">https://mariadb.com/kb/en/mariabackup-overview/#installing-mariabackup</a> 查看对应下载方式。</p><p>语法示例:</p><pre><code>mariabackup <options></code></pre><p>备份的选项</p><pre><code>mariabackup --backup --target-dir /path/to/backup \ --user user_name --password user_passwd</code></pre><p>使用者信息,可以放到配置文件中</p><p>新增参数[mariabackup]并添加使用者和密码:</p><pre><code>[mariabackup]user=<mariabackup>password=<mypassword></code></pre><h2 id="mariabackup-的备份"><a href="#mariabackup-的备份" class="headerlink" title="mariabackup 的备份"></a>mariabackup 的备份</h2><h3 id="完整备份-full-backup-:"><a href="#完整备份-full-backup-:" class="headerlink" title="完整备份(full backup):"></a>完整备份(full backup):</h3><p>示例:备份现有的 MariaDB:</p><pre><code>mariabackup --backup \ --target-dir=/home/sanotsu/mariadb/backup/ \ --user=test --password=P@ssw0rd;</code></pre><p>有两点值得提醒一下:<br>1、–target-dir 后面跟的是数据库备份的路径,最好是提前创建(如果用 sudo 执行则不需要);<br>2、可能会出现操作系统无法处理文件/活页夹的问题,可尝试加 sudo,或者把活页夹的所有权从组 root 更改为 mariadb。</p><p>完整备份出错:</p><p><img alt="完整备份出错" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/3.png" class="lazyload"></p><p>正常执行:</p><p><img alt="完整备份正常执行" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/4.png" class="lazyload"></p><p>可以比较备份的活页夹和原始数据库的活页夹:</p><p><img alt="备份的活页夹和原始数据库的活页夹的比较" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/5.png" class="lazyload"></p><h3 id="部分备份-partial-backup"><a href="#部分备份-partial-backup" class="headerlink" title="部分备份(partial backup)"></a>部分备份(partial backup)</h3><p>上述是备份的全部,如果只想<strong>备份某个/某些数据库</strong>,需要再指定–databases 参数。<br>如果还需要指定<strong>备份某个数据库的某张表</strong>,就需要再指定–tables 参数。<br>这两个参数都支持正则表达式,可以更方便筛选。</p><p>例如:执行</p><pre><code>mariabackup --backup \ --target-dir=/home/sanotsu/mariadb/partialBackup/ \ --databases='testbak' \ --tables='tab_*' \ --user=test --password=P@ssw0rd;</code></pre><p><img alt="执行部分备份" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/6.png" class="lazyload"></p><p>可以查看备份结果:</p><p><img alt="部分备份结果" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/7.png" class="lazyload"></p><p>类似的部分备份的参数还有:</p><p><code>databases-exclude</code>:指定不需要备份的数据库;<br><code>tables-exclude</code>:指定不需要备份的表。</p><h3 id="增量备份-incremental-backup-:"><a href="#增量备份-incremental-backup-:" class="headerlink" title="增量备份(incremental backup):"></a>增量备份(incremental backup):</h3><p>增量备份的基础是完整备份,想要进行增量备份,首先需要进行一次完整备份,再执行增量备份时,就会在原本的完整备份的基础上,备份尚未备份的部分,而不是重新再备份所有,即递增而不是覆盖。</p><p>语法也简单,在完整备份下再加一个–incremental-basedir 参数指定基于哪一个备份的递增:</p><pre><code>mariabackup --backup \ --target-dir=/home/sanotsu/mariadb/incrementalBackup/ \ --incremental-basedir=/home/sanotsu/mariadb/backup/ \ --user=test --password=P@ssw0rd;</code></pre><p><strong>注意 –incremental-basedir 的值,每一个新的增量备份应该以上一个备份的目标路径为基准。</strong></p><p>因为在执行这次增量备份之前,并没有新增或删除过其它数据库/表,但是也可以看出他们的区别。</p><p>下图是增量备份(左)和完整备份(右)的活页夹,可以从占用 size 大小,和指定数据库的指定表的相关信息看出,的确不是完全覆盖的备份:</p><p><img alt="增量备份结果" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/8.png" class="lazyload"></p><h2 id="mariabackup-还原"><a href="#mariabackup-还原" class="headerlink" title="mariabackup 还原"></a>mariabackup 还原</h2><p>还原实际上会有两步需要执行,一是准备(prepare),二是还原(restore)。</p><h3 id="准备作业:"><a href="#准备作业:" class="headerlink" title="准备作业:"></a>准备作业:</h3><p>准备的作用是检查用于还原的备份的数据文件一致性。如果不一致,InnoDB 会中断避免数据库损坏。</p><p>不同的备份准备作业略有些不同</p><h4 id="完整备份的准备:"><a href="#完整备份的准备:" class="headerlink" title="完整备份的准备:"></a>完整备份的准备:</h4><p>语法:</p><pre><code>mariabackup --prepare \ --target-dir=/home/sanotsu/mariadb/backup/</code></pre><p>如果权限不够,可能无法读取文件,解决方法与备份时说明一致,加 sudo 或者把该文件/夹 root 权限赋予 mariadb</p><p><img alt="备份准备的权限不够的报错及解决" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/9.png" class="lazyload"></p><h4 id="部分备份的准备:"><a href="#部分备份的准备:" class="headerlink" title="部分备份的准备:"></a>部分备份的准备:</h4><p>部分备份的还原前准备除了检查数据文件一致性外,还依赖 InnoDB 的可传输表空间。为了让 MariaDB 导入此类表空间,InnoDB 会寻找带有.cfg 扩展名的文件。为了让 Mariabackup 创建这些文件,还需要–export 在准备步骤中添加选项。</p><p>语法:</p><pre><code>mariabackup --prepare --export \ --target-dir=/home/sanotsu/mariadb/backup/</code></pre><p>注意:在 MariaDB 10.2.8 及之前的版本, Mariabackup 不支持 –export 选项。更多区别可查看<a href="https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/#preparing-the-backup" target="_blank" rel="noopener">https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/#preparing-the-backup</a></p><h4 id="增量备份的准备:"><a href="#增量备份的准备:" class="headerlink" title="增量备份的准备:"></a>增量备份的准备:</h4><p>在 MariaDB 10.2 及其之后,准备作业是这样:</p><p>先准备完整备份</p><pre><code>mariabackup --prepare \ --target-dir=/home/sanotsu/mariadb/backup/</code></pre><p>再准备增量备份:</p><pre><code>mariabackup --prepare \ --target-dir=/home/sanotsu/mariadb/backup/ \ --incremental-dir=/home/sanotsu/mariadb/incrementalBackup/ \</code></pre><p>这里的–incremental-dir 是增量备份时–target-dir 的值,–target-dir 是–incremental-basedir 的值。<br>注意多个层级的增量备份还原时的准备,有层级依赖,不要跨级。<br>即先还原 inc1,再还原 inc2、inc3……即依照增量顺序修改–incremental-dir 的值就好。</p><h3 id="还原作业:"><a href="#还原作业:" class="headerlink" title="还原作业:"></a>还原作业:</h3><h4 id="完整备份和增量备份"><a href="#完整备份和增量备份" class="headerlink" title="完整备份和增量备份"></a>完整备份和增量备份</h4><p>还原就稍微麻烦一点,不过以上完整备份和增量备份的还原方式都通用。<br>需要依次执行以下步骤:</p><p>1、停止(stop) MariaDB 服务进程;</p><p>2、确保用于还原的存储数据的目录为<strong>空</strong>。(mariadb 服务器系统参数 datadir)</p><p><img alt="查询用于还原的存储数据的位置" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/10.png" class="lazyload"></p><p>3、使用<code>--copy-back</code>或<code>--move-back</code>参数,执行还原操作,指令语法如:</p><pre><code>mariabackup --copy-back \ --target-dir=/home/sanotsu/mariadb/backup/</code></pre><p>–copy-back 选项允许您保留原始备份文件。<br>–move-back 选项实际上将备份文件移到 datadir,因此原始备份文件会丢失。</p><p>4、调整数据目录的所有者,以匹配 MariaDB 服务器(通常 mysql 是两者)的用户和组。</p><p>例如,要将文件的所有权递归更改给 mysql 用户和组,执行</p><pre><code>sudo chown -R mysql:mysql /var/lib/mysql/</code></pre><p>5、启动 MariaDB 服务进程。</p><p>示例如下(部分显示删减):</p><pre><code class="sh">sudo service mariadb stop # 关闭mariadb服务进程sudo rm -rf /var/lib/mysql/* #清空mariadb datadir目录下数据mariabackup --copy-back --target-dir=/home/sanotsu/mariadb/backup/ #执行还原sudo chown -R mysql:mysql /var/lib/mysql/ #给还原后的文件/夹附加mysql(mariadb的实际用户名)用户/组权限sudo service mariadb start #启动mariadb服务进程</code></pre><p><img alt="完整备份和增量备份的还原步骤" data-src="/../images/TechnicalEssays/MariaDBSeries/08mariadb-dump-backup/11.png" class="lazyload"></p><p>如果一切正常则还原成功。</p><h4 id="部分备份的还原"><a href="#部分备份的还原" class="headerlink" title="部分备份的还原"></a>部分备份的还原</h4><p>注意,部分备份的还原,和完整备份的还原过程完全不同(quite different)。</p><blockquote><p>部分备份不是功能齐全的数据目录。InnoDB 系统表空间中的数据字典仍将包含未包含在备份中的数据库和表的条目。</p></blockquote><blockquote><p>每个单独的 InnoDB 每表文件空间表空间文件都必须手动导入到目标服务器中。用于导入文件的过程将取决于是否涉及分区。</p></blockquote><p><strong>如果单表没有分区</strong></p><p>恢复单个非分区表</p><p>通过丢弃表的原始表空间,将表.ibd 和.cfg 文件从备份位置复制到表的相关表空间位置,然后告诉服务器导入表空间,可以导入未分区的表。</p><ul><li>1、在备份中找到该表的.ibd 和.cfg 文件;</li><li>2、目标服务器上,您需要创建表的副本。使用与 CREATE TABLE 在原始服务器上创建表相同的语句。</li><li>3、使用<code>ALTER TABLE <table_name> DISCARD TABLESPACE</code>丢弃新表的表空间。</li><li>4、将该表的.ibd 和.cfg 文件从备份位置复制需要还原的 mariadb server 的相关路劲。</li><li>5、确定文件放到了正确的位置,使用<code>ALTER TABLE <table_name> IMPORT TABLESPACE</code>语句导入新表的表空间。</li></ul><p><strong>如果单表有涉及到分区</strong></p><p>恢复单个分区和分区表</p><p>创建占位符表,丢弃占位符表的原始表空间,将分区的文件.ibd 和.cfg 文件从备份位置复制到占位符表的相关表空间位置,然后告诉服务器导入表空间来导入分区表。此时,服务器可以将占位符表的表空间与分区的表空间交换。</p><ul><li>1、将保存的表空间文件从原始服务器复制到目标服务器;</li><li>2、将分区表空间导入到目标服务器上。<ul><li>2.1、首先,如果它尚不存在,那么我们需要在目标服务器上创建一个与原始服务器上的分区表匹配的分区表:</li><li>2.2、然后,使用该表作为模型,我们需要使用不使用分区的相同结构创建该表的占位符。这可以通过以下<code>CREATE TABLE <table_name> AS SELECT</code> 语句完成</li></ul></li><li>3、针对每个分区进行以下步骤<ul><li>3.1、使用 <code>ALTER TABLE <table_name> DISCARD TABLESPACE</code> 丢弃占位符表的表空间;</li><li>3.2、将下一个分区的.ibd 和.cfg 文件复制到占位符表目标 MariaDB 服务器上表的相关目录中</li><li>3.3、文件位于目标服务器上的正确目录中后,使用 <code>ALTER TABLE <table_name> IMPORT TABLESPACE</code> 来导入新表的表空间。操作成功,则可以在占位符表中查看到包含源服务器上分区中的数据</li><li>3.4、通过 ALTER TABLE <table_name> EXCHANGE PARTITION 语句将分区从占位符转移到目标表,若成功,目标表将包含源表中的第一个分区。</table_name></li><li>3.5、对要导入的每个分区重复以上 3.X 过程。对于每个分区,我们需要丢弃占位符表的表空间,然后将分区表的表空间导入到占位符表中,然后在占位符表和目标表的分区之间交换表空间。</li><li>3.6、所有分区都完成之后,目标表应该包含所有的对应的数据,则可以从数据库中删除占位符表。</li></ul></li></ul><p>单表(部分)备份,使用 mariabackup 的物理备份还原还是比较麻烦的,使用其它方法可能更简单便捷</p><p>更多 mariabackup 的部分备份/还原信息,可见<a href="https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/#restoring-the-backup" target="_blank" rel="noopener">官网</a></p><p>更多 mariabackup 的使用可见<a href="https://mariadb.com/kb/en/mariabackup/" target="_blank" rel="noopener">官网</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(七)MariaDB设定最佳性能优化简述</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/07mariadb-performance-optimization/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/07mariadb-performance-optimization/</url>
<content type="html"><![CDATA[<p>在使用 MariaDB 之后,肯定也会希望它能够按照一定设定、规则等进行合理的性能优化,提高效能等。此篇将从常见的一些 mariadb-server 的设定上,简单介绍调整 MariaDB 期望能以最佳性能进行运行。</p><p>主要简介以下几种:</p><ul><li>1、启用服务器内置特定最佳化参数设定(optimizer_switch)</li><li>2、线程池(thread pool)</li><li>3、查询缓存(query cache)</li><li>4、MyISAM 键缓存(Key Cache)</li><li>5、InnoDB 缓冲池(Buffer Pool)</li><li>6 优化表 (OPTIMIZE TABLE)</li></ul><p>在此之前,需要记住 mariadb server 常用的查看状态的几个命令:<br><code>show status;</code>、<code>show variables;</code>、<code>show engines;</code>,当然都可以附加<code>like</code>关键词筛选。</p><h1 id="1、启用服务器内置特定最佳化参数设定"><a href="#1、启用服务器内置特定最佳化参数设定" class="headerlink" title="1、启用服务器内置特定最佳化参数设定"></a>1、启用服务器内置特定最佳化参数设定</h1><p>使用 switch 方式开关 MariaDB 特定的最佳化机制,系统变量:<code>@@optimizer_switch</code>。</p><p>这一个服务器变量,可以用来启用/禁用特定的优化。</p><p>可以使用<code>SELECT @@optimizer_switch;</code>来查看 mariadb-server 默认支持哪一些参数的优化(为了一眼看到全貌,此处就用 MariaDB 的命令窗口看):</p><p><img alt="MariaDB默热优化系统参数" data-src="/../images/TechnicalEssays/MariaDBSeries/07mariadb-performance-optimization/1.png" class="lazyload"></p><p>可见,很多 server 的配置的优化,都是有开启的。后续在使用时,可以根据使用到的功能,启用这些设定。</p><p>修改方式一如既往:</p><pre><code>SET [GLOBAL|SESSION] optimizer_switch='cmd[,cmd]...';</code></pre><p>例如<code>set optimizer_switch="engine_condition_pushdown=on";</code></p><p>当然,重启就失效了,修改配置文件操作,在配置文件[mysqld]下新增:</p><pre><code>[mysqld]optimizer_switch="engine_condition_pushdown=on"</code></pre><p>更多最佳化开关的信息,可以查看官网: <a href="https://mariadb.com/kb/en/optimizer-switch/" target="_blank" rel="noopener">https://mariadb.com/kb/en/optimizer-switch/</a> 了解。</p><h1 id="2、线程池(thread-pool)"><a href="#2、线程池(thread-pool)" class="headerlink" title="2、线程池(thread pool)"></a>2、线程池(thread pool)</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><ul><li>MariaDB 5.5 引入<ul><li>传统 MySQL 采用 One Thread Per Client 设计</li></ul></li><li>改用 dynamic/adaptive Pool 方式提供所有 Clients<ul><li>依据状况自动 grows/shrink Pool size</li><li>依据操作系统自动调整最佳设定</li><li>降低内存使用量 , 降低 context switch 造成的问题</li><li>注意:建立 Threads 需要时间 !!!</li></ul></li><li>Windows 版本默认值: ThreadPool (排队等候 Threads 使用权)</li><li>Linux 版本预设: One thread Per Client (所有 Threads 都会轮流)</li></ul><h3 id="使用时机:"><a href="#使用时机:" class="headerlink" title="使用时机:"></a>使用时机:</h3><ul><li>适合 Short-queries , CPU-Bound 类型的应用</li><li>例如 Web Site 或是 OLTP 类型的应用</li><li>IoT 类型应用: 短查询, 短 I/O ,密集 CPU 使用</li></ul><h3 id="不适合时机:"><a href="#不适合时机:" class="headerlink" title="不适合时机:"></a>不适合时机:</h3><ul><li>高负载/瞬间爆量/不容许延迟<ul><li>长时间无任务, 瞬间爆量然后又消失一段时间的查询</li><li>|— 回收线程, —->新增线程 —-> 回收线程</li><li>此类任务,使用 一核心 一线程策略取代</li></ul></li><li>大量 同时发生/长时间执行/长时间占用 的查询应用<ul><li>使用少量线程负担所有联机 需要 queue—> scheduler</li></ul></li><li>低延迟要求的查询应用</li></ul><h2 id="使用配置"><a href="#使用配置" class="headerlink" title="使用配置"></a>使用配置</h2><h3 id="linux-启用线程池"><a href="#linux-启用线程池" class="headerlink" title="linux 启用线程池"></a>linux 启用线程池</h3><p>在配置文件的[mariadb]参数下:</p><pre><code>[mariadb]thread_handling=pool-of-threads</code></pre><h3 id="windows-下启用线程池"><a href="#windows-下启用线程池" class="headerlink" title="windows 下启用线程池"></a>windows 下启用线程池</h3><p>在配置文件的[mariadb]参数下:</p><pre><code>[mariadb]thread_handling=one-thread-per-connection</code></pre><h1 id="3、查询缓存-query-cache"><a href="#3、查询缓存-query-cache" class="headerlink" title="3、查询缓存(query cache)"></a>3、查询缓存(query cache)</h1><blockquote><p>查询缓存存储 SELECT 查询的结果,以便将来以后收到相同的查询时,可以快速返回结果。</p></blockquote><blockquote><p>这在高读、低写环境(例如大多数网站)中非常有用。在多核计算器上具有高吞吐量的环境中,它无法很好地扩展。</p></blockquote><p>可以查看对应的参数设定:<code>show variables like '%query_cache%';</code>和<code>show status like 'Qcache%';</code> ,并修改为符合自身设备和需求需要的值。</p><p><img alt="查询缓存系统参数" data-src="/../images/TechnicalEssays/MariaDBSeries/07mariadb-performance-optimization/2.png" class="lazyload"></p><p><strong>说明:此种类似的系统变量,一般在配置文件的[mysqld]参数下寻找来修改或添加。若不是,查看官网指定参数是否是在其它变量下。</strong></p><p>如果某些查询,要求不允许使用查询缓存里面的值,则可以在 select 加入 SQL_NO_CACHE 去说明。同样,指定要从查询缓存中查询,也可以在 select 后指定 SQL_CACHE。</p><p>示例:</p><pre><code>Select SQL_NO_CACHE … from table …</code></pre><p>或者</p><pre><code>Select SQL_CACHE … from table …</code></pre><p><strong>注意:这些参数的设定还是有一些限制的,例如因为查询缓存大小以 1024 字节做分配,因此应该将 query_cache_size 设置未 1024 的倍数。</strong></p><p>例如,设置 query_cache_size 大小为 40000 就会出现警告:</p><p><img alt="查询缓存大小设置警告" data-src="/../images/TechnicalEssays/MariaDBSeries/07mariadb-performance-optimization/3.png" class="lazyload"></p><p>查询结果存储使用的最小块大小是 query_cache_min_res_unit。</p><p>更多信息可以访问官网<a href="https://mariadb.com/kb/en/query-cache/#limiting-the-size-of-the-query-cache了解。" target="_blank" rel="noopener">https://mariadb.com/kb/en/query-cache/#limiting-the-size-of-the-query-cache了解。</a></p><h2 id="子查询缓存(SubQuery-Cache)"><a href="#子查询缓存(SubQuery-Cache)" class="headerlink" title="子查询缓存(SubQuery Cache)"></a>子查询缓存(SubQuery Cache)</h2><p>MariaDB 独有的快取设计 ,在 MariaDB 5.3.2 预设启用。透过绑定主要查询与子查询结果,避免重复执行子查询。</p><p>设定方式:</p><p>透过 optimizer_switch 设定</p><pre><code>SET optimizer_switch="subquery_cache=on"</code></pre><h1 id="4、MyISAM-键缓存(Key-Cache)"><a href="#4、MyISAM-键缓存(Key-Cache)" class="headerlink" title="4、MyISAM 键缓存(Key Cache)"></a>4、MyISAM 键缓存(Key Cache)</h1><p>在 MariaDB 使用 MyISAM 引擎时,可以设定 <code>key_cache_segments</code> 进行一些优化。</p><blockquote><p>分段密钥缓存(segmented key cache)是常规 MyISAM 密钥缓存(key caches)的结构的集合,称为密钥缓存段(key cache segments)。分段密钥缓存减轻了简单密钥缓存的主要问题之一:密钥缓存锁(mutex)的线程争用。对于常规的键高速缓存,键高速缓存接口功能的每次调用都必须获得此锁。因此,即使线程已获取文件的共享锁并且要从中读取的页面位于键高速缓存缓冲区中,线程也争夺该锁。</p></blockquote><blockquote><p>使用分段键高速缓存时,仅需要一页的任何键高速缓存接口功能都必须仅为分配该页面的段获取键高速缓存锁。这使线程不必竞争同一密钥缓存锁的机会就更好了。</p></blockquote><p>(更多内容查看官网<a href="https://mariadb.com/kb/en/segmented-key-cache/" target="_blank" rel="noopener">https://mariadb.com/kb/en/segmented-key-cache/</a>)</p><p>在并行(concurrent)不成熟的年代使用 SingleThread Access 特性,造成大量存取产生 Mutex Lock & wait 问题。</p><p><strong>将 key cache 切成多段可允许同时多个 MyISAM Threads 同时存取,减少锁和等待。</strong></p><p>配置:</p><p>设定全局变量</p><pre><code>Set Global key_cache_segments=n</code></pre><p>注意,n 只能时 0~64,大于 64 会被截断成 64 并报警告。</p><p>或在配置文件修改,找到[mysqld]参数下添加:</p><pre><code>[mysqld] key_cache_segments = 64</code></pre><h1 id="5、InnoDB-缓冲池(Buffer-Pool)"><a href="#5、InnoDB-缓冲池(Buffer-Pool)" class="headerlink" title="5、InnoDB 缓冲池(Buffer Pool)"></a>5、InnoDB 缓冲池(Buffer Pool)</h1><blockquote><p>XtraDB / InnoDB 的缓冲池是用于优化 MariaDB 的一个关键组成部分。它存储数据和索引,通常希望它尽可能大,以便将尽可能多的数据和索引保留在内存中,从而减少磁盘 IO 成为主要瓶颈。</p></blockquote><p>一般设定 70% ~ 80% 的主机内存用于存放 XtraDB/InnoDB 的数据与索引,将常用的 data-blocks & index-blocks 暂存在内存中。</p><h2 id="缓冲池如何工作"><a href="#缓冲池如何工作" class="headerlink" title="缓冲池如何工作"></a>缓冲池如何工作</h2><blockquote><p>缓冲池尝试将经常使用的块保留在缓冲区中,因此实际上起着两个子列表的作用,一个是最近使用信息的新子列表(New sublist),另一个是旧信息的旧子列表(Old sublist)。默认情况下,列表的 37%保留用于旧子列表。</p></blockquote><blockquote><p>当访问未出现在列表中的新信息时,它将被放置在旧子列表的顶部,旧子列表中最旧的项目将被删除,其它所有内容都将返回列表中的一个位置。</p></blockquote><blockquote><p>当访问的信息出现在旧子列表中时,它将被移到新列表的顶部,并且上方的所有内容将移回一个位置。</p></blockquote><h2 id="InnoDB-的-Buffer-管理"><a href="#InnoDB-的-Buffer-管理" class="headerlink" title="InnoDB 的 Buffer 管理"></a>InnoDB 的 Buffer 管理</h2><h3 id="一般-select-的执行:"><a href="#一般-select-的执行:" class="headerlink" title="一般 select 的执行:"></a>一般 select 的执行:</h3><p>Select SQL—> InnoDB 引擎–> Cache 寻找 –>无 —>执行查询–>结果–>存入 InnoDB Buffer ( New | Old ? ) –> 存入 old-list buffer</p><p>后续的查询:</p><p>SQL —> InnoDB 引擎 —> cache 中发现(old-list) –> 将该笔快取资料从 old-list 放入 new-list 中的第一顺位 –> 被挤出去的数据 存入 old-list –> Old-list 最后一笔被踢出 buffer (从 cache 中移除)</p><h2 id="InnoDB-4-个重要的缓冲池服务器系统变量:"><a href="#InnoDB-4-个重要的缓冲池服务器系统变量:" class="headerlink" title="InnoDB 4 个重要的缓冲池服务器系统变量:"></a>InnoDB 4 个重要的缓冲池服务器系统变量:</h2><h3 id="innodb-buffer-pool-size-(innodb-缓存池大小)"><a href="#innodb-buffer-pool-size-(innodb-缓存池大小)" class="headerlink" title="innodb_buffer_pool_size (innodb 缓存池大小)"></a>innodb_buffer_pool_size (innodb 缓存池大小)</h3><p>设定 70~80% Memory Size ( + 10% 的控制暂存区使用 )。过大容易造成 OS Swapping 或是过长的初始化时程。</p><p>例如:启动后 8G ram 被吃掉 6.4G 用于快取, 当 server 需要执行其它应用程序时,需要 2G ram , 此时将导致 OS 发生 ram-disk swapping。</p><p>在 MariaDB 10.2.2 之后,可以动态调整 InnoDB Buffer size。</p><blockquote><p>调整缓冲池大小的过程由 innodb_buffer_pool_chunk_size 变量的大小确定。</p></blockquote><blockquote><p>调整大小操作将一直等到所有活动事务和操作完成,并且需要访问缓冲池的新事务和操作必须等到调整大小完成为止(尽管减小大小时,在对页面进行碎片整理和撤回时允许访问)。</p></blockquote><blockquote><p>如果在缓冲池调整大小开始之后启动嵌套事务,则该事务可能会失败。</p></blockquote><blockquote><p>新的缓冲池大小必须是 innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances 的倍数。如果尝试设置其它数字,则该值将自动调整为至少为尝试的大小的倍数。请注意,调整 innodb_buffer_pool_chunk_size 设置可能会导致缓冲池大小发生变化。</p></blockquote><blockquote><p>为了避免性能问题,由 innodb_buffer_pool_size / innodb_buffer_pool_chunk_size 计算的块数不应超过 1000。</p></blockquote><h3 id="innodb-buffer-pool-instances-(inondb-缓存池示例数量)"><a href="#innodb-buffer-pool-instances-(inondb-缓存池示例数量)" class="headerlink" title="innodb_buffer_pool_instances (inondb 缓存池示例数量)"></a>innodb_buffer_pool_instances (inondb 缓存池示例数量)</h3><ul><li>innodb_buffer_pool_size 超过 1G 时, 透过设定的 pool instances 将其切割成多个,instances 提供同时 (concurrent) 存取, 增进效能。</li><li>MariaDB 10 预设为 8 (请参考 CPU Core 数,勿无谓增加)。</li><li>每个 instance 负责管理各自所保存的 buffer 数据。</li></ul><p>例如:若 pool size 设定为 4G , instances 设定为 4,则产生四组 1G size 的 instances 保存 buffer 数据。</p><h3 id="innodb-old-blocks-pct"><a href="#innodb-old-blocks-pct" class="headerlink" title="innodb_old_blocks_pct"></a>innodb_old_blocks_pct</h3><p>可以通过更改 innodb_old_blocks_pct 的值来调整为旧子列表保留的默认 37%的值。它可以接受 5%至 95%之间的任何值。</p><h3 id="innodb-old-block-time"><a href="#innodb-old-block-time" class="headerlink" title="innodb_old_block_time"></a>innodb_old_block_time</h3><p>指定之前的块可以从旧子列表被移动到新子列表的延迟。</p><p>MariaDB 5.5 时默认值为 0,表示没有延迟,而自 MariaDB 10.0 起已设置为默认值 1000ms。</p><blockquote><p>在更改这两个值(innodb_old_blocks_pct 和 innodb_old_blocks_time)的默认值之前,请确保了解其影响以及系统当前使用缓冲区的方式。它们存在的主要原因是为了减少全表扫描的影响,这种情况通常很少见,但很大,而且以前可以从缓冲区中清除所有内容。在快速连续执行全表扫描的情况下,设置非零延迟可能会有所帮助。</p></blockquote><h2 id="转储和还原缓冲池"><a href="#转储和还原缓冲池" class="headerlink" title="转储和还原缓冲池"></a>转储和还原缓冲池</h2><p>自 MariaDB 10.0 起,可以转储并还原缓冲池。</p><blockquote><p><strong>服务器启动时,缓冲池为空。在开始访问数据时,缓冲池将慢慢填充。随着将访问更多数据,最常访问的数据将被放入缓冲池,并且旧数据可能会被驱逐。这意味着缓冲池真正有用之前需要一定的时间。该时间段称为预热。</strong></p></blockquote><blockquote><p><strong>从 MariaDB 10.0 开始,InnoDB 可以在服务器关闭之前转储缓冲池,并在再次启动时将其还原。如果使用此功能,则无需预热。</strong> 要分别在关闭时启用缓冲池转储和在启动时启用还原,可以将 innodb_buffer_pool_dump_at_shutdown 和 innodb_buffer_pool_load_at_startup 系统变量设置为 ON。</p></blockquote><blockquote><p>在服务器运行时,还可以随时转储 InnoDB 缓冲池,并且可以随时恢复上一次缓冲池转储。为此,可以将特殊的 innodb_buffer_pool_dump_now 和 innodb_buffer_pool_load_now 系统变量设置为 ON。选择后,它们的值始终为 OFF。</p></blockquote><blockquote><p>通过将 innodb_buffer_pool_load_abort 设置为 ON ,可以中止在启动时或在其它任何时间进行的缓冲池还原。</p></blockquote><blockquote><p>包含缓冲池转储的文件是通过 innodb_buffer_pool_filename 系统变量指定的。</p></blockquote><p>转储和还原缓冲池这一段官网描述得非常清楚明了,我就不再加工说明了。</p><h1 id="6-优化表-(OPTIMIZE-TABLE)"><a href="#6-优化表-(OPTIMIZE-TABLE)" class="headerlink" title="6 优化表 (OPTIMIZE TABLE)"></a>6 优化表 (OPTIMIZE TABLE)</h1><p>优化表的功能有两个:对表进行碎片化处理(defragment tables),或者更新 InnoDB 全文索引(update the InnoDB fulltext index.)</p><p>语法:</p><pre><code>OPTIMIZE [NO_WRITE_TO_BINLOG | LOCAL] TABLE tbl_name [, tbl_name] ... [WAIT n | NOWAIT]</code></pre><h2 id="碎片整理"><a href="#碎片整理" class="headerlink" title="碎片整理"></a>碎片整理</h2><blockquote><p>OPTIMIZE TABLE 适用于 InnoDB(在 MariaDB 10.1.1 之前,仅当设置了 InnoDB_file_per_TABLE server 系统变量)、Aria、MyISAM 和 ARCHIVE 表时,<strong>如果删除了表的很大一部分,或者对具有可变长度行(具有 VARCHAR、VARBINARY、BLOB 或 TEXT 列的表)的表进行了许多更改,则应使用 OPTIMIZE TABLE。</strong> 已删除的行保留在链接列表中,后续插入操作将重用旧的行位置。</p></blockquote><blockquote><p>此语句要求表具有选择和插入权限。</p></blockquote><blockquote><p>默认情况下,OPTIMIZE TABLE 语句将写入二进制日志并进行复制。NO_WRITE_TO_BINLOG 关键字(LOCAL 是别名)将确保语句不会写入二进制日志。</p></blockquote><blockquote><p>分区表也支持优化表。您可以使用 <code>ALTER TABLE <table_name></code>优化分区以优化一个或多个分区。</p></blockquote><blockquote><p>可以使用优化表回收未使用的空间并对数据文件进行碎片整理。对于其它存储引擎,OPTIMIZE TABLE 默认情况下不执行任何操作,并返回以下消息:“表的存储引擎不支持 OPTIMIZE”。但是,如果服务器已使用–skip new 选项启动,那么 OPTIMIZE TABLE 将链接到 ALTER TABLE,并重新创建该表。此操作释放未使用的空间并更新索引统计信息。</p></blockquote><blockquote><p>自 MariaDB 5.3 以来,Aria 存储引擎支持此语句的进度报告。</p></blockquote><blockquote><p>如果 MyISAM 表是分段的,则除非在该表上执行优化表语句,否则不会执行并发插入,除非将 concurrent_insert server 系统变量设置为 ALWAYS。</p></blockquote><h2 id="更新-InnoDB-全文索引"><a href="#更新-InnoDB-全文索引" class="headerlink" title="更新 InnoDB 全文索引"></a>更新 InnoDB 全文索引</h2><blockquote><p>当向 InnoDB 全文索引添加或删除行时,不会立即重新组织索引,因为这可能是一个代价高昂的操作。更改统计信息存储在单独的位置。只有在运行优化表语句时,全文索引才会完全重新组织。</p></blockquote><blockquote><p>默认情况下,优化表将对表进行碎片整理。为了使用它更新全文索引统计信息,innodb_optimize_fulltext_only 系统变量必须设置为 1。这是一个临时设置,应在重新组织全文索引后重置为 0。</p></blockquote><blockquote><p>由于全文重新组织可能需要很长时间,innodb_ft_num_word_optimize 变量将重新组织限制为多个单词(默认为 2000)。可以运行多个优化语句来完全重新组织索引。</p></blockquote><p>值得一提:<strong>碎片化整理和更新全文索引的时机,在大量数据得删除或大量 可变长度行字段异动之后</strong></p><p>一个非常好的例子,MariaDB 的数据库文件.ibd 文件,在大量删除之后,体积不会变小,执行<code>OPTIMIZE TABLE <table_name></code>(MyISAM 优化 table)或<code>ALTER TABLE <table_name> ENGINE='InnoDB';</code> (‘InnoDB’优化 table)之后,体积就会肉眼可见的变小。</p><p>(.ibd 文件默认位置/var/lib/mysql/<table_name>/)</table_name></p><p>更多性能优化相关知识,可到官网<a href="https://mariadb.com/kb/en/optimization-and-tuning/" target="_blank" rel="noopener">https://mariadb.com/kb/en/optimization-and-tuning/</a> 学习了解。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(六)实用插件ServerAudit测试使用示例</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/06mariadb-server-audit-plugin/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/06mariadb-server-audit-plugin/</url>
<content type="html"><![CDATA[<h1 id="server-audit-插件测试使用示例"><a href="#server-audit-插件测试使用示例" class="headerlink" title="server audit 插件测试使用示例"></a>server audit 插件测试使用示例</h1><h2 id="简介与安装"><a href="#简介与安装" class="headerlink" title="简介与安装"></a>简介与安装</h2><p>SERVER_AUDIT 是一个非常不错的插件,在 MariaDB 5.5.34 加入,提供服务器事件(activities) 记录功能。<br>例如联机 client 信息(账号, 主机 ..)、Queries 执行、Tables 信息;或者 Server 变数异动等。<br>是 MariaDB Package 内建的插件。</p><blockquote><p>该 server_audit 插件记录服务器的活动。对于每个客户端会话,它记录谁连接到服务器(即用户名和主机),执行了哪些查询,访问了哪些表以及更改了服务器变量。此信息存储在循环日志文件( rotating log file)中,或者可以发送到本地 syslogd。</p></blockquote><p>因为是内建的,所以安装简单:</p><pre><code>INSTALL SONAME 'server_audit';</code></pre><p>安装成功后,可以查看 MariaDB 的全局参数,了解 server_audit 的配置变量信息:</p><pre><code>show global variables like 'server_audit%';</code></pre><p><img alt="server_audit插件信息" data-src="/../images/TechnicalEssays/MariaDBSeries/06mariadb-server-audit-plugin/1.png" class="lazyload"></p><h2 id="几个重要变量的说明:"><a href="#几个重要变量的说明:" class="headerlink" title="几个重要变量的说明:"></a>几个重要变量的说明:</h2><h3 id="server-audit-events"><a href="#server-audit-events" class="headerlink" title="server_audit_events"></a>server_audit_events</h3><p>审核日志记录的事件类型。默认为空字符串,表示审计日志记录每一种事件类型。可以设定值,用于记录某些指定的事件,例如连接操作、查询操作、操作涉及到的表格等。</p><p>如下:</p><pre><code>SET GLOBAL server_audit_events = 'CONNECT,QUERY,TABLE';</code></pre><p>或者配置文件指定[mysqld]添加:</p><pre><code>[mysqld]server_audit_events=connect,query,table</code></pre><h3 id="server-audit-file-path"><a href="#server-audit-file-path" class="headerlink" title="server_audit_file_path"></a>server_audit_file_path</h3><p>审核日志文件的名称和路径。默认值为“server_audit.log”,这意味着将在数据库目录中创建此文件。</p><h3 id="server-audit-logging"><a href="#server-audit-logging" class="headerlink" title="server_audit_logging"></a>server_audit_logging</h3><p>启用或禁用日志记录。默认是未启用(OFF)的,要记录,则需启用:</p><pre><code>SET GLOBAL server_audit_logging=on</code></pre><p>配置文件修改:找到 my.cnf,在[mysql]参数下配置:</p><pre><code>[server]server_audit_logging=OFF</code></pre><p>更多参数含义,访问官网:<a href="https://mariadb.com/kb/en/mariadb-audit-plugin-options-and-system-variables/#server_audit_events了解。" target="_blank" rel="noopener">https://mariadb.com/kb/en/mariadb-audit-plugin-options-and-system-variables/#server_audit_events了解。</a></p><h2 id="测试使用:"><a href="#测试使用:" class="headerlink" title="测试使用:"></a>测试使用:</h2><p>加入我现在继续修改账号 test2 的密码,执行以下语句:</p><pre><code>GRANT all ON *.* TO 'test2'@'%' identified by '1234';</code></pre><p>根据之前的介绍,因为有安装密码校验插件,所以会报错。可以打开审核日志文件 server_audit.log,查看是否有记录这条日志,默认地址在<code>/var/lib/mysql/server_audit.log</code>:</p><p><img alt="server_audit记录的日志信息" data-src="/../images/TechnicalEssays/MariaDBSeries/06mariadb-server-audit-plugin/2.png" class="lazyload"></p><p>可以看到,在启用 server_audit_logging 之后,就开始记录所有事件信息,修改密码的操作也有记录。</p><p>server_audit 在审核分析数据时可能会提供很多的帮助。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(五)非MariaDB内建插件</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/</url>
<content type="html"><![CDATA[<h1 id="非内嵌的插件"><a href="#非内嵌的插件" class="headerlink" title="非内嵌的插件"></a>非内嵌的插件</h1><p>有些插件,是 MariaDB 内建的,本地安装 MariaDB 就激活了;<br>有的是在服务器的插件,需要 install plugin;<br>还有就是第三方,需要安装到本地,再激活使用。</p><p>区别可以简单这样认为:</p><ul><li><p><code>SHOW PLUGINS;</code>看到所有已安装的激活的插件,可见数量等于<code>SELECT * FROM information_schema.PLUGINS;</code>;</p></li><li><p><code>SHOW PLUGINS SONAME;</code>在 plugin_dir 目录中显示有 关已编译和所有服务器插件的信息,包括尚未安装的插件,可见数量等于<code>SELECT * FROM information_schema.all_plugins</code>。</p></li><li><p>还有就是第三种,不在 MariaDB 服务器的插件,就是不在<code>information_schema.all_plugins</code>的表中的第三方的插件。可能需要在终端中进行额外安装。</p></li></ul><p>例如 Cracklib Password Check,可以 select 一下:</p><p><img alt="未安装的Cracklib Password Check插件" data-src="/../images/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/1.png" class="lazyload"></p><p>ok,为了测试该插件的使用效果,先把之前安装的 simple_password_check 卸载了:</p><pre><code>UNINSTALL PLUGIN IF EXISTS simple_password_check;</code></pre><p>Cracklib Password Check 插件简单说明:</p><ul><li>插件 Cracklib Password Check 是 MariaDB 10.1.2 加入的;</li><li>需要搭配: crackle 2.9.0 (Debian 8 Jessie / Ubuntu 14.04 Trusty,RedHat Enterprise Linux / CentOS 6 之后,系统默认已有)</li><li>非属 MariaDB Package Component, 必须额外安装</li></ul><p>终端安装 cracklib-password-check 插件:</p><pre><code>sudo apt install mariadb-plugin-cracklib-password-check</code></pre><p><img alt="终端安装的Cracklib Password Check插件" data-src="/../images/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/2.png" class="lazyload"></p><p>安装完之后,就可以在 <code>all_plugin</code> 表中看到了,默认安装完成后激活。</p><p><img alt="安装成功后查看信息" data-src="/../images/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/3.png" class="lazyload"></p><p>这也是一个检查密码强度的插件,用于检查设定的密码强度是否足够。测试也简单,同样新建个用户,赋予简单的密码,是不允许的:</p><pre><code>SET PASSWORD FOR 'test2'@'%' = PASSWORD('abc');</code></pre><p><img alt="设置账户密码检验不通过" data-src="/../images/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/4.png" class="lazyload"></p><p>修改为账号 test2 为复杂密码即可通过</p><pre><code>SET PASSWORD FOR 'test2'@'%' = PASSWORD('P@ssw00d');</code></pre><p><img alt="设置账户密码检验通过" data-src="/../images/TechnicalEssays/MariaDBSeries/05not-mariadb-build-in-plugin/5.png" class="lazyload"></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(四)MariaDB密码验证插件使用示例</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/</url>
<content type="html"><![CDATA[<h1 id="插件-PLUGIN-使用示例"><a href="#插件-PLUGIN-使用示例" class="headerlink" title="插件(PLUGIN)使用示例"></a>插件(PLUGIN)使用示例</h1><p>示例介绍密码验证插件 Simple Password Check Plugin (MariaDB 10.1.2.加入)——(顺带简单介绍一些 DBeaver 的使用)</p><p>之前我们在设定 root 密码时,使用的是简单密码“root”,虽然后续连接时,要加 sudo,但是该账号密码依旧可用。</p><p>以 mariadb-server 现有的状态,新建一个账号:</p><p><img alt="新建用户" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/1.png" class="lazyload"></p><p>再输入账号信息:</p><p><img alt="赋予用户权限信息" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/2.png" class="lazyload"></p><p>然后点击右下角的保存,会有执行语句窗口,语句如下</p><pre><code class="sql">CREATE USER 'test'@'%';ALTER USER 'test'@'%'IDENTIFIED BY '123456' ;GRANT Create user ON *.* TO 'test'@'%';GRANT Event ON *.* TO 'test'@'%';GRANT File ON *.* TO 'test'@'%';GRANT Process ON *.* TO 'test'@'%';GRANT Reload ON *.* TO 'test'@'%';GRANT Replication client ON *.* TO 'test'@'%';GRANT Replication slave ON *.* TO 'test'@'%';GRANT Show databases ON *.* TO 'test'@'%';GRANT Shutdown ON *.* TO 'test'@'%';GRANT Super ON *.* TO 'test'@'%';GRANT Create tablespace ON *.* TO 'test'@'%';GRANT Usage ON *.* TO 'test'@'%';FLUSH PRIVILEGES;</code></pre><p>再点击执行,可见保存成功。test 账号新建成功。</p><p>从代码上,可以看到账号 test 的密码是 <strong>123456</strong>,但是这个账号的权限是 check all 选择的所有,相当大的权限。所以这个密码不是很安全。</p><p><strong>事实上,这种权责很大、很重要的账号,其密码就不应该运行设定得如此简单,但现在的默认情况下,MariaDB 是可以这样设定密码的。</strong></p><p>这样,可以使用<strong>simple_password_check</strong> 插件,避免设定账号的密码时过于简单。它可以检查密码是否至少包含一定数量的特定类型的字符。</p><p>首次安装时,密码必须至少为八个字符,并且至少需要一个数字,一个大写字母,一个小写字母以及一个既不是数字也不是字母的字符。</p><p>安装:</p><pre><code>INSTALL SONAME 'simple_password_check';</code></pre><p>或</p><pre><code>INSTALL PLUGIN simple_password_check;</code></pre><p><strong>注意一个是 library,一个是 name,一个有引号,一个没有。</strong></p><p>安装完使用<code>select * from mysql.plugin;</code>查看是否安装成功(不出意外都成功的)。</p><p>注意:<strong>插件还可以在配置文件中启用。</strong></p><p>找到 MariaDB 的配置文件,默认应该是文件<code>/etc/mysql/my.cnf</code>。</p><p>打开文件并在末端添加以下红框参数</p><pre><code>[mariadb]plugin_load_add = simple_password_check</code></pre><p><img alt="配置文件添加插件" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/3.png" class="lazyload"></p><p>修改完配置文件,要重启 MariaDB 服务,例如终端执行<code>sudo service mariadb restart</code>。</p><p>重启完之后,在 dbeaver 中或 mysql 的命令窗口查看 simple_password 的相关参数,就可以看到以下信息:</p><p><img alt="simple_password相关参数" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/4.png" class="lazyload"></p><p>注意:<br><strong>在配置文件中添加的插件配置,<code>select * from mysql.plugin;</code>是查询不到的。<br>不用该插件了,从配置文件中删除即可,当然也要重启生效。</strong></p><p>(后续插件的安装卸载,还是使用指令,不去修改配置文件。)</p><p><strong>从上图参数设定也可看到,simple_password_check 要求密码必须至少为八个字符,并且至少需要一个数字,一个大写字母,一个小写字母以及一个既不是数字也不是字母的字符。</strong></p><p>可以测试:</p><p>创建账号 test2,密码 123456</p><pre><code>GRANT all ON *.* TO 'test2'@'%' identified by '123456;</code></pre><p><img alt="不符合要求的创建账户密码报错" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/5.png" class="lazyload"></p><p>改成符合要求的密码例如 P@ssw0rd 就可以了。</p><pre><code>GRANT all ON *.* TO 'test2'@'%' identified by 'P@ssw0rd';</code></pre><p><img alt="符合要求的创建账户密码" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/6.png" class="lazyload"></p><p><strong>当然,这些限制是可以修改的</strong></p><p>例如,原本是数字至少 1 位,现在改成 2 位</p><pre><code>SET GLOBAL simple_password_check_digits=2</code></pre><p><img alt="修改账户密码的限制要求" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/7.png" class="lazyload"></p><p>使用<code>show variables like 'simple_password%';</code>查看异动。</p><p>之前的密码只有 1 个数字,已经不符合要求了。</p><p><img alt="不符合要求的创建账户密码报错" data-src="/../images/TechnicalEssays/MariaDBSeries/04mariadb-simple_password_check-plugin/8.png" class="lazyload"></p><p>同理,其它参数也是可以修改的,指令类似(n 正整数):</p><pre><code>SET GLOBAL simple_password_check_letters_same_case=n;SET GLOBAL simple_password_check_minimal_length=n;SET GLOBAL simple_password_check_other_characters=n;</code></pre><p>说明:<br><strong>SET GLOBAL 操作修改变量,重启服务之后可能就会被重置,需要永久生效,还是放到配置文件中好些。</strong><br>后续所有提到的 SET GLOBAL,大部分都会有对应的配置文件修改设定。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(三)MariaDB插件(Plugin)简介</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/03mariadb-plugin/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/03mariadb-plugin/</url>
<content type="html"><![CDATA[<p>注:既然已经使用 DBeaver 了,后续许多 MariaDB 的指令,就直接在 dbeaver 的 sql script 里面写(工具栏“SQL 编辑器”->“新建 SQL 编辑器”),如果习惯使用终端窗口,在终端连接 MariaDB 之后,在其 MariaDB 命令窗口输入一样的。</p><h1 id="什么是插件-plugin"><a href="#什么是插件-plugin" class="headerlink" title="什么是插件(plugin)?"></a>什么是插件(plugin)?</h1><p>MariaDB 的插件是:</p><blockquote><p>是通过某种方式增强 MariaDB-server 组件。这些可以是新存储引擎中的任何东西,用于增强全文本分析的插件,甚至是一些小的增强功能,例如将时间戳记作为整数的插件。</p></blockquote><p>说起来:</p><ul><li>MySQL/MariaDB 使用 Plugins 方式扩充 Database 核心功能</li><li>使用外挂方式可避免软件必须重新编译</li><li>动态挂载/ 卸除,提供更弹性的功能扩充。例如 <ul><li>特定用途的 Storage 引擎 </li><li>安全模块 </li><li>稽核纪录</li></ul></li></ul><h1 id="插件管理"><a href="#插件管理" class="headerlink" title="插件管理"></a>插件管理</h1><h2 id="查看插件指令"><a href="#查看插件指令" class="headerlink" title="查看插件指令"></a>查看插件指令</h2><pre><code class="sql">SHOW PLUGINS; -- 查看所有已安装的插件命令SELECT * FROM information_schema.all_plugins; -- 查看所有的插件,包括未安装的SELECT * FROM information_schema.PLUGINS; -- 查看插件更多细节信息SELECT plugin_name, plugin_version, lugin_maturity FROM information_schema.plugins ORDER BY plugin_name; -- 查询某些指定信息</code></pre><h2 id="安装插件"><a href="#安装插件" class="headerlink" title="安装插件"></a>安装插件</h2><p>官网介绍有 3 种方式,使用其一即可。简单归结为</p><ul><li>INSTALL SONAME</li><li>INSTALL PLUGIN</li><li>mysql_plugin 命令</li></ul><p><code>INSTALL PLUGIN</code>语法:</p><pre><code>INSTALL PLUGIN [IF NOT EXISTS] <plugin_name> SONAME '<plugin_library>'</code></pre><ul><li>SONAME: 插件 so 的原始文件名(非必要参数)</li><li>plugin_name: 定义于插件内的名称</li><li>新增后,系统于 mysql.plugin 添加一笔纪录</li></ul><p>安装后,查询 Plugin 对应的模块名称,语法<code>show plugins soname</code></p><p>< plugin_name>就是 Name 字段了,’<plugin_library>就是 library 字段了。</plugin_library></p><p><img alt="查询 Plugin 对应的模块名称" data-src="/../images/TechnicalEssays/MariaDBSeries/03mariadb-plugin/1.png" class="lazyload"></p><p><strong>示例,安装一个名为 BLACKHOLE 的插件</strong></p><p>执行安装语句:</p><pre><code>install plugin [IF NOT EXISTS] BLACKHOLE soname 'ha_blackhole.so'</code></pre><p><img alt="安装BLACKHOLE的插件" data-src="/../images/TechnicalEssays/MariaDBSeries/03mariadb-plugin/2.png" class="lazyload"></p><p>新安装的插件,会显示在<code>mysql.glugin</code>表里面。所以查看此表,可以看到新安装的插件。也可用于查看是否安装成功:</p><p><img alt="查看插件结果" data-src="/../images/TechnicalEssays/MariaDBSeries/03mariadb-plugin/3.png" class="lazyload"></p><h2 id="卸载插件"><a href="#卸载插件" class="headerlink" title="卸载插件"></a>卸载插件</h2><p>同样,卸载组件也类似三种方式,任选其一即可:</p><ul><li>UNINSTALL SONAME</li><li>UNINSTALL PLUGIN</li><li>mysql_plugin 命令</li></ul><p>例如,卸载刚刚安装的 BLACKHOLE:</p><pre><code>UNINSTALL PLUGIN IF EXISTS BLACKHOLE;</code></pre><p><img alt="卸载BLACKHOLE的插件" data-src="/../images/TechnicalEssays/MariaDBSeries/03mariadb-plugin/4.png" class="lazyload"></p><p>再查询<code>select * from mysql.plugin;</code>就没有 BLACKHOLE 了。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(二)MariaDB可视化工具——DBeaver</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/02mariadb-gui/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/02mariadb-gui/</url>
<content type="html"><![CDATA[<p>这个之前有说过,不过不介意再说一遍,当然,也可跳过。</p><p>如果之前使用 mysql,可能会有习惯使用 mysql-workbench。目前 mysql-workbench 依然可以连接 MariaDB,作为其可视化工具。</p><p>当然,其它付费的 GUI 例如 Navicat 的产品也挺好用,有足够预算也可试用后确定是否进行购买。</p><p>不过正如之前 git/gitlab 系列教程中连接 PostgreSQL 所说,DBeaver-ce 是个不错的免费通用型关系型数据库 GUI。</p><p>DBeaver 简介:</p><ul><li>Java based GUI 数据库管理工具</li><li>支持目前主流数据库 ( JDBC-Aware Databases )<br><a href="https://dbeaver.com" target="_blank" rel="noopener">https://dbeaver.com</a></li><li>Enterprise Edititon 可支持更多非 JDBC 数据库( WMI , Redis, Cassandra, MongoDB..)</li></ul><h1 id="安装:"><a href="#安装:" class="headerlink" title="安装:"></a>安装:</h1><p><strong>事实上,官网(<a href="https://dbeaver.io/download/)有各个系统的直接的可执行安装包,下载双击即可。" target="_blank" rel="noopener">https://dbeaver.io/download/)有各个系统的直接的可执行安装包,下载双击即可。</a></strong></p><p>指令安装如下:</p><p>1 jdk 依赖</p><p>确保有安装 jdk:</p><p><img alt="确保有安装jdk" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/1.png" class="lazyload"></p><p>如果没有,使用指令进行安装(openjdk 即可):</p><pre><code>sudo apt install openjdk-8-jre-headless</code></pre><p>2 加入 gpg 金钥</p><pre><code>wget -O - https://dbeaver.io/debs/dbeaver.gpg.key | sudo apt-key add -</code></pre><p>3 加入 repository</p><pre><code>echo "deb https://dbeaver.io/debs/dbeaver-ce /" | sudo tee /etc/apt/sources.list.d/dbeaver.list</code></pre><p>4 更新库文件</p><pre><code>sudo apt update</code></pre><p><img alt="更新库文件" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/2.png" class="lazyload"></p><p>5 安装 dbeaver</p><pre><code>sudo apt install dbeaver-ce</code></pre><p>6 查看版本<br>使用<code>apt policy dbeaver-ce</code>或<code>dpkg -l | grep dbeaver</code>什么的都可以</p><p><img alt="查看版本" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/3.png" class="lazyload"></p><p>7 卸载 dbeaver</p><p>可以使用<code>dpkg -l | grep dbeaver</code>查找确切的软件包名称,使用<code>sudo dpkg -P dbeaver-ce</code>删除它,或<code>sudo dpkg -r dbeaver-ce</code>保留配置文件的卸载。</p><p><img alt="卸载dbeaver" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/4.png" class="lazyload"></p><h1 id="使用-dbeaver"><a href="#使用-dbeaver" class="headerlink" title="使用 dbeaver"></a>使用 dbeaver</h1><p>这个就是 dbeaver 的图标:</p><p><img alt="图标" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/5.png" class="lazyload"></p><p>打开之后,点击工具栏的“数据库”->“新建连接”:</p><p><img alt="新建连接" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/6.png" class="lazyload"></p><p>找到自己需要的数据库,例如 MariaDB:</p><p><img alt="指定数据库" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/7.png" class="lazyload"></p><p>数据连接信息,然后点击“测试连接”,如果连接上,则如下</p><p><img alt="数据库连接成功信息" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/8.png" class="lazyload"></p><p>如果是首次连接,可能会需要联网下载数据库的驱动文件,若有,确认即可。<br>连接成功,即可看到数据库内容:</p><p><img alt="查看连接成功数据库数据" data-src="/../images/TechnicalEssays/MariaDBSeries/02mariadb-gui/9.png" class="lazyload"></p><p>从个人使用角度来看,还行,很多地方还有 mysql-workbench 的味道。可能一开始用起来觉得不咋样,但习惯就好了。最主要,这一个 GUI 小区版就可以连接很多的数据库(不包含任何 nosql),也算比较良心了。</p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(一)MariaDB的安装与卸载</title>
<link href="/2020/06/18/TechnicalEssays/MariaDBSeries/01install-mariadb/"/>
<url>/2020/06/18/TechnicalEssays/MariaDBSeries/01install-mariadb/</url>
<content type="html"><![CDATA[<h1 id="一-安装-MariaDB-10-4"><a href="#一-安装-MariaDB-10-4" class="headerlink" title="一 安装 MariaDB 10.4"></a>一 安装 MariaDB 10.4</h1><p>本系列文章均在 Ubuntu18.04 下进行测试或示例。</p><p>查询已安装的 maria 关键词</p><p>终端执行 <code>sudo dpkg -l | grep maria</code>。可用此检查之前是否已有安装过mariadb。</p><h2 id="安装-MariaDB"><a href="#安装-MariaDB" class="headerlink" title="安装 MariaDB"></a>安装 MariaDB</h2><p>注意:可以在<code>https://downloads.mariadb.org/mariadb/repositories/</code>中去设定添加,选择自己的系统及版本、要安装的 MariaDB 版本、符合自己国家区域的仓库,加快下载数据。</p><p>五月份的时候mariadb10.5.3 RC也已经发布了,感兴趣可以试下。</p><p><img alt="添加区域仓库地址" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/1.png" class="lazyload"></p><h3 id="Step-1-安装-software-properties-common"><a href="#Step-1-安装-software-properties-common" class="headerlink" title="Step 1:安装 software-properties-common"></a>Step 1:安装 software-properties-common</h3><pre><code>sudo apt-get install software-properties-common</code></pre><h3 id="Step-2-将-Repository-Key-放置系统中"><a href="#Step-2-将-Repository-Key-放置系统中" class="headerlink" title="Step 2:将 Repository Key 放置系统中"></a>Step 2:将 Repository Key 放置系统中</h3><p>如果网页<code>https://downloads.mariadb.org/mariadb/repositories/</code>中获取到的添加 key 指令运行失败,可使用以下替代:</p><pre><code>sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8</code></pre><h3 id="Step-3-新增-apt-储存库"><a href="#Step-3-新增-apt-储存库" class="headerlink" title="Step 3:新增 apt 储存库"></a>Step 3:新增 apt 储存库</h3><pre><code>sudo add-apt-repository "deb [arch=amd64,arm64,ppc64el] http://mariadb.mirror.liquidtelecom.com/repo/10.4/ubuntu $(lsb_release -cs) main"</code></pre><p>不行再执行下方指令</p><pre><code>sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] http://ftp.utexas.edu/mariadb/repo/10.4/ubuntu bionic main'</code></pre><p>(需注意版号,如:10.4)</p><p>添加成功后再更新套件:</p><pre><code>sudo apt update</code></pre><h3 id="Step-4-于系统上安装-MariaDB"><a href="#Step-4-于系统上安装-MariaDB" class="headerlink" title="Step 4:于系统上安装 MariaDB"></a>Step 4:于系统上安装 MariaDB</h3><pre><code>sudo apt-get install mariadb-server</code></pre><p>安装完成,检查 MariaDB 服务状态:</p><pre><code>sudo systemctl status mariadb</code></pre><p><img alt="检查MariaDB状态" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/2.png" class="lazyload"></p><p>如上图,则说明安装成功。</p><h2 id="MariaDB-基本配置"><a href="#MariaDB-基本配置" class="headerlink" title="MariaDB 基本配置"></a>MariaDB 基本配置</h2><p>安装完后,可以先进行重启</p><pre><code>sudo service mariadb restart</code></pre><p>再进行环境基本设定:</p><pre><code>sudo mysql_secure_installation</code></pre><p>执行命令之后,终端出现以下问题:</p><p>1、Enter current password for root (enter for none):<br>(直接 enter,预设 MariaDB 没有密码)<br>2、Switch to unix_socket authentication <a href="n,切换到unix_socket身份验证">Y/n</a><br>3、Change the root password? <a href="Y,设定ROOT密码">Y/n</a>(<strong>注意:root 密码最好是复杂密码,否则可能会每次连接 MariaDB 需要加 sudo 的问题,例如我设定的是 root,稍后会提到</strong>) 4、Remove anonymous users? <a href="Y,移除匿名登入">Y/n</a><br>5、Disallow root login remotely? <a href="n,移除远程root登入权限">Y/n</a><br>6、Remove test database and access to it? <a href="Y,移除测试数据库及账号">Y/n</a><br>7、Reload privilege tables now? <a href="Y,重新加载权限表">Y/n</a></p><p>登入指令</p><pre><code>sudo mysql -u root -p</code></pre><p><img alt="登入 MariaDB" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/3.png" class="lazyload"></p><p><strong>注意:解决 MariaDB 需要使用 sudo 才能连接的问题</strong><br>如果使用 Ubuntu 18.04 版本中安装 MariaDB 后,MariaDB 每次访问需要加 sudo 的才能访问 MariaDB,原因是因为 MariaDB 中 root 用户的密码强度不是强类型。</p><p>mysql 亦然。</p><p>分析说明:<br>进入 MariaDB,查看用户权限:</p><pre><code>use mysql;select User,host,plugin from user;</code></pre><p><img alt="查看用户权限" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/4.png" class="lazyload"></p><p>虽然官方不建议使用 <code>mysql_native_password</code> 来作为高强度密码安全机制,但它对密码的设定仍有一些限制。</p><p>例如现在出现的使用密码是 root,可以访问 MariaDB,虽然需要 sudo。</p><p>想要直接命令访问 MariaDB 不加 sudo,只需把该账户的密码改为强类型的密码,例如包含大小写字母、数字、符号的至少 8 位数。</p><p>例如,我将密码修改为“P@ssw0rd”,执行以下指令:</p><pre><code>SET PASSWORD = PASSWORD('P@ssw0rd');</code></pre><p><img alt="修改root密码" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/5.png" class="lazyload"></p><p>可以看到,修改密码之后,可以不加 sudo 直接访问 MariaDB 了。<strong>这目前同样可以解决 mysql 无法直接连接的问题。</strong></p><p>后续会介绍更多关于 MariaDB 账户强密码限制等其它插件,可期。</p><p>如果还只是刚配置 MariaDB,也可以重新运行<code>sudo mysql_secure_installation</code>重新设置。</p><p><strong>解决远程不能访问的问题</strong></p><p>找到 MariaDB 的配置文件,默认地址<code>/etc/mysql/my.cnf</code>。修改[mysqld]参数下<br><code>bind-address = 127.0.0.1</code> => <code>bind-address = 0.0.0.0</code>,再重启 MariaDB service。</p><p>ref:<br><a href="https://medium.com/@jscinin/ubuntu-linux-18-04%E5%AE%89%E8%A3%9Dmariadb%E5%8F%8A%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE-%E7%A7%BB%E9%99%A4%E6%8C%87%E4%BB%A4-8d6d2ce0a73a" target="_blank" rel="noopener">https://medium.com/@jscinin/ubuntu-linux-18-04%E5%AE%89%E8%A3%9Dmariadb%E5%8F%8A%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE-%E7%A7%BB%E9%99%A4%E6%8C%87%E4%BB%A4-8d6d2ce0a73a</a></p><h1 id="二、卸载-MariaDB"><a href="#二、卸载-MariaDB" class="headerlink" title="二、卸载 MariaDB"></a>二、卸载 MariaDB</h1><p>卸载所有 mariadb/mysql 相关的软件</p><pre><code>sudo apt-get remove mysql-\*</code></pre><p>如果安装的是 mariadb 不是 mysql,也可以,有类似以下提示:</p><pre><code>...注意,选中 'mariadb-client-10.4' 而非 'mysql-client-5.5'注意,选中 'mariadb-client-10.4' 而非 'mysql-client-5.6'注意,选中 'mariadb-server-core-10.4' 而非 'mysql-server-core-5.6'注意,选中 'mariadb-client-core-10.4' 而非 'mysql-client-core-5.5'注意,选中 'mariadb-client-core-10.4' 而非 'mysql-client-core-5.6'...</code></pre><p>再执行</p><pre><code>dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P</code></pre><p>会出现窗口:</p><p><img alt="软件包设置窗口" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/7.png" class="lazyload"></p><p>这是清理 MariaDB 中的数据库,是彻底地卸载的话,一并移除即可。</p><p>点击“是”之后,再执行一次<code>dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P</code>。如果出现以下类似的信息:</p><p><img alt="没有找到对应软件包信息" data-src="/../images/TechnicalEssays/MariaDBSeries/01install-mariadb/8.png" class="lazyload"></p><p>则说明卸载成功。</p><p>当然,以上指令是卸载 MariaDB 或 mysql 都可。如果明确知道安装的是 MariaDB,直接使用<br><code>sudo apt-get purge mariadb-*</code>即可。</p><p>ref:<br><a href="https://wsonh.com/article/145.html" target="_blank" rel="noopener">https://wsonh.com/article/145.html</a></p>]]></content>
<categories>
<category> MariaDB系列 </category>
</categories>
<tags>
<tag> mariadb </tag>
<tag> 数据库 </tag>
<tag> db </tag>
<tag> 运维 </tag>
</tags>
</entry>
<entry>
<title>(十八)Git管理项目开发一般规范和开发使用Git常规作业流程</title>
<link href="/2019/12/30/TechnicalEssays/AboutGit/18use-git-as-a-team/"/>
<url>/2019/12/30/TechnicalEssays/AboutGit/18use-git-as-a-team/</url>
<content type="html"><![CDATA[<h1 id="团队开发使用代码版控也是有必要的"><a href="#团队开发使用代码版控也是有必要的" class="headerlink" title="团队开发使用代码版控也是有必要的"></a>团队开发使用代码版控也是有必要的</h1><p>一个开发者想要对自己的代码进行管控,有很多的云带代码托管平台,喜闻乐见的 github、gitlab、gitee、coding(原)、华为云、阿里云代码托管等等。<br>个人使用,那么了解一点点 git 的知识即可满足需求,且也不需要什么规范,如果管理凭自己喜好即可。</p><p>但若是一个团队,需要使用代码托管工具管理自己的代码,那就不一样了。团队协助,最好不能各自按照各自的喜好,统一的作业流程能更加做好合作开发工作,缩短作业流程。</p><p>毕竟,使用这样的方式,肯定比用 U 盘把代码拷来拷去,然后复制粘贴好的多。可能需要传统行业的软件开发代码合并方式就是如此,并不需要惊讶。虽然这样做的风险和不足很明显,但是简单,不出错的话成本也低。</p><h1 id="本章内容"><a href="#本章内容" class="headerlink" title="本章内容"></a>本章内容</h1><p>本篇主要讲解,一个团队,想要统一使用 git 搭配 gitlab 做代码管理的一般思路规范,并不一定适用,但是可以做参考,指定符合自己团队需要的规范。</p><p>基本内容有:</p><ul><li>明确团队组织架构分层;</li><li>项目准备工作<ul><li>根据组织架构分成,做 group/subgroup 准备</li><li>项目初始化准备</li><li>小组成员开发就绪</li><li>后续步骤</li><li>Git 补充的一些说明</li></ul></li><li>开发使用 Git 常规操作<ul><li>gitlab 协作开发模式说明</li><li>日常 Git 操作</li></ul></li></ul><p>具体内容参考<a href="https://github.com/Sanotsu/git-gitlab-advanced-notes" target="_blank" rel="noopener">github 分享 PPT</a>之《17-Git管理项目开发准备和开发使用Git常规作业流程.pdf》。</p><p>到这里,这个 git/gitlab 使用系列的内容基本就说完了,不算全面,看起来也不算专业,若是能有所收获固然是极好了。倘若真的看完还是一无所获,那真是对你浪费的宝贵时间表示遗憾和难过了。</p><p>“只有用心,才能做出最好的菜。”相关内容网络资源还是很多的,多多学习,总有收获,并不一定需要在这里。</p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(十七)Git进阶与测试--使用Git、Git LFS搭配gitlab管控大文件</title>
<link href="/2019/12/29/TechnicalEssays/AboutGit/17about-git-lfs/"/>
<url>/2019/12/29/TechnicalEssays/AboutGit/17about-git-lfs/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>git lfs 一些基本命令使用;</li><li>使用 Git/Git LFS 搭配 gitlab 管控大文件之测试。</li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><ul><li>1、Git 本身作为代码管控软件,是以代码为主,没有直接管控到比较大的文件。</li><li>2、目前比较流行的 git 管理大文件的方式是使用 git-lfs。</li><li>3、git-lfs 是 git 的一个插件,官网说明如下:</li></ul><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/1.png" class="lazyload"></p><ul><li>4、使用比较简单,简单两三步即可完成大文件的提交。</li><li>5、gitlab 新版本默认已经支持 lfs,在配置文件 gitlab.rb 中可见:</li></ul><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/2.png" class="lazyload"></p><h2 id="预期中可能出现的问题"><a href="#预期中可能出现的问题" class="headerlink" title="预期中可能出现的问题"></a>预期中可能出现的问题</h2><ul><li>1、因为是管理到大文件,所以在 push 到远程服务器或者从远程服务器 pull 可能会因为网络带宽、文件大小、同时操作人员过多等因素导致操作耗时较长。</li><li>2、git 记录每次 add、commit 等操作,又以大文件为主,本地的.git 文件夹可能会极速增大。</li><li>3、gitlab 服务器若是还添加定期备份,因为文件管理可能导致 gitlab server 需要较大的硬盘存储数据。</li></ul><h2 id="大概流程"><a href="#大概流程" class="headerlink" title="大概流程"></a>大概流程</h2><ul><li>1 安装 git lfs 插件</li><li>2 准备两份大文件,两份 txt,分别作为文件管理和代码管理。</li><li>3 在 gitlab server 新建仓库,作为文件管理远程仓库。</li><li>4 使用 git lfs 将文件上传到 gitlab server 远程仓库。</li><li>5 克隆远程仓库到本地,查看文件是否完整。</li></ul><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><h3 id="下载安装插件"><a href="#下载安装插件" class="headerlink" title="下载安装插件"></a>下载安装插件</h3><p>在<a href="https://git-lfs.github.com/" target="_blank" rel="noopener">git lfs 官网</a>下载插件并安装。</p><h3 id="本地项目准备"><a href="#本地项目准备" class="headerlink" title="本地项目准备"></a>本地项目准备</h3><p>本地新建文件夹 gitLfsTest,并准备两个较大压缩包文件作文件管理对象。同时新建两份 test3.txt,test4.txt 作为代码管理对象。</p><p>如下图:</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/3.png" class="lazyload"></p><h3 id="创建远程仓库"><a href="#创建远程仓库" class="headerlink" title="创建远程仓库"></a>创建远程仓库</h3><p>在 gitlab server 创建一个仓库,作为远程仓库</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/4.png" class="lazyload"></p><h3 id="初始化文件夹为本地-git-仓库,初始化-git-lfs。"><a href="#初始化文件夹为本地-git-仓库,初始化-git-lfs。" class="headerlink" title="初始化文件夹为本地 git 仓库,初始化 git lfs。"></a>初始化文件夹为本地 git 仓库,初始化 git lfs。</h3><p>执行命令:</p><pre><code>git initgit lfs install</code></pre><p>如下图:</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/5.png" class="lazyload"></p><h3 id="使用-git-lfs-追踪大文件"><a href="#使用-git-lfs-追踪大文件" class="headerlink" title="使用 git lfs 追踪大文件"></a>使用 git lfs 追踪大文件</h3><p>使用 git lfs 追踪(track)大文件(*指代所有),执行之后,在文件根目录会出现.gitattributes 文件,内容即为追踪的大文件类型。<br>执行命令:</p><pre><code>git lfs track "*.zip"</code></pre><p>如下图</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/6.png" class="lazyload"></p><h3 id="确保-gitattributes-文件会被添加到追踪(tracked)"><a href="#确保-gitattributes-文件会被添加到追踪(tracked)" class="headerlink" title="确保.gitattributes 文件会被添加到追踪(tracked)"></a>确保.gitattributes 文件会被添加到追踪(tracked)</h3><p>执行命令:</p><pre><code>git add .gitattributes</code></pre><p>一般来说如果都是执行的<code>git add .</code>,那就没有必要再这样作</p><p>如下图:</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/7.png" class="lazyload"></p><p>到这里,git lfs 追踪管理大文件就基本完成了,后续就像是管理一般代码一样,进行 add,commit,push 等操作。</p><h3 id="将-gitLfsTest-专案-push-到远程仓库。"><a href="#将-gitLfsTest-专案-push-到远程仓库。" class="headerlink" title="将 gitLfsTest 专案 push 到远程仓库。"></a>将 gitLfsTest 专案 push 到远程仓库。</h3><p>当然,要记得先 add,commit。<br>注意:首次 add 时,我使用的是<code>add .</code>,会添加 2 个 zip 文件合计 2.26G 左右,2 个 txt 文件,总共 4 个文件,使用 time 指令记录耗时:</p><pre><code>time git add .</code></pre><p>如下图:</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/8.png" class="lazyload"></p><p>再 commit:</p><pre><code>time git commit -m '初次提交两个大文件'</code></pre><p>如下图:</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/9.png" class="lazyload"></p><p>后续常规,添加远程仓库地址,推送到远程仓库:</p><pre><code>git remote add origin http://192.168.28.83/david/gitlfstest.gittime git push -u origin master</code></pre><p>如下图:</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/10.png" class="lazyload"></p><p>远程仓库内容如下:</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/11.png" class="lazyload"></p><p>可见两个 zip 包后面有 LFS 标识。</p><h3 id="修改本地的-zip-包,再上传到远程仓库。"><a href="#修改本地的-zip-包,再上传到远程仓库。" class="headerlink" title="修改本地的 zip 包,再上传到远程仓库。"></a>修改本地的 zip 包,再上传到远程仓库。</h3><p>修改文件前,留意下.git 文件的大小,如下图:</p><p><img alt="12.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/12.png" class="lazyload"></p><p>修改 test2.zip 文件大小<br>修改前如下图:</p><p><img alt="13.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/13.png" class="lazyload"></p><p>修改后如下图:</p><p><img alt="14.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/14.png" class="lazyload"></p><p>同样的,add,commit,push:</p><pre><code>time git add .time git commit -m '修改test2.zip文件大小'time git push -u origin master</code></pre><p>如下图:</p><p><img alt="15.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/15.png" class="lazyload"></p><p>远程也是一样有新的 commit 信息</p><p>如下图:</p><p><img alt="16.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/16.png" class="lazyload"></p><p>此时,再关注下.git 文件夹的大小</p><p>如下图:</p><p><img alt="17.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/17.png" class="lazyload"></p><p>由 2.26G 上升到了 2.99G。<br>所以,看起来随着修改的次数变多,.git 文件会无休止的增大下去。<br>不过 git lfs 有相关指令避免它:</p><pre><code>git lfs prune</code></pre><p>它会删除本地旧的 fls 文件。</p><p>如下图:</p><p><img alt="18.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/18.png" class="lazyload"></p><h3 id="从远程仓库-clone-一份-gitLfsTest-项目,查看文件内容。"><a href="#从远程仓库-clone-一份-gitLfsTest-项目,查看文件内容。" class="headerlink" title="从远程仓库 clone 一份 gitLfsTest 项目,查看文件内容。"></a>从远程仓库 clone 一份 gitLfsTest 项目,查看文件内容。</h3><p>此时的项目应该是这样的:如下图:</p><p><img alt="19.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/19.png" class="lazyload"></p><p>我们从远程克隆一份下来:</p><p>查看内容,注意.git 的大小。如下图:</p><p><img alt="20.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/20.png" class="lazyload"></p><p>可见项目内容是完整的,test1.zip 和 test2.zip 都完整存在。至此使用 git 搭配插件 git lfs 管理大文件的测试就完成。</p><p>如下图:</p><p><img alt="21.png" data-src="/../images/TechnicalEssays/AboutGit/about-git-lfs/21.png" class="lazyload"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ol><li>git 配合 git lfs 和 gitlab server 管控大文件操作还算简单方便,在系统安装完插件之后,在 git 管理的项目内:</li></ol><pre><code class="sh"> # 添加对大文件的追踪(.zip后缀) git lfs install git lfs track "*.zip" git add .gitattributes # 常规的添加、提交、推送 git add . git commit -m '{message}' git remote add origin {origin-url} git push -u origin master # 删除本地旧的fls文件 git lfs prune</code></pre><ol start="2"><li>即便是针对大文件,add,commit 等在本机的 git 指令依旧不算耗时;</li><li>在将项目需要放到远程 server 管理时,主要的耗时,来源于 push 和 clone 等跨主机操作,因此可以考虑到主要耗时取决网络。</li><li>.git 中的确会保留 fls 文件操作历史,导致 size 变得很大,不过可以使用<br><code>git lfs prune</code>尽量减少大小。</li><li>更多<code>git lfs</code>指令,可參看<a href="https://github.com/git-lfs/git-lfs/tree/master/docs/man" target="_blank" rel="noopener">official man pages.</a>,或者直接終端輸入:</li></ol><pre><code class="sh"> git lfs help <command> # 或 git lfs <command> -h</code></pre>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十六)Git进阶与测试--将单一项目拆成多个小项目并保留各自的历史记录</title>
<link href="/2019/12/28/TechnicalEssays/AboutGit/16project-split/"/>
<url>/2019/12/28/TechnicalEssays/AboutGit/16project-split/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>如何将一个 git 管理的较大的项目按文件夹拆分成几个小项目,且各个小项目只保留自己文件夹中的文件的历史记录。</li><li>两种方式实现<ul><li>使用<code>git filter-branch</code>的实现</li><li>使用<code>git subtree</code>的实现(推荐)</li></ul></li></ul><p>本篇内容,不建议跳过,如果有这个需求,还请仔细详细查看,谢谢。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>与项目合并相反,这是需要把单一项目的.git 的提交记录,抽取出各自子项目想要的部分。不过,相对于合并,拆分要简单些。</p><p>就不考虑把一个单独的文件拆成一个项目了。如果实在需要,就把这个单个文件,也放到一个文件夹中,再拆这个文件夹即可。</p><p>本地 git 仓库使用的是相对路径,所以直接修改 root folder 不会影响 git 历史记录</p><h2 id="项目准备"><a href="#项目准备" class="headerlink" title="项目准备"></a>项目准备</h2><p>不将上一篇合并好的 timetools 再拆开。直接使用之前从 github 上克隆的 dayjs 项目作业。</p><p>在作业前,dayjs 的结构是这样的:</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/project-split/1.png" class="lazyload"></p><p>查看一下,此时所有的日志 log 修改的文件名。如下图(这里是可以看到所有文件修改内容和提交数量):</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/project-split/2.png" class="lazyload"></p><p>dayjs 项目中,dayjs/src/有两个文件夹,locale/和 plugin/,示例假装 locale/需要拆出来,做一个单独的项目。</p><h2 id="大概流程"><a href="#大概流程" class="headerlink" title="大概流程"></a>大概流程</h2><ul><li><p>1 使用<code>git filter-branch</code></p><ul><li>重写提交历史记录</li><li>清除.git 的 object 文件夹(如果觉得有必要的话)</li><li>查看日志信息</li></ul></li><li><p>2 使用<code>git subtree</code></p><ul><li>进入 dayjs,创建一个临时分支</li><li>创建一个新的 git 空项目</li><li>将原仓库的临时分支 my-locale 拉到新仓库</li></ul></li></ul><h2 id="使用git-filter-branch实现–不推荐-仅作了解-不感兴趣可略过"><a href="#使用git-filter-branch实现–不推荐-仅作了解-不感兴趣可略过" class="headerlink" title="使用git filter-branch实现–不推荐,仅作了解,不感兴趣可略过"></a>使用<code>git filter-branch</code>实现–不推荐,仅作了解,不感兴趣可略过</h2><h3 id="重写提交历史记录"><a href="#重写提交历史记录" class="headerlink" title="重写提交历史记录"></a>重写提交历史记录</h3><pre><code>$ git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter src/locale -- --all</code></pre><p>命令说明:</p><p><code>git filter-branch</code>通过重写分支来重写 Git 修订历史记录,并在每个修订版上应用自定义过滤器。</p><ul><li>–tag-name-filter <command> 该参数控制我们要如何处理旧的 tag,cat 即表示原样输出;</li><li>–prune-empty 删除空的(对子目录没有影响的)提交;</li><li>–subdirectory-filter <directory> 指定子目录路径;</li><li>– –all <code>-- all</code>参数必须跟在 – 后面,表示对所有分支进行操作。如果你只想保存当前分支,也可以不添加此参数。</li></ul><p>此操作会花点时间,执行完成,可以看到,原版的 dayjs 下的文件,变成了这样:</p><p><img alt="执行后" data-src="/../images/TechnicalEssays/AboutGit/project-split/3.png" class="lazyload"></p><h3 id="清除-git-的-object-文件夹-如果觉得有必要的话"><a href="#清除-git-的-object-文件夹-如果觉得有必要的话" class="headerlink" title="清除.git 的 object 文件夹(如果觉得有必要的话)"></a>清除.git 的 object 文件夹(如果觉得有必要的话)</h3><pre><code>git reset --hardgit for-each-ref --format="%(refname)" refs/original/ |xargs -n 1 git update-ref -dgit reflog expire --expire=now --allgit gc --aggressive --prune=now</code></pre><p>git for-each-ref 根据给定的集合对它们进行排序之后,迭代所有匹配的 ref <pattern>并根据给定的显示它们。</p><ul><li>–format=<format> %(fieldname)从所显示的 ref 及其指向的对象插入的字符串。</li></ul><p>git-update-ref-安全地更新存储在 ref 中的对象名称</p><ul><li>带-d 标志,它在验证命名的<ref>仍然包含<oldvalue>后将其删除</li></ul><p>git reflog expire 修剪较旧的引用日志条目。</p><ul><li>–expire=<time> 修剪早于指定时间的条目。</li><li>–all 处理所有引用的引用日志。</li></ul><p>git-gc 清理不必要的文件并优化本地存储库</p><ul><li>–aggressive 此选项将导致 git gc 更积极地优化存储库,但花费更多时间。</li><li>–prune=<date> 修剪比日期更旧的松散对象(默认为 2 周前)</li></ul><p>清除的执行如下图:</p><p><img alt="清除object" data-src="/../images/TechnicalEssays/AboutGit/project-split/4.png" class="lazyload"></p><h3 id="查看日志信息"><a href="#查看日志信息" class="headerlink" title="查看日志信息"></a>查看日志信息</h3><p>其实最重要就只有第一步而已,完成之后,现在可以查看到现在的 dayjs 的日志<br>如下图:</p><p><img alt="执行后的日志" data-src="/../images/TechnicalEssays/AboutGit/project-split/5.png" class="lazyload"></p><p>现在只有原来在 dayjs/src/locale 里面的文件被修改的提交记录被保留,其它的都丢掉了。</p><p>只要把这个现在的 dayjs 修改成 locale,就完成了大项目拆分成子项目的操作。</p><h2 id="使用git-subtree实现–推荐做法"><a href="#使用git-subtree实现–推荐做法" class="headerlink" title="使用git subtree实现–推荐做法"></a>使用<code>git subtree</code>实现–推荐做法</h2><p>同样,使用最开始的从 github 中拉下来的 dayjs 做源项目。</p><h3 id="进入-dayjs,创建一个临时分支"><a href="#进入-dayjs,创建一个临时分支" class="headerlink" title="进入 dayjs,创建一个临时分支"></a>进入 dayjs,创建一个临时分支</h3><pre><code>git subtree split -P src/locale -b my-locale</code></pre><p>命令说明:</p><p><code>git subtree</code> 合并子树并将存储库拆分为子树。<br>这个命令不在原本的 git 参考文件上,不过用法比较简单,可以在<a href="https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt" target="_blank" rel="noopener">这里</a>查看的更多用法。</p><ul><li>split<br>从<prefix>子树的历史中提取一个新的合成项目历史。新的历史记录仅包括影响<prefix>的提交(包括合并),并且这些提交中的每个现在都在项目的根目录而不是子目录中具有<prefix>的内容。因此,新创建的历史记录适合作为单独的 git 存储库导出。</li><li>-P <prefix> = –prefix=<prefix> 在存储库中指定的子树的路径</li><li>-b <branch> 创建一个分支</li></ul><p>如下图</p><p><img alt="创建临时分支" data-src="/../images/TechnicalEssays/AboutGit/project-split/6.png" class="lazyload"></p><h3 id="创建一个新的-git-空项目"><a href="#创建一个新的-git-空项目" class="headerlink" title="创建一个新的 git 空项目"></a>创建一个新的 git 空项目</h3><p>在与 dayjs 平级的路径下,创建一个文件夹,例如 my-locale(和上一步创建的分支名没任何关系),并进入,然后 git 初始化</p><pre><code>cd ..mkdir my-localecd my-localegit init</code></pre><p>如下图:</p><p><img alt="新建空git项目" data-src="/../images/TechnicalEssays/AboutGit/project-split/7.png" class="lazyload"></p><h3 id="将原仓库的临时分支-my-locale-拉到新仓库"><a href="#将原仓库的临时分支-my-locale-拉到新仓库" class="headerlink" title="将原仓库的临时分支 my-locale 拉到新仓库"></a>将原仓库的临时分支 my-locale 拉到新仓库</h3><pre><code>git pull ../dayjs my-locale</code></pre><p>如下图</p><p><img alt="空项目完成临时分支的拉取" data-src="/../images/TechnicalEssays/AboutGit/project-split/8.png" class="lazyload"></p><p>查看日志,效果一致,如下图:</p><p><img alt="一样的日志" data-src="/../images/TechnicalEssays/AboutGit/project-split/9.png" class="lazyload"></p><p>对于一开始说的,单个文件,想要这样做,似乎不行。如下图。</p><p><img alt="单个文件拆成项目" data-src="/../images/TechnicalEssays/AboutGit/project-split/10.png" class="lazyload"></p><p>还是放到文件夹吧。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>使用<code>git filter-branch</code>拆分子项目,是会把除了需要被拆分的部分,全部都删除了,包括.git 仓库里的东西。这是在原本的项目上进行作业。</li><li>使用<code>git subtree</code>是在原项目中创建了临时分支,再拉取到新的 git 空项目,不会对原项目进行异动,原项目甚至不会知道子项目的存在。</li><li>如果提交的次数较多,为了筛选所有的历史记录,都会比较耗时间。但不修改原项目的<code>git subtree</code>,显然更好。</li><li>git subtree 创建子项目命令小计</li></ul><pre><code> cd <source-project> git subtree split -P <prefix> -b <temp-branch> cd .. mkdir <sub-project> cd <sub-project> git init git pull <source-project path> <temp-branch></code></pre>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十五)Git进阶与测试--合并两个项目为一个并保留合并前所有历史记录</title>
<link href="/2019/12/27/TechnicalEssays/AboutGit/15combine-projects/"/>
<url>/2019/12/27/TechnicalEssays/AboutGit/15combine-projects/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>如何将两个 git 管理的项目合并成一个项目,并保留住各自项目中所有的历史提交记录。(后续可以自行拓展到三个、四个……的合并)</li></ul><p>本篇内容,不建议跳过,如果有这个需求,还请仔细详细查看,谢谢。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>git 管理的项目合并,还要保留之前的提交历史记录,则表明不能直接异动到原项目.git 文件夹仓库,需要通过其它方式把子项目的.git 文件夹合并到一起,才能保存住所有提交信息。</p><h2 id="项目准备"><a href="#项目准备" class="headerlink" title="项目准备"></a>项目准备</h2><ul><li>先从 github 克隆了两个项目用于测试,一个是 dayjs,一个是 moment;</li><li>计划是把 dayjs 和 moment 合并为一个项目,名为 timetools;<ul><li>该项目包含两个文件夹,一是 dtool,对应原本的 dayjs;</li><li>二是 mtool,对应原本的 moment。</li></ul></li></ul><p>效果,合并前</p><pre><code>- dayjs => 独立的 dayjs 项目,有自己的.gitignore 和 .git/- moment => 独立的 moment 项目,有自己的.gitignore 和 .git/</code></pre><p>合并后:</p><pre><code>- timetools/ => 即最开始的 dayjs,整合完后更名 - .gitignore => 合并两个 repos 的忽略文件 - .git/ => 最终仅余一个 repo + dtool/ => 对应 dayjs + mtool/ => 对应 moment</code></pre><p>克隆的项目,内容如下:</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/1.png" class="lazyload"></p><p>使用<code>git log --oneline | wc -l</code>获取提交数量。</p><p>粗略可见,dayjs 的提交为 1046 次,moment 提交为 3724 次。<br><strong>注意分支名,dayjs 为 dev,moment 为 develop。</strong></p><h2 id="大概流程"><a href="#大概流程" class="headerlink" title="大概流程"></a>大概流程</h2><ul><li>1 进入 dayjs 文件夹,将 moment 作为远程仓库添加到 dayjs 来;</li><li>2 合并添加的库 moment 到原本的 dayjs 项目;</li><li>3 创建 mtool 文件夹,把 moment 的 develop 分支合并到 mtool 文件夹;</li><li>4 完成 moment 转移提交;</li><li>5 完成 dayjs 文件的迁移;</li><li>6 完成项目合并并查看历史记录。</li></ul><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><h3 id="进入-dayjs-文件夹,将-moment-作为远程仓库添加到-dayjs-来"><a href="#进入-dayjs-文件夹,将-moment-作为远程仓库添加到-dayjs-来" class="headerlink" title="进入 dayjs 文件夹,将 moment 作为远程仓库添加到 dayjs 来"></a>进入 dayjs 文件夹,将 moment 作为远程仓库添加到 dayjs 来</h3><p>使用命令:</p><pre><code>git remote add -f moment D:/davidsu/Desktop/GitlabTest/full/moment</code></pre><p>命令说明:<br><code>git remote add</code> 添加远程仓库路径</p><ul><li>-f 的作用是在添加后立刻 fetch。</li><li><code>D:/davidsu/Desktop/GitlabTest/full/</code>为需要被合并 moment 项目的<strong>绝对路径</strong> 。</li></ul><p>如下图:</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/2.png" class="lazyload"></p><h3 id="合并添加的库-moment-到原本的-dayjs-项目"><a href="#合并添加的库-moment-到原本的-dayjs-项目" class="headerlink" title="合并添加的库 moment 到原本的 dayjs 项目"></a>合并添加的库 moment 到原本的 dayjs 项目</h3><p>使用命令(注意分支名):</p><pre><code>git merge --strategy ours --no-commit --allow-unrelated-histories moment/develop</code></pre><p>命令说明:<br><code>git merge</code> 为合并分支</p><ul><li>–strategy ours 解析合并,在合并时,如果遇到冲突,以我的为准。(本例是在 dayjs 中合并 moment,遇到冲突以 dayjs 的为准)。结果就是:<ul><li>moment 的历史记录被合并到 dayjs 的历史记录中。</li><li>moment 的文件树被读取并和 dayjs 的文件树比对进行冲突解析。</li></ul></li><li>–no-commit 合并解析完成后中断,停留在最后的提交步骤之前。<ul><li>只要你还没 commit,那么 merge 的结果就暂时保存在缓存区中,只有完成提交步骤合并才算彻底完成(文件树被正式改变)。</li></ul></li><li>–allow-unrelated-histories 允许合并无关的历史记录。<ul><li>如果不添加此选项,可能会出现<code>fatal: refusing to merge unrelated histories</code>错误。</li></ul></li></ul><p>如下图:</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/3.png" class="lazyload"></p><h3 id="创建-mtool-文件夹,把-moment-的-develop-分支合并到-mtool-文件夹"><a href="#创建-mtool-文件夹,把-moment-的-develop-分支合并到-mtool-文件夹" class="headerlink" title="创建 mtool 文件夹,把 moment 的 develop 分支合并到 mtool 文件夹"></a>创建 mtool 文件夹,把 moment 的 develop 分支合并到 mtool 文件夹</h3><p>使用命令:</p><pre><code class="sh">mkdir mtool # 创建文件夹git read-tree --prefix=mtool/ -u moment/develop</code></pre><p>命令说明:<br><code>git read-tree</code> 给定的树信息读入索引</p><ul><li>–prefix 用于指定文件树读取后保存的路径,相对于当前路径并且一定要追加 /。</li><li>-u 是说在读取后更新 index,使得 working tree 与 index 保持同步。</li></ul><p>这个命令的意义在于,之前的<code>git merge</code>命令可能会在解决冲突的时候,把 moment 的文件树弄得比较混乱,再使用<code>read-tree</code>去修复一下。</p><p>如下图(再次提醒,=前后不要空格):</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/4.png" class="lazyload"></p><h3 id="完成-moment-转移提交"><a href="#完成-moment-转移提交" class="headerlink" title="完成 moment 转移提交"></a>完成 moment 转移提交</h3><p>上一步已经修复了文件数,执行完之后,仍然在 MERGING 状态,需要提交一次修改。</p><p>使用命令:</p><pre><code>git commit --message '完成moment 的迁移,新目录为 mtool'</code></pre><p>如下图(MERGING 过成已完成):</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/5.png" class="lazyload"></p><h3 id="完成-dayjs-文件的迁移"><a href="#完成-dayjs-文件的迁移" class="headerlink" title="完成 dayjs 文件的迁移"></a>完成 dayjs 文件的迁移</h3><p>以上,已把 momet 项目迁移到了 dayjs 下的 mtool 文件夹了。现在要迁移 dayjs 文件夹了。</p><p>在 dayjs 文件夹下,新建文件夹 dtool</p><pre><code>mkdir dtool</code></pre><p>再把所有原本属于 dayjs 的文件移动到新建的 dtool 去。<br>也就是除了 dtool/、mtool/、.git/、.gitignore 之外的所有。</p><p>剪切完之后,把这个原本的 dayjs 的文件夹重命名为 timetools。</p><h3 id="完成项目合并并查看历史记录"><a href="#完成项目合并并查看历史记录" class="headerlink" title="完成项目合并并查看历史记录"></a>完成项目合并并查看历史记录</h3><p>到这一步,原本的 dayjs 项目,就变成了 timetools 项目,里面的 dtool 文件夹就是 dayjs 项目。</p><p>不过还差一点,之前只是把文件放进去了,还需要合并.gitignore 文件。</p><p>在新的 timetools 文件夹下,运行:</p><pre><code>cat mtool/.gitignore >> .gitignore</code></pre><p>把原本 moment 项目,现在的 mtool 文件夹下的.gitignore 的内容,合并到现在 timetools 文件夹下的.gitignore 中,完成忽略文件的合并。</p><p>如下图:</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/6.png" class="lazyload"></p><p>到这里,合并作业就基本完成了,最后在添加提交一次,做合并项目的记录</p><pre><code>git add --all;git commit --message '迁移整合完成!'</code></pre><p>如下图:</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/7.png" class="lazyload"></p><p>合并前后的文件夹结构如下:</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/8.png" class="lazyload"></p><p>查看合并后的项目历史记录,如下图:</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/combine-projects/9.png" class="lazyload"></p><p>提交数:4772 = 1046 + 3724 + 2。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>以上,完成了两个项目合并到一个项目的示例接操作演示,后续有更多的项目想要合并,可以类似。</p><p>本示例使用步驟</p><ul><li>进入 dayjs</li><li>git remote add -f moment D:/davidsu/Desktop/GitlabTest/full/moment</li><li>git merge –strategy ours –no-commit –allow-unrelated-histories moment/develop</li><li>mkdir mtool</li><li>git read-tree –prefix=mtool/ -u moment/develop</li><li>git commit –message ‘完成 moment 的迁移,新目录为 mtool’</li><li>mkdir dtool (还在 dayjs 下面)</li><li>拷贝 dayjs 的原始项目文件(除了 .git/ 和 .gitignore 以外)至 dtool/;</li><li>拷贝完之后,可以把原本文件夹名 dayjs 改为 timetools;</li><li>把此时 mtool 下的.gitignore 文件内容,整理合并到 timetools 下的.gitignore 文件中去。</li><li>合并完之后,再全部添加提交一次,做为整合操作的记录:<ul><li>git add –all; git commit –message ‘迁移整合完成!’</li></ul></li></ul><p><strong>整理引用原作者步骤:</strong><br>目标:将 frontend 项目与 backend 项目,合并到 project 项目下的 client 文件夹与 server 文件夹。</p><blockquote><ol><li>$ [~] <code>cd frontend</code></li><li>$ [frontend] <code>git remote add -f backend /fullpath/to/backend</code></li><li>$ [frontend] <code>git merge --strategy ours --no-commit backend/master</code></li><li>$ [frontend] <code>mkdir -p server</code></li><li>$ [frontend] <code>git read-tree --prefix=server/ -u backend/master</code></li><li>$ [frontend] <code>git commit --message '完成 backend 的迁移,新目录为 server'</code></li><li>$ [frontend] <code>mkdir -p client</code></li><li><code># 拷贝 frontend 的原始项目文件(除了 .git/ 和 .gitignore 以外) 至 client/</code></li><li>$ [frontend] <code>cd ..; mv frontend/ project/; cd project</code></li><li>$ [project] <code>cat server/.gitignore >> .gitignore</code></li><li><code># 整理合并后的 .gitignore,修复其中的路径缺失并保存;修复各种项目依赖的缺失,本地测试。</code></li><li>$ [project] <code>git add --all; git commit --message '迁移整合完成!'</code></li></ol></blockquote><p>参考文件:<br><a href="https://segmentfault.com/a/1190000000678808" target="_blank" rel="noopener">https://segmentfault.com/a/1190000000678808</a></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十四)Git进阶与测试--如何把文件真正的从Git里删除</title>
<link href="/2019/12/26/TechnicalEssays/AboutGit/14delete-file-permanently/"/>
<url>/2019/12/26/TechnicalEssays/AboutGit/14delete-file-permanently/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>利用<code>git filter-branch</code>命令,彻底删除已提交文件。</li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>例如在开发过程中,把私用账号密码文件提交了,或者其它机密文件提交了,那么在 git 中就会保留那份文件,如果 push 到远程,那么其它人也有可能看到这份他们可能不应该看到的文件,所以,如何把这份文件从 git 中移除掉?</p><h2 id="大概流程:"><a href="#大概流程:" class="headerlink" title="大概流程:"></a>大概流程:</h2><ul><li>1、新建一个项目 test-filter-branch,git 初始化,并放入两个文件,初始化提交</li><li>2、模拟误操作添加了不应该提交的 password.txt 文件,并提交</li><li>3、误提交 password.txt 之后,模拟又多次提交</li><li>4、将每个提交中的 password.txt 移除,并清理垃圾回收中的相关设定</li></ul><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><p>新建一个在 test-filter-branch 项目并初次提交</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/1.png" class="lazyload"></p><p>之后,在项目中创建了一个 config,里面有个 password.txt 文件。<br>假设属于私有机密文件,不应该被提交,但是又忘记在创建前加入.gitignore 文件。且已经提交了。</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/2.png" class="lazyload"></p><p>密码提交之后,又进行了很多次提交。</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/3.png" class="lazyload"></p><p>突然想起密码被提交,需要从 commit 中,把文件删除,此时 commit 记录如下</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/4.png" class="lazyload"></p><p>使用以下命名:</p><pre><code>git filter-branch -f --tree-filter "rm -f config/password.txt"</code></pre><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/5.png" class="lazyload"></p><p>此时,config/password.txt 文件是不见了</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/6.png" class="lazyload"></p><p>即便如此,还是可以通过 git reset 指令找回来。<br>所以,还有几个跟资源回收有关的事情需要处理一下<br>删除备份点:<code>rm .git/refs/original/refs/heads/master</code><br>设置 reflog 立即过期:<code>git reflog expire --all --expire=now</code></p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/7.png" class="lazyload"></p><p>此时再查看 git reflog 会发现没有记录,使用 git fsck 指令就可以看到很多 Unreachable 的对象了</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/8.png" class="lazyload"></p><p>不过,查看日志还能看到提交秘密时的 commit id,使用 git reset 能恢复 password.txt 文件吗,试一下。</p><p>查看日志(注意,删除后 commit 日志和删除之前的,有涉及到 password.txt 的 commit id 全都变了。)</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/9.png" class="lazyload"></p><p>使用 git reset 之后,可以看到已然没有 config/password.txt 文件了。</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/10.png" class="lazyload"></p><p>注意:删除 commit 中 password.txt 文件,在本地已经完成了,如果在之前已经推送到了远程,则需要使用<code>git push -f</code>覆盖掉。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>删除文件步骤主要使用命令:</p><pre><code class="sh">git filter-branch -f --tree-filter "rm -f config/password.txt" # 重写分支rm .git/refs/original/refs/heads/master # 删除备份点git reflog expire --all --expire=now # 设置reflog立即过期git push -f # 同步远程</code></pre><p><strong>特别说明</strong>: 重写的历史将具有所有对象的不同对象名称,并且不会与原始分支会聚。您将无法在原始分支的顶部轻松推送和分发重写的分支。如果您不知道完整的含义,请不要使用此命令,并且无论如何都要避免使用它。</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/delete-file-permanently/11.png" class="lazyload"></p><p>此外 git 官网<a href="https://git-scm.com/docs/git-filter-branch#_warning" target="_blank" rel="noopener">git-filter-branch WARNING</a>也不建议使用此命令:</p><p><a href="https://linux.die.net/man/1/git-filter-branch" target="_blank" rel="noopener">https://linux.die.net/man/1/git-filter-branch</a></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十三)Git进阶与测试--多样化处理本地commit记录</title>
<link href="/2019/12/25/TechnicalEssays/AboutGit/13handle-local-commit-message/"/>
<url>/2019/12/25/TechnicalEssays/AboutGit/13handle-local-commit-message/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>利用<code>git rebase</code>命令,多样化处理本地 commit 记录。例如<ul><li>修改提交信息</li><li>删除提交信息</li><li>合并提交信息</li><li>……</li></ul></li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>在本地开发时,有提交很多次,但是其中提交信息,可能有些是可以合并到一起,有的可能没必要可以删除,有的需要修改 commit measssge……</p><p>这些都可以使用<code>git rebase</code>命令的相关参数指令实现。</p><h2 id="项目准备"><a href="#项目准备" class="headerlink" title="项目准备"></a>项目准备</h2><p>在本地的 tensorflow 项目中添加几次提交</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/1.png" class="lazyload"></p><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><h3 id="修改非最近一次的提交信息"><a href="#修改非最近一次的提交信息" class="headerlink" title="修改非最近一次的提交信息"></a>修改非最近一次的提交信息</h3><p>假如需要修改 commit id 为 699b10610 的 commit message。<br>因为这不是最近的一条 commit,所以 <code>git commit --amend</code>无法使用。</p><p>需要使用 git rebase 指令相关参数</p><p>输入<code>git rebase -i <commit id></code>,进入 interactive 模式<br>其中<commit id>为此次想要调整这个节点(commit id)开始至 HEAD 中间的提交纪录。</commit></p><p><strong>因为我们要修改 commit id 为 699b10610 的 commit message,所以此处<code>git rebase -i</code> 后面的 commit id,可以是 699b10610 的前一个 4f092caa。</strong></p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/2.png" class="lazyload"></p><p>输入指令后,会弹出文件,编辑需要调整的 commit 记录,以及指令说明,如下图</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/3.png" class="lazyload"></p><p><strong>注意:在 Rebase 状态看到的这个纪录是跟我们平常看的纪录是反过来的,越新的 Commit 在越下面。</strong></p><p>常用指令说明:</p><ul><li>pick: 只接使用这个 commit,不做任何调整</li><li>reword: 使用这个 commit,只调整 commit message</li><li>squash: 使用这个 commit 融入前一个 commit 中,合并两个 commit message 来表示(可以修改)</li><li>fixup: 使用这个 commit 融入前一个 commit 中,使用前一个 commit 的 message 来表示(不可修改)</li><li>drop: 直接移除这个 commit</li></ul><p>所以,我需要修改 commit id 为 699b10610 的 commit message,只需要把这份文件中第一行改为<code>reword + 修改后的message</code>再保存执行即可</p><p>修改后的文件</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/4.png" class="lazyload"></p><p>保存并关闭文件之后,会弹出一份新的文件,主要用于确认和修改 commit meassge,如下图</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/5.png" class="lazyload"></p><p>保存并退出后,可以看到<code>git rebase</code>命令执行完成</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/6.png" class="lazyload"></p><p>查看日志,之前 commit id 为 699b10610 的提交,已经被修改为 commit id 为 11d4ec53,内容也为修改后的内容。但是其它内容没有异动。</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/7.png" class="lazyload"></p><h3 id="合并多条-commit-内容"><a href="#合并多条-commit-内容" class="headerlink" title="合并多条 commit 内容"></a>合并多条 commit 内容</h3><p>同上,使用<code>git rebase -i</code> 指令即可修改</p><blockquote><ul><li>squash: 使用这个 commit 融入前一个 commit 中,合并两个 commit message 来表示(可以修改)</li><li>fixup: 使用这个 commit 融入前一个 commit 中,使用前一个 commit 的 message 来表示(不可修改)</li></ul></blockquote><p>根据上述指令说明,这可能需要执行多次。如果需要一并修改 commit message,要使用 squash,用第一条代替合并后的 commit message,使用 fixup。<br>示例:合并 commit id aa0312a 和 c78d4fe 和 026345ca,并修改 commit meassge 为:“修改 tensorflow1.txt 内容”<br>使用<code>git rebase -i</code>进入 interactive 模式</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/8.png" class="lazyload"></p><p>修改弹出文件第三句指令为 squash (注意,这个 commit 的 squash,需要从下往上合并,否则可能会报 error: <code>cannot 'squash' without a previous commit</code>错误)</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/9.png" class="lazyload"></p><p>然后会弹出合并 commit message 的确认和修改画面</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/10.png" class="lazyload"></p><p>我修改如下</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/11.png" class="lazyload"></p><p>保存退出后可看到如下信息</p><p><img alt="12.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/12.png" class="lazyload"></p><p>此时查看日志,就发现之前的 3 条 commit,变成两条了</p><p><img alt="13.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/13.png" class="lazyload"></p><p>所以,再执行一次,即可达到最开始的需求,3 合 1</p><p><img alt="14.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/14-1.png" class="lazyload"></p><p><img alt="15.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/14-2.png" class="lazyload"></p><p>修改后</p><p><img alt="16.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/15.png" class="lazyload"></p><p>修改前</p><p><img alt="17.png" data-src="/../images/TechnicalEssays/AboutGit/handle-local-commit-message/16.png" class="lazyload"></p><h3 id="删除指定-commit-message"><a href="#删除指定-commit-message" class="headerlink" title="删除指定 commit message"></a>删除指定 commit message</h3><p>这个不再赘述,同样使用<code>git rebase -i <commit id></code>进入 interactive 模式,把需要删除的信息从 pick 改为 drop,或者直接删除掉,再保存即可。</p><p>注意:<br>不想删除的信息,就不要异动;<br>rebase 的 <code><commit id></code>要在被删除提交信息之前,不然看不到;<br>如果删除的那次提交会导致冲突,根据解决冲突的效果,影响对应 commit 信息保留结果。</p><h3 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h3><p>其它指令不再一一说明,简单带过。例如</p><p>想要<strong>调整提交信息顺序</strong>,直接把 interactive 模式中看到的信息对应调整即可,诸如此类。</p><p>想要<strong>在已提交信息中间添加新的 commit 信息</strong>, 在新增起点的<commit id>的 interactive,模式改为 edit,<br> 这会中止 rebase,然后就可以使用<code>git commit --amend</code>修改当前信息,<br> 或者实际修改文件/夹,再使用<code>git add</code>和<code>git commit</code>命令去添加新的 commit 信息。<br> 直到添加完成,再使用<code>git rebase --continue</code>即可。</p><p>……</p><p><strong>不要一定要注意,慎重,因为有一些提交和后续的提交是相互依存的,删除或者变动之前的可能会导致后续的提交出现异常,导致项目出现问题。</strong></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>使用<code>git rebase -i <commit id></code>,可以对本地的提交记录做很多变动。<br>在进入 interactive 模式后,对该文件(git-rebase-todo)做相应修改:</p><ul><li>想要删除,使用 drop;</li><li>想要修改,使用 reword;</li><li>想要合并,使用 squash 和 fixup;</li><li>想要新增,使用 edit;</li><li>想要调整顺序,调整 pick</li><li>……</li></ul><p>更多内容可以自行尝试。</p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十二)Git进阶与测试--三种实现undo(还原)操作的命令对比</title>
<link href="/2019/12/24/TechnicalEssays/AboutGit/12git-three-undo/"/>
<url>/2019/12/24/TechnicalEssays/AboutGit/12git-three-undo/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li><code>git reset</code>、<code>git checkout</code>和<code>git revert</code>在撤销修改,内容还原功能中的对比。</li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>使用需求大概都是一致,就是在修改了代码之后,想要会到旧版本去。虽然列示的三种操作过程不一样,但都达到了那样的效果。</p><h2 id="指令原理说明"><a href="#指令原理说明" class="headerlink" title="指令原理说明"></a>指令原理说明</h2><p>简单说明区别<br>git revert:只能用于 commit-level,会新建一个 commit,在历史记录中说明还原了什么</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/1.png" class="lazyload"></p><p>git reset:可用于 commit-level 和 file-level,用于撤销未被提交到远程(remote)的改动,即撤销本地(local)的修改。</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/3.png" class="lazyload"></p><p>可以将其 git revert 视为撤销已提交更改的工具,同时 git reset HEAD 用于撤销未提交的更改。</p><p>git checkout:可用于 commit-level 和 file-level,是将 HEAD 指针移动到想要回退的版本,不会修改历史记录</p><h2 id="示例演示说明"><a href="#示例演示说明" class="headerlink" title="示例演示说明"></a>示例演示说明</h2><p>项目准备,一个有简单修改的 tensorflow 项目</p><h3 id="git-checkout-lt-commit-id-gt-示例"><a href="#git-checkout-lt-commit-id-gt-示例" class="headerlink" title="git checkout <commit id>示例"></a><code>git checkout <commit id></code>示例</h3><p>例如,查看 tensorflow 的历史记录,HEAD 目前在 12589</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/4.png" class="lazyload"></p><p>使用<code>git checkout</code>到 47092caa 去。<br>再查看历史记录,HEAD 已经指向了 4f092caa 了。</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/5.png" class="lazyload"></p><p>项目中也把文件还原到了当时提交的情况</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/6.png" class="lazyload"></p><h3 id="git-revert-lt-commit-id-gt-示例"><a href="#git-revert-lt-commit-id-gt-示例" class="headerlink" title="git revert <commit id>示例"></a><code>git revert <commit id></code>示例</h3><p>先将分支切回到 dev</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/7.png" class="lazyload"></p><p>使用 git revert 还原到 a122a10dcd<br>还原过程中会弹窗窗口提示输入 commit 内容</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/8.png" class="lazyload"></p><p>revert 完成之后,查看日志可以看到,会看到新增一条 commit</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/9.png" class="lazyload"></p><p>而项目中已经有还原到当时的文件</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/10.png" class="lazyload"></p><p>但是通常情况下,git revert 不会带 commit id,直接使用,用于撤销最近一次提交。</p><h3 id="git-reset示例"><a href="#git-reset示例" class="headerlink" title="git reset示例"></a><code>git reset</code>示例</h3><p>注意 git reset 的参数</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/11.png" class="lazyload"></p><p>在实际使用时,如果有确切的撤销需求,例如撤销后的提交内容都应该是不需要的,历史记录也不在保留,index 和工作区也回退到撤销的版本,那么就需要使用–hard 参数。</p><p>使用<code>git reset</code>前的日志</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/12.png" class="lazyload"></p><p>使用<code>git reset</code>恢复到 4f092caa</p><p><img alt="12.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/13.png" class="lazyload"></p><p>直接使用<code>git log</code>,则看到第一条已经是 4f092caa 那条提交</p><p><img alt="13.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/14.png" class="lazyload"></p><p>不过使用<code>git log --all --oneline</code>还是可以看到</p><p><img alt="14.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/15.png" class="lazyload"></p><p>但是注意,使用 <code>git log --pretty=oneline</code>是不行的</p><p><img alt="15.png" data-src="/../images/TechnicalEssays/AboutGit/git-three-undo/16.png" class="lazyload"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>表格列示三种指令的作用范围和效果:</p><table><thead><tr><th>git 命令</th><th>作用范围</th><th>常见用例</th></tr></thead><tbody><tr><td>git reset</td><td>commit-level</td><td>放弃在私有分支中的提交或丢弃未提交的更改</td></tr><tr><td>git reset</td><td>file-level</td><td>取消暂存文件</td></tr><tr><td>git checkout</td><td>commit-level</td><td>在分支之间切换或检查旧快照</td></tr><tr><td>git checkout</td><td>file-level</td><td>放弃工作目录中的更改</td></tr><tr><td>git revert</td><td>commit-level</td><td>撤消在公共分支中提交</td></tr><tr><td>git revert</td><td>file-level</td><td>(N/A)</td></tr></tbody></table><p>git 官方文档已有做出意见:</p><blockquote><ul><li>git revert is used to record some new commits to reverse the effect of some earlier commits (often only a faulty one).</li><li>If you want to throw away all uncommitted changes in your working directory, you should see git-reset[1], particularly the –hard option.</li><li>If you want to extract specific files as they were in another commit, you should see git-checkout[1], specifically the git checkout <commit> – <filename> syntax.</filename></commit></li></ul></blockquote><p>即:</p><blockquote><ul><li>git revert 用于记录一些新的提交,以逆转某些较早提交的效果(通常只有一个错误的提交)。</li><li>如果要丢弃工作目录中所有未提交的更改,则应看到 git-reset,尤其是–hard 选项。</li><li>如果要提取特定文件,就像在另一个提交中一样,则应该看到 git-checkout ,特别是<code>git checkout <commit>-<filename></code>语法。</li></ul></blockquote><p>参考内容:</p><ul><li><a href="https://git-scm.com/docs/git-revert" target="_blank" rel="noopener">https://git-scm.com/docs/git-revert</a></li><li><a href="https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86" target="_blank" rel="noopener">https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86</a></li><li><a href="https://segmentfault.com/a/1190000009126517" target="_blank" rel="noopener">https://segmentfault.com/a/1190000009126517</a></li><li><a href="https://dev.to/neshaz/when-to-use-git-reset-git-revert--git-checkout-18je" target="_blank" rel="noopener">https://dev.to/neshaz/when-to-use-git-reset-git-revert--git-checkout-18je</a></li><li><a href="https://stackoverflow.com/questions/8358035/whats-the-difference-between-git-revert-checkout-and-reset" target="_blank" rel="noopener">https://stackoverflow.com/questions/8358035/whats-the-difference-between-git-revert-checkout-and-reset</a></li></ul>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十一)Git进阶与测试--clone远程仓库很慢的处理</title>
<link href="/2019/12/24/TechnicalEssays/AboutGit/11handle-slow-clone/"/>
<url>/2019/12/24/TechnicalEssays/AboutGit/11handle-slow-clone/</url>
<content type="html"><![CDATA[<p>上一篇有讲到克隆远程仓库,在 clone 时,如果每次都 clone 完整的仓库的话,随着提交的次数变多,在项目变大之后,clone 的速度会非常的慢。</p><p>所以克隆时可以设定参数 <code>--depth 1</code>,加快 clone 速度</p><p><code>-- depth</code>代表克隆的深度,<code>--depth 1</code>代表只克隆最新一次提交记录以及这次提交之后的最新内容,不克隆历史提交。</p><p>这样所造成的影响就是不能查看历史提交记录,但是克隆速度大大提升。</p><p>完整命令:</p><pre><code>git clone --branch <branch_name> <remote-address> --depth 1</code></pre><p>查看 commit 总数,可用:</p><pre><code>git rev-list --all --count或者git log --oneline | wc -l</code></pre><p>后续补充:<br><strong>注意,这里 git rev-list 查看到的提交数量,并不一定和仓库中显示的提交数一样,获取的原理不同。后者是一致的。</strong><br>详细请查看官方文档关于<a href="https://git-scm.com/docs/git-rev-list" target="_blank" rel="noopener">git rev-list</a>的说明。</p><p>查看简要显示日志,可用:</p><pre><code>git log --all --oneline</code></pre><p>示例,今日(2019/12/25)克隆 github 中 tensorflow 项目,深度只有 1 层,<br>编写本文示例测试耗时大约<strong>4 分 15 秒</strong>,其它内容如下图:</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/handle-slow-clone/1.png" class="lazyload"></p><p>而直接 clone master 分支的全部,<br>编写本文示例测试耗时大约<strong>13 分 30 秒</strong>,其它内容如下图:</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/handle-slow-clone/2.png" class="lazyload"></p><p><strong>2019/12/26 补充,如果想看实际耗时,在 git 命令前加 time 关键词。</strong></p><p>如果后续想看完整的历史记录,可以将浅层克隆转换为常规克隆。使用:</p><pre><code>git pull --unshallow或者git fetch --unshallow</code></pre><p>不过,这就是重新抓取了该分支所有的提交,也就不如直接一开始就拉取所有了。</p><p>使用示例(同样编写本文示例测试耗时大约<strong>13 分 30 秒</strong>):</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/handle-slow-clone/3.png" class="lazyload"></p><p>查看当前分支所有提交者及其提交次数,按次数由高到低排序,可用:</p><pre><code>git log | grep "^Author: " | awk '{print $2}' | sort | uniq -c | sort -k1,1nr</code></pre><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/handle-slow-clone/4.png" class="lazyload"></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(十)使用docker安裝gitlab-ce</title>
<link href="/2019/12/23/TechnicalEssays/AboutGit/10folder-or-file-not-effect-restore/"/>
<url>/2019/12/23/TechnicalEssays/AboutGit/10folder-or-file-not-effect-restore/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li>项目中的文件数量消长(新增或删除文件时) 与 存在的文件内容消长(同一份文件修改多次) ,这两种情境的版本还原有无区别</li><li>测试误删除文件,然后还原</li><li>本章使用 git reset,更多还原操作可参看下一章</li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>这里是测试不同正常修改的操作会不会影响到项目还原,按道理来讲,代码写到一般,文件未保存计算机电源被扒了,这部分如果编辑器没有缓存,应该是不会在 git 的还原操作内了。</p><h2 id="项目准备"><a href="#项目准备" class="headerlink" title="项目准备"></a>项目准备</h2><p>1、远程仓库准备</p><ul><li>在 github 上找到了一个 commit 次数较多的项目,放置到测试的远程仓库,本例是 tensorflow</li></ul><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/1.png" class="lazyload"></p><p>2、本地仓库的准备</p><ul><li>clone 一个到本地,作为测试仓库</li><li>创建一个 dev 分支,进行测试</li><li>将本地 dev 分支推到远程 dev 分支</li></ul><h2 id="大概流程"><a href="#大概流程" class="headerlink" title="大概流程"></a>大概流程</h2><ul><li>1、使用 git rm 指令删除 tensorflow 子文件夹,commit 一次;</li><li>2、然后再新建 tensorflow 文件夹,并加上两个文件,commit 第二次;</li><li>3、再使用手动删除 third_party 文件夹,commit 第三次;</li><li>4、然后再新建 third_party 文件夹,并放上两个文件,commit 第四次;</li><li>5、最后 push 到远程 dev 分支。</li><li>6、再删除本地 tensorflow,clone 一份远程 dev 分支的 tensorflow,查看此时的 tensorflow 和 third_party 子文件夹内容</li><li>7、还原 clone 下来的项目到删除文件前,比较是否和之前的内容一致。</li></ul><p><strong>注意都是在同一分支(示例使用 dev)中进行的</strong></p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/2.png" class="lazyload"></p><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><p>1 操作前,项目中的 tensorflow 和 third_party 文件夹信息如下:</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/3.png" class="lazyload"></p><p>2 指令删除,添加,并提交</p><pre><code>git rm tensorflow -r -fgit add .git commit -m '指令删除tensorflow子文件夹'</code></pre><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/4.png" class="lazyload"></p><p>3 新建 tensorflow 子文件夹并放两个文件</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/5.png" class="lazyload"></p><p>添加并提交</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/6.png" class="lazyload"></p><p>4 手动删除 third_party 文件夹,并提交</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/7.png" class="lazyload"></p><p>5 新建 third_party 子文件夹并放两个文件</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/8.png" class="lazyload"></p><p>添加并提交</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/9.png" class="lazyload"></p><p>6 推送到远程 dev 分支<br>最好先 pull(因为与 origin 的 dev 比较,文件夹中内容有冲突,pull 会先合并 merge,因此会多一条 commit),<br>再 push 到 origin</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/10.png" class="lazyload"></p><p>7 删除本地项目,再 clone 一份远程的 dev 分支项目</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/11.png" class="lazyload"></p><p>查看内容与推送 push 之前是一致的(一致的)</p><p><img alt="12.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/12.png" class="lazyload"></p><p>查看一下近 10 条记录</p><p><img alt="13.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/13.png" class="lazyload"></p><p>8 将 clone 下来的项目,还原到 27cfc……提交的状态</p><p><img alt="14.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/14.png" class="lazyload"></p><p>查看一下文件内容,完全一致</p><p><img alt="15.png" data-src="/../images/TechnicalEssays/AboutGit/folder-or-file-not-effect-restore/15.png" class="lazyload"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>由此看出:</p><ul><li>无论是手动删除,使用 git 命令删除,<br>无论子文件夹是否有多个层级,还是删除后有其它 commit 操作,<br>只要找到对应的 commit id,使用 git reset 方法都能还原到该次 commit 的状态,文件保持一致。</li><li>文件数量的增减,文件内容的增减,提交后的还原效果一致。</li></ul><p>(更多还原方式,参看下一章)</p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> docker </tag>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(九)Git进阶与测试--merge和rebase分支合并、解决冲突及特征对比</title>
<link href="/2019/12/22/TechnicalEssays/AboutGit/9git-merge-and-rebase/"/>
<url>/2019/12/22/TechnicalEssays/AboutGit/9git-merge-and-rebase/</url>
<content type="html"><![CDATA[<p>本章主要测试讲解</p><ul><li><code>git merge</code>和<code>git rebase</code>指令的用法和进行分支合并,并做简单比较分析。</li></ul><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><h2 id="前置说明"><a href="#前置说明" class="headerlink" title="前置说明"></a>前置说明</h2><p>关于无论是使用 merge 还是 rebase 进行合并,出现冲突的原因都是在不同的分支修改了同一处的代码,合并时版控工具 git 不知道保留哪一份的修改,从而导致冲突,需要合并人员去判断并解决。</p><p>使用 merge 和 rebase 合并的做法</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/1.png" class="lazyload"></p><h2 id="大概流程:"><a href="#大概流程:" class="headerlink" title="大概流程:"></a>大概流程:</h2><p>测试 git merge 和 git rebase 的合并及解决冲突效果:</p><ul><li>1 准备测试项目及分支记录<ul><li>创建 master、dev1、dev2 三个分支</li><li>除了 master 创建 dev1 和 dev2 的初始提交外,3 个分支各自有两个不同的提交记录<ul><li>时间顺序为:<br>master 新建空文件,再初始提交 –><br>创建 dev2 –> dev2 commit 第一次文件修改 –> dev2 commit 第二次文件修改 –><br>切回 master 创建 dev1 –> dev1 commit 第一次文件修改 –> dev1 commit 第二次文件修改 –><br>切回 master –> master commit 第一次文件修改 –> master commit 第二次文件修改 –><br>进行使用 git merge/git merge 合并测试……</li></ul></li></ul></li><li>2 使用 git merge 进行合并</li><li>3 使用 git rebase 进行合并</li><li>4 对比两者合并的历史记录,分析优缺点和使用场景</li></ul><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><h3 id="准备测试项目及分支记录"><a href="#准备测试项目及分支记录" class="headerlink" title="准备测试项目及分支记录"></a>准备测试项目及分支记录</h3><p><em>相关命令请看截图</em></p><p>准备测试项目 test-conflict,新建一个 test1.txt 文件(后续新建的文件,最好都改成 UTF-8,windows 下默认是 ANSI,操作可能会产生乱码),内容为空,并 master 分支初始提交。</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/2.png" class="lazyload"></p><p>以 master 分支创建 dev2 分支</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/3.png" class="lazyload"></p><p>dev2 以 master 分支为基准,所以 test1.txt 还是为空的,两次修改 test1.txt</p><p><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/4.png" class="lazyload"></p><p>此时 dev2 的历史记录为</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/5.png" class="lazyload"></p><p>切换到 master 分支,并创建分支 dev1 并修改文件 test1.txt,然后分别提交</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/6.png" class="lazyload"></p><p>然后再修改一次,然后第二次提交</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/7.png" class="lazyload"></p><p>此时 dev1 的日志记录如下</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/8.png" class="lazyload"></p><p>此时切回到 master 分支,自行也修改并提交两次 test1.txt 的修改</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/9.png" class="lazyload"></p><p>此时 master 分支的记录为</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/10.png" class="lazyload"></p><p>直至,准备工作完整,我们打包一份,保留 2 个一模一样的项目,一个测试 git merge,一个测试 git rebase</p><h3 id="使用-git-merge-进行合并测试"><a href="#使用-git-merge-进行合并测试" class="headerlink" title="使用 git merge 进行合并测试"></a>使用 git merge 进行合并测试</h3><p>步骤说明:</p><ul><li>切换到 master 分支,先合并 dev1 到 master,再合并 dev2 到 master</li><li>因为 dev1、dev2 和 master 原本分支都有修改到 test1.txt 的同一行,所以会出现多次的合并冲突,需要手动解决</li><li>合并完成之后,查看 git merge 的 master 的日志</li></ul><p>创建时现有 dev2 的提交,但是合并时,先合并 dev1<br>合并 dev1 到 master,出现冲突</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/11.png" class="lazyload"></p><p>手动解决冲突并提交</p><p><img alt="12.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/12.png" class="lazyload"></p><p>再合并 dev2 到 master,依然报冲突</p><p><img alt="13.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/13.png" class="lazyload"></p><p>手动解决并提交</p><p><img alt="14.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/14.png" class="lazyload"></p><p>至此,使用 git merge 已把 dev1 和 dev2 合并到 master 分支,查看 master 分支的日志。</p><p><img alt="15.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/15.png" class="lazyload"></p><p>至此使用 git merge 合并和解决冲突测试完成。</p><h3 id="使用-git-rebase-合并冲突"><a href="#使用-git-rebase-合并冲突" class="headerlink" title="使用 git rebase 合并冲突"></a>使用 git rebase 合并冲突</h3><p>使用之前的备份项目测试 git rebase</p><p>步骤说明:</p><ul><li>切到 dev1 分支,rebase dev1 到 master,解决合并冲突</li><li>切回 master 分支(此时 master 的日志还没变),进行一次快速合并到 dev1(现在就变了)</li><li>切到 dev2 分支,rebase dev2 到 master,解决合并冲突</li><li>切回 master 分支,进行一次快速合并到 dev2</li><li>合并完成之后,查看 git rebase 的 master 的日志</li></ul><p>切回 dev1 分支,rebase dev1 到 master,会产生冲突。</p><p><img alt="16.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/16.png" class="lazyload"></p><p>修改成以下内容之后,再执行 git add .(没有执行 commit),然后继续进行 rebase</p><p><img alt="17.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/17.png" class="lazyload"></p><p>继续进行 rebase,则弹出第二次冲突提示</p><p><img alt="18.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/18.png" class="lazyload"></p><p>从文本来看,因为有两行是冲突的,第一次解决冲突是 master 中于 dev1 第一次提交有冲突的内容,现在报的是与 dev1 第二次提交有冲突的内容,同样手动解决,然后继续,可见 rebase 完成。</p><p><img alt="19.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/19.png" class="lazyload"></p><p>至此,使用 rebase,已经把 dev1 上的两次提交的修改变基到了 master 分支的提交修改上。</p><p>现在切回 master 分支(当然,此时 master 的日志还没变),进行一次快速合并到 dev1(现在就变了)</p><p><img alt="20.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/20.png" class="lazyload"></p><p>同样的,再合并 dev2,同样解决两次冲突,<br>第一次冲突</p><p><img alt="21.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/21.png" class="lazyload"></p><p>解决如下</p><p><img alt="22.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/22.png" class="lazyload"></p><p>第二次冲突</p><p><img alt="23.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/23.png" class="lazyload"></p><p>解决如下:</p><p><img alt="24.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/24.png" class="lazyload"></p><p>合并完成</p><p><img alt="25.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/25.png" class="lazyload"></p><p>同样,现在切回 master 分支,进行一次快速合并到 dev2,查看日志</p><p><img alt="26.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/26.png" class="lazyload"></p><h3 id="git-merge-和-git-rebase-的结果对比"><a href="#git-merge-和-git-rebase-的结果对比" class="headerlink" title="git merge 和 git rebase 的结果对比"></a>git merge 和 git rebase 的结果对比</h3><p>使用 git rebase 后,3 个分支的历史记录如下</p><p><img alt="27.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/27.png" class="lazyload"></p><p>git merge 历史记录如下</p><p><img alt="28.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/29.png" class="lazyload"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>git merge 和 git rebase 进行合并的区别:</p><ol><li>历史记录不同<ul><li>git merge 保留了各个分支各自的提交记录,如果有解决冲突,会单独创建一次 commit 记录冲突的解决,历史记录完整。</li><li>git rebase 只有一根线的分支记录历史,手动解决的冲突不会创建保留记录,历史记录清晰简单</li></ul></li><li>操作步骤不同<ul><li>git merge 操作简单,</li><li>git rebase 操作步骤繁琐。</li></ul></li><li>影响范围不同<ul><li>git merge 操作未对 dev1 和 dev2 的项目内容(或提交记录)进行异动,不会影响后续人员对此两个分支进行接续作业。</li><li>git rebase 操作已经对 dev1 和 dev2 分支进行了异动,如果有后续分支使用了这两个分支,可能会导致提交历史记录的混乱和其它异常情况。</li></ul></li></ol><p><strong>建议:</strong><br>只对尚未推送或分享给别人的本地修改执行变基操作清理历史,不要对已推送至别处的提交执行变基操作。</p><p><img alt="29.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/30.png" class="lazyload"></p><p>个人建议<br>对于合并,如果始终不清楚 merge 和 rebase 的区别,推荐使用 merge。<br>merge 的一大优点是简单,不会对其它分支造成影响。<br>唯一可能的不足就是会有比较多(不清晰)的提交记录,这一点可以使用 git rebase -i <commit id>,进入 interactive 模式(后续文章有介绍),对历史记录进行修改</commit></p><p><strong>新手提醒:如果需要合并的分支还有未提交的修改,是没有办法合并的。</strong></p><p><img alt="30.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/31.png" class="lazyload"></p><p><strong>Bonus:修改分支的名字</strong></p><p>假如从 master 分支创建了一个 feature-branch 分支,结果写成了 future-brunch</p><p><img alt="31.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/32.png" class="lazyload"></p><p>直接使用<code>git branch -m</code>参数修改即可</p><pre><code>git branch -m future-brunch feature-branch</code></pre><p><img alt="32.png" data-src="/../images/TechnicalEssays/AboutGit/git-merge-and-rebase/33.png" class="lazyload"></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(八)Git进阶与测试--.git文件夹中object数量过大是否影响commit效率?</title>
<link href="/2019/12/21/TechnicalEssays/AboutGit/8object-effect-commit-performance/"/>
<url>/2019/12/21/TechnicalEssays/AboutGit/8object-effect-commit-performance/</url>
<content type="html"><![CDATA[<p>在此往后的几篇文章,主要是说明一些使用 Git 时比较高级一点的问题或者比较重要的问题。<br>除了一些测试说明、功能介绍、操作引导之外,还可以增长见识和思考方法,可以一看。</p><p>有些测试截图是比较旧(也就几个月),但是目前来看,依然是 ok 的。</p><p>测试过程内容较多,每个步骤都逐一截图以便真实说明,也有列示用法。若不感兴趣,可直接查看总结部分。</p><h1 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h1><p>众所周知,.git 文件夹是 git 管理项目的本地仓库。objects 目录存储所有数据内容,每一次 git commit 都会将信息存到该文件夹。<br>这部分不清楚,可去官网<a href="https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E5%BA%95%E5%B1%82%E5%91%BD%E4%BB%A4%E5%92%8C%E9%AB%98%E5%B1%82%E5%91%BD%E4%BB%A4" target="_blank" rel="noopener">Git 内部原理 - 底层命令和高层命令</a>和<a href="https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-Git-%E5%AF%B9%E8%B1%A1" target="_blank" rel="noopener">Git 内部原理 - Git 对象</a>等地方再巩固。<br>所以,一般情况下来看,git commit 的次数过多,object 文件夹体积就会变大,如果非常巨大了,会不会影响到提交的速度?</p><h2 id="前置准备"><a href="#前置准备" class="headerlink" title="前置准备"></a>前置准备</h2><p>将 github 中的两个项目 tensorflow 和 liunx,clone 一份到本地,并推到自建 gitlab 服务器(内网 1.0Gbps)中,作为测试项目远程仓库。<br>主要说明 Git 客户端的使用,所以本地需要安装 Git</p><h2 id="大概流程"><a href="#大概流程" class="headerlink" title="大概流程"></a>大概流程</h2><p>准备两个比较大的项目,分别测试单次 add 和 commit 的耗时。</p><h2 id="测试步骤"><a href="#测试步骤" class="headerlink" title="测试步骤"></a>测试步骤</h2><p>1 以 tensorflow 项目为例进行 commit 测试<br>准备了一个 git 文件夹有 360M,提交数量超过 5W 的项目 tensorflow</p><p><img alt="1.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/1.png" class="lazyload"></p><p>测试 commit 之前,先提交一次已有的文件,以免出现干扰</p><p><img alt="2.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/2.png" class="lazyload"></p><p>在 tensorflow 中新建一个文件夹 newfoler,并随意放入几个文件</p><p><img alt="3.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/3.png" class="lazyload"></p><p>再测试 add 及 commit 的效果<br><img alt="4.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/4.png" class="lazyload"></p><p>两个命令耗时较短,并没有出现耗时的情况(第一个是 add,第二个是 commit)。排除切换页面和鼠标移动点击的时间,这两个命令耗时只有 1s 左右。</p><p><img alt="5.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/5.png" class="lazyload"></p><p>测试结果看来,一个有着 5W+commit 数量,git 文件夹超过 360M 的项目,在 commit 时并没有发生耗时很长的情况。</p><p>其实 git folder 要大于 500M 其实还是非常少的,我在 github 中找了非常久,到目前为止,就只发现 linux 项目超过 500M,提交数量超过 10W。</p><p>2 1 以 linux 项目为例进行 commit 测试<br>准备了一个提交数量和 git folder 都很大的项目(github 上的 linux 项目)</p><p><img alt="6.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/6.png" class="lazyload"></p><p>测试前,先<code>add .</code>一次,避免对 commit 提交速度进行干扰<br>(实际测试,clone 下来后,第一次<code>git add .</code>是比较耗时间的,好好几分钟)。</p><p>在 linux 下新建一个 new_folder 文件夹,并随意放入几个文件,如下</p><p><img alt="7.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/7.png" class="lazyload"></p><p>测试结果来看,完成 add 和 commit 的速度还是很快的</p><p><img alt="8.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/8.png" class="lazyload"></p><p>两个命令耗时较短,并没有出现耗时的情况(第一个是 add,第二个是 commit)。排除切换页面和鼠标移动点击的时间,这两个命令耗时只有 1s 左右。</p><p><img alt="9.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/9.png" class="lazyload"></p><p>再修改一些文件,删除一些文件</p><p><img alt="10.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/10.png" class="lazyload"></p><p>add 和 commit 的耗时依然不多</p><p><img alt="11.png" data-src="/../images/TechnicalEssays/AboutGit/object-effect-commit-performance/11.png" class="lazyload"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>这个 Linux 项目的 git 文件夹和 commit 数量是目前已经发现最大的项目,测试得出 add 和 commit 的时间都是很短,所以应该是不会出现 commit 非常耗时的情况。</li><li>所以 commit 的数量太大不会影响 commit 的速度。</li></ul>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> git </tag>
</tags>
</entry>
<entry>
<title>(七)Git入门及常用命令</title>
<link href="/2019/12/21/TechnicalEssays/AboutGit/7git-basic/"/>
<url>/2019/12/21/TechnicalEssays/AboutGit/7git-basic/</url>
<content type="html"><![CDATA[<p>罗杰•杜德勒编写整理了一个不错的<a href="https://www.bootcss.com/p/git-guide/" target="_blank" rel="noopener">git - 简易指南</a>,可以查看学习。网上也有很多内容,没记住的,要用时搜一下就好了。</p><p>另外,我在<a href="https://github.com/Sanotsu/git-gitlab-advanced-notes" target="_blank" rel="noopener">github</a>有放一个简单的《7-Git入门指南》的 PPT,可以一并查看,主要说明的是:</p><ul><li>Git 是什么?</li><li>Git 简明指南补充说明</li><li>Git 常用指令(本文正文)</li><li>使用 Git 一般开发规范</li><li>Git Client GUI 及在 VS code 中使用 Git</li></ul><p>此处只是列示一些可能常用的 git 指令:</p><p>配置使用 Git 的账号密码:</p><pre><code>git config --global user.name "Your Name"git config --global user.email [email protected]</code></pre><p>初始化一个 Git 仓库:</p><pre><code>git init</code></pre><p>添加文件到 Git 仓库,分两步:<br>添加到暂存区:</p><pre><code class="sh">git add <file> #注意,可反复多次使用,添加多个档;</code></pre><p>提交到仓库</p><pre><code>git commit -m <message>。</code></pre><p>查看工作区的状态:</p><pre><code>git status。</code></pre><p>可以查看修改内容:</p><pre><code>git diff</code></pre><p>关联一个远程库:</p><pre><code>git remote add origin git@server-name:path/repo-name.git;</code></pre><p>关联后,使用命令第一次推送 master 分支的所有内容:</p><pre><code>git push -u origin master</code></pre><p>此后,每次本地提交后,推送最新修改;</p><pre><code>git push origin master</code></pre><p>要克隆一个仓库,首先必须知道仓库的地址,然后使用</p><pre><code>git clone git@server-name:path/repo-name.git。</code></pre><p>查看分支:</p><pre><code>git branch</code></pre><p>创建分支:</p><pre><code>git branch <name></code></pre><p>切换分支:</p><pre><code>git checkout <name></code></pre><p>创建+切换分支:</p><pre><code>git checkout -b <name></code></pre><p>合并某分支到当前分支:</p><pre><code>git merge <name></code></pre><p>删除分支:</p><pre><code>git branch -d <name></code></pre><p>看到分支合并图:</p><pre><code>git log –graph</code></pre><p>查看远程库信息:</p><pre><code>git remote -v;</code></pre><p>从本地推送分支</p><pre><code>git push origin <branch-name>,</code></pre><p>抓取远程的新提交;</p><pre><code>git pull</code></pre><p>在本地创建和远程分支对应的分支,使用</p><pre><code class="sh">git checkout -b <branch-name> origin/<branch-name> # 本地和远程分支的名称最好一致;</code></pre><p>建立本地分支和远程分支的关联</p><pre><code>git branch --set-upstream branch-name origin/branch-name;</code></pre>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> docker </tag>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(六)远端访问gitlab默认PostgreSQL数据库</title>
<link href="/2019/12/21/TechnicalEssays/AboutGit/6remote-access-gitlab-ce-postgresql/"/>
<url>/2019/12/21/TechnicalEssays/AboutGit/6remote-access-gitlab-ce-postgresql/</url>
<content type="html"><![CDATA[<p>gitlab 默认的数据库是 PostgreSQL ,用它官网的话来说就是“The World’s Most Advanced Open Source Relational Database”。</p><p>一般情况下,我们没有必要去直接访问它。但是,没必要不代表没需求。gitlab 结构、用户数据、配置信息等。</p><p>值得注意的是:</p><blockquote><p>在 GitLab 12.1 中删除了对 MySQL 的支持。建议在 MySQL / MariaDB 上使用 GitLab 的现有用户在升级之前迁移到 PostgreSQL。<br>从 GitLab 10.0 开始,需要 PostgreSQL 9.6 或更高版本,并且不支持较早的版本。我们强烈建议用户使用 PostgreSQL 9.6,因为这是用于开发和测试的 PostgreSQL 版本。</p></blockquote><h1 id="本地访问-PostgreSQL"><a href="#本地访问-PostgreSQL" class="headerlink" title="本地访问 PostgreSQL"></a>本地访问 PostgreSQL</h1><p>gitlab 默认有可以直接访问内部 postgreSQL 的命令:</p><pre><code>sudo gitlab-rails dbconsole或者sudo gitlab-psql -d gitlabhq_production</code></pre><p>这样就进入了 postgreSQL 命令窗口,可以输入 sql 语句进行作业。例如,输入<code>\list</code>查看所有数据库:</p><pre><code>sanotsu@sanotsu-ubt18:~$ sudo gitlab-rails dbconsolepsql (10.9)Type "help" for help.gitlabhq_production=> \list List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges---------------------+-------------+----------+-------------+-------------+--------------------------------- gitlabhq_production | gitlab | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | postgres | gitlab-psql | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | template0 | gitlab-psql | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/"gitlab-psql" + | | | | | "gitlab-psql"=CTc/"gitlab-psql" template1 | gitlab-psql | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/"gitlab-psql" + | | | | | "gitlab-psql"=CTc/"gitlab-psql"(4 rows)gitlabhq_production=></code></pre><p>或者输入<code>select * from namespaces;</code>查看 gitlab 中已经有了哪些用户。<br>输入<code>select * from projects;</code>查看有哪些项目文件等等。</p><p><strong>注意,在不能完全把控风险的情况下,最好不要擅自使用 SQL 的 DDL、DML、DCL 语言,避免造成 gitlab 运行意外。</strong></p><p><strong>特别注意:</strong><br>这里显示的 Name 有 4 个,除了 gitlabhq_porduction 的 owner 是 gitlab 之外,其它的是 gitlab-psql。<br>所以,在连接到 gitlab 内部的 postgresql 数据库时,指定数据库名称为 gitlabhq_porduction 才有实际意义,才能看到需要的信息。<br>这里的 dbconsole 默认是选择的 gitlabhq_production,但后续外部连接就不一定了。<br><del>因为我去看过其它几个数据库,啥都没有,我还以为是权限问题,不让我看,搞了半天……</del></p><h1 id="配置远程访问-PostgreSQL"><a href="#配置远程访问-PostgreSQL" class="headerlink" title="配置远程访问 PostgreSQL"></a>配置远程访问 PostgreSQL</h1><p>默认情况下,外部是无法访问 Gitlab 内部的 postgreSQL 的。实际上,现在很多的数据库,在初始默认安装时,都不允许外部直接访问的。</p><h2 id="了解一下-Gitlab-数据库各个配置文件-不感兴趣可跳到下一节"><a href="#了解一下-Gitlab-数据库各个配置文件-不感兴趣可跳到下一节" class="headerlink" title="了解一下 Gitlab 数据库各个配置文件(不感兴趣可跳到下一节)"></a>了解一下 Gitlab 数据库各个配置文件(不感兴趣可跳到下一节)</h2><p>要验证上述结论,除了亲自在外部试连之外,还可以直接看配置文件。</p><p>默认的 gitlab 数据库配置文件在<code>/var/opt/gitlab/gitlab-rails/etc/databse.yml</code>。</p><p>打开之后,看到的内容应该如下:</p><pre><code># This file is managed by gitlab-ctl. Manual changes will be# erased! To change the contents below, edit /etc/gitlab/gitlab.rb# and run `sudo gitlab-ctl reconfigure`.production: adapter: postgresql encoding: unicode collation: database: gitlabhq_production pool: 1 username: "gitlab" password: host: "/var/opt/gitlab/postgresql" port: 5432 socket: sslmode: sslcompression: 0 sslrootcert: sslca: load_balancing: {"hosts":[]} prepared_statements: false statements_limit: 1000 fdw:</code></pre><p>可以看到,host 属性的值是本地文件路径,外部自然连不到的。</p><p>当然,可以直接查看 postgreSQL 的用户权限配置文件查看,默认路径在<code>/var/opt/gitlab/postgresql/data/pg_hba.conf</code>。</p><p>打开默认应该可以看到只有这样一句配置(Local):</p><pre><code># TYPE DATABASE USER CIDR-ADDRESS METHOD# "local" is for Unix domain socket connections onlylocal all all peer map=gitlab</code></pre><p>此外,在同路径下的<code>postgresql.conf</code>文件中,也能看到(监控地址为空):</p><pre><code># - Connection Settings -listen_addresses = '' # what IP address(es) to listen on; # comma-separated list of addresses; # defaults to 'localhost', '*' = all # (change requires restart)port = 5432 # (change requires restart)max_connections = 200 # (change requires restart)</code></pre><p>以上内容,也为了更加清楚的认识各个文件的构成和作用。</p><h2 id="修改-gitlab-配置文件实现远程访问-PostgreSQL"><a href="#修改-gitlab-配置文件实现远程访问-PostgreSQL" class="headerlink" title="修改 gitlab 配置文件实现远程访问 PostgreSQL"></a>修改 gitlab 配置文件实现远程访问 PostgreSQL</h2><p>实际上,可以一一修改上述文件去实现远程访问,只不过就是重启 gitlab 之后失效。<br>但是从配置文件修改,更加简单,一劳永逸。</p><p>打开<code>/etc/gitlab/gitlab.rb</code>配置文件,找到<code>## Gitlab PostgreSQL</code>区块,在<code>### Advanced settings</code>最末,加上以下内容:</p><pre><code>postgresql['listen_address'] = '{gitlab主机IP}'postgresql['port'] = 5432postgresql['trust_auth_cidr_addresses'] = %w(127.0.0.1/24)postgresql['md5_auth_cidr_addresses'] = %w({gitlab主机IP}/0)postgresql['sql_user'] = "gitlab"postgresql['sql_user_password'] = Digest::MD5.hexdigest "gitlab" << postgresql['sql_user']</code></pre><p>把{gitlab 主机 IP}替换成你 gitlab 主机的真实 IP 即可。</p><p>其实把{gitlab 主机 IP}和 127.0.0.1 换成 0.0.0.0 也行。<br><del>如果不清楚限制,全部给到最大总能有效。</del></p><p>这几行的配置分别是:</p><ul><li>添加 postgresql 的监听地址,</li><li>添加 postgresql 的监听端口,</li><li>本地访问(127.0.0.1 或者 localhost)postgresql 不用输密码,</li><li>需要输入密码的访问地址,</li><li>连接到 postgresql 数据库的账号(示例中为 gitlab),</li><li>连接到 postgresql 数据库的密码(示例中为 gitlab)。</li></ul><p>然后,找到<code>### Gitlab database settings</code>,在最末添加以下内容:</p><pre><code>gitlab_rails['db_username'] = "gitlab"gitlab_rails['db_password'] = "gitlab"gitlab_rails['db_host'] = "{gitlab主机IP}"gitlab_rails['db_port'] = 5432gitlab_rails['db_database'] = "gitlabhq_production"</code></pre><p>依次是:数据库用户名、密码、地址、端口和默认数据库名称。<br>如果不设定最后一行,那么默认连接的数据库就是 postgres。</p><p>到这里,配置就修改完了,运行<code>sudo gitlab-ctl reconfigure</code>重新加载配置运行。</p><p><strong>注意,重新加载配置运行时,可能会从出现以下错误:</strong></p><pre><code>There was an error running gitlab-ctl reconfigure:bash[migrate gitlab-rails database] (gitlab::database_migrations line 54) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '1'---- Begin output of "bash" "/tmp/chef-script20191224-30773-18wzcfl" ----STDOUT: rake aborted!PG::ConnectionBad: FATAL: no pg_hba.conf entry for host "192.168.XX.XX", user "gitlab", database "gitlabhq_production", SSL onFATAL: no pg_hba.conf entry for host "192.168.XX.XX", user "gitlab", database "gitlabhq_production", SSL off/opt/gitlab/embedded/service/gitlab-rails/lib/tasks/gitlab/db.rake:48:in `block (3 levels) in <top (required)>'/opt/gitlab/embedded/bin/bundle:23:in `load'/opt/gitlab/embedded/bin/bundle:23:in `<main>'Tasks: TOP => gitlab:db:configure(See full trace by running task with --trace)STDERR:---- End output of "bash" "/tmp/chef-script20191224-30773-18wzcfl" ----Ran "bash" "/tmp/chef-script20191224-30773-18wzcfl" returned 1</code></pre><p>那是因为,需要重启 postgresql,重新配置才能生效。<br>所以,先运行<code>sudo gitlab-ctl restart postgresql</code>,再运行<code>sudo gitlab-ctl reconfigure</code>即可。</p><p>在旧一点的版本,7.x,8.x,9.x,10.x,11.x 我似乎都没有遇到过。可能是新数据库需求和版本有了变化吧。</p><p>其它的配置,按照实际需求添加即可,也可访问官网<a href="https://docs.gitlab.com/omnibus/settings/database.html" target="_blank" rel="noopener">数据库设置</a>查看更多信息</p><p>到此,应该就可以在远程连接<code>192.168.XX.XX</code>(你的 gitlab 主机 IP),通过账号 gitlab、密码 gitlab 连接到 gitlab 内部的 postgresql 数据库了。</p><h1 id="关系型数据库图形化工具-GUI-推荐及连接说明"><a href="#关系型数据库图形化工具-GUI-推荐及连接说明" class="headerlink" title="关系型数据库图形化工具(GUI)推荐及连接说明"></a>关系型数据库图形化工具(GUI)推荐及连接说明</h1><p>之前我使用连接到 postgresql 的图形化工具是 PgAdmin4,连接 mysql 用的是 MySQL Workbench,还有连接 SQL Server 用了 SQL Server Management Studio,连接 mariadb 用了 heidiSQL,还有 SQLite 等,遇到一个就去找一个,很麻烦,其实也没必要。</p><p>最近我发现一个还不错的 GUI,ce 版本可以支持连接这绝大部分常用的关系型数据库,叫 DBeaver。nosql 也支持,不过这部分就要收费了。所以我上面才没有列 Redis,MongoDB 什么的。</p><p><img alt="DBeaver连接界面" data-src="/../images/TechnicalEssays/AboutGit/remote-access-gitlab-ce-postgresql/DBeaver%E8%BF%9E%E6%8E%A5%E7%95%8C%E9%9D%A2.png" class="lazyload"></p><p>Windows 下,直接去<a href="https://dbeaver.io/download/" target="_blank" rel="noopener">dbeaver 官网</a>下载一个安装包即可。</p><p>linux 下稍微麻烦一点,以 Ubuntu18 为例,安装 DBeaver:</p><p>1、因为 DBeaver 是 java base,所以需要安装 java,openjdk 即可</p><pre><code>sudo apt-get install openjdk-8-jdk</code></pre><p>2、 添加 GPG key:</p><pre><code>wget -O - https://dbeaver.io/debs/dbeaver.gpg.key | sudo apt-key add -</code></pre><p>3、 添加仓库:</p><pre><code>echo "deb https://dbeaver.io/debs/dbeaver-ce /" | sudo tee /etc/apt/sources.list.d/dbeaver.list</code></pre><p>4、 更新,然后安装</p><pre><code>sudo apt updatesudo apt -y install dbeaver-ce</code></pre><p>5、 检查 dbeaver 版本,有就安装成功</p><pre><code>apt policy dbeaver-ce</code></pre><p>使用上就是选择连接的数据库类型,输入地址、端口、账号、密码、数据库名称等等,就不赘述了。</p><p>工作界面如下:</p><p><img alt="DBeaver连接postgresql工作界面" data-src="/../images/TechnicalEssays/AboutGit/remote-access-gitlab-ce-postgresql/DBeaver%E8%BF%9E%E6%8E%A5postgresql%E5%B7%A5%E4%BD%9C%E7%95%8C%E9%9D%A2.png" class="lazyload"></p><p><strong>注意,如果在外部使用 DBeaver 或者其它 GUI 连接到 gitlab 内部的 postgresql 时,没有填写数据库名称为 gitlabhq_production,那默认连接的就是 postgres。</strong></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(五)Gitlab用户数据备份与定时备份</title>
<link href="/2019/12/20/TechnicalEssays/AboutGit/5gitlab-ce-usedata-backup/"/>
<url>/2019/12/20/TechnicalEssays/AboutGit/5gitlab-ce-usedata-backup/</url>
<content type="html"><![CDATA[<p>在安装 gitlab 的时候,有使用命令<code>sudo gitlab-rake gitlab:backup:create</code>备份用户数据。该备份路径是默认配置中的路径,我们可以对其进行修改。</p><p>此外,仅仅是备份在 gitlab 的主机中对数据丢失也有风险,例如硬盘坏了。</p><p>所以这里我简单列举了 gitlab-ce userdata(用户数据)备份到本机其它位置、备份到远程主机 2 种方式。</p><p>更多的,gitlab 还默认支持将用户数据备份到云端,配置中列示有 Amazon S3、Digital Ocean Spaces、 Google Cloud Storage 等。</p><p>具体详细的内容,可以查看官网的<a href="https://docs.gitlab.com/ce/raketasks/backup_restore.html" target="_blank" rel="noopener">Backing up and restoring GitLab</a></p><h1 id="常规备份设定——备份到本机其它位置"><a href="#常规备份设定——备份到本机其它位置" class="headerlink" title="常规备份设定——备份到本机其它位置"></a>常规备份设定——备份到本机其它位置</h1><p>打开<code>/etc/gitlab/gitlab.rb</code>文件,找到<code>Backup Settings</code>区块。<br>可以看到,默认的备份地址配置<code>gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"</code>。</p><p>所以,只需要修改这一句,调整路径,例如<code>gitlab_rails['backup_path'] = "/home/{username}/gitlab</code>,后续备份的用户数据,就在/home/{username}/gitlab 下了。<br>{username}为你的主机名。</p><h1 id="备份到远程主机"><a href="#备份到远程主机" class="headerlink" title="备份到远程主机"></a>备份到远程主机</h1><p>备份到远程主机,一开始不是很清楚这个配置设定,看着那段英文字翻译成中文没有看懂,假装配置几次失败后,就放弃了。使用了透过 ssh 使用 scp 指令,编写脚本文件,将 gitlab 主机的用户数据,copy 到其它主机。</p><p>以上做法是 ok 的,实际运行这么久也没什么问题。不管,这里我还是说明一下,如何使用 gitlab 的配置完成备份时一并备份到远程主机。<br>当然,前提条件是,在局域网内,可以直接访问指定位置。如果本来就无法访问,那肯定是这么配置都没用的。</p><p>仔细查看<a href="https://docs.gitlab.com/ce/raketasks/backup_restore.html#uploading-to-locally-mounted-shares" target="_blank" rel="noopener">官方文档的说明</a>,整理出实现步骤:</p><ol><li>将远程主机路径,挂载到 gitlab 主机,</li><li>将挂载地址的所有权赋予 git 账号,</li><li>在 gitlab.rb 中配置备份设定,</li><li>重新加载配置文件运行 gitlab。</li></ol><h2 id="ubuntu-中挂载远程主机共享文件夹"><a href="#ubuntu-中挂载远程主机共享文件夹" class="headerlink" title="ubuntu 中挂载远程主机共享文件夹"></a>ubuntu 中挂载远程主机共享文件夹</h2><p>一般情况下,我们在 ubuntu 中,点击‘其它位置’–>’连接到服务器’–>输入服务器地址–>输入授权账号密码网域等,就可以直接访问到对应的位置。此次的挂载效果类似。</p><p>我的示例,是将 gitlab 服务器的用户数据,备份到一台 windows 系统的远程主机,所以需要将 windows 指定文件夹,挂在到 gitlab 所在的 ubuntu 系统。</p><p>1 gitlab 主机安装 cifs 工具</p><p>gitlab 主机是 ubuntu,运行<code>sudo apt-get install cifs-utils</code>即可。</p><p>2 新加需要挂载的目标文件夹</p><p>我的示例,是想把 windows 系统中的<code>//192.168.XX.XX/share/GitlabBackupDir</code>挂载到 ubuntu 中的<code>/mnt/backups</code>中。<br>所以执行<code>mkdir /mnt/backups</code>去创建对应文件夹,权限不够在前面加<code>sudo</code>。</p><p>3 挂载文件夹<br>一般直接使用 mount 指令的话,是临时挂载,计算机重启之后就没有了。现在这个场景,比较适合永久挂在,所以调价配置到文件为佳。<br>在挂载前,仔细阅读一下官网这句话:</p><blockquote><p>The directory pointed to by the local_root key must be owned by the git user when mounted (mounting with the uid= of the git user for CIFS and SMB) or the user that you are executing the backup tasks under (for Omnibus packages, this is the git user).</p></blockquote><p>经过我的测试分析,它的意思大概说明,这个挂载的地址,本例中为<code>/mnt/backups</code>,必须是执行挂载动作时的 git 用户,或者执行备份作业是的用户。使用 Omnibus packages 安装的 gitlab,这个执行的用户,就是 git 用户。</p><p>什么意思呢,简单理解就是,这个挂载地址文件夹的拥有者,必须是 git 用户。</p><p>到这里,我们再来添加挂载配置。</p><p>打开<code>/etc/fstab</code>文件,在最后添加以下内容:</p><pre><code>{被挂载的远程主机源路径} {gitlab主机的目标路径} cifs auto,username={远程主机的用户名},password={远程主机用户名的密码},domain={远程主机的网域},gid={ubuntu下git用户的gid},uid={ubuntu下git用户的uid} 0 0</code></pre><p>空白留个 tab 键间隔或者空格就好了。各个间隔的参数含义,配置文件有说明,分别是</p><p><file system> <mount point> <type> <options> <dump> <pass></p><p>如果获取 git 用户的 uid 和 gid?在终端中输入<code>id git</code>即可。<br>其它用户就是<code>id {user}</code>。我的挂载命令就是</p><pre><code>//192.168.XX.XX/share/GitlabBackupDir /mnt/backups cifs auto,username=XXX,password=XXX,domain=XXX,gid=998,uid=998 0 0</code></pre><p>要让挂载立即生效,执行<code>sudo mount -a</code>即可。<br>查看是否挂载成功,执行<code>mount</code>查看,应该可以看到类似如下一句:</p><pre><code>……//192.168.XX.XX/share/GitlabBackupDir on /mnt/backups type cifs (rw,relatime,vers=2.1,cache=strict,username=XXX,domain=XXX,uid=998,forceuid,gid=998,forcegid,addr=192.168.XX.XX,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,rsize=1048576,wsize=1048576,bsize=1048576,echo_interval=60,actimeo=1)……</code></pre><p>说明挂载成功。</p><p>额外说一句,如果只有临时挂载,重启就没有了,那就不写到配置文件,只需要在终端执行:</p><pre><code>mount -t cifs {被挂载的远程主机源路径} {gitlab主机的目标路径} -o username="{username}",password="{password}",domain={domain}</code></pre><p><strong>注意:</strong></p><ul><li>如果是 windows10 系统,可能需要在最末加一句 vers=2.0,写在配置文件也是一样要加。</li><li>终端中输入 option 要加引号。写到配置时,不要加,否则会报错。</li><li>如果没有网域,当然就不用添加这个参数。</li></ul><p>到这里挂载文件夹和赋予所有权给 git 用户已完成。</p><h2 id="修改-gitlab-rb-对应配置文件"><a href="#修改-gitlab-rb-对应配置文件" class="headerlink" title="修改 gitlab.rb 对应配置文件"></a>修改 gitlab.rb 对应配置文件</h2><p>打开<code>/etc/gitlab/gitlab.rb</code>文件,找到</p><pre><code># gitlab_rails['backup_upload_connection'] = {# 'provider' => 'AWS',# 'region' => 'eu-west-1',# 'aws_access_key_id' => 'AKIAKIAKI',# 'aws_secret_access_key' => 'secret123'# }# gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'# gitlab_rails['backup_multipart_chunk_size'] = 104857600</code></pre><p>最好复制一份,修改为:</p><pre><code>gitlab_rails['backup_upload_connection'] = { 'provider' => 'Local', 'local_root' => '/mnt/backups'}gitlab_rails['backup_upload_remote_directory'] = 'gitlab_backups'</code></pre><p>这个配置完成,那么在执行 geilab 备份时,会在<code>/mnt/backups</code>文件夹下创建<code>gitlab_backups</code>子文件夹,并放入该次备份的用户数据。<br>又因为这个路径,实际是 windows 下<code>//192.168.XX.XX/share/GitlabBackupDir</code>的挂载路径,所以实际上,用户数据的备份文件,就在这里。</p><p>以上,就完成了备份到远程主机的操作。配置好之后可能执行<code>sudo gitlab-rake gitlab:backup:create</code>命令测试一下,看是否在上述的路径下备份了用户数据。</p><p>当然,备份到 U 盘,外挂硬盘什么的,操作类似,不重复。至于备份到云,我没有这个条件,但是<a href="https://docs.gitlab.com/ce/raketasks/backup_restore.html#uploading-backups-to-a-remote-cloud-storage" target="_blank" rel="noopener">文檔</a>也写得比较清楚,照做即可。</p><p>此外,编写脚本,使用其它系统指令也可以实现类似的效果,这个不用 gitlab 进行配置,所以不赘述。</p><h2 id="实现定时备份"><a href="#实现定时备份" class="headerlink" title="实现定时备份"></a>实现定时备份</h2><p>可以将备份操作写到 cron 定时备份任务中去,那么就可以省略手动备份的操作了。</p><p>这个比较简单,在终端执行<code>sudo crontab -e</code>,或者</p><pre><code>sudo su -crontab -e</code></pre><p>系统自动备份的话,用户还是用 root 较好<br>选择一个编辑器,在最末,加一句(示例是每天凌晨 2 点进行备份,等级优先)</p><pre><code>0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1</code></pre><p>注意,GitLab 12.1 及之前的版本, 使用 <code>0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create CRON=1</code>.</p><p>保存,重启 cron 服务</p><pre><code>sudo service cron restart</code></pre><p>后续要修改,可以直接修改其文件,位置在<code>/var/spool/cron/crontabs</code>文件夹,如果是 root 账户,这里面就有个 root 文件。如果是其它用户{user},那就是{user}文件。</p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(四)gitlab-ce设置SMTP</title>
<link href="/2019/12/20/TechnicalEssays/AboutGit/4gitlab-ce-set-smtp/"/>
<url>/2019/12/20/TechnicalEssays/AboutGit/4gitlab-ce-set-smtp/</url>
<content type="html"><![CDATA[<h1 id="Gitlab-ce-smtp-设定"><a href="#Gitlab-ce-smtp-设定" class="headerlink" title="Gitlab-ce smtp 设定"></a>Gitlab-ce smtp 设定</h1><p>在安装 Omnibus package 时,有推荐安装 postfix 搭建 mail 服务器。这可能比较麻烦。</p><p>此外,使用 gitlab 作为简单版控工具或其它功能,大部分都不需要接收其它用户发送的邮件,而是发出邮件。例如用户注册需要验证用户账户,合并冲突发送给对应使用者提醒有冲突,重大任务分配设置邮件提醒指定开发者……考虑到这些功能 gitlab 主要是作为发件者,配置 SMTP 即可。gitlab 默认支持 SMTP 的配置。</p><blockquote><p>SMTP 是一种提供可靠且有效的电子邮件传输的协议。SMTP 是建立在 FTP 文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。</p></blockquote><p>它与 POP3 和 IMAP 可共同使用。SMTP 是用于发送邮件,而 POP3 和 IMAP 用于接收邮件。</p><p>基本步骤如下:</p><h2 id="修改-gitlab-ce-默认-SMTP-配置"><a href="#修改-gitlab-ce-默认-SMTP-配置" class="headerlink" title="修改 gitlab-ce 默认 SMTP 配置"></a>修改 gitlab-ce 默认 SMTP 配置</h2><p>打开 gitlab-ce 的配置文件,默认在<code>/etc/gitlab/gitlab.rb</code>,找到对应配置 smtp 的位置,按照实际配置修改,如下图:</p><p><img alt="gitlab邮箱设定" data-src="/../images/TechnicalEssays/AboutGit/gitlab-ce-set-smtp/gitlab%E9%82%AE%E7%AE%B1%E8%AE%BE%E5%AE%9A.png" class="lazyload"><br><img alt="gitlab邮箱服务器设定" data-src="/../images/TechnicalEssays/AboutGit/gitlab-ce-set-smtp/gitlab%E9%82%AE%E7%AE%B1%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%AE%BE%E5%AE%9A.png" class="lazyload"></p><p>(为了方便修改,我把 Email Settings 部分和 GitLab email server settings 内容放到了一起)</p><p>对应的主要配置说明:</p><ul><li><p>设定 Email 相关信息(设定档中「Email Settings」区块为设定 Email 相关信息部分。)</p><ul><li>gitlab_email_enabled:启用 Email 功能。</li><li>gitlab_email_from:寄件人信箱。</li><li>gitlab_email_display_name:寄件人显示名称(预设为 GitLab 或是 GitLab 账号名称)。</li><li>gitlab_email_reply_to:回复信箱(预设为 noreply@ + 外部 URL)</li></ul></li><li><p>设定 SMTP Server(设定档中「GitLab email server settings」区块为设定 SMTP Server 部分)</p><ul><li>smtp_enable:启用 SMTP 功能。</li><li>smtp_address:SMTP Server。</li><li>smtp_port:SMTP Port。</li><li>smtp_user_name:SMTP 使用者账号。</li><li>smtp_password:SMTP 使用者密码。</li><li>smtp_domain:SMTP 网域。</li><li>smtp_authentication:SMTP 验证模式。</li><li>smtp_enable_starttls_auto:SMTP 开启 TLS 设定。</li><li>smtp_tls:使用 TLS 设定。</li><li>smtp_openssl_verify_mode:SMTP SSL 验证模式。</li></ul></li></ul><p>更多对应的配置,可参考一下官网的<a href="https://docs.gitlab.com/omnibus/settings/smtp.html" target="_blank" rel="noopener">SMTP settings</a></p><p>配置更改完成之后,需要执行<code>sudo gitlab-ctl reconfigure</code>使配置生效。</p><h2 id="测试是否成功"><a href="#测试是否成功" class="headerlink" title="测试是否成功"></a>测试是否成功</h2><h3 id="控制台命令测试"><a href="#控制台命令测试" class="headerlink" title="控制台命令测试"></a>控制台命令测试</h3><p>终端输入<code>sudo gitlab-rails console</code>,进入 gitlab-rails 工作区.</p><p>在命令行输入测试命令,测试命令格式:</p><pre><code>Notify.test_email({收件者邮箱地址},{邮件主题},{邮件内容}).deliver_now</code></pre><p>按照实际内容替换{}及其中文字即可。</p><p>如果发送成功,终端会显示测试命令发出的邮件信息,或者直接到收件者邮箱从查看。如果失败,可以根据终端中错误提示进行判断。</p><p>如下图:</p><p><img alt="终端指令测试SMTP配置" data-src="/../images/TechnicalEssays/AboutGit/gitlab-ce-set-smtp/%E7%BB%88%E7%AB%AF%E6%8C%87%E4%BB%A4%E6%B5%8B%E8%AF%95SMTP%E9%85%8D%E7%BD%AE.png" class="lazyload"></p><p><em>值得注意,虽然我确认我是安装的 gitlab-ce 版本,但是这里显示的是 12.6.0-ee。我猜是一个小的 bug。</em></p><h3 id="设定-gitlab-注册用户需验证邮箱"><a href="#设定-gitlab-注册用户需验证邮箱" class="headerlink" title="设定 gitlab 注册用户需验证邮箱"></a>设定 gitlab 注册用户需验证邮箱</h3><p>或者直接使用 giltab 相关功能测试</p><p>可以测试,注册用户时,需要邮件确认之后,才能登入。gitlab 账号注册时验证邮箱的正确性,在注册时可以减少使用不存在的邮箱进行注册,保证 user 的有效性。</p><p>首先开启注册需要邮件验证。</p><p>使用 root 管理员账号登入,点击“管理员区域”–>“设定”–>”注册限制”,把<code>Send confirmation email on sign-up</code>打勾,最后保存。</p><p>然后新注册一个用户。</p><p>注销 root 账号之后,输入注册信息,点击注册按钮,会跳转到发送确认邮件的画面。</p><p>如果直接返回到登入页面,使用刚刚注册的账号登入,则会出现以下<code>You have to confirm your email address before continuing</code>字样。</p><p>这样,说明 gitlab 的注册验证邮箱的设定生效了。</p><p>然后查看刚刚注册账号使用的邮件,如果有收到自己 gitlab 发送的注册确认邮件,那么 gitlab SMTP 设定也是成功了。</p><p>当然,后续点击蓝色连接,则会跳转到登入页面,并有显示邮箱已被成功确认的信息,这时再使用刚刚注册账号登入即可成功。</p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(三)gitlab-web基本功能说明</title>
<link href="/2019/12/19/TechnicalEssays/AboutGit/3gitlab-web-basic/"/>
<url>/2019/12/19/TechnicalEssays/AboutGit/3gitlab-web-basic/</url>
<content type="html"><![CDATA[<p>gitlab 安装成功之后,登录网页,可以看到它提供的很多功能。这个东西要写的话,恐怕还是非常复杂和麻烦。</p><p>例如其核心的自动部署和 CI/CD,到现在我也没有在生产环境下使用过。如果把 gitlab-ce 作为一个内部代码版控工具,也就还用不到这样的功能。</p><p>所以,这部分,使用者的 gitlab 基本功能使用介绍,我不再赘述,可以查看我之前有简单做的 PPT,放置在<a href="https://github.com/Sanotsu/git-gitlab-advanced-notes" target="_blank" rel="noopener">github</a>《3-gitlab基本功能测试使用介绍.pdf》。</p><p>主要内容有介绍:</p><ul><li>项目私有性测试</li><li>问题追踪</li><li>其它实用功能测试说明<ul><li>专案<ul><li>细节</li><li>活动</li></ul></li><li>档案库<ul><li>档案</li><li>更动记录</li><li>分支</li><li>标签</li><li>协作者</li><li>图表</li><li>比较</li><li>统计图</li></ul></li><li>议题<ul><li>里程碑</li><li>标签</li><li>清单</li><li>广告牌</li></ul></li><li>合并请求</li><li>Wiki</li><li>程序代码片段</li></ul></li></ul><p>因为当时作业环境是繁体,截图依旧保留繁体。</p><p>一般使用者和 gitlab 管理员的权限有所区别。主要在于管理员都一个<code>admin area</code>,这个最大最高权限,少数者拥有就好了,更多内容可参看官方文档<a href="https://docs.gitlab.com/ce/user/admin_area/" target="_blank" rel="noopener">GitLab Admin Area</a></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(二)omnibus package安裝gitlab-ce</title>
<link href="/2019/12/19/TechnicalEssays/AboutGit/2omnibus-gitlab-ce/"/>
<url>/2019/12/19/TechnicalEssays/AboutGit/2omnibus-gitlab-ce/</url>
<content type="html"><![CDATA[<h1 id="omnibus-package-安装-gitlab-ce"><a href="#omnibus-package-安装-gitlab-ce" class="headerlink" title="omnibus-package 安装 gitlab-ce"></a>omnibus-package 安装 gitlab-ce</h1><p><a href="https://about.gitlab.com/install/#ubuntu" target="_blank" rel="noopener">ubuntu 下安装 gitlab-ce 官方推荐安装</a>,步骤也非常简单.</p><h2 id="安装并配置需要的依赖"><a href="#安装并配置需要的依赖" class="headerlink" title="安装并配置需要的依赖"></a>安装并配置需要的依赖</h2><p>1 先更新 apt-get:</p><pre><code>sudo apt-get update</code></pre><p>2 再安装 openssh-server</p><pre><code>sudo apt-get install -y curl openssh-server ca-certificates</code></pre><p>注意,在 ubuntu18 安装时 openssh-server 时,可能会出现类似这样的错误:</p><pre><code>sanotsu@sanotsu-ubt18:~$ sudo apt-get install -y curl openssh-server ca-certificates正在读取软件包列表... 完成正在分析软件包的依赖关系树正在读取状态信息... 完成ca-certificates 已经是最新版 (20180409)。ca-certificates 已设置为手动安装。curl 已经是最新版 (7.58.0-2ubuntu3)。有一些软件包无法被安装。如果您用的是 unstable 发行版,这也许是因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件包尚未被创建或是它们已被从新到(Incoming)目录移出。下列信息可能会对解决问题有所帮助:下列软件包有未满足的依赖关系: openssh-server : 依赖: openssh-client (= 1:7.6p1-4) 依赖: openssh-sftp-server 但是它将不会被安装 推荐: ssh-import-id 但是它将不会被安装E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。sanotsu@sanotsu-ubt18:~$</code></pre><p>这是因为安装 openssh-server 依赖 openssh-client。ubuntu 默认有安装 openssh-client,但是版本可能不满足,所以只需再安装一次需要的版本。</p><p>例如上面的出错信息,则需要降级,命令安装如下:</p><pre><code>sudo apt-get install openssh-client=1:7.6p1-4</code></pre><p>安装成功之后,再安装 openssh-server 即可。</p><h2 id="安装邮箱服务器-Postfix-非必要,大可不必"><a href="#安装邮箱服务器-Postfix-非必要,大可不必" class="headerlink" title="安装邮箱服务器 Postfix(非必要,大可不必)"></a>安装邮箱服务器 Postfix(非必要,大可不必)</h2><pre><code>sudo apt-get install -y postfix</code></pre><p>然后按照提示,输入自己的配置。大概有需要输入的邮箱服务器地址,邮件名等等,还有一些使用 default 就好了。</p><p>如果不用 Postfix 来配置邮件收发,例如 gitlab 配置使用 SMTP 来发送邮件(后续文章再说明),这个部分可以跳过。</p><p>如果安装之后,想要移除,可使用<code>sudo apt-get remove postfix</code>来卸载。</p><h2 id="添加-GitLab-软件包存储库并安装软件包"><a href="#添加-GitLab-软件包存储库并安装软件包" class="headerlink" title="添加 GitLab 软件包存储库并安装软件包"></a>添加 GitLab 软件包存储库并安装软件包</h2><p>添加 GitLab 软件包存储库命令:</p><pre><code>curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash</code></pre><p>安装命令:</p><pre><code>sudo EXTERNAL_URL="http://192.168.XX.XX" apt-get install gitlab-ce</code></pre><p>其中 EXTERNAL_URL 为 gitlab-ce 的访问地址,如果不设定,默认就是 <code>http://127.0.0.1</code>。</p><p><strong>注意,在之前的版本,设置<code>EXTERNAL_URL="192.168.XX.XX"</code>是可以的,不过我现在使用 12.6.0 这样设置,会报错,错误如下:</strong></p><pre><code>There was an error running gitlab-ctl reconfigure:GitLab external URL must include a schema and FQDN, e.g. http://gitlab.example.com/</code></pre><p>下载和安装过程需要一点时间。</p><p>安装成功之后,打开之前设置的访问地址,应该会出现修改管理员密码画面,就表示 gitlab 安装成功。</p><p><strong>如果安装完成之后的自动运行配置出现错误,例如 url 配置出错等等,解决问题后再手动再运行一次<code>sudo gitlab-ctl reconfigure</code>。</strong></p><p>安装完成之后的组件分析:</p><p>gitlab 的结构分析,可参看<a href="https://docs.gitlab.com/ce/development/architecture.html#simplified-component-overview" target="_blank" rel="noopener">官网说明</a>,有助于理解各个组件的作用。</p><h2 id="一些常用指令"><a href="#一些常用指令" class="headerlink" title="一些常用指令"></a>一些常用指令</h2><p>1.查看状态:</p><pre><code>sudo gitlab-ctl status</code></pre><p>2.停止/启动/重启 gitlab</p><pre><code>sudo gitlab-ctl stopsudo gitlab-ctl startsudo gitlab-ctl restart</code></pre><p>3.重新加载配置</p><pre><code>sudo gitlab-ctl reconfigure</code></pre><p>3 关闭/启用开机自启动(<strong>慎重</strong>)这个 Gitlab 默认是开机自启动的。</p><p>Ubuntu 下禁止 Gitlab 开机自启动:</p><pre><code>sudo systemctl disable gitlab-runsvdir.service</code></pre><p>如果要设置开机自启动,Ubuntu 下启用 Gitlab 开机自启动:</p><pre><code>sudo systemctl enable gitlab-runsvdir.service</code></pre><p>自启动也还 ok,如果 disable 掉,开机在使用<code>sudo gitlab-ctl start</code>就启动不了了,因为所有的服务都关了,要启动起来才行。</p><p><strong>注意,如果 docker 的 gitlab 和 omnibus-package gitlab 安装在同一台机器,注意只开一个,因为端口什么的是一样的。</strong></p><p>如果安装完 omnibus-package gitlab,发现启动不了 docker 的 gitlab,并提示端口 22 已被占用,可能就是 sshd 占用了端口,关闭 ssh 即可。</p><pre><code>/etc/init.d/ssh stop</code></pre><p>当然,开启就是</p><pre><code>/etc/init.d/ssh start</code></pre><p>如果要关闭开机自启动 ssh(沒必要),删除其自动配置</p><pre><code>sudo mv /etc/init/ssh.conf /etc/init/ssh.conf/disabled</code></pre><h1 id="备份和还原用户数据"><a href="#备份和还原用户数据" class="headerlink" title="备份和还原用户数据"></a>备份和还原用户数据</h1><h2 id="备份"><a href="#备份" class="headerlink" title="备份"></a>备份</h2><p>对应命令:</p><pre><code>sudo gitlab-rake gitlab:backup:create</code></pre><p>默认的备份地址在<code>/var/opt/gitlab/backups</code>中,查看该路径可以看到以下内容,即为备份的 userdata。</p><p>格式是:<code>{时间戳10位}_{年_月_日}_{gitlab版本号}_gitlab_backup.tar</code>。</p><p><strong>注意,在还原时,版本不一致的备份,是不能还原的,所以需要将 gitlab 的版本保持在一个固定的版本。</strong></p><h2 id="还原"><a href="#还原" class="headerlink" title="还原"></a>还原</h2><p>前提条件:</p><ul><li>您已经安装了与创建备份的 GitLab Omnibus 完全相同的版本和类型(CE / EE)。</li><li>你 sudo gitlab-ctl reconfigure 至少跑了一次。</li><li>GitLab 正在运行。如果没有,请使用它 sudo gitlab-ctl start。</li></ul><p>操作步骤:</p><ul><li>停止连接到数据库的进程,剩下部分继续 running</li></ul><pre><code>sudo gitlab-ctl stop unicornsudo gitlab-ctl stop sidekiq</code></pre><p>可以在停止之后,查看 gitlab 的状态<code>sudo gitlab-ctl status</code>,确认一下两个服务已经停止。</p><ul><li>再在已有的备份中,选择需要恢复的版本</li></ul><pre><code>sudo gitlab-rake gitlab:backup:restore BACKUP={备份的文件夹名}</code></pre><ul><li><p>恢复过程中,会有几次确认信息要手动确认,如果是确认要恢复,按照提示点击 yes 就好了。</p></li><li><p>恢复完之后,要重启 gitlab 服务</p></li></ul><pre><code>sudo gitlab-ctl restart</code></pre><p>此时再去访问 gitlab 的访问地址,就恢复到重置 root 密码的状态了。</p><p>如果是例如公司内部需要一个私有的仓库,最好还是使用 omnibus-package 安装,官方推荐,直接在设备的安装,配置等比较方便。</p><p>后续的内容都是以这种方式安装为例子。docker 之类的也可参考,不过是需要透过一层 docker 指令了。</p><p><strong>默认配置文件地址<code>/etc/gitlab/gitlab.rb</code>,后续会说明更多的配置,非常重要。</strong></p>]]></content>
<categories>
<category> Git/Gitlba系列 </category>
</categories>
<tags>
<tag> gitlab </tag>
</tags>
</entry>
<entry>
<title>(一)使用docker安裝gitlab-ce</title>
<link href="/2019/12/19/TechnicalEssays/AboutGit/1docker-install-gitlab-ce/"/>
<url>/2019/12/19/TechnicalEssays/AboutGit/1docker-install-gitlab-ce/</url>
<content type="html"><![CDATA[<h1 id="系列文章前言"><a href="#系列文章前言" class="headerlink" title="系列文章前言"></a>系列文章前言</h1><p>此 git/gitlab 系列文章,预计会分为 3 个部分</p><ul><li><p>gitlab 的安装及常用配置说明</p></li><li><p>Git 入门和高级功能及常见问题的测试与解决</p></li><li><p>gitlab/git 推行使用规范示例</p></li></ul><p>当然不会非常全面,着重于代码托管和合作开发部分。部分章节主用 PPT 说明,可通过相关章节内容去 Github 获取。</p><p>虽然目前相关内容很多,不过对于此份内容部分,都是亲自测试并在内部进行了推广测试,比较详实。对于团体希望使用 git/gitlab 管理代码和合作开发,多多少少能有些参考作用;对于个人学习使用 git 和 gitlab,也有更多一点的帮助。</p><p>一些测试和功能实现部分,未必是最优解,但的确是一个解,可做参考。</p><p>此篇后续十七篇文章,一起入门 git/gitlab 的世界。</p><p>如果命令中有诸如 <XXX> 或者 {XXX}的指代,记得把符号一起替换成实际的参数。</p><p><em>Git入门及常用命令、Gitlab用户数据备份与定时备份、gitlab-web基本功能说明、omnibus package安裝gitlab-ce 的cover图源网络。</em></p><h1 id="docker-安装-gitlab-ce"><a href="#docker-安装-gitlab-ce" class="headerlink" title="docker 安装 gitlab-ce"></a>docker 安装 gitlab-ce</h1><h2 id="安装-docker"><a href="#安装-docker" class="headerlink" title="安装 docker"></a>安装 docker</h2><pre><code>sudo apt install docker.io</code></pre><p>安装完成之后,直接使用 docker 命令,可能会出现权限不足(permission denied)。</p><p>解决方法,将一般用户加入可用:</p><pre><code>sudo usermod –aG docker <username></code></pre><p>设置完之后,一定要注销用户,再登入,才能生效,生效之后。<br>ubuntu18 可能需要重启。</p><p>更多 docker 常用指令的简单说明,可参看之前使用 《Ubuntu18.04下docker基本指令和使用docker安装mysql》</p><h2 id="安装前的清理"><a href="#安装前的清理" class="headerlink" title="安装前的清理"></a>安装前的清理</h2><p>因为重头来过,所以,我们先查看下是否有之前安装过的名叫 gitlab 的容器</p><pre><code>docker ps </code></pre><p>此处若没有,则没有 gitlab 的 docker;如果有,则用命令:<code>docker rm gitlab</code>移除</p><h2 id="抓取官方-gitlab-image-并使用-docker-运行容器"><a href="#抓取官方-gitlab-image-并使用-docker-运行容器" class="headerlink" title="抓取官方 gitlab image 并使用 docker 运行容器"></a>抓取官方 gitlab image 并使用 docker 运行容器</h2><p>直接终端输入指令</p><pre><code>docker pull gitlab/gitlab-ce:latest</code></pre><p>pull 可能需要一点时间,取决你下载的网速。</p><p>下载成功之后,使用<code>docker images</code>命令可以看到下载的 docker 镜像列表。</p><p>使用下载好的 images,创建容器,例如:</p><pre><code>docker run --detach \--hostname 192.168.XX.XX \--publish 443:443 --publish 80:80 --publish 22:22 \--name gitlab \--restart always \--volume /srv/gitlab-ce/config:/etc/gitlab \--volume /srv/gitlab-ce/logs:/var/log/gitlab \--volume /srv/gitlab-ce/data:/var/opt/gitlab \gitlab/gitlab-ce:latest</code></pre><p>以上配置了:<br>hostname:gtilab 的访问地址;<br>publish:映像主机端口和 docker 中访问 gitlab 的端口;<br>name:docker 容器名称;<br>restart:是否自动重启;<br>–volume:设定创建存放配置、日志、数据的文件夹.</p><p>在设定的位置(–volume),会生成以下几个文件夹,如下图</p><p><img alt="创建的gitlab文件夹" data-src="/../images/TechnicalEssays/AboutGit/docker-install-gitlab-ce/%E5%88%9B%E5%BB%BA%E7%9A%84gitlab%E6%96%87%E4%BB%B6%E5%A4%B9.png" class="lazyload"></p><p>其作用可参考以下:</p><table><thead><tr><th>本地位置</th><th>容器位置</th><th>用途</th></tr></thead><tbody><tr><td>/srv/gitlab-ce/data</td><td>/var/opt/gitlab</td><td>For storing application data</td></tr><tr><td>/srv/gitlab-ce/logs</td><td>/var/log/gitlab</td><td>For storing logs</td></tr><tr><td>/srv/gitlab-ce/config</td><td>/etc/gitlab</td><td>For storing the GitLab configuration files</td></tr></tbody></table><p>正常的话,在创建完之后,会自动开启,开启成功之后,效果如下图(当看到 STATUS 为 healthy,表明已经正常启动):</p><p><img alt="docker正常启动gitlab容器" data-src="/../images/TechnicalEssays/AboutGit/docker-install-gitlab-ce/docker%E6%AD%A3%E5%B8%B8%E5%90%AF%E5%8A%A8gitlab%E5%AE%B9%E5%99%A8.png" class="lazyload"></p><p>登入之前创建 container 时的 hostname,可以查看到,如下图:</p><p><img alt="gitlab初始首页" data-src="/../images/TechnicalEssays/AboutGit/docker-install-gitlab-ce/gitlab%E5%88%9D%E5%A7%8B%E9%A6%96%E9%A1%B5.png" class="lazyload"></p><p>首次访问时,需要设定 root 管理员的密码,账号默认为 root,修改密码成功之后,则进入到登入画面,即可输入 root 账号密码,进入查看。</p><p>如果需要关闭容器,使用 stop 命令,例如停止/开启已有的 gitlab( 例如 docker name 为 gitlab)</p><pre><code class="sh">docker stop gitlab # 停止docker start gitlab # 开启</code></pre><p>如果发现启动不了 docker 的 gitlab,并提示端口 22 已被占用,可能就是 sshd 占用了端口。</p><p>关闭 ssh 即可:</p><pre><code>/etc/init.d/ssh stop</code></pre><p>当然,开启就是</p><pre><code>/etc/init.d/ssh start</code></pre><p>如果配置有错,需要修改 gitlab 的配置文件<code>gitlab.rb</code>,可是使用命令</p><pre><code>sudo docker exec -it gitlab editor /etc/gitlab/gitlab.rb</code></pre><p>去打开文件编辑。不过一旦打开了这个文件,就注意给<code>external_url</code>参数,赋予一个有效的值。就是 gitlab 访问地址需要可用。</p><p>修改了配置文件,需要重启该容器使其生效:</p><pre><code>docker restart gitlab</code></pre><h1 id="备份和还原用户数据"><a href="#备份和还原用户数据" class="headerlink" title="备份和还原用户数据"></a>备份和还原用户数据</h1><h2 id="手动备份用户数据"><a href="#手动备份用户数据" class="headerlink" title="手动备份用户数据"></a>手动备份用户数据</h2><p>目前除了设定了一个 root 账号的密码之外,其它什么都没有,我现在备份一次此时的 gitlab user data,使用指令</p><pre><code>docker exec -it gitlab gitlab-rake gitlab:backup:create</code></pre><p>备份成功之后,默认位置在存放 data 的路径下,也就是创建并运行容器时的配置路径:<code>/srv/gitlab-ce/data/backups</code>。</p><p>在 root 权限或者当前用户取得该文件夹权限后,可以看到该文件夹内部文件,gitlab-ce 备份的用户数据的格式例如:</p><p><code>{时间戳10位}_{年_月_日}_{gitlab版本号}_gitlab_backup.tar</code></p><p>或者可直接使用命令行查看:<code>docker exec -it gitlab ls /var/opt/gitlab/backups/</code></p><h2 id="还原备份的文件"><a href="#还原备份的文件" class="headerlink" title="还原备份的文件"></a>还原备份的文件</h2><p>备份之后,后续作业如果出现问题,可以还原到这个原始版本;当然,如果定时备份,则可以随时还原到需要的时间节点版本。</p><p>还原命令:</p><pre><code>docker exec -it gitlab /opt/gitlab/bin/gitlab-rake gitlab:backup:restore BACKUP={时间戳10位}_{年_月_日}_{gitlab版本号}</code></pre><p>BACKUP=后面输入需要返回的备份文件名称</p><p><strong>注意,gitlab 只能还原版本相同的备份文件,版本不同不能还原。</strong></p><p>使用 docker 安装就像是装在了沙盒,不想要了可以直接删除,没有什么顾虑。但是操作起来比较麻烦,毕竟中间隔了一层。用于测试等轻量使用较宜。</p>]]></content>