二进制日志. 来记载让数据变更的日志。只有让数据有变化的语句日志才会被记录下来。
在MySQL 各库的目录下会有许多类似 mysql-bin.000001 这种文件.当然,这个是可以在 MySQL 配置文件
my.cnf 中配置的 (log-bin 和 log-bin-index).
另外,还有一个 binlog 索引文件。默认是 mysql-bin.index 用来追踪已有的 binlog
文件。以便服务器能在必要的时候创建正确的新的 binlog 文件。文件文件每一行都包括一个 binlog 文件的完整名称。
正常情况下,当数据库启动时会建一个新的 binlog 文件,也可以在命令中强行让数据库使用新的 binlog.
命令是: mysql> flush logs;
另外,binlog 每个文件有大小限制,当达到后就会新建一个新的使用。
由于 binlog
是所有库公用的,所以会出现多个库要写入内容的情况。为避免冲突,服务器会给它建一个互斥锁。这个锁可能会阻塞某些线程。另外,binlog
中记录的日志顺序可能和实际语句的执行顺序不一样。这样带来的问题就是,由于 binlog
中记录的是SQL语句,而日志顺序和实际执行顺序不一样,就会导致 master 和 slave
上面数据不一致。因为顺序不一样,更新的行可能也不一样。
MySQL
除了有上面说的这种基于让数据变更的SQL语句的复制。还提供基于行的复制,它就是将变更的行保存起来。两种方式各有补充。如果一条语句改动大量的行,肯定是直接记录语句更实用。如果有多个表连接的复杂更新,直接记行更简单。
show binlog events;
可以看到日志中有哪些事件。默认它会看第一个日志文件中的事件。如果要查看指定文件的内容,如下:
mysql> show binlog events in 'mysql-bin.000005'\G
*************************** 956. row
***************************
Log_name:
master-bin.000001
Pos: 147470
Event_type: Xid
Server_id: 1
End_log_pos: 147497
Info: COMMIT
*************************** 957. row
***************************
Log_name:
master-bin.000001
Pos: 147497
Event_type: Rotate
Server_id: 1
End_log_pos: 147541
Info: master-bin.000002;pos=4
所以,可以看当前正在使用的是哪个日志文件,然后看该文件中的内容
mysql> show master status;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB |
Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-bin.000005 | 40862252 | payment | test,mysql
|
+-------------------+----------+--------------+------------------+
查看当前主服务器的状态,该状态中 File 就是当前正在使用的文件。
binlog 到达 slave 后将日志中的语句再执行一遍。这个时候 slave 有几个是一定要明确的:
1.当前数据库
如果语句中引用了表,函数,或存储过程,但没有指定是哪个数据库,则默认是使用当前数据库的。
为解决该问题,记录日志时会多记一个字段,表示是哪个库。
2.rand 函数的种子
random 是基于伪随机数的函数,生成一系列可再生的数字。看上去是随机的,但实际上是均匀分布的。如果种子相同,rand
函数生成的值是一样的。
如果用到了该函数,binlog 会把种子记下。
3.当前时间.now()
如果master 和 slave 上执行有延迟,该函数的结果就不一样了。
now() 是返回语句开始执行时的时间。为了保证主从返回的时间一样,binlog
会记下每个事件的时间戳表明事件是何时开始执行的。
4.auto_increment 的值
这个值是和上一条语句有关。
如果有用到这个的,binlog 会记下这个值。
5.last_insert_id 的值
同样,这个值也取决于上条记录。
如果用到这个,binlog 会记下这个值。
6.线程 ID
如果SQL中使用了临时表或者调用了 CURRENT_ID 函数。该值可能不一样。
影响数据的SQL语句(DML): delete, insert, update 肯定会被记入 binlog
中。为了保证安全的记录日志,MySQL 在获取事务级锁时写
binlog.然后在日志写操作完成后释放锁。表未释放锁之前,在语句提交的同时将语句写入binlog.这样保证 binlog
始终与语句的更新一致。过程如下:
解析到DML --> 获得锁 --> 提交语句到引擎 & 写入 binlog -->
释放锁
影响数据库结构的SQL语句(DDL): create table, alter table
会改变数据库的结构。而我们的数据库结构是定义在库所在目录下的后缀名为 .frm 的文件中.
为了保护这些内部数据结构的更新,在修改表结构的语句执行前,要先获得锁。
而这些行为都会影响性能的。