DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Custom Model Context Protocol (MCP) for NL2SQL: A Rigorous Evaluation Framework on Oracle Database
  • Why Queues Don’t Fix Scaling Problems
  • Using Arrow Flight SQL to Improve Data Transfer Performance in Apache Doris
  • Automating a Web Form With Playwright MCP and MySQL MCP

Trending

  • Stateless JWT Auth Microservice Architecture With Spring Boot 3 and Redis Sentinel
  • A Walk-Through of the DZone Article Editor
  • Offline-First Patch Management for 10,000 Edge Nodes: A Practical Architecture That Scales
  • The Agentic Agile Office: Streamlining Enterprise Agile With Autonomous AI Agents
  1. DZone
  2. Data Engineering
  3. Databases
  4. Rate Limit (Throttle) for MySQL With ProxySQL

Rate Limit (Throttle) for MySQL With ProxySQL

In this article, explore rate limit for MySQL with ProxySQL.

By 
Daniel Guzman Burgos user avatar
Daniel Guzman Burgos
·
Oct. 14, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
7.9K Views

Join the DZone community and get the full member experience.

Join For Free

Maybe one of the more "obscure" operations when dealing with replica lag, or, in general, when one needs to control writes to the database, is the Rate limit. It's also lately one of the most popular conversations around the community.

But what is it? In plain words: holding up queries for a while, giving air to the replicas to breath and catch up. Something similar to the Galera's Flow Control mechanism, although flow control, when it kicks in, stops all the writes while the nodes catch up. With a throttle no write is stopped, just delayed.

There are several ways to do this. A popular tool is Freno but this is also something that can be achieved with ProxySQL. Let's see how.

Delay

ProxySQL has a variable called "mysql-default_query_delay" that is pretty self-explanatory. It will add a delay, in milliseconds, to all the queries passing through ProxySQL.

Now, the trick is to monitor the replica lag and apply the delay. Something that in this case is solved with a small bash script:

Shell
 




x
46


 
1
#/bin/bash
2

           
3
set -o pipefail
4

           
5
proxysqlhost=127.0.0.1
6
proxysqladmport=6032
7
proxysqluser=admin
8
proxysqlpass=admin
9

           
10
replicahost=mysql2
11
replicauser=pmm
12
replicapass=pmm
13

           
14
lagThreshold=3
15

           
16

           
17
function check_lag() {
18
         lag=$(mysql -h$replicahost -u$replicauser -p$replicapass -e "SHOW SLAVE STATUS\G" | grep  "Seconds_Behind_Master" | awk -F\: '{print $2}' 2>&1)
19
}
20

           
21
function modifyProxysqlVariable () {
22
        out=$(mysql -u$proxysqluser -p$proxysqlpass -h$proxysqlhost -P6032 -e"set mysql-default_query_delay = $delay ; LOAD MYSQL VARIABLES TO RUNTIME;" 2>&1)
23
        echo $out
24
}
25

           
26
function destructor () {
27
        delay=0
28
        modifyProxysqlVariable
29
        echo "bye"
30
}
31

           
32
trap destructor EXIT INT TERM
33

           
34
while true; do
35

           
36
        check_lag
37
        echo $lag
38
        if [ $lag -ge $lagThreshold ]; then
39
                delay=1
40
                modifyProxysqlVariable
41
        elif [ $lag -eq 0 ]; then
42
                delay=0
43
                modifyProxysqlVariable
44
        fi
45
        sleep 0.001
46
done



Replica lag will be monitored on a loop, and when it's bigger than the threshold, 1mS of delay will be added overall. And after lag is under control, the delay is removed.

For testing purposes, I have set up a basic Primary/Replica environment, running with sysbench on high concurrency setup to make the replica lag on purpose. I collected some graphs with Percona Monitoring and Management, and here's how it looks:


The above graph shows the lag constantly growing until the script starts to run and the replica eventually catches up. Fantastic! Until you see the Questions graphs and it looks very....flat


So what happened is that until the lag reached the threshold (in this case, 3 seconds) all the traffic was delayed. Once the lag is under control, traffic is back but not at 100% since the throttle script continues to run. So it maintains the replica up to date at a cost of rate-limiting the writes.


And the above graph shows the same (questions) but from the ProxySQL dashboard perspective.

Now, what's the alternative?

Delay on Rules

ProxySQL query rules can be set with delays per rule. Since the idea is to add less overhead, a good approach is to check which query rule is the least used and see if by adding a delay to it we can control the lag.

Plain Text
 




xxxxxxxxxx
1
12


 
1
Admin> SELECT hits, mysql_query_rules.rule_id, match_digest, match_pattern, replace_pattern, cache_ttl, apply, delay FROM mysql_query_rules NATURAL JOIN stats.stats_mysql_query_rules ORDER BY mysql_query_rules.rule_id;
2
+-----------+---------+--------------+-----------------------+-----------------+-----------+-------+-------+
3
| hits      | rule_id | match_digest | match_pattern         | replace_pattern | cache_ttl | apply | delay |
4
+-----------+---------+--------------+-----------------------+-----------------+-----------+-------+-------+
5
| 0         | 1       | NULL         | ^SELECT .* FOR UPDATE | NULL            | NULL      | 0     | NULL  |
6
| 609897074 | 2       | NULL         | ^SELECT .*            | NULL            | NULL      | 0     | NULL  |
7
| 87128148  | 3       | NULL         | ^UPDATE .*            | NULL            | NULL      | 0     | 0     |
8
| 43561905  | 4       | NULL         | ^INSERT .*            | NULL            | NULL      | 0     | 0     |
9
| 43562935  | 5       | NULL         | ^DELETE .*            | NULL            | NULL      | 0     | 0     |
10
| 0         | 6       | NULL         | ^REPLACE .*           | NULL            | NULL      | 0     | NULL  |
11
+-----------+---------+--------------+-----------------------+-----------------+-----------+-------+-------+
12
6 rows in set (0.01 sec)



From that query, we can see that the rule with id 5, the one that routes the DELETEs, is the least used from all the rules that hit the Primary.

We just need to make a small adjustment to the script to modify the mysql_query_rules table, by adding a proper function. The full script with the modification looks like this:

Shell
 




xxxxxxxxxx
1
46


 
1
#/bin/bash
2

           
3
set -o pipefail
4

           
5
proxysqlhost=127.0.0.1
6
proxysqladmport=6032
7
proxysqluser=admin
8
proxysqlpass=admin
9

           
10
replicahost=mysql2
11
replicauser=pmm
12
replicapass=pmm
13

           
14
lagThreshold=3
15

           
16
ruleId=5
17

           
18
function destructor () {
19
        delay=0
20
        modifyRuleDelay
21
        echo "bye"
22
}
23

           
24
function check_lag() {
25
         lag=$(mysql -h$replicahost -u$replicauser -p$replicapass -e "SHOW SLAVE STATUS\G" | grep  "Seconds_Behind_Master" | awk -F\: '{print $2}' 2>&1)
26
}
27

           
28
function modifyRuleDelay () {
29
        out=$(mysql -u$proxysqluser -p$proxysqlpass -h$proxysqlhost -P6032 -e"update mysql_query_rules set delay = $delay where rule_id = $ruleId ; LOAD MYSQL QUERY RULES TO RUNTIME;" 2>&1)
30
}
31

           
32
trap destructor EXIT INT TERM
33

           
34
while true; do
35

           
36
        check_lag
37
        echo $lag
38
        if [ $lag -ge $lagThreshold ]; then
39
                delay=1
40
                modifyRuleDelay
41
        elif [ $lag -eq 0 ]; then
42
                delay=0
43
                modifyRuleDelay
44
        fi
45
        sleep 0.001
46
done



Now, running the script we can see that the same behavior happens. Lag is controlled:


What about the Questions? Well, now the drop is not complete, and some traffic can still be routed and when the replica catches up, the behavior is the same as a small reduction, being that the cost of keeping the lag controlled.


ProxySQL reports the same.


Now, we have talked about controlling lag but pretty much any status variable can be monitored. Perhaps your issues are with contention (Threads_running) or with IO-bound issues (InnoDB checkpoint age). Regardless of the variable, rate limit can be achievable with ProxySQL.

rate limit Database MySQL

Published at DZone with permission of Daniel Guzman Burgos. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Custom Model Context Protocol (MCP) for NL2SQL: A Rigorous Evaluation Framework on Oracle Database
  • Why Queues Don’t Fix Scaling Problems
  • Using Arrow Flight SQL to Improve Data Transfer Performance in Apache Doris
  • Automating a Web Form With Playwright MCP and MySQL MCP

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook