1. 程式人生 > >MySql 高可用架構Atlas

MySql 高可用架構Atlas

stop creat st2 正常 utf8 spa key target box

Atlas是由 Qihoo 360公司Web平臺部基礎架構團隊開發維護的一個基於MySQL協議的數據中間層項目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基礎上,修改了大量bug,添加了很多功能特性。目前該項目在360公司內部得到了廣泛應用,很多MySQL業務已經接入了Atlas平臺,每天承載的讀寫請求數達幾十億條。

Atlas主要功能:
1.讀寫分離
2.從庫負載均衡
3.IP過濾
4.自動分表
5.DBA可平滑上下線DB
6.自動摘除宕機的DB

Atlas介紹

Atlas是一個位於應用程序與MySQL之間中間件。在後端DB看來, Atlas相當於連接它的客戶端,在前端應用看來, Atlas相當於一個DB。 Atlas作為服務端與應用程序通訊,它實現了MySQL的客戶端和服務端協議,同時作為客戶端與MySQL通訊。它對應用程序屏蔽了DB的細節,同時為了降低MySQL負擔,它還維護了連接池

技術分享圖片

Atlas相對於官方MySQL-Proxy的優勢
1.將主流程中所有Lua代碼用C重寫,Lua僅用於管理接口
2.重寫網絡模型、線程模型
3.實現了真正意義上的連接池
4.優化了鎖機制,性能提高數十倍

Atlas安裝配置

    1. 從https://github.com/Qihoo360/Atlas/releases 頁面下載最新版RPM包,然後執行:
      sudo rpm –i Atlas-XX.el6.x86_64.rpm安裝。

註: Atlas只能安裝運行在64位的系統上。後端mysql版本應大於5.1,建議使用Mysql 5.6 及以上

    1. 配置文件修改
      Atlas運行需要依賴一個配置文件(test.cnf)。在運行Atlas之前,需要對該文件進行配置。
      Atlas的安裝目錄是/usr/local/mysql-proxy,進入安裝目錄下的conf目錄,可以看到已經有一個名為test.cnf的默認配置文件,我們只需要修改裏面的某些配置項
      test.cnf
[mysql-proxy]
(必備,默認值即可)管理接口的用戶名
• admin-username = user
(必備,默認值即可)管理接口的密碼
• admin-password = pwd
(必備,根據實際情況配置)主庫的IP和端口
• proxy-backend-addresses = 192.168.0.12:3306
(非必備,根據實際情況配置)從庫的IP和端口, @後面的數字代表權重,用來作負載均衡,若省略則默認
為1,可設置多項, 用逗號分隔。如果想讓主庫也能分擔讀請求的話,只需要將主庫信息加入到下面的配
置項中。
• proxy-read-only-backend-addresses = 192.168.0.13:3306,192.168.0.14:3306
(必備,根據實際情況配置)用戶名與其對應的加密過的MySQL密碼,密碼使用PREFIX/bin目錄下的加密程
序encrypt加密,用戶名與密碼之間用冒號分隔。 主從數據庫上需要先創建該用戶並設置密碼(用戶名和密
碼在主從數據庫上要一致) 。比如用戶名為myuser,密碼為mypwd,執行./encrypt mypwd結果為
HJBoxfRsjeI=。如果有多個用戶用逗號分隔即可。則設置如下行所示:
• pwds = myuser: HJBoxfRsjeI=,myuser2:HJBoxfRsjeI=
(必備,默認值即可)Atlas的運行方式,設為true時為守護進程方式,設為false時為前臺方式,一般開發
調試時設為false,線上運行時設為true
• daemon = true
(必備,默認值即可)設置Atlas的運行方式,設為true時Atlas會啟動兩個進程,一個為monitor,一個為
worker, monitor在worker意外退出後會自動將其重啟,設為false時只有worker,沒有monitor,一般開發
調試時設為false,線上運行時設為true
• keepalive = true
(必備,根據實際情況配置)工作線程數,推薦設置成系統的CPU核數的2至4倍
• event-threads = 4

(必備,默認值即可)日誌級別,分為message、 warning、 critical、 error、 debug五個級別
• log-level = message
(必備,默認值即可)日誌存放的路徑
• log-path = /usr/local/mysql-proxy/log

(必備,根據實際情況配置)SQL日誌的開關,可設置為OFF、 ON、 REALTIME,OFF代表不記錄
SQL日誌,ON代表記錄SQL日誌,該模式下日誌刷新是基於緩沖區的,當日誌填滿緩沖區後,
才將日誌信息刷到磁盤。 REALTIME用於調試,代表記錄SQL日誌且實時寫入磁盤,默認為OFF
• sql-log = OFF
(可選項,可不設置)慢日誌輸出設置。當設置了該參數時,則日誌只輸出執行時間超過sql-logslow(單位:ms)的日誌記錄。不設置該參數則輸出全部日誌。
• sql-log-slow = 10
(可選項,可不設置)關閉不活躍的客戶端連接設置。當設置了該參數時,Atlas會主動關閉經過
‘wait-timeout‘時間後一直未活躍的連接。單位:秒
wait-timeout = 10
(必備,默認值即可)Atlas監聽的工作接口IP和端口
proxy-address = 0.0.0.0:1234
(必備,默認值即可)Atlas監聽的管理接口IP和端口 admin-address = 0.0.0.0:2345
(可選項,可不設置)默認字符集,若不設置該項,則默認字符集為latin1
charset = utf8
(可選項,可不設置)允許連接Atlas的客戶端的IP,可以是精確IP,也可以是IP段,以逗
號分隔,若不設置該項則允許所有IP連接,否則只允許列表中的IP連接
client-ips = 127.0.0.1, 192.168.0.1

  

運行Atlas
進入/usr/local/mysql-proxy/bin目錄,執行下面的命令啟動、重啟或停止Atlas。
(1). sudo ./mysql-proxyd test start,啟動Atlas。
(2). sudo ./mysql-proxyd test restart,重啟Atlas。
(3). sudo ./mysql-proxyd test stop,停止Atlas。
執行命令:mysql -h127.0.0.1 -P1234 -u用戶名 -p密碼,如果能連上則證明Atlas初步
測試正常,可以再嘗試發幾條SQL語句看看執行結果是否正確。

Atlas讀寫分離

Atlas後端連接的MySQL主庫的IP和端口,可設置多項,用逗號分隔
例如
proxy-backend-addresses = 192.168.237.128:3308

Atlas後端連接的MySQL從庫的IP和端口,@後面的數字代表權重,用來作負載均衡,若省略則默認為1,可設置多項,用逗號分隔
proxy-read-only-backend-addresses = 192.168.237.130:3308@1

關閉主備庫復制關系,在主庫上查看

當MySQL主庫關閉的情況下,寫操作失敗,讀操作依然可以執行
當MySQL僅有的一個從庫關閉的情況下,寫操作成功,讀操作也漂移到主庫上執行

Atlas負載均衡

當有多個從庫的情況下
Atlas後端連接的MySQL主庫的IP和端口,可設置多項,用逗號分隔
proxy-backend-addresses = 192.168.237.128:3308
Atlas後端連接的MySQL從庫的IP和端口,@後面的數字代表權重(數字越大讀取的機會更高),用來作負載均衡,若省略則默認為1,可設置多項,用逗號分隔

例如:

proxy-read-only-backend-addresses =192.168.237.130:3308@1,192.168.237.131:3308@1

  

當第一個從庫崩潰時執行查詢語句,語句都在第二個節點查詢

當有多個讀節點時,權重越大,被讀取的可能性就越高

Atlas後端連接的MySQL從庫的IP和端口, @後面的數字代表權重,用來作負載均衡,若省略則默認為1,
可設置多項,用逗號分隔

例:

proxy-read-only-backend-addresses = 192.168.237.130:3308@1,192.168.237.131:3308@2

自動讀寫分離挺好,但有時候寫完馬上就想讀,萬一主從同步延遲怎麽辦?
SQL語句前增加 /*master*/ 就可以將讀請求強制發往主庫。在mysql命令行測試該功能時,需要加-c選項,以防mysql客戶端過濾掉註釋信息。

主庫宕機,讀操作受影響麽?
在Atlas中讀操作不受影響,Atlas會將讀請求轉發到其他還存活的從庫上。但此時寫請求將會失敗,因為主庫宕機了。

Altas支持多個主庫的運行模式嗎?
官網:目前還未對於Atlas後面掛接多個主庫的情形進行測試過,不建議這樣使用。建議使用一主一從或一主多從的模式。
可以做雙主,在proxy-backend-addresses = ip1,ip2 但是不建議使用

Atlas分表功能

類似在一個庫,創建了多個子表

使用Atlas的分表功能時,首先需要在配置文件(test.cnf)設置tables參數。

tables參數設置格式:數據庫名.表名.分表字段.子表數量,比如你的數據庫名叫school,表名叫stu,分表字段叫id,總共分為100張表,那麽就寫為school.stu.id.100,如果還有其他的分表,以逗號分隔即可。用戶
需要在數據庫手動建立100張子表(stu_0,stu_1,…stu_99,註意子表序號是從0開始的)。 且所有的子表必須在DB的同一個database裏·

分表的效果是:
當通過Atlas執行(SELECT、 DELETE、 UPDATE、 INSERT、 REPLACE)操作時,
Atlas會根據分表字段結果(id%100=k),定位到相應的子表(stu_k)
例如,執行
select * from stu where id=110;,Atlas會自動從stu_10這張子表返回查詢結果。
但如果執行SQL語句(select * from stu;)時不帶上id,則會提示執行stu 表不存在。

Atlas暫不支持自動建表和跨庫分表的功能
Atlas目前支持分表的語句有SELECT、 DELETE、 UPDATE、 INSERT、 REPLACE

需要安裝非shard版本,sharding版本不支持分表功能
分表設置,此例中person為庫名,mt為表名,id為分表字段,3為子表數量,可設置多項,以逗號分隔,若不分表則不需要設置該項

局限性:
應用程序連接atlas分表的時候,查詢必須要加where 條件 ,分表字段= 不能用範圍查詢>,<,或者between and ,不支持全表查詢。

例:

mysql> select * from students where id=0;
Empty set (0.00 sec)
mysql> select * from students;
ERROR 1146 (42S02): Table ‘test.students‘ doesn‘t exist
mysql> select * from students where id>2;
ERROR 1146 (42S02): Table ‘test.students‘ doesn‘t exist

  

Atlas 分片

Sharding當前是Atlas的分布式分支, 是Atlas最近重點開發的功能. Sharding的基本思想
就是把個數據表中的數據切分成多個部分, 存放到不同的主機上去(切分的策略有多種),從而緩解單臺機器的性能跟容量的問題. sharding是一種水平切分, 適用於單表數據龐大的情景

Atlas以表為單位sharding, 同一個數據庫內可以同時共有sharding的表和不sharding的表, 不sharding的表數據存在未sharding的數據庫組中.

目前Atlas sharding支持insert, delete, select, update語句, 所有的寫操作如insert,delete, update只能一次命中一個組, 否則會報”ERROR 1105 (HY000):write operationis only allow to one dbgroup!”錯誤.

Sharding數據庫組

在Atlas中, 將一個組看做是數據存儲的單位,一個組由一臺master, 零臺或者多臺slave組成(mysql主從同步需要由用戶自己配置). 每個組之間的數據獨立, 沒有關系, 表的數據的各個部分存儲在各個組中.

組內讀寫分離

與非sharding的方案一樣,Atlas sharding也支持組內的讀寫分離, 也就是說Atlas在命中了某個組之後, 還是會對這個組內的master和slave執行讀寫分離(讀發送到slave, 寫發送到master)

技術分享圖片

Sharding 數據切分策略

Range 方式
範圍數據切分方式,比如
shard Key範圍在0-1000的數據存放在Group0中,
範圍在1000-2000的數據存放在Group1中,
2000-MaxInt 的數據存放在Group2 中.
這些範圍的大小不需要相同.比如id為shard key的話, sql: “select * from test where id = 1500;”,
Atlas會將此語句發往Group1. 暫時Atlas的range是靜態的, 不支持動態的增加範圍

hash 方式
目前Atlas使用取模的方式實現Hash, 也就是說Hash(id) = id % group_count, 如id =10, id % 3 = 1, 所以會命中到DbGroup1中.

Atlas sharding部分新增配置項,包含兩個部分:
shardrule. 一個shardrule對應一個分表規則,不同的shardrule通過下劃線後面的數字區分

例如shardrule-0, shardrule-1….。
一個shardrule裏面有以下幾項:

[shardrule-0]
table = test.sharding_test #分表名,由數據庫+表名組成
type = range #sharding類型:range 或 hash
shard-key = id #sharding 字段
groups = 0:0-999,1:1000-1999 #分片的group,
如果是range類型的sharding,則groups的格式是:group_id:id範圍。
如果是hash類型的sharding,則groups的格式是:group_id。例如groups = 0, 1
group. 一個group一般包含一主多從,由master(proxy-backend-addresses)和
slave(proxy-read-only-backend-addresses)組成。 group之間的區別也是通過下
劃線後面的數字區分。

  

假設我們有以下一個sharding的表, 建表語句如下:

DROP TABLE IF EXISTS `sharding_test`;
CREATE TABLE `sharding_test` ( `id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(50) COLLATE utf8_bin NOT NULL,
`age` int(11) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`nickname` char(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`) );

  

有兩個dbgroup(數據庫組), 每個dbgroup有一個master, sharding_test使用range的方
式, 以id作為shard key, 屬於test數據庫, dbgroup0屬於範圍0 - 999, dbgroup1 屬於
範圍 1000 - 1999

dbgroup0 有一主, 192.168.237.130:3308
dbgroup1 有一主, 192.168.237.131:3308

[mysql-proxy]
admin-username = user
admin-password = pwd
#Atlas後端連接的MySQL主庫的IP和端口,可設置多項,用逗號分隔
proxy-backend-addresses = 192.168.237.128:3308
#proxy-read-only-backend-addresses = 192.168.237.130:3308@1,192.168.237.131:3308@1
daemon = true
keepalive = false
event-threads = 4
log-level = debug
log-path = /usr/local/mysql-proxy/log
sql-log = realtime
proxy-address = 0.0.0.0:1234
admin-address = 0.0.0.0:2345
charset = UTF8
wait-timeout = 3600
pwds = root:S4HJu78/H/6I/aYp2Xdb8Q==
[shardrule-0]
table = test3.sharding_test
type = range
shard-key = id
groups = 0:0-999,1:1000-1999
[group-0]
# master
proxy-backend-addresses=192.168.237.130:3308
# slave
#proxy-read-only-backend-addresses=127.0.0.1:3308
[group-1]
proxy-backend-addresses=192.168.237.131:3308
#proxy-read-only-backend-addresses=127.0.0.1:3310

  

運行Atlas
進入/usr/local/mysql-proxy/bin目錄,執行下面的命令啟動、重啟或停止Atlas。
(1). sudo ./mysql-proxyd test start,啟動Atlas。
(2). sudo ./mysql-proxyd test restart,重啟Atlas。
(3). sudo ./mysql-proxyd test stop,停止Atlas

執行命令: mysql -h 127.0.0.1 -P 1234 -u 用戶名 -p,如果能連上則證明Atlas初步
測試正常,可以再嘗試發幾條SQL語句看看執行結果是否正確。

關於支持的語句

Atlas sharding只對sql語句提供有限的支持, 目前支持基本的Select, insert/replace, delete, update語句, 支持全部的Where語法(SQL-92標準), 不支持DDL(create drop alter)以及一些管理語句, DDL請直連MYSQL執行, 請只在Atlas上執行Select, insert, delete, update(CRUD)語句

對於以下語句, 如果語句命中了多臺dbgroup, Atlas均未做支持(如果語句只命中了一個dbgroup, 如select count(*) from test where id < 1000, 其中dbgroup0範圍是0 - 1000, 那麽這些特性都是支持的)
Limit Offset (支持Limit 同一個dbgroup)
Order by
Group by
Join
count, Max, Min等函數不支持

子查詢在Sharding中可能會返回不正確的結果, 也請不要使用子查詢. 請把語句拆分成多句執行
對於寫操作, 如果寫操作命中了多個數據庫組, 由於部分成功(某個組執行失敗)需要回滾的問題, 暫時不支持寫操作命中多個數據組的語句.請拆分成多個sql語句執行

Atlas可能會在接下來的版本中對其中的一些特性中做出支持.

例用Atlas插入幾條數據,做一下測試:

$ mysql -h127.0.0.1 -P1234 -uroot -pmysqltest -c
mysql> use test3;
Database changed
mysql> insert into sharding_test(id, name, age) values(1, ‘test‘, 0);
Query OK, 1 row affected (0.00 sec)
mysql> insert into sharding_test(id, name, age) values(50, ‘test‘, 0), (999, ‘test‘, 0);
Query OK, 2 rows affected (0.00 sec)

  

以上幾條數據都插入到了dbgroup0, 請註意第二條多值插入的語句, 因為50和999都命中了dbgroup0, 所以其執行成功, 但是如果執行以下的語句:

mysql> insert into sharding_test(id, name, age) values(100, ‘test‘, 0), (1500, ‘test‘,
0);
ERROR 1105 (HY000): Proxy Warning - write operation is only allow to one

  

dbgroup! 在sharding的表中, 這是不允許的, 因為id為100命中了dbgroup0, 而id為1500 命中了dbgroup1, 由於分布式的多值插入可能導致部分成功, 需要回滾, 這個Atlas暫不支持. update, delete, replace同理.

再插幾條數據到dbgroup1:

mysql> insert into sharding_test(id, name, age) values(1000, ‘test‘, 0), (1999,
‘test‘, 0);
Query OK, 2 rows affected (0.00 sec)
mysql> select * from sharding_test;
+------+------+------+----------+----------+
| id | name | age | birthday | nickname |
+------+------+------+----------+----------+
| 1 | test | 0 | NULL | NULL |
| 50 | test | 0 | NULL | NULL |
| 999 | test | 0 | NULL | NULL |
| 1000 | test | 0 | NULL | NULL |
| 1999 | test | 0 | NULL | NULL |

mysql> select * from sharding_test where id>50;
+------+------+------+----------+----------+
| id | name | age | birthday | nickname |
+------+------+------+----------+----------+
| 999 | test | 0 | NULL | NULL |
| 1000 | test | 0 | NULL | NULL |
| 1999 | test | 0 | NULL | NULL |


#JOIN操作,不支持
mysql> select * from sharding_test a,test.temp b on a.id=b.id;
ERROR 1105 (sqlst): Proxy Warning - Sharing Hit Multi Dbgroup Not Support
SQL

#update操作
mysql> update sharding_test set name=‘test2‘;
ERROR 1105 (HY000): Proxy Warning - Syntax Forbidden!
mysql> update sharding_test set name=‘test2‘ where id<2000;
ERROR 1105 (sqlst): Proxy Warning - write operation is only allow to one
dbgroup!
mysql> update sharding_test set name=‘test2‘ where id<999;
Query OK, 2 rows affected (0.01 sec)

#delete操作
mysql> delete from sharding_test;
ERROR 1105 (HY000): Proxy Warning - Syntax Forbidden!
mysql> delete from sharding_test where id<2000;
ERROR 1105 (sqlst): Proxy Warning - write operation is only allow to one
dbgroup!
mysql> delete from sharding_test where id>1900;
Query OK, 1 row affected (0.01 sec)

  

更多的看看官方文檔:https://github.com/Qihoo360/Atlas/wiki

MySql 高可用架構Atlas