1. 程式人生 > >ProxySQL簡介原理及讀寫分離應用

ProxySQL簡介原理及讀寫分離應用

#### MySQL-ProxySQL中介軟體簡介 ##### 同類型產品 - MySQL Route:是現在MySQL官方Oracle公司釋出出來的一箇中間件。 - Atlas:是由奇虎360公發的基於MySQL協議的資料庫中介軟體產品,它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基礎上,修改了若干Bug,並增加了很多功能特性。目前該產品在360內部得到了廣泛應用。 - DBProxy:是由美團點評公司技術工程部DBA團隊(北京)開發維護的一個基於MySQL協議的資料中間層。它在奇虎360公司開源的Atlas基礎上,修改了部分bug,並且添加了很多特性。 - Cobar:是阿里巴巴B2B開發的關係型分散式系統,管理將近3000個MySQL例項。 在阿里經受住了考驗,後面由於作者的走開的原因cobar沒有人維護 了,阿里也開發了tddl替代cobar。 - MyCAT:是社群愛好者在阿里cobar基礎上進行二次開發,解決了cobar當時存 在的一些問題,並且加入了許多新的功能在其中。目前MyCAT社群活躍度很高,目前已經有一些公司在使用MyCAT。總體來說支援度比較高,也會一直維護下去。 > ProxySQL是使用C++語言開發的,官網文件也很齊全,以下是其特色功能點: > > 上面提到的MyCAT我Mysql哪一個分類文章有親測過程,有興趣小夥伴可以移步看看. https://www.cnblogs.com/you-men/p/12838333.html - 查詢快取 - 查詢路由 - 故障轉移 - 線上配置立刻生效無需重啟 - 應用層代理 - 跨平臺 - 高階拓展支援 - 防火牆 通過上述,我們可以看到ProxySQL可以做許多事情,已經不僅僅是純粹的MySQL讀寫分離,其實我們通過後面所述結合業務發散,ProxySQL還可以支援以下高階功能: - 讀寫分離 - 資料庫叢集、分片 - 分庫分表 - 主從切換 - SQL審計 - 連線池 多路複用 - 負載均衡 - 查詢重寫 - 流量映象 - 自動重連 - 自動下線 `高可用架構` ![](https://img2020.cnblogs.com/blog/1871335/202006/1871335-20200607001408734-851453124.jpg) #### ProxySQL部署配置 ##### 環境清單 `list` ```python CentOS7.3 proxysql-2.0.12-1-centos7.x86_64.rpm mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar ``` | 主機 | 作業系統 | IP地址 | 硬體/網路 | | :---------- | :-------- | :------------ | :--------- | | Mysql105 | CentOS7.3 | 192.168.0.105 | 2C4G / nat | | Mysql106 | CentOS7.3 | 192.168.0.106 | 2C4G / nat | | Mysql107 | CentOS7.3 | 192.168.0.107 | 2C4G / nat | | ProxySQL109 | CentOS7.3 | 192.168.0.109 | 2C4G / nat | ##### 安裝Mysql ```shell #!/usr/bin/env bash # Author: ZhouJian # Mail: [email protected] # Time: 2019-9-3 # Describe: CentOS 7 Install Mysql.rpm Script clear echo -ne "\\033[0;33m" cat<_/___.' >' "". | | : '- \\'.;'\\ _ /';.'/ - ' : | | \\ \\ '_. \\_ __\\ /__ _/ .-' / / ====='-.____'.___ \\_____/___.-'____.-'===== '=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 建議系統 CentOS7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # PS:請儘量使用純淨的CentOS7系統,我們會在伺服器安裝Mysql5.7, # 將mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar包和指令碼放到root目錄下執行即可,密碼為ZHOUjian.20 EOT echo -ne "\\033[m" init_security() { systemctl stop firewalld systemctl disable firewalld &>/dev/null setenforce 0 sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config systemctl enable sshd crond &> /dev/null echo -e "\033[32m [安全配置] ==> OK \033[0m" } init_yumsource() { if [ ! -d /etc/yum.repos.d/backup ];then mkdir /etc/yum.repos.d/backup fi mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null if ! ping -c2 www.baidu.com &>/dev/null then echo "您無法上外網,不能配置yum源" exit fi curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo timedatectl set-timezone Asia/Shanghai echo "nameserver 114.114.114.114" > /etc/resolv.conf echo "nameserver 8.8.8.8" >> /etc/resolv.conf chattr +i /etc/resolv.conf echo -e "\033[32m [YUM Source] ==> OK \033[0m" } init_mysql() { rpm -e mariadb-libs --nodeps rm -rf /var/lib/mysql rm -rf /etc/my.cnf tar xvf /root/mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar -C /usr/local/ cd /usr/local rpm -ivh mysql-community-server-5.7.23-1.el7.x86_64.rpm \ mysql-community-client-5.7.23-1.el7.x86_64.rpm \ mysql-community-common-5.7.23-1.el7.x86_64.rpm \ mysql-community-libs-5.7.23-1.el7.x86_64.rpm rm -rf mysql-community-* } changepass() { sed -i '/\[mysqld]/ a skip-grant-tables' /etc/my.cnf systemctl restart mysqld mysql <
show master status; #+------------------+----------+--------------+------------------+-------------------+ #| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | #+------------------+----------+--------------+------------------+-------------------+ #| mysql-bin.000001 | 600 | | | | #+------------------+----------+--------------+------------------+-------------------+ #1 row in set (0.00 sec) ``` ##### 從庫開啟Slave ```python change master to master_host='192.168.0.102', master_user='slave', master_password='ZHOUjian.200', master_auto_position=0; mysql>
start slave; # 檢視從庫狀態 mysql> show slave status\G; ``` ##### 下載部署ProxySQL https://github.com/sysown/proxysql/releases ```shell wget https://github.com/sysown/proxysql/releases/download/v2.0.12/proxysql-2.0.12-1-centos7.x86_64.rpm yum install perl-DBD-MySQL3 -y rpm -ivh proxysql-2.0.12-1-centos7.x86_64.rpm service proxysql start proxysql --version # ProxySQL version 2.0.12-38-g58a909a, codename Truls # 本地配置檔案 # proxysql 有個配置檔案/etc/proxysql.cnf,只在第一次啟動的時候有用, # 後續所有的配置修改都是對 SQLite 資料庫操作,並且不會更新到proxysql.cnf檔案中。 # ProxySQL 絕大部分配置都可以線上修改,配置儲存在/var/lib/proxysql/proxysql.db ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:6032 *:* LISTEN 0 128 *:6033 *:* # 管理介面的埠是 6032 , 賬號密碼是 admin( 可以動態修改 ) 只能通過本地連線 , # 客戶端介面的埠是 6033 , 賬號密碼通過管理介面去設定。 ``` ##### 登入配置ProxySQL `登入管理介面,配置資訊從啟動程序的配置檔案檢視` ```shell cat /etc/proxysql.cnf |grep admin admin_variables= admin_credentials="admin:admin" # mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock" mysql -uadmin -padmin -h 127.0.0.1 -P6032 --prompt='proxysql>
' # 不推薦跟傳統服務一樣修改/etc/proxysql.conf # 之所以不推薦,是因為我們可以通過ProxySQL控制檯線上修改配置,無需重啟,立即生效。 show databases; +-----+---------------+-------------------------------------+ | seq | name | file | +-----+---------------+-------------------------------------+ | 0 | main | | | 2 | disk | /var/lib/proxysql/proxysql.db | | 3 | stats | | | 4 | monitor | | | 5 | stats_history | /var/lib/proxysql/proxysql_stats.db | +-----+---------------+-------------------------------------+ # main:預設資料庫,存放使用者驗證、路由規則等資訊。我們要做的配置都是針對這個庫的 # disk:持久化到硬碟的配置 # stats:proxysql執行抓取的統計資訊,如各命令的執行次數、查詢執行時間等 # monitor:monitor模組收集的資訊,db的健康情況、各種檢查等 # 設定SQL日誌記錄[ProxySQL] set mysql-eventslog_filename='queries.log'; # 新增主從[ProxySQL] insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'192.168.0.105',3306,1,'主庫'); insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'192.168.0.106',3306,9,'從庫'); insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'192.168.0.107',3306,1,'從庫'); # 檢視主從[ProxySQL] proxysql>select * from mysql_servers; +--------------+---------------+------+-----------+--------+--------+-------------+-----------------+----------- | hostgroup_id | hostname | port | gtid_port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment | +--------------+---------------+------+-----------+--------+--------+-------------+-----------------+----------- | 1 | 192.168.0.105 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | 主庫 | | 1 | 192.168.0.106 | 3306 | 0 | ONLINE | 9 | 0 | 1000 | 0 | 0 | 0 | 從庫 | | 1 | 192.168.0.107 | 3306 | 0 | ONLINE | 1 | 0 | 1000 | 0 | 0 | 0 | 從庫 | +--------------+---------------+------+-----------+--------+--------+-------------+-----------------+----------- # hostgroup_id:一個角色一個id,該表的主鍵是hostgroup_id+hostname+port # hostname:db例項IP # port:db例項埠 # weight:權重,如果有多個相同角色的例項,會優先選擇權重高的 # status:狀態 # -ONLINE 正常 # -SHUNNED 臨時被剔除 # -OFFLINE_SOFT 軟離線狀態,不再接受新的連線,已建立的連線會等待 # -OFFLINE_HARD 離線,不接收新連線, 已建立的連線也會強制斷開(宕機或者網路不可用) # max_connections:最大連線數 # max_replication_lag:允許的最大延遲 # 建立主從賬號[MySQL] create user 'proxysql'@'%' identified by 'ZHOUjian.21'; mysql> grant all privileges on *.* to 'proxysql'@'%' with grant option; # 新增主從賬號[ProxySQL] insert into mysql_users(username,password,default_hostgroup,transaction_persistent)values('proxysql','ZHOUjian.21',1,1); # 檢視主從賬號 select * from mysql_users\G; *************************** 1. row *************************** username: proxysql password: ZHOUjian.21 active: 1 use_ssl: 0 default_hostgroup: 1 default_schema: NULL schema_locked: 0 transaction_persistent: 1 fast_forward: 0 backend: 1 frontend: 1 max_connections: 10000 comment: # 建立監控賬號[MySQL] CREATE USER 'monitor'@'%' IDENTIFIED BY 'ZHOUjian.21'; GRANT SELECT ON *.* TO 'monitor'@'%' WITH GRANT OPTION; # 新增監控賬號[ProxySQL] set mysql-monitor_username='monitor'; set mysql-monitor_password='ZHOUjian.21'; # 檢視監控賬號[ProxySQL] select * from global_variables where variable_name like 'mysql-monitor_%'; +--------------------------------------------------------------+----------------+ | variable_name | variable_value | +--------------------------------------------------------------+----------------+ | mysql-monitor_enabled | true | | mysql-monitor_connect_timeout | 600 | | mysql-monitor_ping_max_failures | 3 | | mysql-monitor_ping_timeout | 1000 | | mysql-monitor_read_only_max_timeout_count | 3 | | mysql-monitor_replication_lag_interval | 10000 | | mysql-monitor_replication_lag_timeout | 1000 | | mysql-monitor_groupreplication_healthcheck_interval | 5000 | | mysql-monitor_groupreplication_healthcheck_timeout | 800 | | mysql-monitor_groupreplication_healthcheck_max_timeout_count | 3 | | mysql-monitor_groupreplication_max_transactions_behind_count | 3 | | mysql-monitor_galera_healthcheck_interval | 5000 | | mysql-monitor_galera_healthcheck_timeout | 800 | | mysql-monitor_galera_healthcheck_max_timeout_count | 3 | | mysql-monitor_replication_lag_use_percona_heartbeat | | | mysql-monitor_query_interval | 60000 | | mysql-monitor_query_timeout | 100 | | mysql-monitor_slave_lag_when_null | 60 | | mysql-monitor_threads_min | 8 | | mysql-monitor_threads_max | 128 | | mysql-monitor_threads_queue_maxsize | 128 | | mysql-monitor_wait_timeout | true | | mysql-monitor_writer_is_also_reader | true | | mysql-monitor_username | monitor | | mysql-monitor_password | ZHOUjian.21 | | mysql-monitor_history | 600000 | | mysql-monitor_connect_interval | 60000 | | mysql-monitor_ping_interval | 10000 | | mysql-monitor_read_only_interval | 1500 | | mysql-monitor_read_only_timeout | 500 | +--------------------------------------------------------------+----------------+ # 也可以像下面這樣快速定位 select @@mysql-monitor_username; +--------------------------+ | @@mysql-monitor_username | +--------------------------+ | monitor | +--------------------------+ select @@mysql-monitor_password; +--------------------------+ | @@mysql-monitor_password | +--------------------------+ | ZHOUjian.21 | +--------------------------+ ``` `檢測監控` ```python # 檢測上述配置是否正確:connect_error為NULL則正確 SELECT * FROM monitor.mysql_server_connect_log ORDER BY time_start_us DESC LIMIT 10; +---------------+------+------------------+-------------------------+------------------------------------------------------------------------+ | hostname | port | time_start_us | connect_success_time_us | connect_error | +---------------+------+------------------+-------------------------+------------------------------------------------------------------------+ | 192.168.0.106 | 3306 | 1591457209205112 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | | 192.168.0.107 | 3306 | 1591457208536560 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | | 192.168.0.105 | 3306 | 1591457207868147 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | SELECT * FROM monitor.mysql_server_ping_log ORDER BY time_start_us DESC LIMIT 10; +---------------+------+------------------+----------------------+------------------------------------------------------------------------+ | hostname | port | time_start_us | ping_success_time_us | ping_error | +---------------+------+------------------+----------------------+------------------------------------------------------------------------+ | 192.168.0.105 | 3306 | 1591457358442163 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | | 192.168.0.106 | 3306 | 1591457358348350 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | | 192.168.0.107 | 3306 | 1591457358252207 | 0 | Access denied for user 'monitor'@'192.168.0.109' (using password: YES) | ``` ##### 配置讀寫對映[ProxySQL] > 這裡配置主從自動切換: 互為主從,自動切換,保證高可用 `新增讀寫分離的路由規則` - 將select語句全部路由至hostgroup_id=2的組(也就是讀組) - 但是select * from tb for update這樣的語句是修改資料的,所以需要單獨定義,將它路由至hostgroup_id=1的組(也就是寫組) - 其他沒有被規則匹配到的組將會被路由至使用者預設的組(mysql_users表中的default_hostgroup) ```python insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(1,1,'^SELECT.*FOR UPDATE$',1,1); insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(2,1,'^SELECT',2,1); select rule_id,active,match_digest,destination_hostgroup,apply from mysql_query_rules; +---------+--------+----------------------+-----------------------+-------+ | rule_id | active | match_digest | destination_hostgroup | apply | +---------+--------+----------------------+-----------------------+-------+ | 1 | 1 | ^SELECT.*FOR UPDATE$ | 1 | 1 | | 2 | 1 | ^SELECT | 2 | 1 | +---------+--------+----------------------+-----------------------+-------+ # 將剛才我們修改的資料載入至RUNTIME中(參考ProxySQL的多層配置結構): # load進runtime,使配置生效 load mysql query rules to runtime; load admin variables to runtime; # save到磁碟(/var/lib/proxysql/proxysql.db)中,永久儲存配置 save mysql query rules to disk; save admin variables to disk; ``` #### 測試讀寫分離 ##### 連結proxysql客戶端 > 登入使用者是剛才我們在mysql_user表中建立的使用者,埠為6033 ```mysql mysql -uproxysql -ppwproxysql -h127.0.0.1 -P6033 ``` ##### 驗證讀寫分離是否成功 - proxysql有個類似審計的功能,可以檢視各類SQL的執行情況。在proxysql管理端執行: - 從下面的hostgroup和digest_text值來看,所有的寫操作都被路由至1組,讀操作都被路由至2組, - 其中1組為寫組,2組為讀組! ```mysql select * from stats_mysql_query_dige