1. 程式人生 > >ProxySQL實現讀寫分離

ProxySQL實現讀寫分離

ProxySQL簡介

ProxySQL 是一款可以實際用於生產環境的 MySQL 中介軟體,它有官方版和 percona 版兩種。percona版是在官方版的基礎上修改的,添加了幾個比較實用的工具。生產環境建議用官方版。
ProxySQL 是用 C++ 語言開發的,雖然也是一個輕量級產品,但效能很好(據測試,能處理千億級的資料),功能也足夠,能滿足中介軟體所需的絕大多數功能,包括:
最基本的讀/寫分離,且方式有多種
可定製基於使用者、基於schema、基於語句的規則對SQL語句進行路由。換句話說,規則很靈活。基於schema和與語句級的規則,可以實現簡單的sharding
可快取查詢結果。雖然ProxySQL的快取策略比較簡陋,但實現了基本的快取功能,絕大多數時候也夠用了。此外,作者已經打算實現更豐富的快取策略
監控後端節點。ProxySQL可以監控後端節點的多個指標,包括:ProxySQL和後端的心跳資訊,後端節點的read-only/read-write,slave和master的資料同步延遲性(replication lag)

需求說明

通過mysql中介軟體ProxySQL實現mysql資料庫的讀寫分離

環境說明

ip 伺服器型別
192.168.161.154 mysql-mster
192.168.161.155 mysql-slave
192.168.161.164 ProxySQL

mysql-master和mysql-slave都已經安裝好mysql

操作步驟

  • 192.168.161.164

配置proxysql的yum源,安裝proxysql並啟動

[[email protected] ~]# vim /etc/yum.repos.d/proxysql.repo
[proxysql_repo]
name= ProxySQL
baseurl=http://repo.proxysql.com/ProxySQL/proxysql-1.4.x/centos/7
gpgcheck=1
gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
[[email protected] ~]# yum -y install proxysql
[
[email protected]
~]# systemctl start proxysql [[email protected] ~]# ss -antl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:6032 *:* LISTEN 0 128 *:6033 *:* LISTEN 0 128 *:6033 *:* LISTEN 0 128 *:6033 *:* LISTEN 0 128 *:6033 *:* LISTEN 0 128 *:22 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 128 :::22 :::* LISTEN 0 100 ::1:25
  • 192.168.161.154

新增proxysql可以增刪改查的賬號

[[email protected] ~]# mysql -uroot -p
Enter password: 
mysql> grant all on *.* to 'proxy'@'192.168.161.164' identified by 'proxy123!';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

  • 192.168.161.164

①.登陸proxysql管理端

[[email protected] ~]# yum -y install mariadb   
[[email protected] ~]# export MYSQL_PS1="(\[email protected]\h:\p) [\d]>"
 [[email protected] ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
  ([email protected]:6032) [(none)]>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 |
+-----+---------------+-------------------------------------+
5 rows in set (0.00 sec)
    

資料庫說明

  • main 記憶體配置資料庫,表裡存放後端db例項、使用者驗證、路由規則等資訊。表名以 runtime開頭的表示proxysql當前執行的配置內容,不能通過dml語句修改,只能修改對應的不以 runtime 開頭的(在記憶體)裡的表,然後 LOAD 使其生效, SAVE 使其存到硬碟以供下次重啟載入
  • disk 是持久化到硬碟的配置,sqlite資料檔案
  • stats 是proxysql執行抓取的統計資訊,包括到後端各命令的執行次數、流量、processlist、查詢種類彙總/執行時間等等
  • monitor 庫儲存 monitor 模組收集的資訊,主要是對後端db的健康/延遲檢查
  • stats_history 統計資訊歷史庫

②.proxysql新增連結後端mysql主從資料庫的配置

([email protected]:6032) [(none)]> show tables from main;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |  # ProxySQL的基本配置引數,類似與MySQL
| mysql_collations                           |  # 配置對MySQL字符集的支援
| mysql_group_replication_hostgroups         |  # MGR相關的表,用於例項的讀寫組自動分配
| mysql_query_rules                          |  # 路由表
| mysql_query_rules_fast_routing             |  # 主從複製相關的表,用於例項的讀寫組自動分配
| mysql_replication_hostgroups               |  # 儲存MySQL例項的資訊
| mysql_servers                              |  # 儲存MySQL使用者
| mysql_users                                |  # 儲存ProxySQL的資訊,用於ProxySQL Cluster同步
| proxysql_servers                           |  # 執行環境的儲存校驗值
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |  # 與上面對應,但是執行環境正在使用的配置
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |  # 定時任務表
+--------------------------------------------+
20 rows in set (0.00 sec)

([email protected]:6032) [(none)]>insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'192.168.161.154',3306,1,'Write Group');        //新增表示寫組的伺服器ip
([email protected]:6032) [(none)]>insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(2,'192.168.161.155',3306,1,'Read Group');             //新增表示讀組的伺服器ip
([email protected]:6032) [(none)]>select * from mysql_servers;
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| hostgroup_id | hostname        | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment     |
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| 1            | 192.168.161.154 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              | Write Group |
| 2            | 162.168.161.155 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              | Read Group  |
+--------------+-----------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+

([email protected]:6032) [(none)]>load mysql servers to runtime;          //載入到runtime
Query OK, 0 rows affected (0.00 sec)

([email protected]:6032) [(none)]>save mysql servers to disk;           //儲存到disk
Query OK, 0 rows affected (0.07 sec)

runtime_ 開頭的是執行時的配置,這些是不能修改的。要修改 ProxySQL 的配置,需要修改了非 runtime_ 表,修改後必須執行 LOAD … TO RUNTIME 才能載入到 RUNTIME 生效,執行 save … to disk 才能將配置持久化儲存到磁碟
下面語句中沒有先切換到 main 庫也執行成功了,因為 ProxySQL 內部使用的 SQLite3 資料庫引擎,和 MySQL 的解析方式是不一樣的。即使執行了 USE main 語句也是無任何效果的,但不會報錯
使用 insert 語句新增 mysql 主機到 mysql_servers 表中,其中:hostgroup_id 1 表示寫組,2表示讀組

③.新增用於操作讀寫分離的賬號到管理端

在 proxysql 主機的 mysql_users 表中新增剛才在 master 上建立的賬號 proxysql,proxysql 客戶端需要使用這個賬號來訪問資料庫
default_hostgroup 預設組設定為寫組,也就是1;
當讀寫分離的路由規則不符合時,會訪問預設組的資料庫;

(ad[email protected]:6032) [(none)]> insert into mysql_users(username,password,default_hostgroup,transaction_persistent)values('proxy','proxy123!',1,1);
Query OK, 1 row affected (0.00 sec)

([email protected]:6032) [(none)]> select * from mysql_users \G
*************************** 1. row ***************************
              username: proxy        # 後端mysql例項的使用者名稱
              password: proxy123!      # 後端mysql例項的密碼
                active: 1               # active=1表示使用者生效,0表示不生效
               use_ssl: 0
     default_hostgroup: 1               # 使用者預設登入到哪個hostgroup_id下的例項
        default_schema: NULL            # 使用者預設登入後端mysql例項時連線的資料庫,這個地方為NULL的話,則由全域性變數mysql-default_schema決定,預設是information_schema
         schema_locked: 0
transaction_persistent: 1       # 如果設定為1,連線上ProxySQL的會話後,如果在一個hostgroup上開啟了事務,那麼後續的sql都繼續維持在這個hostgroup上,不論是否會匹配上其它路由規則,直到事務結束。雖然預設是0
          fast_forward: 0       # 忽略查詢重寫/快取層,直接把這個使用者的請求透傳到後端DB。相當於只用它的連線池功能,一般不用,路由規則 .* 就行了
               backend: 1
              frontend: 1
       max_connections: 10000   # 該使用者允許的最大連線數
1 row in set (0.00 sec)

([email protected]:6032) [(none)]> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

([email protected]:6032) [(none)]> save mysql users to disk;
Query OK, 0 rows affected (0.00 sec)
  • 192.168.161.154

新增健康檢測賬號,在master上建立一個只有讀許可權的賬號

mysql> grant select on *.* to 'read'@'%' identified by 'read123!';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
  • 192.168.161.164

①.在proxysql管理端新增健康監測的賬號

([email protected]:6032) [(none)]>set mysql-monitor_username='read';
Query OK, 1 row affected (0.00 sec)

([email protected]:6032) [(none)]>set mysql-monitor_password='read123!';
Query OK, 1 row affected (0.00 sec)

([email protected]:6032) [(none)]>load mysql variables to runtime;
Query OK, 0 rows affected (0.00 sec)

([email protected]:6032) [(none)]>save mysql variables to disk;
Query OK, 97 rows affected (0.00 sec將 select 查詢語句全部路由至 hostgroup_id=2 的組(也就是讀組)

②.新增讀寫分離的路由規則

  • 將 select 查詢語句全部路由至 hostgroup_id=2 的組(也就是讀組)
  • 但是 select * from tb for update 這樣的語句是會修改資料的,所以需要單獨定義,將它路由至 hostgroup_id=1 的組(也就是寫組)
  • 其他沒有被規則匹配到的組將會被路由至使用者預設的組(mysql_users 表中的 default_hostgroup)
([email protected]:6032) [(none)]>insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(1,1,'^SELECT.*FOR UPDATE$',1,1);
Query OK, 1 row affected (0.00 sec)

([email protected]:6032) [(none)]>insert into mysql_query_rules(rule_id,active,match_digest,destination_hostgroup,apply)values(2,1,'^SELECT',2,1);
Query OK, 1 row affected (0.00 sec)

([email protected]:6032) [(none)]>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     |
+---------+--------+----------------------+-----------------------+-------+
2 rows in set (0.00 sec)

([email protected]:6032) [(none)]>load mysql query rules to runtime;
Query OK, 0 rows affected (0.00 sec)

([email protected]:6032) [(none)]>load admin variables to runtime;
Query OK, 0 rows affected (0.00 sec)

([email protected]:6032) [(none)]>save mysql query rules to disk;
Query OK, 0 rows affected (0.01 sec)

([email protected]:6032) [(none)]>save admin variables to disk;
Query OK, 31 rows affected (0.00 sec)

驗證讀寫分離

登陸proxysql客戶端,使用我們之前建立的賬號

建立一個數據庫並檢視一下表

[[email protected] ~]# mysql -uproxysql -pproxy123! -h127.0.0.1 -P6033
([email protected]:6033) [(none)]>create database test;         
Query OK, 1 row affected (0.01 sec)  

([email protected]:6033) [(none)]>select user,host from mysql.user;
+---------------+-----------------+
| user          | host            |
+---------------+-----------------+
| read          | %               |
| proxy         | 192.168.161.164 |
| mysql.session | localhost       |
| mysql.sys     | localhost       |
| root          | localhost       |
+---------------+-----------------+
5 rows in set (0.00 sec)


在proxysql管理端檢視

[[email protected] ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
([email protected]:6032) [(none)]>select * from stats_mysql_query_digest;
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+
| hostgroup | schemaname         | username | digest             | digest_text                      | count_star | first_seen | last_seen  | sum_time | min_time | max_time |
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+
| 2         | information_schema | proxy    | 0xD67B48164A6380F2 | select user from mysql.user      | 1          | 1543200189 | 1543200189 | 27857    | 27857    | 27857    |
| 1         | information_schema | proxy    | 0x30327C1D25D51434 | create database test             | 1          | 1543200283 | 1543200283 | 5543     | 5543     | 5543     |
+-----------+--------------------+----------+--------------------+----------------------------------+------------+------------+------------+----------+----------+----------+

可以看到讀操作是在hostgroup=2也就是讀組上面進行,寫操作是在hostgroup=1也就是寫組上面進行的