ProxySQL hand-on
René Cannaò ProxySQL
Frankfurt, 5th Nov 2018
René Cannaò ProxySQL
Frankfurt, 5th Nov 2018
ProxySQL hand-on Ren Canna Ren Canna ProxySQL ProxySQL Frankfurt, - - PowerPoint PPT Presentation
ProxySQL hand-on Ren Canna Ren Canna ProxySQL ProxySQL Frankfurt, 5 th Nov 2018 Frankfurt, 5 th Nov 2018 A bit about ProxySQL LLC We provide services to help build, support We provide services to help build, support as well as
René Cannaò ProxySQL
Frankfurt, 5th Nov 2018
René Cannaò ProxySQL
Frankfurt, 5th Nov 2018
2
We provide services to help build, support as well as improve the performance & reliability of your Cloud-Based or On- Premise MySQL infrastructure:
We provide services to help build, support as well as improve the performance & reliability of your Cloud-Based or On- Premise MySQL infrastructure:
3
4
5
7
8
Data gateway Clients connect to ProxySQL Requests are evaluated Actions are performed
9
1
1 1
1 2
1 3
1 4
1 5
1 6
HG0: main write masters HG1: main read slaves HG2: reporting slaves HG3: ad-hoc queries slaves HG4: data warehouse write masters HG5: data warehouse read slaves HG6: remote site servers HG7: test servers HG8 : mirror for traffjc on HG0 HG9 : mirror for traffjc on HG1 HG0: main write masters HG1: main read slaves HG2: reporting slaves HG3: ad-hoc queries slaves HG4: data warehouse write masters HG5: data warehouse read slaves HG6: remote site servers HG7: test servers HG8 : mirror for traffjc on HG0 HG9 : mirror for traffjc on HG1
1 7
HG0 HG2 HG1
1 8
HG0 HG2 HG1
1 9
2
2 1
2 2
DB DB DB
APP
DB PROXYSQL DB DB
APP
PROXYSQL
APP
PROXYSQL
APP
PROXYSQL PROXYSQL PROXYSQL DBMANAGER PROXYSQL
Clustered Proxy Layer
2 3
Tested with:
proxysqls (16k total)
connections each (150k total) Single ProxySQL was tested with up to 950k connections ProxySQL 1.4 is able to process up to 750k QPS
Tested with:
proxysqls (16k total)
connections each (150k total) Single ProxySQL was tested with up to 950k connections ProxySQL 1.4 is able to process up to 750k QPS
2 4
Real setups: Over 1000 proxysql instances in a single network Over 100 mysql servers configured on a single proxysql instances Over 2 millions unique users Routing with over 100 thousands shards Real setups: Over 1000 proxysql instances in a single network Over 100 mysql servers configured on a single proxysql instances Over 2 millions unique users Routing with over 100 thousands shards
2 6
HG0 HG1
Queries cache Query Processor
Thread #1 Thread #2 Thread #3 Users Auth
Connection Pool Hostgroup Manager Admin Monitoring
2 7
HG0 HG1
Queries cache Query Processor
Thread #1 Thread #2 Thread #3 Users Auth
Connection Pool Hostgroup Manager Admin Monitoring ClickHouse Server
ClickHouse Auth
Cluster SQLite3 Server
Thread #3 idles Thread #2 idles Thread #1 idles
Purge Thread
2 8
Threads in ProxySQL are known as "MySQL Threads" Fixed number of worker threads (confjgurable) All threads listen on the same port(s) Client connections are not shared between threads All threads perform their own network I/O Uses "poll()"... (does it scale?)
2 9
Pros: Thread contention is reduced No need for synchronization Each thread calls "poll()" Cons: Possibly imbalanced load Thread 1 Thread 2 Thread 3
3
"poll()" is O(N) "epoll()" is O(1) "epoll()" scales better than "poll()" Why does ProxySQL use "poll()"? It is faster than "epoll()" for fewer connections (~1000) Performance degrades when there are a lot of connections
3 1
Each worker thread has an auxiliary thread Worker thread uses "poll()" Auxiliary thread uses "epoll()" Worker thread passes idle connections to auxiliary thread When a connections becomes active auxiliary thread passes connection to the worker thread Solution scales to almost 1 million connections Thread 1 Aux 1 Thread 2 Aux 2 Thread 3 Aux 3
3 2
MySQL Session MySQL Session MySQL Session MySQL Session
MySQL Thread
MySQL Session MySQL Session
All other Modules:
For low contention, threads independently: Track internal metrics Store values for mysql-XXX variables Store a copy of the defjned query rules
3 3
Based on Queries Rules Defjnes what to cache Defjnes the hostgroup target Timeout/delay Firewall Mirroring Rewrite queries Based on Queries Rules Defjnes what to cache Defjnes the hostgroup target Timeout/delay Firewall Mirroring Rewrite queries
3 4
Complex rules to match incoming traffjc:
Rules can be chained Complex rules to match incoming traffjc:
Rules can be chained
3 5
Caching on the wire Internal key/value storage In memory only Pattern based Expired by timeout Rewrite on the wire Regex match/replace on query on digest text Optionally cached or mirrored Caching on the wire Internal key/value storage In memory only Pattern based Expired by timeout Rewrite on the wire Regex match/replace on query on digest text Optionally cached or mirrored
3 6
3 7
3 8
3 9
4
4 1
Replies to ping. From hundreds of millions of ping per day, to 0:
https://www.percona.com/blog/2017/09/01/life360-used-proxysql-lower-database-load/
Replies to ping. From hundreds of millions of ping per day, to 0:
https://www.percona.com/blog/2017/09/01/life360-used-proxysql-lower-database-load/
4 2
4 3
4 4
4 5
No ProxySQL: ProxySQL:
4 6
No ProxySQL: ProxySQL:
4 7
ProxySQL: No ProxySQL:
4 8
4 9
https://www.percona.com/blog/2017/09/01/life360-used-proxysql-lower-database-load/ https://www.percona.com/blog/2017/09/01/life360-used-proxysql-lower-database-load/
5
MyHGM is a shared resource so it can cause contention when accessed by MySQL Threads
MySQL_Thread MySQL_Thread
5 1
MySQL_Thread MySQL_Thread
Connections Cache Connections Cache
5 3
5 4
5 5
5 6
5 7
5 8
It monitors backends and collects metrics Monitors replication lag and shun hosts Monitors read_only (and super_read_only and innodb_read_only in 2.0) variables (replication hostgroups) Ping and terminates unresponsive nodes It monitors backends and collects metrics Monitors replication lag and shun hosts Monitors read_only (and super_read_only and innodb_read_only in 2.0) variables (replication hostgroups) Ping and terminates unresponsive nodes
5 9
Built in support for asynchronous replication: second behind master and pt-heartbeat Support for any type of clustering solution via external scripts (Galera/PXC , and any heterogeneous replication setup) In ProxySQL 1.4, support for Group Replication In ProxySQL 2.0, support for Galera Built in support for asynchronous replication: second behind master and pt-heartbeat Support for any type of clustering solution via external scripts (Galera/PXC , and any heterogeneous replication setup) In ProxySQL 1.4, support for Group Replication In ProxySQL 2.0, support for Galera
6 1
Allows runtime confjguration Exports internal statuses It uses MySQL protocol Confjguration possible from any client/tool using MySQL API Covered during the tutorial Allows runtime confjguration Exports internal statuses It uses MySQL protocol Confjguration possible from any client/tool using MySQL API Covered during the tutorial
6 2
Disk Memory Runtime Disk Memory Runtime
6 3
6 5
https://github.com/renecannao/ProxySQL-Tutorial-PLSC2018
https://github.com/renecannao/ProxySQL-Tutorial-PLSC2018
6 7
Introduced in 1.4.2 Support for MySQL Query Rules, MySQL Users, MySQL Servers and ProxySQL Servers (no Global Variables, no Scheduler) A group of instances constantly check each other for changes in configuration A configuration change applied in a proxy is pulled by the other proxies Allow to keep multiple ProxySQL instances with the same configuration(s) Introduced in 1.4.2 Support for MySQL Query Rules, MySQL Users, MySQL Servers and ProxySQL Servers (no Global Variables, no Scheduler) A group of instances constantly check each other for changes in configuration A configuration change applied in a proxy is pulled by the other proxies Allow to keep multiple ProxySQL instances with the same configuration(s)
6 8
Largest setup we know: 1) 3 core nodes 2) 900 satellite nodes
6 9
Conflict resolution is timestamp based
No quorum (in the roadmap) Highly scalable: Core nodes vs satellite nodes Conflict resolution is timestamp based
No quorum (in the roadmap) Highly scalable: Core nodes vs satellite nodes
7
mysql> SET admin-cluster_username='radmin'; mysql> SET admin-cluster_password='radmin'; mysql> LOAD ADMIN VARIABLES TO RUNTIME; mysql> SAVE ADMIN VARIABLES TO DISK; mysql> INSERT INTO proxysql_servers (hostname) VALUES ('proxysql1'),('proxysql2'), ('proxysql3'); mysql> LOAD PROXYSQL SERVERS TO RUNTIME; mysql> SAVE PROXYSQL SERVERS TO DISK; mysql> SET admin-cluster_username='radmin'; mysql> SET admin-cluster_password='radmin'; mysql> LOAD ADMIN VARIABLES TO RUNTIME; mysql> SAVE ADMIN VARIABLES TO DISK; mysql> INSERT INTO proxysql_servers (hostname) VALUES ('proxysql1'),('proxysql2'), ('proxysql3'); mysql> LOAD PROXYSQL SERVERS TO RUNTIME; mysql> SAVE PROXYSQL SERVERS TO DISK;
mysql> SHOW VARIABLES LIKE 'admin-cluster%'; +---------------------------------------------------+--------+ | Variable_name | Value | +---------------------------------------------------+--------+ | admin-cluster_username | radmin | | admin-cluster_password | radmin | | admin-cluster_check_interval_ms | 1000 | | admin-cluster_check_status_frequency | 10 | | admin-cluster_mysql_query_rules_difgs_before_sync | 3 | | admin-cluster_mysql_servers_difgs_before_sync | 3 | | admin-cluster_mysql_users_difgs_before_sync | 3 | | admin-cluster_proxysql_servers_difgs_before_sync | 3 | | admin-cluster_mysql_query_rules_save_to_disk | true | | admin-cluster_mysql_servers_save_to_disk | true | | admin-cluster_mysql_users_save_to_disk | true | | admin-cluster_proxysql_servers_save_to_disk | true | +---------------------------------------------------+--------+ 12 rows in set (0.00 sec) mysql> SHOW VARIABLES LIKE 'admin-cluster%'; +---------------------------------------------------+--------+ | Variable_name | Value | +---------------------------------------------------+--------+ | admin-cluster_username | radmin | | admin-cluster_password | radmin | | admin-cluster_check_interval_ms | 1000 | | admin-cluster_check_status_frequency | 10 | | admin-cluster_mysql_query_rules_difgs_before_sync | 3 | | admin-cluster_mysql_servers_difgs_before_sync | 3 | | admin-cluster_mysql_users_difgs_before_sync | 3 | | admin-cluster_proxysql_servers_difgs_before_sync | 3 | | admin-cluster_mysql_query_rules_save_to_disk | true | | admin-cluster_mysql_servers_save_to_disk | true | | admin-cluster_mysql_users_save_to_disk | true | | admin-cluster_proxysql_servers_save_to_disk | true | +---------------------------------------------------+--------+ 12 rows in set (0.00 sec)
7 1
stats_proxysql_servers_checksums stats_proxysql_servers_metrics stats_proxysql_servers_checksums stats_proxysql_servers_metrics
7 4
7 5
7 6
7 7
mysql_users
mysql_users
mysql_query_rules
mysql_query_rules
7 8
flagOUT replace_pattern destination_hostgroup cache_ttl timeout retries delay mirror_flagOUT mirror_hostgroup OK_msg error_msg log multiplex apply flagOUT replace_pattern destination_hostgroup cache_ttl timeout retries delay mirror_flagOUT mirror_hostgroup OK_msg error_msg log multiplex apply
active New in 2.0 : gtid_from_hostgroup cache_empty_result cache_timeout active New in 2.0 : gtid_from_hostgroup cache_empty_result cache_timeout
7 9
Disk Memory Runtime Disk Memory Runtime
8
Confirm the query hits with stats_mysql_query_rules double check rules and rewrite results hold off on writing rules to disk until you're sure they are working as expected have a rollback plan
test select query rules and rewrites on a slaves first test mutable rules on a mirror or other throw away db. Confirm the query hits with stats_mysql_query_rules double check rules and rewrite results hold off on writing rules to disk until you're sure they are working as expected have a rollback plan
test select query rules and rewrites on a slaves first test mutable rules on a mirror or other throw away db.
8 1 mysql> SELECT username, default_hostgroup FROM mysql_users\G *************************** 1. row *************************** username: root default_hostgroup: 0 1 row in set (0.00 sec) mysql> SELECT match_digest, destination_hostgroup FROM mysql_query_rules\G *************************** 1. row *************************** match_digest: ^SELECT.*FOR UPDATE destination_hostgroup: 0 *************************** 2. row *************************** match_digest: ^SELECT destination_hostgroup: 1 2 rows in set (0.00 sec) mysql> SELECT username, default_hostgroup FROM mysql_users\G *************************** 1. row *************************** username: root default_hostgroup: 0 1 row in set (0.00 sec) mysql> SELECT match_digest, destination_hostgroup FROM mysql_query_rules\G *************************** 1. row *************************** match_digest: ^SELECT.*FOR UPDATE destination_hostgroup: 0 *************************** 2. row *************************** match_digest: ^SELECT destination_hostgroup: 1 2 rows in set (0.00 sec)
For production configuration guide, see: https://proxysql.com/blog/configure-read-write-split
Click to add text Click to add text
8 4
Requires Linux Kernel 3.9 Use different datadir (optionally different config file) Close the listener for a process Drain connections from one node Wait all the connections to pass over Requires Linux Kernel 3.9 Use different datadir (optionally different config file) Close the listener for a process Drain connections from one node Wait all the connections to pass over
Click to add text Click to add text
8 6
8 7
8 8
Validate performance on a difgerent server using difgerent hostgroups. Validate performance of query rewrite or schema change Pre-fetch slave replication (Replication Booster) Validate performance on a difgerent server using difgerent hostgroups. Validate performance of query rewrite or schema change Pre-fetch slave replication (Replication Booster)
8 9
mysql>SHOW CREATE TABLE mysql_query_rules\G *********************** 1. row ************************ table: mysql_query_rules Create T able: 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, fmagIN INT NOT NULL DEFAULT 0, *snip* mirror_fmagOUT INT UNSIGNED, mirror_hostgroup INT UNSIGNED, error_msg VARCHAR, *snip*) mysql>SHOW CREATE TABLE mysql_query_rules\G *********************** 1. row ************************ table: mysql_query_rules Create T able: 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, fmagIN INT NOT NULL DEFAULT 0, *snip* mirror_fmagOUT INT UNSIGNED, mirror_hostgroup INT UNSIGNED, error_msg VARCHAR, *snip*)
9
9 1
mysql> SELECT username, destination_hostgroup, mirror_hostgroup, mirror_fmagOUT FROM mysql_query_rules WHERE username='plam_mirror'\G ****************** 1. row ********************** username: pl_mirror destination_hostgroup: 3 mirror_hostgroup: 4 mirror_fmagOUT: NULL mysql> SELECT username, destination_hostgroup, mirror_hostgroup, mirror_fmagOUT FROM mysql_query_rules WHERE username='plam_mirror'\G ****************** 1. row ********************** username: pl_mirror destination_hostgroup: 3 mirror_hostgroup: 4 mirror_fmagOUT: NULL
9 2
Click to add text Click to add text
9 4
Can be dropped: mysql-mirror_max_concurrency, mysql-mirror_max_queue_length Can be executed out of order No error handling of failed queries Can be dropped: mysql-mirror_max_concurrency, mysql-mirror_max_queue_length Can be executed out of order No error handling of failed queries
9 6
improve failover time as perceived by the application prevent errors sent to the application perform transparent database failovers: gracefully redirecting traffic without the application knowing existing applications do not have to be rewritten to autoreconnect since connections are not lost from failovers improve failover time as perceived by the application prevent errors sent to the application perform transparent database failovers: gracefully redirecting traffic without the application knowing existing applications do not have to be rewritten to autoreconnect since connections are not lost from failovers
9 7
9 8
9 9
1
1 1
1 2
1 3
https://www.nylas.com/blog/growing-up-with-mysql/
1 4
https://www.nylas.com/blog/growing-up-with-mysql/
1 5
mysql> SELECT hostgroup_id, hostname, status FROM mysql_servers WHERE hostname IN ('mysql1, 'mysql2’)\G *************************** 1. row *************************** hostgroup_id: 0 hostname: mysql1 status: ONLINE *************************** 2. row *************************** hostgroup_id: 1 hostname: mysql2 status: ONLINE 2 rows in set (0.00 sec) mysql> SELECT hostgroup_id, hostname, status FROM mysql_servers WHERE hostname IN ('mysql1, 'mysql2’)\G *************************** 1. row *************************** hostgroup_id: 0 hostname: mysql1 status: ONLINE *************************** 2. row *************************** hostgroup_id: 1 hostname: mysql2 status: ONLINE 2 rows in set (0.00 sec)
1 6
mysql> SELECT * FROM mysql_replication_hostgroups\G *************************** 1. row *************************** writer_hostgroup: 0 reader_hostgroup: 1 comment: 1 row in set (0.00 sec) mysql> SELECT * FROM mysql_replication_hostgroups\G *************************** 1. row *************************** writer_hostgroup: 0 reader_hostgroup: 1 comment: 1 row in set (0.00 sec)
1 7
Click to add text Click to add text
Click to add text Click to add text
1 1
New in 1.4.3 – experimental (not fully completed, subject to change) Support for ClickHouse: https://clickhouse.yandex/ Fast, really fast data analytics using MySQL client Users management Supports only one backend Supports only DDL and SELECT (no INSERT) New in 1.4.3 – experimental (not fully completed, subject to change) Support for ClickHouse: https://clickhouse.yandex/ Fast, really fast data analytics using MySQL client Users management Supports only one backend Supports only DDL and SELECT (no INSERT)
1 1 1
1 1 2
1 1 3
New in 1.4.3 – experimental (not fully completed, subject to change) Support for SQLite3 : https://www.sqlite.org/ Fully transactional, in-memory Same users as MySQL backends A lot of features in the roadmap New in 1.4.3 – experimental (not fully completed, subject to change) Support for SQLite3 : https://www.sqlite.org/ Fully transactional, in-memory Same users as MySQL backends A lot of features in the roadmap
1 1 4
What other service should become part of ProxySQL ? What other service should become part of ProxySQL ?
1 1 5
Feature introduced in 2.0 Ensures that reads sent to slave returns what the client has written on master Requires GTID and MySQL 5.7+ Feature introduced in 2.0 Ensures that reads sent to slave returns what the client has written on master Requires GTID and MySQL 5.7+
1 1 6
11 6
1 1 7
11 7
1 1 8
11 8
1 1 9
Feature introduced in 1.4.7 Simpler version of mysql_query_rules Used as a hash table
mysql> SELECT username,schemaname,flagIN, destination_hostgroup dest FROM mysql_query_rules_fast_routing; +----------+------------+--------+------+ | username | schemaname | flagIN | dest | +----------+------------+--------+------+ | userA | shard1 | 0 | 1 | | userA | shard2 | 0 | 1 | | userA | shard3 | 0 | 1 | | userA | shard4 | 0 | 1 | | userA | shard5 | 0 | 2 | | userA | shard6 | 0 | 2 | | userA | shard7 | 0 | 2 | +----------+------------+--------+------+
Feature introduced in 1.4.7 Simpler version of mysql_query_rules Used as a hash table
mysql> SELECT username,schemaname,flagIN, destination_hostgroup dest FROM mysql_query_rules_fast_routing; +----------+------------+--------+------+ | username | schemaname | flagIN | dest | +----------+------------+--------+------+ | userA | shard1 | 0 | 1 | | userA | shard2 | 0 | 1 | | userA | shard3 | 0 | 1 | | userA | shard4 | 0 | 1 | | userA | shard5 | 0 | 2 | | userA | shard6 | 0 | 2 | | userA | shard7 | 0 | 2 | +----------+------------+--------+------+
1 2
1 2 1
https://github.com/sysown/proxysql/
https://groups.google.com/forum/#!forum/proxysql
https://github.com/sysown/proxysql/
https://groups.google.com/forum/#!forum/proxysql