距离上一次在segmentfault上发文章足足过了两年时间,本身也已经从在日本留学进入到了工做岗位。选择留在日本工做的理由其实本身也不是很清楚,只是不管身在哪里,都只想作一个技术人员的理想至少如今并无改变。虽然目前为止日本的IT行业不管在规模仍是技术层面都没法和国内相提并论, 可是本身身边仍是有不少大神的,本身在这段时间学到的东西不管如何也想和你们交流分享。还请你们多多指教。html
这个系列主要介绍本身工做上面关于MySQL的运用和研究。这个系列可能会偏向MySQL的底层和架构设计。对于开发方面的SQL语句设计以及数据表的设计等可能只会在介绍索引index的时候稍微说起。最后, 本系列涉及到的MySQL版本将主要集中在5.7和8.0。存储引擎将只介绍Innodb。(主要Myasim等由于本身也没接触过-_-)mysql
说到为何要学MySQL,先得说为何IT公司要用MySQL。MySQL是开源的,你能够在Github上随意的浏览它的源码, 给MySQL开发者送bug report。最主要它是免费的,不论是本身买服务器搭架构,仍是用云服务,MySQL都是很好的选择。虽然Oracle, SQL Server等在功能上可能更强大,可是对于中等规模的IT公司来讲,MySQL每每已经足够够用了。git
那可能就有人会说, 如今谁还用关系型数据库呀。确实如今的数据库种类也是愈来愈多,NoSQL数据库不断提供着时髦的使用方法,对开发者来讲也能更好的节省开发时间。Google的firestore(firebase)在最近也是被日本的开发者们视为掌中宝。可是MySQL在这么多年的企业级使用中,也性能调优方面,数据安全方面也变的不断成熟。虽然如今的NoSQL很方便,可是当涉及到一些敏感或者重要数据的时候,为了数据完整性和安全性,我会选择MySQL。学习MySQL, 对于一个公司的发展或者对于一个技术人员的自我提高来讲,其实都是一件颇有逼格的事情。(虽然好像没什么说服力)github
说了这么对废话,仍是快点进入今天的正题。Replicaiton多是学习数据库架构的最基础的东西了。Replication翻译过来是复制,那就是复制数据库,或者备份数据库呗。那为何须要复制数据库呢?sql
想象一下下面一个场景,若是你只有一台数据库服务器,写数据和读数据全都经过这一个数据库来作,当你的流量大了之后,这台服务器的负载将愈来愈大, 发生故障的机率也愈来愈大。最后当这台服务器挂掉之后,你的数据库将变的不可用,整个应用死掉,那可能你就要写好多故障报告了。docker
为了减小上面发生的几率,咱们会使用replication,也就是主从架构。一台master(主)服务器底下挂着几台slave(从)服务器。slave数据库经过Replication和master数据库保持数据同步。这时候master数据库能够只用来写数据,读数据的流量就能够分散到slave数据库服务器上了。可以前相比,服务器的负载获得了分散。并且对于这个架构来讲,容错性也获得了提升,当一台slave服务器死掉之后,其余或者的slave依然能够接受流量,应用也不会中断。master死掉之后,只要将一台slave升级成master就好了(故障损害虽然不是0,但也能尽量的减小)。数据库
在上图的架构中,有一台slave没有读操做也没有写操做,这个服务器能够被用来按期获取数据库的snapshot。这样作的话就不会由于常常获取snapshot而对生产环境中的服务器形成影响。segmentfault
若是在master服务器中设置binlog有效的话,对数据库有更新的操做都会被记录在binlog文件中。(binlog文件将在以后的文章中作详细介绍)
当slave链接到master服务器上时,master会建立一个binlog dump现成。而slave会建立一个IO线程和SQL线程。
具体的复制过程:安全
官方文档:https://dev.mysql.com/doc/ref...bash
方便你们hands-on,可使用我准备的这个库。(只要装了docker,就能够立马动手了)
https://github.com/leeif/mysq...
在docker中启动MySQL。
//启动container : mysql57_master,mysql57_slave,mysql80_master,mysql80_slave docker-compose up -d //进入container里 docker-compose exec mysql57_master(mysql57_slave) bash
数据库用户root,密码为root。
要使用replication,master须要存储binlog。要存储binlog,须要在master中设置指定log-bin(binlog的名字和存储位置)。
※MySQL8.0开始,默认binlog是有效的,无需设置log-bin。
master的配置文件以下:
//mysql57_master root@76e96aaae65d:/# cat /etc/mysql/conf.d/config-file.cnf [mysqld] server-id = 0001 log-bin = /var/log/mysql/mysql-bin.log binlog_format = statement binlog_cache_size = 1M max_binlog_size = 200M root@76e96aaae65d:/#
为了让slave识别master,server-id也是必须的。
这时候咱们能够查看一下master的情况。
//mysql57_master mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
能够看到当前的binlog文件名是mysql-bin.000003, 而且当前的binlog记录位置是154。
咱们尝试在数据库写入一些数据。运行如下脚本。
//mysql57_master root@76e96aaae65d:/# cat /mysql_etc/mysql_data_generator.sh #!/bin/bash mysql -uroot -P 3306 -proot -D mysql -e "create database replication_test;" mysql -uroot -P 3306 -proot -D mysql -e "create table replication_test.test_table (id int not null auto_increment, name varchar(255), primary key (id));" data="" for i in {1..99}; do d="('name_$i'),"; data=$data$d; done mysql -uroot -P 3306 -proot -D mysql -e "insert into replication_test.test_table (name) values $data('name_100');" root@76e96aaae65d:/#
//mysql57_master //写入了100条数据 mysql> select count(*) from replication_test.test_table; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.00 sec) mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 2163 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec) mysql>
能够看到binlog的参数发生了改变,说明数据库被更新了,而且更新内容被写入binlog文件里了。
在slave服务器中,咱们要让它和master实现同步。首先咱们用change master语句让slave知道要从哪一个master复制数据。
//mysql57_slave mysql> change master to MASTER_HOST='10.1.0.100', -> MASTER_USER='root', -> MASTER_PASSWORD='root', -> MASTER_LOG_FILE='mysql-bin.000003', -> MASTER_LOG_POS=154; Query OK, 0 rows affected, 2 warnings (0.12 sec) mysql>
MASTER_LOG_POS设置成了写入数据以前master的binlog位置。
(这里咱们用了root用户,在实际的运用场景中咱们通常会在master建立一个只用于replication的用户,给它赋予只能replication的权限。)
启动slave
//mysql57_slave mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.1.0.100 Master_User: root Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 2163 Relay_Log_File: ebd7cc002e88-relay-bin.000002 Relay_Log_Pos: 2329 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: 2163 Relay_Log_Space: 2543 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: 50655a33-bda5-11e8-b007-02420a010064 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) mysql>
... Slave_IO_Running: Yes Slave_SQL_Running: Yes ... Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: ...
从上面的参数重,能够看到IO线程和SQL线程已经在运行,而且没有出现错误,说明replication被成功创建。
查看数据同步状况:
//mysql57_slave mysql> select count(*) from replication_test.test_table; +----------+ | count(*) | +----------+ | 100 | +----------+ 1 row in set (0.01 sec) mysql>
能够看到master中的数据已经被同步了过来。
master中运行的process
//mysql57_master mysql> show processlist\G *************************** 1. row *************************** //binlog dump线程 Id: 7 User: root Host: mysql_learning_hard_mysql57_slave_1.mysql_learning_hard_test: db: NULL Command: Binlog Dump Time: 693 State: Master has sent all binlog to slave; waiting for more updates Info: NULL *************************** 2. row *************************** Id: 8 User: root Host: localhost db: NULL Command: Query Time: 0 State: starting Info: show processlist 2 rows in set (0.00 sec) mysql>
slave中运行的process
//mysql57_slave mysql> show processlist\G *************************** 1. row *************************** //IO线程 Id: 3 User: system user Host: db: NULL Command: Connect Time: 790 State: Waiting for master to send event Info: NULL *************************** 2. row *************************** //SQL线程 Id: 4 User: system user Host: db: NULL Command: Connect Time: 92220 State: Slave has read all relay log; waiting for more updates Info: NULL *************************** 3. row *************************** Id: 5 User: root Host: localhost db: NULL Command: Query Time: 0 State: starting Info: show processlist 3 rows in set (0.00 sec) mysql>
关于MySQL replication的原理以及基本用法就先说到这。下篇准备具体介绍一下show slave status中的参数, 经过这些参数咱们能够实时把握当前主从复制的状况。