1. 程式人生 > 資料庫 >ProxySQL+Mysql實現資料庫讀寫分離實戰

ProxySQL+Mysql實現資料庫讀寫分離實戰

ProxySQL+Mysql實現資料庫讀寫分離實戰

收錄於話題
#MySQL從入門到放棄
26個

點選上方“民工哥Linux運維”,選擇“置頂公眾號”
有趣有內涵的文章第一時間送達!

ProxySQL介紹

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

1、連線池,而且是multiplexing
2、主機和使用者的最大連線數限制
3、自動下線後端DB
延遲超過閥值
ping 延遲超過閥值
網路不通或宕機
4、強大的規則路由引擎
實現讀寫分離
查詢重寫
sql流量映象
5、支援prepared statement
6、支援Query Cache
7、支援負載均衡,與gelera結合自動failover

整體環境介紹

ProxySQL+Mysql實現資料庫讀寫分離實戰

1、系統環境

三臺伺服器系統環境一致如下


[root@db1 ~]# cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core) 
[root@db1 ~]# uname -r
3.10.0-693.el7.x86_64

2、IP地址與軟體版本

  • proxy 192.168.22.171
  • db1 192.168.22.173
  • db2 192.168.22.174
  • mysql 5.7.17
  • proxy sql 1.4.8
    3、關閉防火牆、selinux
    systemctl stop firewalld  #停止防火牆服務
    systemctl disable firewalld  #禁止開機自啟動
    sed -i 's#SELINUX=enforcing#SELINUX=disabled#g'  /etc/selinux/conf  && reboot
    #用sed命令替換的試修改selinux的配置檔案

    4、mysql安裝與主從同步

安裝請參考以下文章

LAMP架構應用實戰——MySQL服務

主從同步請參以下文章

Linux系統MySQL資料庫主從同步實戰過程

安裝佈署過程

1、資料庫主從同步

檢視主從同步狀態

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.22.173
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-log.000001
          Read_Master_Log_Pos: 154
               Relay_Log_File: db2-relay-bin.000002
                Relay_Log_Pos: 321
        Relay_Master_Log_File: master-log.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 526
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 70a61633-63ae-11e8-ab86-000c29fe99ea
             Master_Info_File: /mysqldata/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

檢測主從同步

[root@db1 ~]# mysql -uroot -p -e "create database testdb;"
Enter password: 
[root@db1 ~]# mysql -uroot -p -e "show  databases;" |grep testdb
Enter password: 
testdb
#db2上檢視是否同步
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+
5 rows in set (0.01 sec)

2、準備proxySQL軟體

[root@proxy ~]# wget https://github.com/sysown/proxysql/releases/download/v1.4.8/proxysql-1.4.8-1-centos7.x86_64.rpm
[root@proxy ~]# ll proxysql-1.4.8-1-centos7.x86_64.rpm 
-rw-r--r-- 1 root root 5977168 Apr 10 11:38 proxysql-1.4.8-1-centos7.x86_64.rpm

3、安裝配置

[root@proxy ~]# yum install -y proxysql-1.4.8-1-centos7.x86_64.rpm
[root@proxy ~]# rpm -ql  proxysql
/etc/init.d/proxysql    #啟動指令碼
/etc/proxysql.cnf       #配置檔案,僅在第一次(/var/lib/proxysql/proxysql.db檔案不存在)啟動時有效。啟#動後可以在proxysql管理端中通過修改資料庫的方式修改配置並生效(官方推薦方式。)
/usr/bin/proxysql       #主程式檔案
/usr/share/proxysql/tools/proxysql_galera_checker.sh
/usr/share/proxysql/tools/proxysql_galera_writer.pl

4、配置檔案詳解


[root@proxy ~]# egrep -v "^#|^$" /etc/proxysql.cnf
datadir="/var/lib/proxysql"     #資料目錄
admin_variables=
{
    admin_credentials="admin:admin"   #連線管理端的使用者名稱與密碼
    mysql_ifaces="0.0.0.0:6032"       #管理埠,用來連線proxysql的管理資料庫
}
mysql_variables=
{
    threads=4                         #指定轉發埠開啟的執行緒數量
    max_connections=2048
    default_query_delay=0
    default_query_timeout=36000000
    have_compress=true
    poll_timeout=2000
    interfaces="0.0.0.0:6033"        #指定轉發埠,用於連線後端mysql資料庫的,相當於代理作用
    default_schema="information_schema"
    stacksize=1048576
    server_version="5.5.30"          #指定後端mysql的版本
    connect_timeout_server=3000
    monitor_username="monitor"
    monitor_password="monitor"
    monitor_history=600000
    monitor_connect_interval=60000
    monitor_ping_interval=10000
    monitor_read_only_interval=1500
    monitor_read_only_timeout=500
    ping_interval_server_msec=120000
    ping_timeout_server=500
    commands_stats=true
    sessions_sort=true
    connect_retries_on_failure=10
}
mysql_servers =
(
)
mysql_users:
(
)
mysql_query_rules:
(
)
scheduler=
(
)
mysql_replication_hostgroups=
(
)
#因此我們使用官方推薦的方式來配置proxy sql

5、啟動服務並檢視


[root@proxy ~]# /etc/init.d/proxysql start
Starting ProxySQL: DONE!
[root@proxy ~]# ss -lntup|grep proxy
tcp    LISTEN     0   128   *:6032      *:*    users:(("proxysql",pid=1199,fd=23))
tcp    LISTEN     0   128   *:6033      *:*    users:(("proxysql",pid=1199,fd=22))
tcp    LISTEN     0   128   *:6033      *:*    users:(("proxysql",pid=1199,fd=21))
tcp    LISTEN     0   128   *:6033      *:*    users:(("proxysql",pid=1199,fd=20))
tcp    LISTEN     0   128   *:6033      *:*    users:(("proxysql",pid=1199,fd=19))
#可以看出轉發埠6033是啟動了四個執行緒

6、在mysql上配置賬號並授權

mysql> GRANT ALL ON *.* TO 'proxysql'@'192.168.22.%' IDENTIFIED BY '123456';
Query OK, 0 rows affected, 1 warning (0.03 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.02 sec)

7、proxysql預設資料庫說明


[root@proxy ~]# yum install mysql -y
[root@proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.30 (ProxySQL Admin Module)

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(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的健康/延遲檢查。

8、proxysql的配置系統

ProxySQL具有一個複雜但易於使用的配置系統,可以滿足以下需求:

1、允許輕鬆動態更新配置(這是為了讓ProxySQL使用者可以在需要零宕機時間配置的大型基礎架構中使用它)。與MySQL相容的管理介面可用於此目的。
2、允許儘可能多的配置專案動態修改,而不需要重新啟動ProxySQL程序
3、可以毫不費力地回滾無效配置
4、這是通過多級配置系統實現的,其中設定從執行時移到記憶體,並根據需要持久儲存到磁碟。

3級配置由以下幾層組成:

+-------------------------+
|         RUNTIME         |
+-------------------------+
       /|\          |
        |           |
    [1] |       [2] |
        |          \|/
+-------------------------+
|         MEMORY          |
+-------------------------+ _
       /|\          |      |\
        |           |        \
    [3] |       [4] |         \ [5]
        |          \|/         \
+-------------------------+  +-------------------------+
|          DISK           |  |       CONFIG FILE       |
+-------------------------+  +-------------------------+
參考文章:https://github.com/sysown/proxysql/wiki/Configuring-ProxySQL

9、配置proxysql管理使用者

proxysql預設的表資訊如下


MySQL [main]> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| 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)
#這裡是使用insert into語句來動態配置,而可以不需要重啟
MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(1,'db1','3306',1,'Write Group');
Query OK, 1 row affected (0.01 sec)

MySQL [(none)]> insert into mysql_servers(hostgroup_id,hostname,port,weight,comment) values(2,'db2','3307',1,'Read Group');
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> select * from mysql_servers;
+--------------+----------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| hostgroup_id | hostname | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment     |
+--------------+----------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| 1            | db1      | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              | Write Group |
| 2            | db2      | 3307 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              | Read Group  |
+--------------+----------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+

2 rows in set (0.00 sec)
#接下來將剛剛在mysql客戶端建立的使用者寫入到proxy sql主機的mysql_users表中,它也是用於proxysql客戶端訪問資料庫,預設組是寫組,當讀寫分離規則出現問題時,它會直接訪問預設組的資料庫。
MySQL [main]> INSERT INTO mysql_users(username,password,default_hostgroup) VALUES ('proxysql','123456',1);
Query OK, 1 row affected (0.00 sec)

MySQL [main]> select * from mysql_users;
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| username | password | active | use_ssl | default_hostgroup | default_schema | schema_locked | transaction_persistent | fast_forward | backend | frontend | max_connections |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
| proxysql | 123456   | 1      | 0       | 1                 | NULL           | 0             | 1                      | 0            | 1       | 1        | 10000           |
+----------+----------+--------+---------+-------------------+----------------+---------------+------------------------+--------------+---------+----------+-----------------+
1 row in set (0.00 sec)

在mysql上新增監控的使用者

mysql> GRANT SELECT ON *.* TO 'monitor'@'192.168.22.%' IDENTIFIED BY 'monitor';
Query OK, 0 rows affected, 1 warning (0.00 sec)

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

#在proxysql主機端配置監控使用者
MySQL [main]> set mysql-monitor_username='monitor';
Query OK, 1 row affected (0.00 sec)

MySQL [main]> set mysql-monitor_password='monitor';
Query OK, 1 row affected (0.00 sec)
#參考文章:https://github.com/sysown/proxysql/wiki/ProxySQL-Configuration

10、配置proxysql的轉發規則

MySQL [main]> 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.01 sec)

MySQL [main]> 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)

MySQL [main]> 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)
#配置查詢select的請求轉發到hostgroup_id=2組上(讀組)
#徵對select * from table_name  for update這樣的修改語句,我們是需要將請求轉到寫組,也就是hostgroup_id=1
#對於其它沒有被規則匹配的請求全部轉發到預設的組(mysql_users表中default_hostgroup)

11、更新配置到RUNTIME中

由上面的配置系統層級關係可以得知所有進來的請求首先是經過RUNTIME層


MySQL [main]> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

MySQL [main]> load mysql servers to runtime;
Query OK, 0 rows affected (0.02 sec)

MySQL [main]> load mysql query rules to runtime;
Query OK, 0 rows affected (0.00 sec)

MySQL [main]> load mysql variables to runtime;
Query OK, 0 rows affected (0.00 sec)

MySQL [main]> load admin variables to runtime;
Query OK, 0 rows affected (0.00 sec)

12、將所有配置儲存至磁碟上

所有配置資料儲存到磁碟上,也就是永久寫入/var/lib/proxysql/proxysql.db這個檔案中

MySQL [main]> save mysql users to disk;
Query OK, 0 rows affected (0.03 sec)

MySQL [main]> save mysql servers to disk;
Query OK, 0 rows affected (0.04 sec)

MySQL [main]> save mysql query rules to disk;
Query OK, 0 rows affected (0.03 sec)

MySQL [main]> save mysql variables to disk;
Query OK, 94 rows affected (0.02 sec)

MySQL [main]> save admin variables to disk;
Query OK, 31 rows affected (0.02 sec)

MySQL [main]> load mysql users to runtime;
Query OK, 0 rows affected (0.00 sec)

13、測試讀寫分離

[root@proxy ~]# mysql -uproxysql -p123456 -h 127.0.0.1 -P 6033
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.30 (ProxySQL)

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb             |
+--------------------+
5 rows in set (0.02 sec)
#這才是我們真正的資料庫啊

建立資料與表,測試讀寫分離情況


MySQL [(none)]> create database test_proxysql;
Query OK, 1 row affected (0.02 sec)

MySQL [(none)]> use test_proxysql;
Database changed

MySQL [test_proxysql]> create table test_tables(name varchar(20),age int(4));
Query OK, 0 rows affected (0.07 sec)

MySQL [test_proxysql]> insert into test_tables values('zhao','30');
Query OK, 1 row affected (0.09 sec)

MySQL [test_proxysql]> select * from test_tables;
+------+------+
| name | age  |
+------+------+
| zhao |   30 |
+------+------+
1 row in set (0.02 sec)

在proxysql管理端檢視讀寫分離

MySQL [main]> 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         | test_proxysql      | proxysql | 0x57CF7EC26C91DF9A | select * from test_tables                            | 1          | 1527667635 | 1527667635 | 14253    | 14253    | 14253    |
| 1         | information_schema | proxysql | 0x226CD90D52A2BA0B | select @@version_comment limit ?                     | 1          | 1527667214 | 1527667214 | 0        | 0        | 0        |
| 1         | test_proxysql      | proxysql | 0xFF9877421CFBDA6F | insert into test_tables values(?,?)                  | 1          | 1527667623 | 1527667623 | 89033    | 89033    | 89033    |
| 1         | information_schema | proxysql | 0xE662AE2DEE853B44 | create database test-proxysql                        | 1          | 1527667316 | 1527667316 | 8470     | 8470     | 8470     |
| 1         | information_schema | proxysql | 0x02033E45904D3DF0 | show databases                                       | 1          | 1527667222 | 1527667222 | 19414    | 19414    | 19414    |
| 1         | information_schema | proxysql | 0xB9EF28C84E4207EC | create database test_proxysql                        | 1          | 1527667332 | 1527667332 | 15814    | 15814    | 15814    |
| 2         | information_schema | proxysql | 0x620B328FE9D6D71A | SELECT DATABASE()                                    | 1          | 1527667342 | 1527667342 | 23386    | 23386    | 23386    |
| 1         | test_proxysql      | proxysql | 0x02033E45904D3DF0 | show databases                                       | 1          | 1527667342 | 1527667342 | 2451     | 2451     | 2451     |
| 1         | test_proxysql      | proxysql | 0x59F02DA280268525 | create table test_tables                             | 1          | 1527667360 | 1527667360 | 9187     | 9187     | 9187     |
| 1         | test_proxysql      | proxysql | 0x99531AEFF718C501 | show tables                                          | 1          | 1527667342 | 1527667342 | 1001     | 1001     | 1001     |
| 1         | test_proxysql      | proxysql | 0xC745E37AAF6095AF | create table test_tables(name varchar(?),age int(?)) | 1          | 1527667558 | 1527667558 | 68935    | 68935    | 68935    |
+-----------+--------------------+----------+--------------------+------------------------------------------------------+------------+------------+------------+----------+----------+----------+
11 rows in set (0.01 sec)
#從上述結果就可以看出讀寫分離配置是成功的,讀請求是轉發到2組,寫請求轉發到1組

ProxySQL+Mysql實現資料庫讀寫分離實戰
整個讀寫分離的架構配置到此就完成了,但是此架構存在需要優化的地方,那就是此架構存在單點問題。實際生產環境中可採用MHA+ProxySQL+Mysql這類架構解決此問題,請持續關注【民工哥Linux運維】公眾號,後續輸出相關的架構實戰。

關於Mysql各類高可用架構可閱讀前面的文章

ProxySQL+Mysql實現資料庫讀寫分離實戰