Mysql数据库的主从与主主

Wesley13
• 阅读 1080

前言:

首先,我们得知道我们为什么要做数据库的主从与主主,而后,再讨论他们的优劣与特点:为什么要做主从呢?因为Mysql数据库没有增量备份的机制,当数据量太大的时候备份是个难以解决的问题。但是mysql数据库有主从备份的机制,说白了就是把主数据库的所有的数据同时写到备份的数据库中。实现mysql数据库的热备份。 要想实现主从或主主,首先要满足主从数据库服务器的版本的需求。要实现热备,mysql的版本需要都高于5.5。还有一个基本的原则就是作为从数据库的数据版本可以高于主服务器数据库的版本,但是不可以低于主服务器的数据库版本。最好保持版本一致(其实要实现mysql双机热备,除了mysql本身自带的REPLICATION功能可以实现外,也可以用Heartbeat这个开源软件来实现。不过本文主要讲如何用mysql自带的REPLICATION来实现mysql主从或主主),而主主呢,就是两个数据库互为主从,这样的话,就可以实现另一个功能,这也是主主的优点:实现mysql的读写分离与高可用。ok,下面我们来着重了解其原理与配置实例:

一、工作原理:

Mysql主从复制的实现原理图大致如下(来源网络):

Mysql数据库的主从与主主

MySQL之间数据复制的基础是二进制日志文件(binary log file)。一台MySQL数据库一旦启用二进制日志后,其作为master,它的数据库中所有操作都会以“事件”的方式记录在二进制日志中,其他数据库作为slave通过一个I/O线程与主服务器保持通信,并监控master的二进制日志文件的变化,如果发现master二进制日志文件发生变化,则会把变化复制到自己的中继日志中,然后slave的一个SQL线程会把相关的“事件”执行到自己的数据库中,以此实现从数据库和主数据库的一致性,也就实现了主从复制。

二、主从复制实例:

1.准备工作与环境介绍:

A服务器(主服务器Master):59.151.15.36

B服务器(从服务器Slave):218.206.70.146

Linux环境下将主服务器需要同步的数据库内容进行备份一份,上传到从服务器上,保证始初时两服务器中数据库内容一致。

不过这里说明下,由于我是利用Mysql在安装后就有的数据库test进行测试的,所以两台服务器里面是没有建立表的,只不分别在test里面建立了同样的一张空表tb_mobile;

Sql语句如下:

mysql> create table tb_mobile( mobile VARCHAR(20) comment'手机号码', time timestamp DEFAULT now() comment'时间' );

2.Master服务器上创建同步用户:

进入mysql操作界面,在主服务器上为从服务器建立一个连接帐户,该帐户必须授予REPLICATION SLAVE权限。因为从mysql版本3.2以后就可以通过REPLICATION对其进行双机热备的功能操作。

操作指令如下:

mysql> grant replication slave on *.* to 'replicate'@'218.206.70.146' identified by '123456';

mysql> flush privileges;

创建好同步连接帐户后,我们可以通过在从服务器(Slave)上用replicat帐户对主服务器(Master)数据库进行访问下,看下是否能连接成功。

在从服务器(Slave)上输入如下指令:

[root@YD146 ~]# mysql -h59.151.15.36 -ureplicate -p123456

如果出现下面的结果,则表示登录成功,说明对这两台服务器进行主从操作的前提具备。

Mysql数据库的主从与主主

3.修改mysql的配置文件:

首先找到mysql配置所有在目录,一般在安装好mysql服务后,都会将配置文件复制一一份出来放到/ect目录下面,并且配置文件命名为:my.cnf。即配置文件准确目录为/etc/my.cnf

(Linux下用rpm包安装的MySQL是不会安装/etc/my.cnf文件的,

至于为什么没有这个文件而MySQL却也能正常启动和作用,这里有两种情况,

第一种:my.cnf只是MySQL启动时的一个参数文件,可以没有它,这时MySQL会用内置的默认参数启动,

第二种:MySQL在启动时自动使用/usr/share/mysql目录下的my-medium.cnf文件,这种说法仅限于rpm包安装的MySQL,

解决方法:只需要复制一个/usr/share/mysql目录下的my-medium.cnf文件到/etc目录,并改名为my.cnf即可。

找到配置文件my.cnf打开后,在[mysqld]下修改即可:

[mysqld]

server-id = 1

log-bin=mysql-bin                //其中这两行是本来就有的,可以不用动,添加下面两行即可

binlog-do-db = test

binlog-ignore-db = mysql

修改完配置文件,保存并重启mysql服务。而后查看master服务的状态:

输入如下指令:

Mysql数据库的主从与主主

注意看里面的参数,特别前面两个File和Position,在从服务器(Slave)配置主从关系会有用到的。

注:这里使用了锁表,目的是为了产生环境中不让进新的数据,好让从服务器定位同步位置,初次同步完成后,记得解锁。

Mysql数据库的主从与主主

4.salve服务器的配置:

直接打开配置文件my.cnf进行修改即可,道理还是同修改主服务器上的一样,只不过需要修改的参数不一样而已。如下:

[mysqld]

server-id = 2

log-bin=mysql-bin

replicate-do-db = test

replicate-ignore-db = mysql,information_schema,performance_schema

修改完配置文件后,保存后,重启一下mysql服务,如果成功则没问题。

Mysql数据库的主从与主主

5.用change mster 语句指定同步位置:

这步是最关键的一步了,在进入mysql操作界面后,输入如下指令:

mysql>stop slave;          //先停步slave服务线程,这个是很重要的,如果不这样做会造成以下操作不成功。

mysql>change master to

>master_host='59.151.15.36',master_user='replicate',master_password='123456',

> master_log_file=' mysql-bin.000016 ',master_log_pos=107;

注:master_log_file, master_log_pos由主服务器(Master)查出的状态值中确定。也就是刚刚叫注意的。master_log_file对应File, master_log_pos对应Position。Mysql 5.x以上版本已经不支持在配置文件中指定主服务器相关选项。

遇到的问题,如果按上面步骤之后还出现如下情况:

Mysql数据库的主从与主主
则要重新设置slave。指令如下

mysql>stop slave;

mysql>reset slave;

之后停止slave线程重新开始。成功后,则可以开启slave线程了。

mysql>start slave;

查看从服务器(Slave)状态:

用如下指令进行查看

mysql> show slave status\G;

Mysql数据库的主从与主主

查看下面两项值均为Yes,即表示设置从服务器成功。

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

6.测试:

之前开始已经说过了在数据库test只有一个表tb_mobile没有数据,我们可以先查看下两服务器的数据库是否有数据:

Master:59.151.15.36

Mysql数据库的主从与主主
Slave:218.206.70.146

Mysql数据库的主从与主主
好了,现在可以在Master服务器中插入数据看下是否能同步。

Master:59.151.15.36

Mysql数据库的主从与主主

Slave:218.206.70.146

Mysql数据库的主从与主主
可以从上面两个截图上看出,在Master服务器上进行插入的数据在Slave服务器可以查到,这就表示主从配置成功了。

7.注意要点:

1)主从复制是异步的逻辑的SQL语句级的复制

2)复制时,主库有一个I/O线程,从库有两个线程,I/O和SQL线程

3)实现主从复制的必要条件是主库要开启记录binlog功能

4)作为复制的所有Mysql节点的server-id都不能相同

5)binlog文件只记录对数据库有更改的SQL语句(来自主库内容的变更),不记录任何查询(select,show)语句

...................................................................................................

彻底解除主从复制关系

1)stop slave;

2)reset slave; 或直接删除master.info和relay-log.info这两个文件;

3)修改my.cnf删除主从相关配置参数。

让slave不随MySQL自动启动

修改my.cnf 在[mysqld]中增加 skip-slave-start 选项。

做了MySQL主从复制以后,使用mysqldump对数据备份时,一定要注意按照如下方式:

mysqldump --master-data --single-transaction --user=username --password=password dbname> dumpfilename

这样就可以保留 file 和 position 的信息,在新搭建一个slave的时候,还原完数据库, file 和 position 的信息也随之更新,接着再start slave 就可以很迅速

的完成增量同步!

需要限定同步哪些数据库,有3个思路:

1)在执行grant授权的时候就限定数据库;

2)在主服务器上限定binlog_do_db = 数据库名;

3)主服务器上不限定数据库,在从服务器上限定replicate-do-db = 数据库名;

[mysqld]

server-id=1 #数据库唯一ID,主从的标识号绝对不能重复。
log-bin=mysql-bin #开启bin-log,并指定文件目录和文件名前缀
binlog-do-db=liting  #需要同步liting数据库。如果是多个同步库,就以此格式另写几行即可。如果不指明对某个具体库同步,就去掉此行,表示同步所有库(除了ignore忽略的库)。
binlog-ignore-db=mysql #不同步mysql系统数据库。如果是多个不同步库,就以此格式另写几行;也可以在一行,中间逗号隔开。
sync_binlog = 1 #确保binlog日志写入后与硬盘同步
binlog_checksum = none #跳过现有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none
binlog_format = mixed #bin-log日志文件格式,设置为MIXED可以防止主键重复。

最后:在主服务器上最重要的二进制日志设置是sync_binlog,这使得mysql在每次提交事务的时候把二进制日志的内容同步到磁盘上,即使服务器崩溃也会把事件写入日志中。
sync_binlog这个参数是对于MySQL系统来说是至关重要的,他不仅影响到Binlog对MySQL所带来的性能损耗,而且还影响到MySQL中数据的完整性。对于"sync_binlog"参数的各种设置的说明如下:
sync_binlog=0,当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来做同步,或者cache满了之后才同步到磁盘。
sync_binlog=n,当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。

在MySQL中系统默认的设置是sync_binlog=0,也就是不做任何强制性的磁盘刷新指令,这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。而当设置为“1”的时候,是最安全但是性能损耗最大的设置。因为当设置为1的时候,即使系统Crash,也最多丢失binlog_cache中未完成的一个事务,对实际数据没有任何实质性影响。

三、双机热备:

1.理论上:先说说它的原理,两台mysql都可读写,互为主备,默认只使用一台(masterA)负责数据的写入,另一台(masterB)备用;masterA是masterB的主库,masterB又是masterA的主库,它们互为主从;两台主库之间做高可用,可以采用keepalived等方案(使用VIP对外提供服务);所有提供服务的从服务器与masterB进行主从同步(双主多从);

2.与主从相比,需要注意的地方:

主主复制和主从复制有一些区别,因为多主中都可以对服务器有写权限,所以设计到自增长重复问题,例如:
出现的问题(多主自增长ID重复)
1)首先在A和B两个库上创建test表结构;
2)停掉A,在B上对数据表test(存在自增长属性的ID字段)执行插入操作,返回插入ID为1;
3)然后停掉B,在A上对数据表test(存在自增长属性的ID字段)执行插入操作,返回的插入ID也是1;
4)然后 同时启动A,B,就会出现主键ID重复

解决方法:
只要保证两台服务器上的数据库里插入的自增长数据不同就可以了
如:A插入奇数ID,B插入偶数ID,当然如果服务器多的话,还可以自定义算法,只要不同就可以了
在下面例子中,在两台主主服务器上加入参数,以实现奇偶插入!
记住:在做主主同步时需要设置自增长的两个相关配置,如下:
auto_increment_offset 表示自增长字段从那个数开始,取值范围是1 .. 65535。这个就是序号。如果有n台mysql机器,则从第一台开始分为设1,2...n
auto_increment_increment 表示自增长字段每次递增的量,其默认值是1,取值范围是1 .. 65535。如果有n台mysql机器,这个值就设置为n。

在主主同步配置时,需要将两台服务器的:
auto_increment_increment 增长量都配置为2
auto_increment_offset 分别配置为1和2。这是序号,第一台从1开始,第二台就是2,以此类推.....
这样才可以避免两台服务器同时做更新时自增长字段的值之间发生冲突。(针对的是有自增长属性的字段)

3.修改并检验:

修改配置文件my.cnf

服务器A

[mysqld]

       server-id = 1

log-bin=mysql-bin 

binlog-do-db = test

       binlog-ignore-db = mysql

#主-主形式需要多添加的部分

       log-slave-updates

       sync_binlog = 1

       auto_increment_offset = 1

       auto_increment_increment = 2

       replicate-do-db = test

       replicate-ignore-db = mysql,information_schema

服务器B:

[mysqld]

server-id = 2

log-bin=mysql-bin 

master-slave need

       replicate-do-db = test

       replicate-ignore-db = mysql,information_schema,performance_schema

      

#主-主形式需要多添加的部分

       binlog-do-db = test

       binlog-ignore-db = mysql

       log-slave-updates

       sync_binlog = 1

       auto_increment_offset = 2

       auto_increment_increment = 2

分别重启A服务器和B服务器上的mysql服务,重启服务器方式和上面的一样,这里就不做讲解了。分别查A服务器和B服务器作为主服务器的状态

服务器A:

Mysql数据库的主从与主主
服务器B:

Mysql数据库的主从与主主
分别在A服务器和B服务器上用change master to 指定同步位置:

服务器A:

mysql>change master to

>master_host='218.206.70.146',master_user='replicate',master_password='123456',

> master_log_file=' mysql-bin.000011 ',master_log_pos=497;

服务器B:

mysql>change master to

>master_host='59.151.15.36',master_user='replicate',master_password='123456',

> master_log_file=' mysql-bin.000016 ',master_log_pos=107;

分别在A和B服务器上重启从服务线程

mysql>start slave;

分别在A和B服务器上查看从服务器状态

mysql>show slave status\G;

查看下面两项值均为Yes,即表示设置从服务器成功。

Slave_IO_Running: Yes

Slave_SQL_Running: Yes

测试主-主同步例子

测试服务器A:

在服务器A上插入一条语句如下图所示:

Mysql数据库的主从与主主
之后在服务器B上查看是否同步如下图所示:

Mysql数据库的主从与主主
测试服务器B:

在服务器B上插入一条语句如下图所示:

Mysql数据库的主从与主主
然后在从服务器A上查看是否有同步数据如下图所示:

Mysql数据库的主从与主主

Mysql数据库的主从与主主
最后从结果可以看出主-主形式的双机热备是能成功实现的。

四、配置参数的相关说明:

Server-id

ID值唯一的标识了复制群集中的主从服务器,因此它们必须各不相同。Master_id必须为1到232-1之间的一个正整数值,slave_id值必须为2到232-1之间的一个正整数值。

Log-bin

表示打开binlog,打开该选项才可以通过I/O写到Slave的relay-log,也是可以进行replication的前提。

Binlog-do-db

表示需要记录二进制日志的数据库。如果有多个数据可以用逗号分隔,或者使用多个binlog-do-dg选项。

Binglog-ingore-db

表示不需要记录二进制日志的数据库,如果有多个数据库可用逗号分隔,或者使用多binglog-ignore-db选项。

Replicate-do-db

表示需要同步的数据库,如果有多个数据可用逗号分隔,或者使用多个replicate-do-db选项。

Replicate-ignore-db

表示不需要同步的数据库,如果有多个数据库可用逗号分隔,或者使用多个replicate-ignore-db选项。

Master-connect-retry

master-connect-retry=n表示从服务器与主服务器的连接没有成功,则等待n秒(s)后再进行管理方式(默认设置是60s)。如果从服务器存在mater.info文件,它将忽略些选项。

Log-slave-updates

配置从库上的更新操作是否写入二进制文件,如果这台从库,还要做其他从库的主库,那么就需要打这个参数,以便从库的从库能够进行日志同步。

Slave-skip-errors

在复制过程,由于各种原因导致binglo中的sql出错,默认情况下,从库会停止复制,要用户介入。可以设置slave-skip-errors来定义错误号,如果复制过程中遇到的错误是定义的错误号,便可以路过。如果从库是用来做备份,设置这个参数会存在数据不一致,不要使用。如果是分担主库的查询压力,可以考虑。

Sync_binlog=1 Or N

Sync_binlog的默认值是0,这种模式下,MySQL不会同步到磁盘中去。这样的话,Mysql依赖操作系统来刷新二进制日志binary log,就像操作系统刷新其他文件的机制一样。因此如果操作系统或机器(不仅仅是Mysql服务器)崩溃,有可能binlog中最后的语句丢失了。要想防止这种情况,可以使用sync_binlog全局变量,使binlog在每N次binlog写入后与硬盘同步。当sync_binlog变量设置为1是最安全的,因为在crash崩溃的情况下,你的二进制日志binary log只有可能丢失最多一个语句或者一个事务。但是,这也是最慢的一种方式(除非磁盘有使用带蓄电池后备电源的缓存cache,使得同步到磁盘的操作非常快)。

即使sync_binlog设置为1,出现崩溃时,也有可能表内容和binlog内容之间存在不一致性。如果使用InnoDB表,Mysql服务器处理COMMIT语句,它将整个事务写入binlog并将事务提交到InnoDB中。如果在两次操作之间出现崩溃,重启时,事务被InnoDB回滚,但仍然存在binlog中。可以用-innodb-safe-binlog选项来增加InnoDB表内容和binlog之间的一致性。(注释:在Mysql 5.1版本中不需要-innodb-safe-binlog;由于引入了XA事务支持,该选项作废了),该选项可以提供更大程度的安全,使每个事务的binlog(sync_binlog=1)和(默认情况为真)InnoDB日志与硬盘同步,该选项的效果是崩溃后重启时,在滚回事务后,Mysql服务器从binlog剪切回滚的InnoDB事务。这样可以确保binlog反馈InnoDB表的确切数据等,并使从服务器保持与主服务器保持同步(不接收回滚的语句)。

Auto_increment_offset和Auto_increment_increment

Auto_increment_increment和auto_increment_offset用于主-主服务器(master-to-master)复制,并可以用来控制AUTO_INCREMENT列的操作。两个变量均可以设置为全局或局部变量,并且假定每个值都可以为1到65,535之间的整数值。将其中一个变量设置为0会使该变量为1。

这两个变量影响AUTO_INCREMENT列的方式:auto_increment_increment控制列中的值的增量值,auto_increment_offset确定AUTO_INCREMENT列值的起点。

如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值被忽略。例如:表内已有一些数据,就会用现在已有的最大自增值做为初始值。

最后,本篇博客来自我对网上博客的整理,在测试无误的情况下,对原博主的内容进行了相关的整理与补充,附上原文链接:

http://yunnick.iteye.com/blog/1845301

https://www.cnblogs.com/wade-lt/p/9008058.html

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这