|
|
楼主 |
发表于 2024-8-12 09:52:42
|
显示全部楼层
AB复制(重点)
" H' Q$ n) u9 m! }# s一、什么是主从复制?# ]. w5 K0 m3 Q( c' x @5 d+ X' L
1、主从同步也叫AB复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是准实时的业务数据库。3 H! J# G t3 h h- i
: C+ e. j7 b% n. t6 {2、主从复制的作用
, p2 f# o+ z( D
& ?/ b3 R5 g4 @1.做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。* i" M. {8 \, E
2.架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
! X5 b: e# e* q# Y [8 Q( o$ @6 o3.读写分离,使数据库能支撑更大的并发。
8 Y' F4 d$ j! O. d. ] 1--在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;(主库写,从库读,降压)
) L2 \- p2 Y. y2 s" W* B% d5 e 2--在从服务器进行备份,避免备份期间影响主服务器服务;(确保数据安全)1 y$ p! ?6 l# }) O
' M ^5 K. g6 i9 V$ ~& B为什么要搞主从同步?( t }6 Q n% E
因为只有一个服务器 上面跑着mysql 万一发生故障 数据会丢失 业务访问无法正常运行,业务量过大的情况下,对服务器的压力也是很大的,所以要考虑到服务要高可用,既降低服务器压力又提高可用性
( b* s& ~. ?/ }, S& r/ y! l) B' | s- l O: f4 ]* r
写库(写入)专门放一个数据库 主库负责写入9 |4 S1 P- L3 }, T0 b1 ^6 m
查询(select)在专门放一个库 从库负责查询
9 h% x- z! [# c. V u* ?# G
- {/ u4 w+ O. X4 DAB复制也叫读写分离. b: R$ I- z0 ~! F+ f: m
! f6 M/ j+ s6 |' ?" M$ f二、主从同步原理(面试题)
! ~" h; g9 u- Z主服务器把数据修改之后,会放入到二进制日志中(binary log)中,然后通过内部进程机制把日志传递到从服务器(从服务器在通过IO线程写入到中继日志)中并表示为中继日志(中继日志在通过sql线程传输给从服务器并执行),从而达到了主从一致- P1 j7 U) p; L; x
从服务器有俩个线程(I/O线程和SQL线程)I/O线程负责把主服务器上的日志拉取过来,slq线程是负责把日志执行的,从服务器干的活最多
( x5 L! I5 m3 B7 |主服务器写入数据,从服务器就写入,主服务器删除数据,从服务器就会接着删除数据
. \# R" s( c- }
4 @8 F% e/ N2 W( S0 z" J( @" o4 u从服务器不能写入数据
: _; Z+ e* ]9 m$ Q: z
, g6 I) Z0 ]# f主从同步也叫异步模式,时间会有0.几毫秒延时,2 a p f: Y! l7 M0 }5 \; t4 b9 T" Z
6 |+ C7 ?- [* o+ B' T主服务器做好授权 从服务器具有授权的凭证进行把日志传递3 l* ]8 p2 `$ m/ m% @4 I# c1 {
8 F. P+ r3 }, M4 j$ F! l6 C丛库可以写数据库 但是主库是不会有的" _* e4 P# D3 [/ [# }5 |' W0 y
: I9 b4 |3 ^7 y% v
三、M-S 架构GTID 基于事务ID复制
% d6 Z! J2 I1 l9 @. b1、什么是GTID?/ D! y# g5 w6 K
全局事务标识:global transaction identifiers
* S+ M9 B% ?. w8 W3 m! |8 D4 _+ O是用来代替传统复制的方法,GTID复制与普通复制模式的最大不同就是不需要指定二进制文件名和位置。6 W6 U. }' i' b/ A2 K. a8 y
, G+ L% p$ J' B2、GTID工作原理7 S/ h8 _1 n( q5 Z3 u: v) U3 w
1、master更新数据时,会在事务前产生GTID,一同记录到binlog日志中。
8 a0 x1 ^( e4 u5 _" b- l% I2、slave端的i/o 线程将变更的binlog,写入到本地的relay log中。
- v9 R9 Y: H* [2 n' l1 Z3、sql线程从relay log中获取GTID,然后对比slave端的binlog是否有记录。
, t4 {" d2 t. L, R- ~3 C S9 }4、如果有记录,说明该GTID的事务已经执行,slave会忽略。/ u( S. W- \) s) d
5、如果没有记录,slave就会从relay log中执行该GTID的事务,并记录到binlog。: i2 T* R1 S- v
8 K; {7 E# ^( M3 |$ C4 m3 ]
3、部署主从复制
! k; w* s% x. T* Y- G9 ?5 ^9 d `- E* i-A, --all-databases #备份所有库$ K3 ?2 k* m7 ~* r: ~5 u# ~
-B, --databases #备份多个数据库 h7 ~# \0 ]9 F* F$ F
-F, --flush-logs #备份之前刷新binlog日志9 g1 a! n# y9 |/ {
--default-character-set #指定导出数据时采用何种字符集,如果数据表不是采用默认的latin1字符集的话,那么导出时必须指定该选项,否则再次导入数据后将产生乱码问题。
# l, b. a$ c5 r7 D1 Z& u, c--no-data,-d #不导出任何数据,只导出数据库表结构。4 s& {, N. L- ?6 k2 ^7 b* [
--lock-tables #备份前,锁定所有数据库表4 s0 C+ v3 K* @% `
--single-transaction #保证数据的一致性和服务的可用性0 e9 G0 C6 O, ^8 T9 K* [0 u: V' ^
-f, --force #即使在一个表导出期间得到一个SQL错误,继续。
5 B: l) W/ v- y/ o! }% _# P1 M( u6 x5 @: I/ e- u& U9 z, u/ X7 A/ E
/ M# s5 p' O2 q' d对主库已有的数据库不会进行自动同步(可选操作 两边的库要一样)- `, y5 Y7 e' c( r
逻辑备份 先暂时关闭gtid
6 d3 \& i1 L4 V) i--single-transaction 做一次性检查0 c, p7 H4 l: m& V* u1 n
--all-databases 导出所有数据库
* Z* ?8 U }6 ~& s+ }6 Q1 t1 N4 t7 \
+ O, b/ J$ \6 D% Kmkdir /dackupdb! r7 m5 s5 W) O. i) Y+ ^ J
mysqldump -uroot -p'123456' --set-gtid-purged=OFF --single-transaction --all-databases > /data/backupdb/all_$(date +%Y%m%d%H%M%S).sql& y0 Y7 S8 j% y F
; |' V+ N( D; S) }8 o% h
在从库上导入单个数据库。( K6 F3 ]# Y' |. I
mysql -uroot -p'' 库名 < /path/dbname.bak, L+ }- y% A- h- U% m9 R
mysql -uroot -p'123456' company < all_20240524195401.sql
6 z9 P8 J+ u/ V9 C' k, `4 r2 G `+ \7 u2 d: v2 b- B- @
在从库上导入多个数据库- a p7 Z- b% a) J. q# Y$ y4 M
mysql -uroot -p'123456' < all_20240524195401.sql
r* y/ k3 r0 q5 B, J
- ?+ f! ?- |7 \7 w. s部署主从复制详细流程
, _: M2 j; _" f& _: J开始执行第一步8 o, ]5 G9 L" Q
master操作:
" R8 u j: Z; a9 c+ h. X0 Fcd /usr/local/mysql/( d) M8 W% `$ f, i3 R; A
mkdir bin-log
- R. y3 [, }! w% j2 z$ s& Dchown -R mysql:mysql bin-log
3 w3 a& T: k8 I5 s0 ?% [# D, ~2 o: N) @
[root@mysql-master ~]# vim /etc/my.cnf
0 Y+ F) `6 C2 i- `9 A" A2 j#在[mysqld]下添加如下内容2 t( [; `5 _# d% R* n8 I3 [
server-id=1
$ o, F; h3 v. w6 N/ Blog-bin = /usr/local/mysql/bin-log/binlog //前面是路径后面是文件名
7 w; n! W4 l8 G( ggtid_mode = on
/ c5 H; Q3 c3 {; w- z& Z; Jenforce_gtid_consistency=14 D0 Y) U2 \; i: Q) e
#强制gtid$ J: `7 F: z# D* x3 ? D) ?; I& x
sync_binlog = 1
5 K8 s; \8 X5 P* E% V- {: o8 f F; `1 L" T( _
[root@mysql-master ~]# systemctl restart mysqld
+ D8 ]7 I. M1 C& s* l; ]3 c6 w( }% z S% e( M: [
检查一下bin-log文件夹(此时二进制文件已经生成好了)0 I% j) @; Y. K0 Y8 }& D
cd /usr/local/mysql/
/ X$ `5 F: U8 p @: mcd bin-log/ ll
% u6 f; Z, i$ [8 a1 [- C r
, ~, i% m2 c2 R4 O9 l1 \( t/ E' W3 g1 Z4 ?1 x' o7 J. d
replication slave //同步到从服务器
6 w& Y; C) T" N9 P# e7 N5 w( }8 Qreload //重新加载
6 {8 ]* y+ `, ~$ m# ?- asuper //超级权限3 k' i5 N- u9 _
slave //账号. C7 g& h3 D, f/ H, O5 u3 y
% //从服务器的id地址和主机+ G8 s/ L; Z6 Z: m& m* |1 n( H+ p
openssl rand -base64 40 | cut -c 2-152 c& l6 k* ^# f9 Q' X m
+GVUrydHxuf4FK- i# [0 k* Y% t/ ^* n0 c
+ P2 B5 u" Z3 @6 f8 G* X3 O0 w( R8 f在主服务器创建授权账户:
- P$ c8 F: h" _5 P/ R+ r4 L' m$ Dmysql> grant replication slave,reload,super on *.* to 'slave'@'%' identified by '+GVUrydHxuf4FK';2 `9 n- V# |, P, a+ Q
#注:生产环境中密码采用高级别的密码,实际生产环境中将'%'换成slave的ip
. P" B0 t/ l/ S1 g5 e2 r$ }8 L# xmysql> flush privileges;1 _4 W) l( u; ^- s U; L e8 i# M
mysql> show master status; //查看状态
3 ?0 y3 v5 `% A4 j6 k% R: d7 i- {' ~, L, Y N, d
注意:如果不成功删除以前的binlog日志
# K) `, N4 p' I/ y6 I" Nreplication slave:拥有此权限可以查看从服务器,从主服务器读取二进制日志。
- v0 f0 M" ?+ O$ X6 r+ B; Rsuper权限:允许用户使用修改全局变量的SET语句以及CHANGE MASTER语句
" s4 u1 G9 R; V6 L6 K7 l" ~reload权限:必须拥有reload权限,才可以执行flush [tables | logs | privileges]
7 r, b# `: _4 J" Y9 E
. x7 Q/ D1 y ]slave操作(从服务器):" c" k7 j+ w, U$ z% {1 w2 m/ e
[root@mysql-slave ~]# vim /etc/my.cnf #添加如下配置
2 ~2 i' m" r5 J% w7 d
r0 M3 @ M$ c) Brelay-log-info-repository=TABLE //要不要这个表的数据记录; w5 X9 ]* K7 t; G |0 n8 Z
) L5 I7 l5 N. A* b# \, o
server-id=2
. B [' M% e3 ]6 lgtid_mode = ON
5 ?3 A0 x* P5 ^& {$ Jenforce_gtid_consistency=1* V( ~& O; Q8 `% d2 m: n$ u
master-info-repository=TABLE+ V1 [& q& U5 p* {' s7 z, C& G) H
relay-log-info-repository=TABLE# p* G& q- e3 h4 a
# p$ L+ w4 k; p) M4 A
在重启服务
$ r5 J& A" L" r0 T' D[root@mysql-slave ~]# systemctl restart mysqld
: V1 O' R1 m$ [: Q; a/ Z9 E& ~( @1 y. e/ j1 x7 E( b
检查一下有没有错误的配置文件 Q3 m6 ?. [4 {1 j; ?) ]
cat /usr/local/mysql/mysql.log 7 G+ l4 Y9 v; k5 W& N4 ?$ N
9 J: K" ^! x8 M8 J! }2 f1 b$ }
9 b. J5 G7 \' v, `5 F4 Gmaster_host='' //主服务器是多少
& `. o }# v- m# l8 G1 e; V" gmaster_user='' //账号是多少3 H1 M- ^- r. J2 W
master_password='+GVUrydHxuf4FK', //主服务器的密码是多少
$ S$ P/ e- \$ j2 V0 hmaster_auto_position=1; //主服务器的标识是几7 H+ F/ H7 P% m4 E1 i3 W ?
[root@mysql-slave ~]# mysql -uroot -p'123456' #登陆mysql& V4 b7 Y' C( j" f; x! D
q& T3 G. b8 _: g% S+ [" z7 N5 v5 P
mysql> change master to+ p3 i: m" {# z4 [ B3 j, W
master_host='192.168.171.15',) d3 E8 x" _0 ~
master_user='slave',
0 f" G' j3 y2 u: s1 E% ^master_password='+GVUrydHxuf4FK',
% ?" ?& o' |1 f! d0 V3 G. e) {master_auto_position=1;" T# U8 q' q: `( `% b0 S% P3 z% Z
Query OK, 0 rows affected, 2 warnings (0.02 sec)% k* D$ Q2 ~# Q# L9 c
+ j0 @0 Z O/ pmysql> start slave; #真实启动slave(从)角色5 n# r; ^3 Z+ y: ]4 |
mysql> show slave status\G #查看状态,验证sql和IO是不是yes。2 T7 |; k3 [2 ]3 K" n1 {' q% q( d
Slave_IO_Running: Yes //表示主从同步已经配置成功$ S0 C9 i+ t7 ]- R `4 V
Slave_SQL_Running: Yes9 e$ P) O) X$ y' f! \4 |; M9 {
; i4 q$ r3 p7 F& \! @
4、测试同步
# ]5 N s& U. ?/ r* B: Z) [5 W在主库新建数据库,在从库查看同步% v b/ v" c+ B; m# o4 p3 J6 r
6 S$ n$ \8 M7 c, S: z4 n
回到主服务器上: N8 S7 W5 U$ J3 l
mysql> show master status;
" Y' D: Z; u4 r! r( Z创建数据库
0 f. x! ?8 M" m1 u1 ^1 S9 {9 P1 Qmysql> create database test_db;9 n1 ]5 ^: w: \. E
主服务器状态码会发生变化为773
* W! \5 h6 u; @1 j% ~ cmysql> show master status;! n6 ]6 Z, h2 e* m
回到从服务器上 状态码也会发生变化为773
9 K G! c3 @ ~5 |( E9 h* Hmysql> show slave status\G & x( J/ _9 x5 _- }
查看test_db库是否存在
# u9 l' z6 ]* v6 Q% Omysql> show databases;
6 w" ~- \2 [! e( N8 x8 b5 B0 l/ {: M
在主服务器上创建库shuihu
- c5 p- [: Q9 amysql -uroot -p'123456' -e"create database shuihu";
3 Z8 k7 `& w2 @2 t# V- L回到从服务器上 查看shuihu库是否存在. x8 _( x' W* s7 o$ _8 ~1 h
mysql> show databases;( U) y1 I! {% M2 a y8 j$ a
查看动态日志
' E2 F3 K3 q$ Q/ F3 @tail -f /usr/local/mysql/mysql.log( c W5 D( T9 S
- Y/ `+ S- h6 L7 w7 j% |5、重设从库4 H, s9 Q+ p- \ i3 Z0 {
什么场景需要重设从库,比如网络发生异常,主库地址(position)会发生变化,从库上方网络ok就可以做一次从连
+ G+ b7 C* \$ H$ ?& g' `
' s: H# }: J1 L6 ?7 i/ H5 d从库重设#全在从库执行(断开于主库之间的通信,脱离主从关系)
8 H2 E4 e/ L r, v# ~6 _' o" [mysql>stop slave;5 P- D, W; u# f: l6 [: k
mysql>reset slave;0 `1 G) K" B/ M1 q4 _; y
mysql>reset master;
) O% z% {- L) |1 y, ~0 `' _- g! b#从库的binlog已经无效了,所以要执行这个命令清空binlog( Y# E) e6 \* F% O5 A2 E* E2 Y
4 _/ Y; t+ T8 B4 ]& g2 x
mysql> change master to3 @) b4 }8 t! G3 |5 A
master_host='192.168.171.15',
: D: X( Z) S2 xmaster_user='slave',
- U: c7 {$ o9 ?/ I6 j( J/ g& Xmaster_password='+GVUrydHxuf4FK', 6 x5 |* H( @- c! m7 N! t6 r: V
master_auto_position=1;) R' \& ^, x% L( u
% x; a" u" y* O7 u: Q2 ^mysql> start slave; #启动slave角色
, |, Z5 D+ X& U7 n, q7 R% mQuery OK, 0 rows affected (0.00 sec)$ S6 ^. z2 \* N8 h3 b9 l$ {! ~
mysql> show slave status\G #查看状态,验证sql和IO是不是yes。
5 n- H8 \/ r, u) @
5 |* `- y% Z" [' u/ j( ^6、常见错误
3 e& P& W( F- c# x7 f0 aERROR 3081 (HY000): This operation cannot be performed with running replication threads; run STOP SLAVE FOR CHANNEL '' first
% \4 F- N; C' @, _, A如果遇到这种错误(是因为之前做主从同步的时候有残留)
% M: }- B' C* b( X5 z# F% N3 d R
要先断开服务
w' Q% P! a' x4 r- @& j4 x从库重设#全在从库执行(断开于主库之间的通信,脱离主从关系)
. k- u: U0 \* D3 V8 Mmysql>stop slave;, ^$ z4 q/ ~! R) S4 q" N1 ~7 t
mysql>reset slave;
" }: y9 h+ e% u: ]; ^- O3 G& Imysql>reset master;
- |* g9 D V3 B) Y% O在进行重启就ok了
( p6 M- P0 G) F T) Tsystemctl stop mysqld
8 m& o$ d" u6 V- K2 Esystemctl start mysqld, w1 M; L* f. i8 R4 D
% m* e6 k1 i) K/ l, Y4 e0 J. i, Y0 I4 G( s8 p
1 c% U: x# o1 e
$ C. z9 @- M% G% \- M! {常见故障1
F& E8 c4 l& Q: ZSlave has more GTIDs than the master has,using the master's SERVER_UUID) ?+ [- E) v' d6 G5 {
该问题代表从库获取到的GTID超过了主库,比如主库在未指定binlog文件名的同时修改了系统主机名,导致binlog全部被修改,从库就会判断失败;或者主库未配置双1参数时断电,导致从库提前获取到了还未执行的GTID,解决方法如下:9 B. G( s' ~& a n! f3 Q
重设从库% [( ?3 }) O# V/ }! k t
stop slave;/ V& F' a" G$ O) x
reset slave;
+ V2 J8 E0 u# d1 lreset master;
% M2 l: o7 _2 ]( f9 k2 M0 Z#从库的binlog已经无效了,所以要执行这个命令清空binlog
% h7 z! F# M t7 y5 [- Rchange master to/ m: E. |! S) N0 [
master_host='10.36.107.10',
" n% b) C% I5 @) ]+ A6 I. u) G9 Mmaster_port=3306,
3 f/ a/ G5 L" U6 umaster_user='slave',
3 D9 N3 U! o+ Dmaster_password='Qf@12345!',- Y5 l; D/ V9 H* n ?. w) M: l
master_auto_position=1;
3 g Q3 G$ s! M1 F4 L/ W5 X% w; }9 y: u# q7 V
常见故障2
' k; s$ t& h; n' I4 ^) R如果从库未指定relaylog的同时修改了系统主机名,只需要在从库重新执行一次同步; i7 G' \; A9 |6 U( G/ I6 r: z
stop slave;' V# N" s, k2 t% H4 D3 s3 a
reset slave;
6 Q. a, ?0 C+ e# w; j) f, vchange master to
Y. ~5 R. N, ?2 O% q* ymaster_host='10.36.107.10',
) f' s4 |6 y& `+ Q! smaster_port=3306,
0 _. P( O/ x" ?) B3 V- Nmaster_user='slave',
5 |. S0 C d" omaster_password='Qf@12345!', e, [1 X; z$ M5 @
master_auto_position=1;1 L; Y+ F" t7 F) w1 f% R! h
0 @+ W( H+ ]; {常见故障32 u$ T- L! J6 i' b/ b
Master_has_purged_require_gtids# s$ M3 B3 Z& ?( {0 d; s
主库提前删除了还未同步完成的binlog7 K% [ N% Q; A9 C/ ^/ g
在主库上查看master信息% `( Z0 d' B# T3 g
mysql> show master status\G;) M& h- T P2 I* U
*************************** 1. row ***************************
1 U+ `* j& r) O4 n! M2 d3 ? File: mylog.000001
$ p. c; d' j' @! K" O6 S) k Position: 4655 E7 R0 ?6 J: w! A, I! q% w
Binlog_Do_DB:
$ R; r, _1 h9 _/ Y* K0 } Binlog_Ignore_DB:
8 b* ?4 f+ E: F, q2 ?) U( {# }% H0 rExecuted_Gtid_Set: 402c0020-4012-11ed-8d7e-000c292b8f0e:1-2
8 E2 X8 t6 }# v7 i1 row in set (0.00 sec). X+ V& k% ?0 W4 T/ o, Z5 g
#在从库上手动指定二进制日志文件master_log_file和位置master_log_pos与master上的一致
, M1 ~# Y8 b# k \mysql > stop slave;
+ s1 M! |& \$ V4 [, B" P2 V2 Jmysql > change master to . X2 m/ Q) ^8 w
master_host='10.36.107.10',
( |; L" e C4 [: Dmaster_user='slave',
/ G- ]7 g6 w emaster_password='Qf@12345!',% j% k7 s7 }1 s W9 y/ N' k& v
master_log_file='mylog.000001',% o& g( ^5 E* ?& ^5 K
master_log_pos=465,( S* j8 P6 q0 ~, J7 I0 S; X( I1 o# x
master_auto_position=0;
* j2 F: c: X+ y# i+ w/ _' Vmysql > start slave;5 V. i1 @/ R* r, K; o. F
6 L5 g& j3 H. }3 h( s; s6、故障切换( Q9 I- O: o; C# o2 j0 w
丛库可以创数据库 但是主库是不会有的( m+ W. P3 J# Q/ c6 }9 _* T2 r! w
% \! j, P1 ~( {' g6 y) ^# [5 ]
mysql主从,主服务器发生故障,如何进行切换?
* n/ Z7 K/ G( W) a主机故障,要把从服务器替换成主服务器! y* r3 C( d" z- I- q
# F8 s" u! `3 R1)在从服务器执行:(脱离主从关系)) K- X) T4 P! l% q; ~: j& s" j
mysql> stop slave;
$ c [" A1 q2 U- Hmysql> reset master;$ y% M: s3 d- d: n
; u# N5 q+ J. T. _: d/ R
' ]/ N- T' z- @( ?' B% X4 x2 z/ t2)查看是否只读模式:(此时只读模式是关闭模式 OFF)% `. d/ o# Q) `* e: u5 i
show variables like 'read_only';; ?4 l- K- v8 b9 ?
关闭只读模式+ A1 Z3 K; N& r; f
vim /etc/my.cnf
' P& X9 e0 g' l P0 Qread-only=1
- l# F8 r( M# E9 h- r并重启mysql服务# B5 G# f. c: A5 ?" u
systemctl restart mysqld
) J; i7 \* z/ d# {% f7 h! c8 e8 q5 y* ^1 |& H
或者不重启使用命令关闭只读,但下次重启后失效:set global read_only=off;
& [1 f, I* R8 s$ d* t2 c3)查看show slave status \G;
+ `, S/ Y8 F0 ^# U( \: u* i) ^4)在程序中将原来主库IP地址改为现在的从库IP地址,测试应用连接是否正常* U/ P6 l) K! q/ a& w2 d
- j6 g% y& F: N( R* V
2 m9 Q5 @$ H& G) ]$ g
|
|