MySQL高可用實現:主從結構下ProxySQL中的讀寫分離

ProxySQL是一個高性能的MySQL中間件,擁有強大的規則引擎。 
ProxySQL提供強大的路由規則。當應用程序自身不支持讀寫分離時,DBA可以通過配置路由規則爲應用程序提供透明的讀寫分離,使用Keepalived + ProxySQL + Orchestrator爲主從提供高可用時,能夠有效的避免keepalived + 雙主結構 由於keepalived腦裂而造成數據被寫錯亂的痛點。


介紹



ProxySQL是一個高性能的MySQL中間件,擁有強大的規則引擎。具有以下特性:

1.爲對多個數據庫的應用程序請求提供“智能”的負載均衡。 
2.實現了MySQL請求協議,能夠對應用程序提供透明的讀寫分離,避免了應用程序實現複雜的讀寫分離。 
3.能夠自動感知數據庫健康狀態和拓撲結構並且能夠自動將應用程序請求路由到處於健康狀態的MySQL實例。 
4.保護應用程序不受底層數據庫複雜拓撲結構變化而受影響,能夠自動將寫請求轉發的主庫,自動按照權重將讀請求發送的主庫和從庫。 
5.提供了對查詢SQL的監控分析統計。 
6.爲管理員提供了強大的控制機制,可以在代理層緩存查詢,以便更快地響應查詢、重新路由查詢,甚至重新改寫那些質量較差的查詢語句。

模塊




ProxySQL組成模塊

Qurey Processor 用於匹配查詢規則並根據規則決定是否緩存查詢或者將查詢加入黑名單或者重新路由、重寫查詢或者鏡像查詢到其他hostgroup。 
User Auth 爲底層後端數據庫認證提供了用戶憑證。 
Hostgroup manager – 負責管理髮送SQL請求都後端數據庫並跟蹤SQL請求狀態。 
Connection pool – 負責管理後端數據庫連接,連接池中建立的連接被所有的前端應用程序共享。 
Monitoring – 負責監控後端數據庫健康狀態主從複製延時並臨時下線不正常的數據庫實例。


安裝



1.從 https://github.com/sysown/proxysql/releases 下載相應的版本。 
2.yum local×××tall proxysql-1.x.rpm 
3.啓動ProxySQL


/etc/init.d/proxysql start


配置結構



ProxySQL配置可以存儲到SQLite數據庫並通過SQL語句來管理配置,並通過如下三層配置來管理ProxySQL。 

DISK: 使用SQLite來持久存儲ProxySQL配置,以防ProxySQL重啓後配置丟失。 
Memory: 存在於內存中的配置,也是用戶通過SQL直接管理的配置。 
Runtime: 當前正在使用的配置,處於生效部分。 


223.jpg


使用ProxySQL修改配置時,可以通過SQL語句直接修改Memory中的配置,然後使用load命令將Memory中的配置加載的到runtime層來驗證配置是否正確,如果驗證通過可以通過save將配置保存到SQLite數據庫中,如果驗證不通過也可以通過load命令將DISK層中的配置加載到Memory和runtime層中,達到回滾到效果。


內置庫表介紹



登錄到proxysql管理端口,默認用戶名密碼爲:admin/admin


mysql -uadmin -padmin -h127.0.0.1 -P6032

Welcome to the MySQL monitor. Commands end with ; or \g.

Your MySQL connection id is 2

Server version: 5.6.30 (ProxySQL Admin Module)

Admin> show databases;

+-----+---------+-------------------------------+

| seq | name   | file                         |

+-----+---------+-------------------------------+

| 0   | main   |                               |

| 2   | disk   | /var/lib/proxysql/proxysql.db |

| 3   | stats   |                               |

| 4   | monitor |                               |

+-----+---------+-------------------------------+

  * main: 數據庫裏存放後端db實例、用戶驗證、路由規則等信息。表名以 runtime開頭的表示proxysql當前運行的配置內容,不能通過dml語句修改,只能修改對應的不以 runtime 開頭的(在內存)裏的表,然後 LOAD 使其生效, SAVE 使其存到硬盤以供下次重啓加載。 
  * disk 是持久化到硬盤的配置,sqlite數據文件。 
  * stats 是proxysql運行抓取的統計信息,包括到後端各命令的執行次數、流量、processlist、查詢種類彙總/執行時間,等等。 
  * monitor 庫存儲 monitor 模塊收集的信息,主要是對後端db的健康/延遲檢查。

Admin> show tables; 
+--------------------------------------+ 
| tables                               | 
+--------------------------------------+ 
| global_variables                     | 
| mysql_collations                     | 
| mysql_query_rules                   | 
| mysql_replication_hostgroups         | 
| mysql_servers                       | 
| mysql_users                         | 
| runtime_global_variables             | 
| runtime_mysql_query_rules           | 
| runtime_mysql_replication_hostgroups | 
| runtime_mysql_servers               | 
| runtime_mysql_users                 | 
| runtime_scheduler                   | 
| scheduler                           | 
+--------------------------------------+ 
13 rows in set (0.00 sec)

Admin> show tables from stats; 
+--------------------------------+ 
| tables                         | 
+--------------------------------+ 
| global_variables               | 
| stats_mysql_commands_counters | 
| stats_mysql_connection_pool   | 
| stats_mysql_global             | 
| stats_mysql_processlist       | 
| stats_mysql_query_digest       | 
| stats_mysql_query_digest_reset | 
| stats_mysql_query_rules       | 
+--------------------------------+ 
8 rows in set (0.00 sec)

mysql_servers


Admin> show create table mysql_servers\G

    CREATE TABLE mysql_servers (  

hostgroup_id INT NOT NULL DEFAULT 0,  

hostname VARCHAR NOT NULL,  

port INT NOT NULL DEFAULT 3306,  

status VARCHAR CHECK (UPPER(status) IN ('ONLINE','SHUNNED','OFFLINE_SOFT', 'OFFLINE_HARD')) NOT NULL DEFAULT 'ONLINE',  

weight INT CHECK (weight >= 0) NOT NULL DEFAULT 1,  

compression INT CHECK (compression >=0 AND compression <= 102400) NOT NULL DEFAULT 0,  

max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 1000,  

max_replication_lag INT CHECK (max_replication_lag >= 0 AND max_replication_lag <= 126144000) NOT NULL DEFAULT 0,  

use_ssl INT CHECK (use_ssl IN(0,1)) NOT NULL DEFAULT 0,  

max_latency_ms INT UNSIGNED CHECK (max_latency_ms>=0) NOT NULL DEFAULT 0, 

comment VARCHAR NOT NULL DEFAULT '',  

PRIMARY KEY (hostgroup_id, hostname, port) )

1 row in set (0.00 sec)

mysql_servers對數據庫實例進行了分組和實例信息配置。 
 ·hostgroup_id: MySQL實例所屬組 
 · status: 
 · ONLINE: 運行狀態 
 · SHUNNED: 數據庫被處於暫時踢出狀態,由於後臺數據庫出現“too many connections error”或者後端數據庫主從延時超過了允許的閾值。
 · OFFLINE_SOFT: “軟離線”狀態,不再接受新的連接,但已建立的連接會等待活躍事務完 
 · OFFLINE_HARD: “硬離線”狀態,不再接受新的連接,已建立的連接或被強制中斷。當後端實例宕機或網絡不可達,會出現。 
 · weight:負載均衡時選擇後端數據庫的權重值,權重越高被選中的比率越高。 
 · max_connections:允許連接到該後端實例的最大連接數,不要設置此值大於後端數據庫的最多連接數。 
 · max_latency_ms:mysql_ping 響應時間,大於這個閥值會把它從連接池剔除(即使是ONLINE)


mysql_replication_hostgroups


此表用於傳統的異步/半同步的主從複製,對於MGT/GALERA需要使用mysql_group_replication_hostgroups或者mysql_galera_hostgroups(ProxySQL 2.x之後)。在此表中的每一行代表一對writer_hostgroup和reader_hostgroup。ProxySQL將監控read_only的值,ProxySQL將基於read_only的值來分配MySQL實例爲reader_hostgroup還是writer_hostgroup,,如果發現從庫的 read_only 變爲0、主庫變爲1,則認爲角色互換了,自動改寫 mysql_servers 表裏面 hostgroup 關係,達到自動 Failover 效果。


Admin> SHOW CREATE TABLE mysql_replication_hostgroups\G

*************************** 1. row *************************** 

     table: mysql_replication_hostgroupsCreate Table: 

CREATE TABLE mysql_replication_hostgroups (

  writer_hostgroup INT CHECK (writer_hostgroup>=0) NOT NULL PRIMARY KEY,

  reader_hostgroup INT NOT NULL CHECK (reader_hostgroup<>writer_hostgroup AND reader_hostgroup>0),

  check_type VARCHAR CHECK (LOWER(check_type) IN ('read_only','innodb_read_only','super_read_only')) NOT NULL DEFAULT 'read_only',

  comment VARCHAR,  UNIQUE (reader_hostgroup))

1 row in set (0.00 sec)


mysql_users


CREATE TABLE mysql_users (  

 username VARCHAR NOT NULL,  

 password VARCHAR, 

 active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 1,  use_ssl INT CHECK (

 use_ssl IN (0,1)) NOT NULL DEFAULT 0,

 default_hostgroup INT NOT NULL DEFAULT 0, 

 default_schema VARCHAR, 

 schema_locked INT CHECK (schema_locked IN (0,1)) NOT NULL DEFAULT 0,

 transaction_persistent INT CHECK (transaction_persistent IN (0,1)) NOT NULL DEFAULT 0, 

 fast_forward INT CHECK (fast_forward IN (0,1)) NOT NULL DEFAULT 0, 

 backend INT CHECK (backend IN (0,1)) NOT NULL DEFAULT 1, 

 frontend INT CHECK (frontend IN (0,1)) NOT NULL DEFAULT 1, 

 max_connections INT CHECK (max_connections >=0) NOT NULL DEFAULT 10000, 

 PRIMARY KEY (username, backend), 

 UNIQUE (username, frontend)

)

· username, password: 連接後端db的用戶密碼。這個密碼你可以插入明文,也可以插入hash加密後的密文。 
· default_hostgroup: 這個用戶的請求沒有匹配到規則時,默認發到這個 hostgroup。 
· default_schema: 這個用戶連接時沒有指定 database name 時,默認使用的schema 注意表面上看默認爲NULL,但實際上受到變量 mysql-default_schema 的影響,默認爲 information_schema。 
· transaction_persistent: 如果設置爲1,連接上ProxySQL的會話後,如果在一個hostgroup上開啓了事務,那麼後續的sql都繼續維持在這個hostgroup上,不倫是否會匹配上其它路由規則,直到事務結束。 
· fast_forward: 忽略查詢重寫/緩存層,直接把這個用戶的請求透傳到後端DB。相當於只用它的連接池功能,一般不用,路由規則 .* 就行了。


mysql_query_rules


CREATE TABLE mysql_query_rules (  

  rule_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,  

  active INT CHECK (active IN (0,1)) NOT NULL DEFAULT 0, 

  username VARCHAR, 

  schemaname VARCHAR, 

  flagIN INT NOT NULL DEFAULT 0, 

  client_addr VARCHAR, 

  proxy_addr VARCHAR,

  proxy_port INT,

  digest VARCHAR, 

  match_digest VARCHAR, 

  match_pattern VARCHAR, 

  negate_match_pattern INT CHECK (negate_match_pattern IN (0,1)) NOT NULL DEFAULT 0, 

  flagOUT INT, 

  replace_pattern VARCHAR,

  destination_hostgroup INT DEFAULT NULL,

  cache_ttl INT CHECK(cache_ttl > 0),

  reconnect INT CHECK (reconnect IN (0,1)) DEFAULT NULL,

  timeout INT UNSIGNED,

  retries INT CHECK (retries>=0 AND retries <=1000),

  delay INT UNSIGNED,  mirror_flagOUT INT UNSIGNED,

  mirror_hostgroup INT UNSIGNED,  error_msg VARCHAR,

  log INT CHECK (log IN (0,1)),

  apply INT CHECK(apply IN (0,1)) NOT NULL DEFAULT 0,

  comment VARCHAR)


 · rule_id: 表主鍵,自增。規則處理是以 rule_id 的順序進行。

 · active: 只有 active=1 的規則纔會參與匹配。 
username: 如果非 NULL,只有連接用戶是 username 的值纔會匹配 
 · : 如果非 NULL,只有查詢連接使用的db是 schemaname 的值纔會匹配。 
 · client_addr: 匹配客戶端來源IP 
  · digest: 精確的匹配一類查詢。 
 · match_digest: 使用正則來匹配查詢指紋(去掉查詢參數後的查詢) 
  · match_pattern: 正則匹配查詢文本。 
  · negate_match_pattern: 反向匹配,相當於對 match_digest/match_pattern 的匹配取反。 
  · re_modifiers: 修改正則匹配的參數,比如默認的:忽略大小寫CASELESS、禁用GLOBAL上面都是匹配規則。 
  · replace_pattern: 查詢重寫,默認爲空,不rewrite。 
  · destination_hostgroup: 路由查詢到這個 hostgroup。當然如果用戶顯式 start transaction 且 transaction_persistent=1,那麼即使匹配到了,也依然按照事務裏第一條sql的路由規則去走。 
  · cache_ttl: 查詢結果緩存的毫秒數。 
  · timeout: 這一類查詢執行的最大時間(毫秒),超時則自動kill. 
  · retries: 語句在執行時失敗時,重試次數。默認由 mysql-query_retries_on_failure變量指定,爲1。 
  · delay: 查詢延遲執行,這是ProxySQL提供的限流機制,會讓其它的查詢優先執行。 
  · error_msg: 默認爲NULL,如果指定了則這個查詢直接被 block 掉,馬上返回這個錯誤信息。 
  · multiplex: 連接是否複用。 
  · log: 是否記錄查詢日誌。可以看到log是否記錄的對象是根據規則。


讀寫分離



ProxySQL作爲中間件能夠監聽接收到應用程序端的數據庫請求,並解析前端的SQL語句並將解析結果與查詢規則進行匹配,將匹配的SQL發送到相應的MySQL實例從而實現讀寫分離。這個過程入下圖所示:

 


1. 搭建MySQL主從,結構如下:


master: 192.168.20.31:3306

slave1: 192.168.20.32:3306

slave2:  192.168.20.33:3306

2. 在主庫中創建監控賬號用於ProxySQL監控目標主機。

create user 'monitor'@'%' identified with mysql_native_password by 'monitor';

grant select on sys.* to 'monitor'@'%';

grant select on performance_schema.* to 'monitor'@'%';

flush privileges;

3. 插入3個數據庫實例節點到ProxySQL

Admin> ×××ert into mysql_replication_hostgroups (writer_hostgroup,reader_hostgroup) values(10,20);

Admin> ×××ert into mysql_servers (hostgroup_id,hostname,port) values (10,'192.168.20.31',3306);

Admin> ×××ert into mysql_servers (hostgroup_id,hostname,port) values (20,'192.168.20.32',3306);

Admin> ×××ert into mysql_servers (hostgroup_id,hostname,port) values (10,'192.168.20.33',3306);

Admin> save mysql servers to disk;

Admin> load mysql servers to runtime;

4. 配置讀寫分離規則

Admin> INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply)VALUES

(1,1,'^SELECT.*FOR UPDATE$',10,1),(2,1,'^SELECT',20,1);

Admin> LOAD MYSQL QUERY RULES TO RUNTIME;

Admin> SAVE MYSQL QUERY RULES TO DISK;

5. 配置MySQL用戶到ProxySQL


Admin> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('app','pass',10);

Admin> save mysql users to disk;

Admin> load mysql users to runtime;


ProxySQL + Orchestrator實現高可用



Orchestrator(https://github.com/github/orchestrator)是MySQL複製結構的一個拓撲管理工具,能夠自動檢測MySQL拓撲結構,當主庫出現故障時能夠自動將“最優”從庫提升爲主庫。Orchestrator提供了豐富的API接口和故障檢測以及故障切換的鉤子函數,MyData正是通過Orchestrator提供的鉤子函數配合ProxySQL、Keepalived、HAProxy實現對應用程序無感知的故障切換。 


切換流程:


1. 首先Orchestrator檢測的後端主庫出現故障後會通過從庫二次確認主庫出現故障,避免了主庫高負載時出現誤判主庫down機。


2. Orchestrator切換之前將調用PreFailoverProcesses鉤子函數,MyData在鉤子函數中首先將“down”機的主庫從ProxySQL中踢出,避免應用程序將請求寫入到“假死”的主庫,執行語句如下: 

#強制關閉與假死主庫的連接,避免數據被寫入的假死的老主庫。 
Admin> update runtime_mysql_servers set status="HARD_OFFLINE" where hostname='192.168.20.31' and port='3306'


#將假死的老主庫提出集羣,避免後續數據被寫入到老主庫 
Admin> delete from mysql_servers where hostname='192.168.20.31' and port='3306' 
Admin> load mysql servers to runtime 
Admin> save mysql serbers to disk

3. MyData能夠根據用戶RPO、RTO“智能”作出恢復決定。 


4. MyData通知Orchestrator開發切換,Orchestrator切換完成之後,將修改新主庫的read_only值爲0。 

5. ProxySQL將新的寫請求路由到主庫。

整個流程之中MyData作了大量優化,能夠在滿足用戶RTO情況下,能將用戶丟失的數據減少到原來的10%以下,MyData還爲ProxySQL本身提供了高可用方案,避免了ProxySQL本身的單點故障。


總結



ProxySQL提供強大的路由規則。當應用程序自身不支持讀寫分離時,DBA可以通過配置路由規則爲應用程序提供透明的讀寫分離,使用Keepalived + ProxySQL + Orchestrator爲主從提供高可用時,能夠有效的避免keepalived + 雙主結構 由於keepalived腦裂而造成數據被寫錯亂的痛點。

鄭州不孕不育醫院:http://jbk.39.net/yiyuanzaixian/zztjyy//

關於MyData



MyData是雲和恩墨自主研發的,針對MySQL數據庫提供高可用、高可靠、高安全性和易於使用的整體解決方案。MyData融合了雲和恩墨資深數據庫工程師的經驗和最佳實踐,來幫助客戶快速構建高可用的數據庫集羣環境,保證了MySQL數據庫運行環境符合企業級數據庫的要求,幫助客戶提高快速交付的能力。 
雲和恩墨對MyData提供專業、靈動的端到端服務,涵蓋規劃設計、建設實施、運營管理和優化提升四個階段,爲客戶構建安全、連續、高效和穩定的數據環境。 
MyData目前已經在政府和金融行業擁有多個最佳實踐的案例,致力於爲企業提供開展開源數據庫一體化的解決方案。


轉載於:https://blog.51cto.com/14393777/2409359

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章