环境介绍:
最近网站总是出问题,因为play服务总是跑着跑着就死了,于是经理尝试把play跑在我的MySQL这两台服务器上(因为这两台服务器的资源很空闲),可是没想到才跑了半天,就把服务器的128G内存耗尽,服务器无法正常使用,输入任何命令都报错,无法分配内存,reboot都不可以,只能去机房强制关机了。
我这里一两台,主主复制的mysql:
192.10.0.143
192.10.0.144
通过keepalived映射出来了vip:192.10.0.145,目前vip在144上。
重启的是143.
启动之后,mysql服务成功开启了,可是主从状态报错,sql进程状态为NO,如下:
MariaDB [(none)]> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.144
Master_User: info_syncer
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000823
Read_Master_Log_Pos: 60049919
Relay_Log_File: mysql-relay-bin.000047
Relay_Log_Pos: 268334387
Relay_Master_Log_File: mysql-bin.000822
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: 1594
Last_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
Skip_Counter: 0
Exec_Master_Log_Pos: 268334100
Relay_Log_Space: 535066509
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: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1594
Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
Replicate_Ignore_Server_Ids:
Master_Server_Id: 2
Master_SSL_Crl:
Master_SSL_Crlpath:
Using_Gtid: No
Gtid_IO_Pos:
1 row in set (0.00 sec)
ERROR: No query specified
报错原因:
从上面红体字可以知道,由于从库的异常关机,导致接收的主库的二进制日志崩溃,进而导致从库的relay日志损坏,sql进程无法读取,导致从库的sql进程状态为:NO。
问题解决:
MariaDB [(none)]> stop slave ;
Query OK, 0 rows affected (0.00 sec)
解决方法一:
找到,第一行记录了当前正在执行的log-relay文件名
找到该文件的下一个文件
使用mysqlbinlog查看该文件,在#98这行有Rotate to log-bin.000004 pos: 4等信息,这就是目前slave停止的位置 ,或者
在slave上重新指定同步位置,重新执行:
change master to
master_host='1.1.1.1',
master_user='repl',
master_password='111111',
master_port=3306,
master_log_file='log-bin.000004',
master_log_pos=4;
然后启动slave,
start slave ;
解决方法二:
stop slave之后,重新reset slave;
查看slave状态,正常了。。。。。
reset slave到底做了什么??
RESET SLAVE
官方的解释如下
1)RESET SLAVE makes the slave forget its replication position in the master's binary log. This statement is meant to be used for a clean start: It clears the master info and relay log info repositories, deletes all the relay log files, and starts a new relay log file. It also resets to 0 the replication delay specified with the MASTER_DELAY option to CHANGE MASTER TO. To use RESET SLAVE, the slave replication threads must be stopped (use STOP SLAVE if necessary).
2)RESET SLAVE does not change any replication connection parameters such as master host, master port, master user, or master password, which are retained in memory. This means that START SLAVE can be issued without requiring a CHANGE MASTER TO statement following
reset slave
其实,它是直接删除master.info和relay-log.info文件,并删除所有的relay log,然后重新生成一个新的relay log,即使relay log中还有SQL没有被SQL线程apply完。
但是RESET SLAVE有个问题,它虽然删除了上述文件,但内存中的change master信息并没有删除,此时,可直接执行start slave,但因为删除了master.info和relay-log.info,它会从头开始接受主的binlog并应用。(注意:这里所说的从头是说:reset的时候,正在接受的主的binlog,从新接受这个binlog).如果SQL thread 正在复制临时表的过程中,执行了stop slave ,并且执行了reset slave,这些被复制的临时表将被删除。
题外话:reset master 做了什么?
1. reset master 将删除日志索引文件中记录的所有binlog文件,创建一个新的日志文件 起始值从000001 开始,
2. reset master 不能用于有任何slave 正在运行的主从关系的主库。因为在slave 运行时刻 reset master 命令不被支持,reset master 将master 的binlog从000001 开始记录,slave 记录的master log 则是reset master 时主库的最新的binlog,从库会报错无法找的指定的binlog文件。
继续解决问题:
主从状态正常后,查看告警日志,发现报错
告警日志报错:表crashed,需要repaire
ERROR] log.logs: 1 client is using or hasn't closed the table properly
170310 11:54:14 [ERROR] mysqld: Table './log/oprlogs' is marked as crashed and should be repaired
170310 11:54:14 [Warning] Checking table: './log/oprlogs'
170310 11:54:14 [ERROR] log.oprlogs: 1 client is using or hasn't closed the table properly
170310 11:54:14 [ERROR] log.oprlogs: Size of datafile is: 1656831165 Should be: 1656830670
170310 11:54:47 [ERROR] log.oprlogs: Found 495 deleted space. Should be 0
170310 11:54:47 [ERROR] log.oprlogs: Found 15 deleted blocks Should be: 0
170310 11:54:47 [ERROR] log.oprlogs: Found 50207005 key parts. Should be: 50206990
170310 11:54:47 [ERROR] mysqld: Table './log/history' is marked as crashed and should be repaired
170310 11:54:47 [Warning] Checking table: './log/history'
170310 11:54:47 [ERROR] log.history: 1 client is using or hasn't closed the table properly
直接repair table table_name就可以了。。。。,依次修复日志中出现的被标记为crashed的表。
MariaDB [(none)]> repair table log.logs;
下面讲下修复 table:整理自网络。。。。。
多数情况下,数据库被破坏只是指索引文件受到了破坏,真正的数据被破坏掉的情况非常少。大多数形式的数据库破坏的的修复相当简单。
和前面的校验一样,修复的方式也有三种。
下面讲的方法只对MyISAM格式的表有效。其他类型的损坏需要从备份中恢复。
1,REPAIR TABLE SQL statement(mysql服务必须处于运行状态)。
2,命令mysqlcheck(mysql服务可以处于运行状态)。
3,命令myisamchk(必须停掉mysql服务,或者所操作的表处于不活动状态)。
在修复表的时候,最好先作一下备份。所以你需要两倍于原始表大小的硬盘空间。请确保在进行修复前你的硬盘空间还没有用完。
1>用”repair table”方式修复
语法:repair table 表名 [选项]
选项如下:
QUICK 用在数据表还没被修改的情况下,速度最快
EXTENDED 试图去恢复每个数据行,会产生一些垃圾数据行,万般无奈的情况下用
USE_FRM 用在.MYI文件丢失或者头部受到破坏的情况下。利用.frm的定义来重建索引
多数情况下,简单得用”repair table tablename”不加选项就可以搞定问题。但是当.MYI文件丢失或者头部受到破坏时,这样的方式不管用,例如:
mysql> REPAIR TABLE mytable;
+————————-+——–+———-+———————————————+
| Table | Op | Msg_type | Msg_text |
+————————-+——–+———-+———————————————+
| sports_results.mytable | repair | error | Can’t find file: ‘mytable.MYI’ (errno: 2) |
+————————-+——–+———-+———————————————+
修复失败的原因时索引文件丢失或者其头部遭到了破坏,为了利用相关定义文件来修复,需要用USE_FRM选项。例如:
mysql> REPAIR TABLE mytable USE_FRM;
+————————-+——–+———-+————————————+
| Table | Op | Msg_type | Msg_text |
+————————-+——–+———-+————————————+
| sports_results.mytable | repair | warning | Number of rows changed from 0 to 2 |
| sports_results.mytable | repair | status | OK |
+————————-+——–+———-+————————————+
我们可以看到Msg_test表项的输出信息”ok”,表名已经成功修复受损表。
2>用mysql内建命令mysqlcheck来修复
当mysql服务在运行时,也可以用mysql内建命令mysqlcheck来修复。
语法:mysqlcheck -r 数据库名 表名 -uuser -ppass
%mysqlcheck -r sports_results mytable -uuser -ppass
sports_results.mytable OK
利用mysqlcheck可以一次性修复多个表。只要在数据库名后列出相应表名即可(用空格隔开)。或者数据库名后不加表名,将会修复数据库中的所有表,例如:
%mysqlcheck -r sports_results mytable events -uuser -ppass
sports_results.mytable OK
sports_results.events OK
%mysqlcheck -r sports_results -uuser -ppass
sports_results.mytable OK
sports_results.events OK
3>用myisamchk修复
用这种方式时,mysql服务必须停掉,或者所操作的表处于不活动状态(选项skip-external-locking没被使用)。记着一定要在相关.MYI文件的路径下或者自己定义其路径。
语法:myisamchk [选项] [表名]
下面是其选项和描述
–backup, -B 在进行修复前作相关表得备份
–correct-checksum 纠正校验和
–data-file-length=#, -D # 重建表时,指定数据文件得最大长度
–extend-check, -e 试图去恢复每个数据行,会产生一些垃圾数据行,万般无奈的情况下用
–force, -f 当遇到文件名相同的.TMD文件时,将其覆盖掉。
keys-used=#, -k # 指定所用的keys可加快处理速度,每个二进制位代表一个key.第一个key为0
–recover, -r 最常用的选项,大多数破坏都可以通过它来修复。如果你的内存足够大,可以增大参数sort_buffer_size的值来加快恢复的速度。但是遇到唯一键由于破坏而不唯一 的表时,这种方式不管用。
–safe-recover -o 最彻底的修复方式,但是比-r方式慢,一般在-r修复失败后才使用。这种方式读出 所有的行,并以行为基础来重建索引。它的硬盘空间需求比-r方式稍微小一点,因 为它没创建分类缓存。你可以增加key_buffer_size的值来加快修复的速度。
–sort-recover, -n mysql用它类分类索引,尽管结果是临时文件会非常大
–character-sets-dir=… 包含字符集设置的目录
–set-character-set=name 为索引定义一个新的字符集
–tmpdir=path, -t 如果你不想用环境变量TMPDIR的值的话,可以自定义临时文件的存放位置
–quick, -q 最快的修复方式,当数据文件没有被修改时用,当存在多键时,第二个-q将会修改 数据文件
–unpack, -u 解开被myisampack打包的文件
myisamchk应用的一个例子
% myisamchk -r mytable
- recovering (with keycache) MyISAM-table ‘mytable.MYI’
题外引申。。。
REPAIR TABLE `table_name` 修复表
OPTIMIZE TABLE `table_name` 优化表
REPAIR TABLE语句被写入二进制日志中,除非使用了自选的NO_WRITE_TO_BINLOG关键词(或其别名LOCAL)。
REPAIR TABLE 用于修复被破坏的表。
OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)。 多数时间并不需要运行OPTIMIZE TABLE,只需在批量删除数据行之后,或定期(每周一次或每月一次)进行一次数据表优化操作即可,只对那些特定的表运行。
从新chang 的日志位置和日志号
无论是新搭建主从复制,还是
在拷贝之前要先锁定数据,然后再获得相关的日志信息(FILE & POSITION):
mysql> FLUSH TABLES WITH READ LOCK; 锁表,一般新加主从的时候,保重一致性
MariaDB [log]> SHOW MASTER STATUS;
+------------------+-----------+--------------+--------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+-----------+--------------+--------------------------+
| mysql-bin.000825 | 287366341 | | mysql,information_schema |
+------------------+-----------+--------------+--------------------------+
1 row in set (0.00 sec)
接下来拷贝数据文件时,如果是MyISAM表类型的话,直接拷贝即可;如果是InnoDB表类型的话,一定要先停止MySQL服务再拷贝,否则拷贝文件可能无法使用。把拷贝的数据文件直接复制到从服务器的数据目录。
最后还需要再指定一下日志信息:
mysql> CHANGE MASTER TO
MASTER_HOST="",
MASTER_USER="",
MASTER_PASSWORD="",
MASTER_LOG_FILE="",
MASTER_LOG_POS=;
在主服务器上直接拷贝数据文件虽然很快,但需要锁表或者停止服务,这会影响线上服务。如果先前已经有了从服务器,那么可以用旧的从服务器做母本来克隆新的从服务器:
先在旧的从服务器上查询日志信息:
mysql> SHOW SLAVE STATUS;
我们需要的是其中的Relay_Master_Log_File & Exec_Master_Log_Pos。
然后在旧的从服务器上按照前面的方法得到数据,可以先stop slave,然后拷贝数据并在新的从服务器上还原。
接着在新的从服务器上设置日志信息:
mysql> CHANGE MASTER TO
MASTER_HOST="",
MASTER_USER="",
MASTER_PASSWORD="",
MASTER_LOG_FILE="",
MASTER_LOG_POS=;
不管用那个方法,最后记得在从服务器上启动复制,并检查工作是否正常:
mysql> START SLAVE;
mysql> SHOW SLAVE STATUS;
注意:
MariaDB [(none)]> show slave status\G;
显示的Master_Log_File和 Read_Master_Log_Pos 这两个只对应这master
show master status\G;的文件号和位置
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.0.143
Master_User: info_syncer
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000019
Read_Master_Log_Pos: 1038
总结:万不得一不要在服务还没有停的情况下去停服务器,尤其是数据库,否则会出现意想不到的错误,但是当服务器出现不可解决的问题的时候,一定要果断的去重启,不要犹豫,难免出现更严重的问题,再就是play或者tomcat等等这些服务最好分开跑,以免互相影响。