不看说明的下场!

本来参加网易云课堂的MySQL课程上的还算开心,一系列课程都通过了。国庆之前提前把第五节课程赶时间做完了。我还盘算的第五节考试能顺利完成,等国庆回来的再过第六节的考试。结果,国庆一过第五节的成绩就公布了,只有62分,险过。然后大意的看看第六节的考试没出来就没管它。今天一看,才发现第六节没有考试!成绩是平时课后习题60%+课后讨论40%,压根没有考试,而且10号,也就是昨天已经截至。
功亏一篑,功亏一篑!

请简述InnoDB如何保证事务的持久化特性

在数据库运行时,为了保障整个数据库系统的正常运行,防止数据意外和不一致,数据库管理系统就要对数据库进行保护和管理。这些管理主要通过数据库的恢复、并发控制、完整性控制和安全性控制,进而引申出事务和事务的特性。

事务是构成单一逻辑工作单元的操作集合。为了保证数据库中的数据总是正确的,我们要求事务具有ACID的性质,也就是原子性、一致性、隔离性和持久性。

其中,事务的持久性就是指一个事务一旦完成全部操作之后,它对数据库的所有更新应永久地反映在数据库中,不会丢失。即使以后系统发生故障,也是如此。MySQL为了实现数据库ACID的要求,引入了支持事务的InnoDB引擎。

InnoDB一方面实现了对事务的实现,另一方通过redo log日志实现了事务的原子性和持久性。 InnoDB是事务的存储引擎,当数据操作提交commit时,必须先将该事务的所有日志写入到redo log文件进行持久化,待事务的commit操作完成才算完成。为了保证每次日志都要写入redo log,InnoDB都要调用fsync操作将日志写入磁盘。

MySQL的主从同步

MySQL从3.23版本开始提供复制的功能。复制是指将主数据库的DDL和DML操作通过二进制日志传到从数据库上,然后在从库上对这些日志redo,从而使得从库和主库的数据保持同步。


概述

  1. 主库在commit时把数据变更作为events记录在binlog中;
  2. 主库推送binlog到从库的relay_log,之后从库从relay_log执行redo,通过逻辑复制以达到主从数据一致。

MySQL通过三个线程来完成主从复制:
1. binlog dump线程在主库上运行,将数据操作推送给从库;
2. I/O线程跑在从库上,将binlog日志中的事件更新到relay_log中;
3. SQL线程跑在从库上,将relay_log中更新的数据库事件应用到从库。

架构

复制的常见架构有:
1. 一主多从复制,适用于读压力大,实现读写分离;
2. 多级复制架构,主要为了解决主库的I/O负载和网络压力,但延迟大;
3. 双主复制架构,适用于主从切换;


搭建

主库

操作系统为ubuntu,域名beijing.sujx.net,关闭ufw,开启vsftpd;

$ sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf 

server-id = 100
log_bin                 = /var/log/mysql/mysql-bin.log
bind-address            = 192.168.122.106

$ sudo systemctl restart mysql 
$ mysql -u root -p 
mysql> grant replication slave on *.* to replica@'%' identified by 'password'; 
mysql> flush privileges; 
mysql> flush tables with read lock; 

mysql> show master status\G
*************************** 1. row ***************************
File: **mysql-bin.000012**
Position: **1677**
Binlog_Do_DB: 
Binlog_Ignore_DB: 
Executed_Gtid_Set: 
1 row in set (0.00 sec)
mysql> exit
mysqldump -uroot -p --all-databases --lock-all-tables --events > mysql_dump.sql
lftp sujx@shanghai.sujx.net
put mysql_dump.sql
$ mysql -u root -p 
mysql> unlock tables;

从库

操作系统为ubuntu,域名shanghai.sujx.net,关闭ufw,开启vsftpd;

$ mysql -u root -p < /tmp/mysql_dump.sql 
$ sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

server-id = 101
read_only=1
report-host=beijing.sujx.net

$sudo systemctl restart mysql 
$ mysql -u root -p 
mysql> change master to
-> master_host='beijing.sujx.net',
-> master_user='replica',
-> master_password='password',
-> master_log_file='mysql-bin.000012',
-> master_log_pos=1677;
mysql> SET GLOBAL sql_slave_skip_counter = 1;
mysql> start slave;
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: beijing.sujx.net
                  Master_User: replica
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000012
          Read_Master_Log_Pos: 1677
               Relay_Log_File: shanghai-relay-bin.000020
                Relay_Log_Pos: 1202
        Relay_Master_Log_File: mysql-bin.000012
             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: 1007
                   Last_Error: Error 'Can't create database 'sujx'; database exists' on query. Default database: 'sujx'. Query: 'create database sujx'
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 989
              Relay_Log_Space: 2147
              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: 1007
               Last_SQL_Error: Error 'Can't create database 'sujx'; database exists' on query. Default database: 'sujx'. Query: 'create database sujx'
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 100
                  Master_UUID: d84bbcff-a41f-11e7-a7e7-525400537531
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 170929 17:39:55
               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)

测试

在主库上面进行删库、建库、导入数据即可。

Tips

Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
这个问题是因为mysql目录中的auto.conf中的UUID值相同,修改之后就可以正常。

Last_IO_Errno: 1045 Last_IO_Error: error connecting to master ‘replication@
这个问题是change master语句错误

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

IO和SQL线程显示正常却无法复制数据时,需要设置SET GLOBAL sql_slave_skip_counter Syntax跳过内部出错的地方。

MySQL的配置文件

#
# The MySQL database server configuration file.
#
# Here is entries for some specific programs
# The following values assume you have at least 32M ram

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
#
# * Basic Settings
#
user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
lc-messages-dir = /usr/share/mysql
skip-external-locking
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
bind-address        = 192.168.122.106
#
# * Fine Tuning
#
key_buffer_size     = 16M
max_allowed_packet  = 16M
thread_stack        = 192K
thread_cache_size       = 8
# This replaces the startup script and checks MyISAM tables if needed
# the first time they are touched
myisam-recover-options  = BACKUP
max_connections        = 100
table_open_cache       = 64
#thread_concurrency     = 10
#
# * Query Cache Configuration
#
query_cache_limit   = 1M
query_cache_size        = 16M
#
# * Logging and Replication
#

general_log_file        = /var/log/mysql/mysql.log
general_log             = 1
#
# Error log - should be very few entries.
#
log_error = /var/log/mysql/error.log
#
# Here you can see queries with especially long duration
slow_query_log      = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 2
log-queries-not-using-indexes
#
# The following can be used as easy to replay backup logs or for replication.
server-id       = 100
log_bin         = /var/log/mysql/mysql-bin.log
expire_logs_days    = 10
max_binlog_size   = 100M
#binlog_do_db      = include_database_name
#binlog_ignore_db  = include_database_name
#
# * InnoDB
#
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
# Read the manual for more InnoDB related options. There are many!
#
# * Security Features
#
# Read the manual, too, if you want chroot!
# chroot = /var/lib/mysql/
#
# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
#
# ssl-ca=/etc/mysql/cacert.pem
# ssl-cert=/etc/mysql/server-cert.pem
# ssl-key=/etc/mysql/server-key.pem

Ubuntu上的ibdata1文件去哪里了?

在Ubuntu桌面版上使用apt安装MySQL之后,无论使用find还是locate都找不到MySQL的重要文件ibdata1。解决问题的方法很简单,就是切换到root账号之下。

$ locate ibdata1 
$ 
$ su
# locate ibdata1
# /var/lib/mysql/ibdata1

MySQL的数据文件位置

root@TC8304:/var/lib/mysql# ls
auto.cnf         ibdata1      ibtmp1              phpmyadmin  TC8304-slow.log
debian-5.7.flag  ib_logfile0  mysql               sujx
ib_buffer_pool   ib_logfile1  performance_schema  sys