公司規模已經造成,用戶數據已成爲公司的核心命脈,一次老王一不當心把數據庫文件刪除,經過mysqldump備份策略恢復用了兩個小時,在這兩小時中,公司業務中斷,損失100萬,老王作出深入檢討,公司也所以對於數據庫的性能和可靠性提出更高要求。要求對數據庫進行改造,使其承載力進行提高,故障修復時間減小,有沒有能實現的方案呢? css
一、向上拓展 scale up :針對單臺服務器,提升服務器的硬件性能,好比:內存,cpu等,個體自己 容易達到極限 前端
二、向外拓展 scale out :多臺服務器造成集羣,共同完成一件事情 mysql
高可用架構對於互聯網服務基本是標配,不管是應用服務仍是數據庫服務都須要作到高可用。雖然互聯網服務號稱7*24小時不間斷服務,但多多少少有一些時候服務不可用,好比某些時候網頁打不開,百度不能搜索或者沒法發微博,發微信等。通常而言,衡量高可用作到什麼程度能夠經過一年內服務不可用時間做爲參考,要作到3個9的可用性,一年內只能累計有8個小時不可服務,而若是要作到5個9的可用性,則一年內只能累計5分鐘服務中斷。因此雖然說每一個公司都說本身的服務是7*24不間斷的,但實際上能作到5個9的屈指可數,甚至根本作不到,國內互聯網巨頭BAT(百度,阿里巴巴,騰訊)都有由於故障致使的停服問題。對於一個系統而言,可能包含不少模塊,好比前端應用,緩存,數據庫,搜索,消息隊列等,每一個模塊都須要作到高可用,才能保證整個系統的高可用。對於數據庫服務而言,高可用可能更復雜,對用戶的服務可用,不只僅是能訪問,還須要有正確性保證,所以,對於實現數據庫高可用,對互聯網公司來講極其重要! 緩存
Mysql內建的複製功能是構建大型,高性能應用程序的基礎。將Mysql的數據分佈到多個系統上去,這種分佈的機制,是經過將Mysql的某一臺主機(Master)的數據複製到其它主機(slaves)上,並從新執行一遍來實現的。複製過程當中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。主服務器將更新寫入二進制日誌文件,這些日誌能夠記錄發送到從服務器的更新。當一個從服務器鏈接主服務器時,它通知主服務器從服務器在日誌中讀取的最後一次成功更新的位置。從服務器接收從那時起發生的任何更新,而後封鎖並等待主服務器通知新的更新。 安全
(4) 高可用性和容錯性 High availabilityand failover
(1) 主服務器(master)將改變記錄到二進制日誌(binarylog)中(這些記錄叫作二進制日誌事件,binary log events)
(2) 從服務器(slave)將主服務器master的binary logevents拷貝到它的中繼日誌(relay log)
(3) slave重作中繼日誌中的事件,將改變反映它本身的數據。
一、該過程的第一部分就是master記錄二進制日誌。在每一個事務更新數據完成以前,master在二進制日誌記錄這些改變。MySQL將事務串行的寫入二進制日誌,在事件寫入二進制日誌完成後,master通知存儲引擎提交事務。此後可接收slave的請求
二、下一步就是slave將master的binary log拷貝到它本身的中繼日誌。首先,slave開始一個工做線程——I/O線程。I/O線程在master上打開一個普通的鏈接,而後開始在主節點上binlog dump process(二進制轉存線程)。Binlog dump process從master的二進制日誌中讀取事件,若是已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日誌。
三、 SQL slave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日誌讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日誌一般會位於OS的緩存中,因此中繼日誌的開銷很小。
I/O線程:將master數據庫二進制日誌拉到slave數據庫上,並將二進制日誌寫到中繼日誌,寫完以後,他會睡眠並等待master數據庫二進制日誌更新,一旦更新,就會寫入slave數據庫的中繼日誌中
SQL線程:讀取中繼日誌的事件,並在數據庫中執行,寫入到內存中,使slave數據庫的數據與master數據庫中的數據一致
注意:slave數據庫只能是可讀的,不能是可寫的,若是改變了slave數據庫的數據,master不能從slave數據庫上同步數據,致使主從數據庫數據不一致。
centos系統服務器2臺、一臺用戶作Mysql主服務器,一臺用於作Mysql從服務器,都在同一個網段中,配置好yum源、防火牆關閉、各節點時鐘服務同步、各節點之間能夠經過主機名互相通訊
一、iptables -F && setenforce 清空防火牆策略,關閉selinux
二、拿兩臺服務器都使用yum方式安裝Mysql服務,要求版本一致
對master進行配置,包括打開二進制日誌,指定惟一的servr ID。例如,在配置文件加入以下值
server-id=1 #配置server-id,讓主服務器有惟一ID號(讓從服務器知道他的主服務器是誰)
log-bin=mysql-bin #打開Mysql日誌,日誌格式爲二進制
skip-name-resolve#關閉名稱解析,(非必須)
在Master的數據庫中創建一個備份賬戶:每一個slave使用標準的MySQL用戶名和密碼鏈接master
。進行復制操做的用戶會授予REPLICATION SLAVE權限。(給從服務器受權,讓他能從主服務器拷貝二進制日誌)
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO slave@'192.168.10.%' IDENTIFIED BY 'magedu';
在Master的數據庫執行show master status,查看主服務器二進制日誌狀態
對slave進行配置,打開中繼日誌,指定惟一的servr ID,設置只讀權限。在配置文件加入以下值
server-id=2 #配置server-id,讓從服務器有惟一ID號
relay_log = mysql-relay-bin #打開Mysql日誌,日誌格式爲二進制
log_bin = mysql-bin #開啓從服務器二進制日誌
log_slave_updates = 1 #使得更新的數據寫進二進制日誌中
讓slave鏈接master,並開始重作master二進制日誌中的事件。
CHANGE MASTER TO MASTER_HOST='192.168.10.190',
MASTER_LOG_FILE='mysql-bin.000001',
可以使用SHOW SLAVE STATUS\G查看從服務器狀態,以下所示,也可用show processlist \G查看前複製狀態:
Slave_IO_Running: Yes #IO線程正常運行
Slave_SQL_Running: Yes #SQL線程正常運行
假如master已經運行好久了,想對新安裝的slave進行數據同步,甚至它沒有master的數據。
此時,有幾種方法可使slave從另外一個服務開始,例如,從master拷貝數據,從另外一個slave克隆,從最近的備份開始一個slave。爲了加快Slave與master同步,可用如下方式先進行數據同步:
就是在從服務器也開啓二進制日誌,而後從的從I/O線程再將從的二進制日誌給拷貝過來寫入到本身的relay log中,而後sql線程再讀取relay log中的事件,在數據庫中執行,寫入到內存中。
僅複製有限一個或幾個數據庫相關的數據,而非全部;由複製過濾器進行;
從服務器的SQL THREAD僅重放關注的數據庫或表相關的事件,並將其應用於本地;
在實際應用場景中,MySQL複製90%以上都是一個Master複製到一個或者多個Slave的架構模式,主要用於讀壓力比較大的應用的數據庫端廉價擴展解決方案。由於只要Master和Slave的壓力不是太大(尤爲是Slave端壓力)的話,異步複製的延時通常都不多不多。尤爲是自從Slave端的複製方式改爲兩個線程處理以後,更是減少了Slave端的延時問題。而帶來的效益是,對於數據實時性要求不是特別高的應用,只須要經過廉價的pcserver來擴展Slave的數量,將讀壓力分散到多臺Slave的機器上面,便可經過分散單臺數據庫服務器的讀壓力來解決數據庫端的讀性能瓶頸,畢竟在大多數數據庫應用系統中的讀壓力仍是要比寫壓力大不少。這在很大程度上解決了目前不少中小型網站的數據庫壓力瓶頸問題,甚至有些大型網站也在使用相似方案解決數據庫瓶頸。
(1) 不一樣的slave扮演不一樣的做用(例如使用不一樣的索引,或者不一樣的存儲引擎);
(2) 用一個slave做爲備用master,只進行復制;#主服務器掛了以後,可在從服務器執行
1> 在備機上執行STOP SLAVE 和RESET MASTER
Master-Master複製的兩臺服務器,既是master,又是另外一臺服務器的slave。這樣,任何一方所作的變動,都會經過複製應用到另一方的數據庫中。
即:在兩臺服務器上既執行master的操做又執行slave的操做(注意:兩臺數據庫都必須是可寫的)
互爲主從:兩個節點各自都要開啓binlog和relay log;
對於某些惟一性的字段,能夠經過設置自增加ID來實現,自增加ID的數據,表明這個表中存在一條惟一的記錄;而自增加id是確定不會重複的;
create table userInfo (id int PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
insert into userInfo(name) value('xiao'),('da'),('lao');
auto_increment_increment=2 #表示自增加字段每次遞增的量
auto_increment_offset=1 #表示自增加字段從那個數開始
二、均啓用binlog和relay log; read only = 0(由於互爲主從,因此必須是可寫的)
三、存在自動增加id的表,爲了使得id不相沖突,須要定義其自動增加方式;
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO slave@'192.168.10.%' IDENTIFIED BY 'magedu';
讓slave鏈接master,並開始重作master二進制日誌中的事件。
CHANGE MASTER TO MASTER_HOST='192.168.10.190',
MASTER_LOG_FILE='mysql-bin.000001',
可以使用SHOW SLAVE STATUS\G查看從服務器狀態,以下所示,也可用show processlist \G查看前複製態:
Slave_IO_Running: Yes #IO線程正常運行
Slave_SQL_Running: Yes #SQL線程正常運行
create table userinfo (id int PRIMARY KEY AUTO_INCREMENT,name varchar(20) NOT NULL);
insert into userinfo (name) values('ni'),('wo'),('ta');
而後查看錶,由於是自增加id,從1開始,步長爲2,因此添加的數據id爲1,3,5
而後在另外一臺數據庫服務器插入數據,由於是自增加id,從2開始,步長爲2,因此新添加的數據id爲6,8,10
排錯:當配置文件中配置中繼日誌格式不當心配置錯了,或者讓slave鏈接master,執行sql語句不當心寫錯了,都有可能致使start slave;報錯,此時能夠show slave status\G;會出現一大串信息,裏面會提示錯誤。找到錯誤之後,重置slave,reset slave;從新設置,而後再start slave;
注意:mysql的錯誤日誌很是重要,能夠提供錯誤信息,從而找到錯誤緣由。
互爲主從容易致使數據不一致,此時咱們能夠用兩個實例來互爲主從
MySQL默認的複製便是異步的,主庫在執行完客戶端提交的事務後會當即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主若是crash掉了,此時主上已經提交的事務可能並無傳到從上,若是此時,強行將從提高爲主,可能致使新主上的數據不完整
指當主庫執行完一個事務,全部的從庫都執行了該事務才返回給客戶端。由於須要等待全部從庫執行完該事務才能返回,因此全同步複製的性能必然會收到嚴重的影響。須要有超時時間。
介於異步複製和全同步複製之間,主庫在執行完客戶端提交的事務後不是馬上返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。相對於異步複製,半同步複製提升了數據的安全性,同時它也形成了必定程度的延遲,這個延遲最少是一個TCP/IP往返的時間。因此,半同步複製最好在低延時的網絡中使用。
支持多種插件:/usr/lib64/mysql/plugins/
mysql> INSTALL PLUGIN plugin_name SONAME 'shared_library_name';
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
+------------------------------------+-------+
+------------------------------------+-------+
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_no_slave | ON |
+------------------------------------+-------+
MariaDB [mydb]> SET GLOBAL rpl_semi_sync_master_enabled=ON/1;
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
+---------------------------------+-------+
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
MariaDB [mydb]> STOP SLAVE IO_THREAD;
MariaDB [mydb]> SET GLOBAL rpl_semi_sync_slave_enabled = ON ;
MariaDB [mydb]> SHOW GLOBAL VARIABLES LIKE 'rpl_semi%';
MariaDB [mydb]> START SLAVE IO_THREAD;