本文例子是以docker基础上搭建Mysql 5.7 版本的主从,能够直接用于物理服务器上.mysql
macOS Mojave 10.14
docker 18.09.9
my.cnf
文件vim ~/Item/conf/mysql_master.cnf ## 这是macOS下路径,仅做参考
sql
[client]
port = 3306
socket = /tmp/mysql.sock
[mysqld]
port = 3306
socket = /tmp/mysql.sock
# 不启用避免 error-message file not find
# basedir = /usr/share/mysql/
datadir = /var/lib/mysql
pid-file = /var/lib/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1 #表示是本机的序号为1,通常来说就是master的意思
#log-bin设置此参数表示启用binlog功能,并指定路径名称
log-bin=/var/lib/mysql/mysql-bin
sync_binlog=0
#设置日志的过时天数,最好避免7,30等数字,避免被人恶意利用
expire_logs_days=8
skip-name-resolve
# 禁止MySQL对外部链接进行DNS解析,使用这一选项能够消除MySQL进行DNS解析的时间。但须要注意,若是开启该选项,
# 则全部远程主机链接受权都要使用IP地址方式,不然MySQL将没法正常处理链接请求
# 关闭MySQL的TCP/IP链接方式
# 仅在单机状况下使用
#skip-networking
back_log = 600
# MySQL能有的链接数量。当主要MySQL线程在一个很短期内获得很是多的链接请求,这就起做用,
# 而后主线程花些时间(尽管很短)检查链接而且启动一个新线程。back_log值指出在MySQL暂时中止回答新请求以前的短期内多少个请求能够被存在堆栈中。
# 若是指望在一个短期内有不少链接,你须要增长它。也就是说,若是MySQL的链接数据达到max_connections时,新来的请求将会被存在堆栈中,
# 以等待某一链接释放资源,该堆栈的数量即back_log,若是等待链接的数量超过back_log,将不被授予链接资源。
# 另外,这值(back_log)限于您的操做系统对到来的TCP/IP链接的侦听队列的大小。
# 你的操做系统在这个队列大小上有它本身的限制(能够检查你的OS文档找出这个变量的最大值),试图设定back_log高于你的操做系统的限制将是无效的。
max_connections = 1000
# MySQL的最大链接数,若是服务器的并发链接请求量比较大,建议调高此值,以增长并行链接数量,固然这创建在机器能支撑的状况下,由于若是链接数越多,介于MySQL会为每一个链接提供链接缓冲区,就会开销越多的内存,因此要适当调整该值,不能盲目提升设值。能够过’conn%’通配符查看当前状态的链接数量,以定夺该值的大小。
max_connect_errors = 6000
# 对于同一主机,若是有超出该参数值个数的中断错误链接,则该主机将被禁止链接。如需对该主机进行解禁,执行:FLUSH HOST。
open_files_limit = 65535
# MySQL打开的文件描述符限制,默认最小1024;当open_files_limit没有被配置的时候,比较max_connections*5和ulimit -n的值,哪一个大用哪一个,
# 当open_file_limit被配置的时候,比较open_files_limit和max_connections*5的值,哪一个大用哪一个。
table_open_cache = 128
# MySQL每打开一个表,都会读入一些数据到table_open_cache缓存中,当MySQL在这个缓存中找不到相应信息时,才会去磁盘上读取。默认值64
# 假定系统有200个并发链接,则需将此参数设置为200*N(N为每一个链接所需的文件描述符数目);
# 当把table_open_cache设置为很大时,若是系统处理不了那么多文件描述符,那么就会出现客户端失效,链接不上
max_allowed_packet = 4M
# 接受的数据包大小;增长该变量的值十分安全,这是由于仅当须要时才会分配额外内存。例如,仅当你发出长查询或MySQLd必须返回大的结果行时MySQLd才会分配更多内存。
# 该变量之因此取较小默认值是一种预防措施,以捕获客户端和服务器之间的错误信息包,并确保不会因偶然使用大的信息包而致使内存溢出。
binlog_cache_size = 1M
# 一个事务,在没有提交的时候,产生的日志,记录到Cache中;等到事务提交须要提交的时候,则把日志持久化到磁盘。默认binlog_cache_size大小32K
max_heap_table_size = 8M
# 定义了用户能够建立的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变
tmp_table_size = 16M
# MySQL的heap(堆积)表缓冲大小。全部联合在一个DML指令内完成,而且大多数联合甚至能够不用临时表便可以完成。
# 大多数临时表是基于内存的(HEAP)表。具备大的记录长度的临时表 (全部列的长度的和)或包含BLOB列的表存储在硬盘上。
# 若是某个内部heap(堆积)表大小超过tmp_table_size,MySQL能够根据须要自动将内存中的heap表改成基于硬盘的MyISAM表。还能够经过设置tmp_table_size选项来增长临时表的大小。也就是说,若是调高该值,MySQL同时将增长heap表的大小,可达到提升联接查询速度的效果
read_buffer_size = 2M
# MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。
# 若是对表的顺序扫描请求很是频繁,而且你认为频繁扫描进行得太慢,能够经过增长该变量值以及内存缓冲区大小提升其性能
read_rnd_buffer_size = 8M
# MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,
# MySQL会首先扫描一遍该缓冲,以免磁盘搜索,提升查询速度,若是须要排序大量数据,可适当调高该值。但MySQL会为每一个客户链接发放该缓冲空间,因此应尽可能适当设置该值,以免内存开销过大
sort_buffer_size = 8M
# MySQL执行排序使用的缓冲大小。若是想要增长ORDER BY的速度,首先看是否可让MySQL使用索引而不是额外的排序阶段。
# 若是不能,能够尝试增长sort_buffer_size变量的大小
join_buffer_size = 8M
# 联合查询操做所能使用的缓冲区大小,和sort_buffer_size同样,该参数对应的分配内存也是每链接独享
thread_cache_size = 8
# 这个值(默认8)表示能够从新利用保存在缓存中线程的数量,当断开链接时若是缓存中还有空间,那么客户端的线程将被放到缓存中,
# 若是线程从新被请求,那么请求将从缓存中读取,若是缓存中是空的或者是新的请求,那么这个线程将被从新建立,若是有不少新的线程,
# 增长这个值能够改善系统性能.经过比较Connections和Threads_created状态的变量,能够看到这个变量的做用。(–>表示要调整的值)
# 根据物理内存设置规则以下:
# 1G —> 8
# 2G —> 16
# 3G —> 32
# 大于3G —> 64
query_cache_size = 8M
#MySQL的查询缓冲大小(从4.0.1开始,MySQL提供了查询缓冲机制)使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中,
# 从此对于一样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。根据MySQL用户手册,使用查询缓冲最多能够达到238%的效率。
# 经过检查状态值’Qcache_%’,能够知道query_cache_size设置是否合理:若是Qcache_lowmem_prunes的值很是大,则代表常常出现缓冲不够的状况,
# 若是Qcache_hits的值也很是大,则代表查询缓冲使用很是频繁,此时须要增长缓冲大小;若是Qcache_hits的值不大,则代表你的查询重复率很低,
# 这种状况下使用查询缓冲反而会影响效率,那么能够考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE能够明确表示不使用查询缓冲
query_cache_limit = 2M
#指定单个查询可以使用的缓冲区大小,默认1M
key_buffer_size = 4M
#指定用于索引的缓冲区大小,增长它可获得更好处理的索引(对全部读和多重写),到你能负担得起那样多。若是你使它太大,
# 系统将开始换页而且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。经过检查状态值Key_read_requests和Key_reads,
# 能够知道key_buffer_size设置是否合理。比例key_reads/key_read_requests应该尽量的低,
# 至少是1:100,1:1000更好(上述状态值可使用SHOW STATUS LIKE ‘key_read%’得到)。注意:该参数值设置的过大反而会是服务器总体效率下降
ft_min_word_len = 4
# 分词词汇最小长度,默认4
transaction_isolation = REPEATABLE-READ
# MySQL支持4种事务隔离级别,他们分别是:
# READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
# 如没有指定,MySQL默认采用的是REPEATABLE-READ,ORACLE默认的是READ-COMMITTED
log_bin = mysql-bin
binlog_format = mixed
expire_logs_days = 30 #超过30天的binlog删除
# 日志暂时不启动
# log_error = /var/log/mysql/mysql-error.log #错误日志路径
# slow_query_log = 1
# long_query_time = 1 #慢查询时间 超过1秒则为慢查询
# slow_query_log_file = /var/log/mysql/mysql-slow.log
performance_schema = 0
explicit_defaults_for_timestamp
#lower_case_table_names = 1 #不区分大小写
skip-external-locking #MySQL选项以免外部锁定。该选项默认开启
default-storage-engine = InnoDB #默认存储引擎
innodb_file_per_table = 1
# InnoDB为独立表空间模式,每一个数据库的每一个表都会生成一个数据空间
# 独立表空间优势:
# 1.每一个表都有自已独立的表空间。
# 2.每一个表的数据和索引都会存在自已的表空间中。
# 3.能够实现单表在不一样的数据库中移动。
# 4.空间能够回收(除drop table操做处,表空不能自已回收)
# 缺点:
# 单表增长过大,如超过100G
# 结论:
# 共享表空间在Insert操做上少有优点。其它都没独立表空间表现好。当启用独立表空间时,请合理调整:innodb_open_files
innodb_open_files = 500
# 限制Innodb能打开的表的数据,若是库里的表特别多的状况,请增长这个。这个值默认是300
innodb_buffer_pool_size = 64M
# InnoDB使用一个缓冲池来保存索引和原始数据, 不像MyISAM.
# 这里你设置越大,你在存取表里面数据时所须要的磁盘I/O越少.
# 在一个独立使用的数据库服务器上,你能够设置这个变量到服务器物理内存大小的80%
# 不要设置过大,不然,因为物理内存的竞争可能致使操做系统的换页颠簸.
# 注意在32位系统上你每一个进程可能被限制在 2-3.5G 用户层面内存限制,
# 因此不要设置的过高.
innodb_write_io_threads = 4
innodb_read_io_threads = 4
# innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,根据你的 CPU 核数来更改,默认是4
# 注:这两个参数不支持动态改变,须要把该参数加入到my.cnf里,修改完后重启MySQL服务,容许值的范围从 1-64
innodb_thread_concurrency = 0
# 默认设置为 0,表示不限制并发数,这里推荐设置为0,更好去发挥CPU多核处理能力,提升并发量
innodb_purge_threads = 1
# InnoDB中的清除操做是一类按期回收无用数据的操做。在以前的几个版本中,清除操做是主线程的一部分,这意味着运行时它可能会堵塞其它的数据库操做。
# 从MySQL5.5.X版本开始,该操做运行于独立的线程中,并支持更多的并发数。用户可经过设置innodb_purge_threads配置参数来选择清除操做是否使用单
# 独线程,默认状况下参数设置为0(不使用单独线程),设置为 1 时表示使用单独的清除线程。建议为1
innodb_flush_log_at_trx_commit = 2
# 0:若是innodb_flush_log_at_trx_commit的值为0,log buffer每秒就会被刷写日志文件到磁盘,提交事务的时候不作任何操做(执行是由mysql的master thread线程来执行的。
# 主线程中每秒会将重作日志缓冲写入磁盘的重作日志文件(REDO LOG)中。不论事务是否已经提交)默认的日志文件是ib_logfile0,ib_logfile1
# 1:当设为默认值1的时候,每次提交事务的时候,都会将log buffer刷写到日志。
# 2:若是设为2,每次提交事务都会写日志,但并不会执行刷的操做。每秒定时会刷到日志文件。要注意的是,并不能保证100%每秒必定都会刷到磁盘,这要取决于进程的调度。
# 每次事务提交的时候将数据写入事务日志,而这里的写入仅是调用了文件系统的写入操做,而文件系统是有 缓存的,因此这个写入并不能保证数据已经写入到物理磁盘
# 默认值1是为了保证完整的ACID。固然,你能够将这个配置项设为1之外的值来换取更高的性能,可是在系统崩溃的时候,你将会丢失1秒的数据。
# 设为0的话,mysqld进程崩溃的时候,就会丢失最后1秒的事务。设为2,只有在操做系统崩溃或者断电的时候才会丢失最后1秒的数据。InnoDB在作恢复的时候会忽略这个值。
# 总结
# 设为1固然是最安全的,但性能页是最差的(相对其余两个参数而言,但不是不能接受)。若是对数据一致性和完整性要求不高,彻底能够设为2,若是只最求性能,例如高并发写的日志服务器,设为0来得到更高性能
innodb_log_buffer_size = 2M
# 此参数肯定些日志文件所用的内存大小,以M为单位。缓冲区更大能提升性能,但意外的故障将会丢失数据。MySQL开发人员建议设置为1-8M之间
innodb_log_file_size = 32M
# 此参数肯定数据日志文件的大小,更大的设置能够提升性能,但也会增长恢复故障数据库所需的时间
innodb_log_files_in_group = 3
# 为提升性能,MySQL能够以循环方式将日志文件写到多个文件。推荐设置为3
innodb_max_dirty_pages_pct = 90
# innodb主线程刷新缓存池中的数据,使脏数据比例小于90%
innodb_lock_wait_timeout = 120
# InnoDB事务在被回滚以前能够等待一个锁定的超时秒数。InnoDB在它本身的锁定表中自动检测事务死锁而且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒
bulk_insert_buffer_size = 8M
# 批量插入缓存大小, 这个参数是针对MyISAM存储引擎来讲的。适用于在一次性插入100-1000+条记录时, 提升效率。默认值是8M。能够针对数据量的大小,翻倍增长。
myisam_sort_buffer_size = 8M
# MyISAM设置恢复表之时使用的缓冲区的尺寸,当在REPAIR TABLE或用CREATE INDEX建立索引或ALTER TABLE过程当中排序 MyISAM索引分配的缓冲区
myisam_max_sort_file_size = 10G
# 若是临时文件会变得超过索引,不要使用快速排序索引方法来建立一个索引。注释:这个参数以字节的形式给出
myisam_repair_threads = 1
# 若是该值大于1,在Repair by sorting过程当中并行建立MyISAM表索引(每一个索引在本身的线程内)
interactive_timeout = 28800
# 服务器关闭交互式链接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。默认值:28800秒(8小时)
wait_timeout = 28800
# 服务器关闭非交互链接以前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值,
# 取决于客户端类型(由mysql_real_connect()的链接选项CLIENT_INTERACTIVE定义)。参数默认值:28800秒(8小时)
# MySQL服务器所支持的最大链接数是有上限的,由于每一个链接的创建都会消耗内存,所以咱们但愿客户端在链接到MySQL Server处理完相应的操做后,
# 应该断开链接并释放占用的内存。若是你的MySQL Server有大量的闲置链接,他们不只会白白消耗内存,并且若是链接一直在累加而不断开,
# 最终确定会达到MySQL Server的链接上限数,这会报’too many connections’的错误。对于wait_timeout的值设定,应该根据系统的运行状况来判断。
# 在系统运行一段时间后,能够经过show processlist命令查看当前系统的链接状态,若是发现有大量的sleep状态的链接进程,则说明该参数设置的过大,
# 能够进行适当的调整小些。要同时设置interactive_timeout和wait_timeout才会生效。
## 参考:https://blog.csdn.net/chushoutaizhong/article/details/79972768
复制代码
## my.cnf 配置文件存放位置以实际状况而定,笔者这里是Mac下的路径
docker rm -f mysql_master \ ## 防止屡次重复建立
docker run -d --name mysql_master \
-v /Users/a/Item/conf/mysql_master.cnf:/etc/mysql/my.cnf \
-p 33306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
## 返回容器ID
>>> 2dca79d4ce07350294d9620cfea5050189ee074cbb1f84772e7c3eefd0144c8f
## 顺便获取主库的内网IP
docker inspect mysql_master | grep -w IPAddress
>>>"IPAddress": "172.17.0.2"
#### 建立从库的`my.cnf` 文件
```conf
[mysqld]
server-id=2 ## copy一份主库的配置后,只须要修改这里
复制代码
my.cnf
文件能够直接从主库copy一份过来,改下 server-id 就是从库的配置文件了docker
cp -f mysql_master.cnf mysql_slave.cnf
sed "s/server-id=1/server-id=2/g" mysql_slave.cnf
## 或者手动修改server-id 不为主库相同值
vim mysql_slave.cnf
[mysqld]
server-id = 2 ## 不跟主库相同即为从库
复制代码
## 注意:这里没有写对外开放端口,若是须要能够 -p port:port
docker rm -f mysql_slave \ ## 防止屡次重复建立
docker run -d --name mysql_slave \
-v /Users/a/Item/conf/mysql_slave.cnf:/etc/mysql/my.cnf \
-p 33307:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:5.7
## 返回容器ID
>>> 3578a4bf3da66bb644bf29cb8c5d81ca8099c81c8a7b41d32b99b88594271044
## 顺便获取从库的内网IP
docker inspect mysql_slave | grep -w IPAddress
>>>"IPAddress": "172.17.0.3"
复制代码
每一个从库使用MySQL用户名和密码链接到主库,所以主库上必须有用户账户,从库能够链接。任何账户均可以用于此操做,只要它已被授予 REPLICATION SLAVE权限。能够选择为每一个从库建立不一样的账户,或者每一个从库使用相同账户链接到主库数据库
虽然没必要专门为复制建立账户,但应注意,复制用到的用户名和密码会以纯文本格式存储在主信息存储库文件或表中 。所以,须要建立一个单独的账户,该账户只具备复制过程的权限,尽可能控制vim
## 注!生产环境上禁止把密码写在命令行上
docker exec -it mysql_master mysql -uroot -p123456
复制代码
以root登录主库,给从库添加帐号和受权,每增长一个从库都得须要从新受权缓存
GRANT REPLICATION SLAVE,RELOAD,SUPER ON *.* TO 'slave_copy'@'172.17.0.3' IDENTIFIED BY 'RememberChargePass';
grant FILE on *.* to 'slave_copy'@'172.17.0.3' identified by 'RememberChargePass';
flush privileges;
复制代码
查看 Master-Server ,binlog File 文件名称和 Position值位置 而且记下来安全
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 904 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
复制代码
要设置从库与主库进行通讯,进行复制,在从库下执行如下语句bash
docker exec -it mysql_slave mysql -uroot -p123456
复制代码
参数格式服务器
mysql> CHANGE MASTER TO
-> MASTER_HOST='master_host_name',
-> MASTER_USER='replication_user_name',
-> MASTER_PASSWORD='replication_password',
-> MASTER_LOG_FILE='recorded_log_file_name',
-> MASTER_LOG_POS=recorded_log_position;
复制代码
实际状况并发
CHANGE MASTER TO
MASTER_HOST='172.17.0.2',
MASTER_USER='slave_copy',
MASTER_PASSWORD='RememberChargePass',
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=904;
复制代码
从库开启复制线程
mysql> START SLAVE;
Query OK, 0 rows affected (0.01 sec)
复制代码
查看从库同步状态
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: slave_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 904
Relay_Log_File: 779f104f69e3-relay-bin.000002
Relay_Log_Pos: 1070
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 904
Relay_Log_Space: 1284
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: dbd0d8d2-ea7c-11e9-9b86-0242ac110002
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
复制代码
检查主从复制通讯状态
Slave_IO_State
#从站的当前状态Slave_IO_Running
Yes #读取主程序二进制日志的I/O线程是否正在运行Slave_SQL_Running
Yes #执行读取主服务器中二进制日志事件的SQL线程是否正在运行。与I/O线程同样Seconds_Behind_Master
#是否为0,0就是已经同步了在主库建立一张测试表并快速生成百万条测试数据
## 登录主库
docker exec -it mysql_master mysql -uroot -p123456
复制代码
-- 避免发生1814错误
set global log_bin_trust_function_creators=TRUE;
-- 建立生成长度为n的随机字符串的函数
DELIMITER // -- 修改MySQL delimiter:'//'
DROP FUNCTION IF EXISTS `rand_string` //
SET NAMES utf8 //
CREATE FUNCTION `rand_string` (n INT) RETURNS VARCHAR(255) CHARSET 'utf8'
BEGIN
DECLARE char_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE return_str varchar(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = concat(return_str, substring(char_str, FLOOR(1 + RAND()*62), 1));
SET i = i+1;
END WHILE;
RETURN return_str;
END //
-- 建立插入数据的存储过程
DROP PROCEDURE IF EXISTS `add_vote_record_memory` //
CREATE PROCEDURE `add_vote_record_memory`(IN n INT)
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE vote_num INT DEFAULT 0;
DECLARE group_id INT DEFAULT 0;
DECLARE status TINYINT DEFAULT 1;
WHILE i < n DO
SET vote_num = FLOOR(1 + RAND() * 10000);
SET group_id = FLOOR(0 + RAND()*3);
SET status = FLOOR(1 + RAND()*2);
INSERT INTO `vote_record_memory` VALUES (NULL, rand_string(20), vote_num, group_id, status, NOW());
SET i = i + 1;
END WHILE;
END //
DELIMITER ; -- 改回默认的 MySQL delimiter:';'
-- 调用存储过程 生成1000条数据
CALL add_vote_record_memory(1000);
复制代码
查看生成数据数量以及写入到普通表中
-- 查看内存表生成数据
mysql> SELECT count(*) FROM `vote_record_memory`;
+----------+
| count(*) |
+----------+
| 999 |
+----------+
1 row in set (0.00 sec)
-- 把数据从内存表插入到普通表中
mysql> REPLACE INTO vote_record SELECT * FROM `vote_record_memory`;
Query OK, 999 rows affected (0.02 sec)
Records: 999 Duplicates: 0 Warnings: 0
-- 查询普通表已的生成记录
SELECT count(*) FROM `vote_record`;
-- count(*)
-- 105646
复制代码
安装 mysqldiff
## Mac
brew install mysql-utilities
## Centos 6.5 +
yum install mysql-utilities
复制代码
使用方法
mysqldiff --server1='用户名:密码@mysql服务器地址' --server2='用户名:密码@mysql服务器地址' 数据库名:数据库名 --force
复制代码
检验结果
mysqldiff --server1='root:123456@172.17.0.2:3306' --server2='root:123456@172.17.0.3:3306' test_data:test_data --forc
# WARNING: Using a password on the command line interface can be insecure.
# server1 on 172.17.0.2: ... connected.
# server2 on 172.17.0.3: ... connected.
# WARNING: Objects in server1.test_data but not in server2.test_data:
# PROCEDURE: add_vote_record_memory
# FUNCTION: rand_string
# Comparing `test_data` to `test_data` [PASS]
# Comparing `test_data`.`runoob_tbl` to `test_data`.`runoob_tbl` [PASS]
# Comparing `test_data`.`vote_record` to `test_data`.`vote_record` [FAIL]
# Object definitions differ. (--changes-for=server1)
#
--- `test_data`.`vote_record`
+++ `test_data`.`vote_record`
@@ -7,4 +7,4 @@
`create_time` datetime NOT NULL DEFAULT '2019-01-01 00:00:00' COMMENT '建立时间',
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`) USING HASH COMMENT '用户ID哈希索引'
-) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT='投票记录表'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='投票记录表'
# Comparing `test_data`.`vote_record_memory` to `test_data`.`vote_record_memory` [FAIL]
# Object definitions differ. (--changes-for=server1)
#
--- `test_data`.`vote_record_memory`
+++ `test_data`.`vote_record_memory`
@@ -7,4 +7,4 @@
`create_time` datetime NOT NULL DEFAULT '2019-01-01 00:00:00',
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`) USING HASH
-) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
# Compare failed. One or more differences found.
复制代码
显示从库并无同步,排查缘由
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: slave_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 130170909
Relay_Log_File: bc723c0c914e-relay-bin.000004
Relay_Log_Pos: 9444
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: No
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 1418
Last_Error: Error 'This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)' on query. Default database: 'test_data'. Query: 'CREATE DEFINER=`root`@`%` FUNCTION `rand_string`(n INT) RETURNS varchar(255) CHARSET utf8 BEGIN DECLARE char_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; DECLARE return_str varchar(255) DEFAULT ''; DECLARE i INT DEFAULT 0; WHILE i < n DO SET return_str = concat(return_str, substring(char_str, FLOOR(1 + RAND()*62), 1)); SET i = i+1; END WHILE; RETURN return_str; END'
......
......
1 row in set (0.00 sec)
复制代码
发现是主库建立函数后,由于CREATE PROCEDURE, CREATE FUNCTION, ALTER PROCEDURE,ALTER FUNCTION,CALL, DROP PROCEDURE, DROP FUNCTION等语句都会被写进二进制日志,而后在从服务器上执行。可是,一个执行更新的不肯定子程序(存储过程、函数、触发器)是不可重复的,在从服务器上执行(相对与主服务器是重复执行)可能会形成恢复的数据与原始数据不一样,从服务器不一样于主服务器的状况。
为了解决这个问题,MySQL强制要求: 在主服务器上,除非子程序被声明为肯定性的或者不更改数据,不然建立或者替换子程序将被拒绝。 这意味着当建立一个子程序的时候,必需要么声明它是肯定性的,要么它不改变数据
-- 1. 检查从库的参数状态
mysql> show variables like '%function%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF |
+---------------------------------+-------+
1 row in set (0.01 sec)
-- 2.暂停复制线程
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
-- 3.设置log_bin_trust_function_creators 参数开启
mysql> set global log_bin_trust_function_creators=1;
Query OK, 0 rows affected (0.00 sec)
-- 4.检查是否开启
mysql> show variables like '%func%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | ON |
+---------------------------------+-------+
1 row in set (0.01 sec)
-- 5. 启动复制线程
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
-- 6. 检查从库状态.正常
mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.17.0.2
Master_User: slave_copy
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 130170909
Relay_Log_File: bc723c0c914e-relay-bin.000005
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 130170909
Relay_Log_Space: 130171502
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
Master_UUID: 841e9d15-ee45-11e9-b0cf-0242ac110002
Master_Info_File: /var/lib/mysql/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
复制代码