惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
博客园 - 聂微东
小众软件
小众软件
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
TaoSecurity Blog
TaoSecurity Blog
博客园 - 司徒正美
罗磊的独立博客
N
News and Events Feed by Topic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security Affairs
S
Security @ Cisco Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
月光博客
月光博客
S
Secure Thoughts
P
Proofpoint News Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Forbes - Security
Forbes - Security
H
Heimdal Security Blog
W
WeLiveSecurity
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
L
LangChain Blog
T
The Blog of Author Tim Ferriss
NISL@THU
NISL@THU
Google DeepMind News
Google DeepMind News
Cloudbric
Cloudbric
H
Hacker News: Front Page
The Last Watchdog
The Last Watchdog
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cisco Blogs
博客园 - 三生石上(FineUI控件)
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
Project Zero
Project Zero
SecWiki News
SecWiki News
爱范儿
爱范儿
The Register - Security
The Register - Security
AI
AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Y
Y Combinator Blog
L
Lohrmann on Cybersecurity
Application and Cybersecurity Blog
Application and Cybersecurity Blog
P
Privacy International News Feed
J
Java Code Geeks
S
Securelist
C
Cyber Attacks, Cyber Crime and Cyber Security
V
Visual Studio Blog

Blog — PlanetScale

Keeping a Postgres queue healthy — PlanetScale Patterns for Postgres Traffic Control — PlanetScale Graceful degradation in Postgres — PlanetScale High memory usage in Postgres is good, actually — PlanetScale Stripe Projects partnership: Provision PlanetScale Postgres and MySQL databases from the Stripe CLI — PlanetScale Enhanced tagging in Postgres Query Insights — PlanetScale Behind the scenes: How Database Traffic Control works — PlanetScale Introducing Database Traffic Control — PlanetScale Scaling Postgres connections with PgBouncer — PlanetScale Drizzle joins PlanetScale — PlanetScale Video Conferencing with Postgres — PlanetScale Faster PlanetScale Postgres connections with Cloudflare Hyperdrive — PlanetScale Introducing the PlanetScale MCP server — PlanetScale Database Transactions — PlanetScale Automating our changelog with Cursor commands — PlanetScale Postgres 18 is now available — PlanetScale Using MotherDuck with PlanetScale — PlanetScale $50 PlanetScale Metal is GA for Postgres — PlanetScale AI-Powered Postgres index suggestions — PlanetScale $5 PlanetScale is live — PlanetScale Announcing Vitess 23 — PlanetScale $50 PlanetScale Metal — PlanetScale Report on our investigation of the 2025-10-20 incident in AWS us-east-1 — PlanetScale $5 PlanetScale — PlanetScale Benchmarking Postgres 17 vs 18 — PlanetScale Larger than RAM Vector Indexes for Relational Databases — PlanetScale Partnering with Cloudflare to bring you the fastest globally distributed applications — PlanetScale Processes and Threads — PlanetScale PlanetScale for Postgres is now GA — PlanetScale Postgres High Availability with CDC — PlanetScale Announcing Neki — PlanetScale Caching — PlanetScale The principles of extreme fault tolerance — PlanetScale Announcing PlanetScale for Postgres — PlanetScale Benchmarking Postgres — PlanetScale Announcing Vitess 22 — PlanetScale The Real Failure Rate of EBS — PlanetScale IO devices and latency — PlanetScale Announcing PlanetScale Metal — PlanetScale PlanetScale Metal: There’s no replacement for displacement — PlanetScale Upgrading Query Insights to Metal — PlanetScale Automating cherry-picks between OSS and private forks — PlanetScale Database Sharding — PlanetScale Anatomy of a Throttler, part 3 — PlanetScale Introducing sharding on PlanetScale with workflows — PlanetScale Announcing Vitess 21 — PlanetScale Announcing the PlanetScale vectors public beta — PlanetScale Instant deploy requests — PlanetScale Anatomy of a Throttler, part 1 — PlanetScale Increase IOPS and throughput with sharding — PlanetScale Tracking index usage with Insights — PlanetScale Faster backups with sharding — PlanetScale Building data pipelines with Vitess — PlanetScale The State of Online Schema Migrations in MySQL — PlanetScale Optimizing aggregation in the Vitess query planner — PlanetScale Dealing with large tables — PlanetScale Announcing Vitess 20 — PlanetScale Self-managed Vitess vs Managed Vitess with PlanetScale — PlanetScale Achieving data consistency with the consistent lookup Vindex — PlanetScale The MySQL adaptive hash index — PlanetScale Introducing global replica credentials — PlanetScale Profiling memory usage in MySQL — PlanetScale Summer 2023: Fuzzing Vitess at PlanetScale — PlanetScale How PlanetScale makes schema changes — PlanetScale Identifying and profiling problematic MySQL queries — PlanetScale The Problem with Using a UUID Primary Key in MySQL — PlanetScale Announcing Vitess 19 — PlanetScale PlanetScale forever — PlanetScale Introducing schema recommendations — PlanetScale Amazon Aurora Pricing: The many surprising costs of running an Aurora database — PlanetScale Three common MySQL database design mistakes — PlanetScale OAuth applications are now available to everyone — PlanetScale Deprecating the Scaler plan — PlanetScale PlanetScale branching vs. Amazon Aurora blue/green deployments — PlanetScale Databases at scale — PlanetScale Considerations for building a database disaster recovery plan — PlanetScale Working with Geospatial Features in MySQL — PlanetScale PlanetScale vs Amazon Aurora replication — PlanetScale Introducing the Vantage and PlanetScale integration — PlanetScale MySQL isolation levels and how they work — PlanetScale Introducing the schemadiff command line tool — PlanetScale $ pscale ping — PlanetScale Announcing foreign key constraints support — PlanetScale The challenges of supporting foreign key constraints — PlanetScale What is HTAP? — PlanetScale Introducing Insights Anomalies — PlanetScale Webhook security: a hands-on guide — PlanetScale Announcing the Fivetran integration — PlanetScale Introducing webhooks — PlanetScale What is MySQL replication and when should you use it? — PlanetScale Sync user data between Clerk and a PlanetScale MySQL database — PlanetScale Introducing database reports — PlanetScale Distributed caching systems and MySQL — PlanetScale What is MySQL partitioning? — PlanetScale MySQL High Availability: Connection handling and concurrency — PlanetScale Personalizing your onboarding with Markdoc — PlanetScale PlanetScale vs. Amazon Aurora — PlanetScale PlanetScale vs. Amazon RDS — PlanetScale PlanetScale is bringing vector search and storage to MySQL — PlanetScale PlanetScale Managed is now PCI compliant — PlanetScale
Anatomy of a Throttler, part 2 — PlanetScale
Shlomi Noach · 2024-10-10 · via Blog — PlanetScale

Shlomi Noach |

This is part 2 of a 3-part series. You can catch up with part 1 here.

Up until now, we've only discussed the existence of the throttler and did not make assumptions about its deployment or distribution. We have referenced it in singular form, and indeed it is possible to run a throttler as a singular service. Let's consider the arguments for singular vs. distributed throttler deployments.

Singular throttler design

A singular throttler is an all-knowing service that serves all requests. It should be able to probe and collect all metrics, which means it may need direct access to all database servers and to OS metrics (such as load average, which we mentioned in part 1). Such access could be acceptable in some environments. The throttler will likely hold on to a large group of persistent connections, each of which the throttler will use to read a subset of metrics. It's a simple, monolithic, synchronous approach.

This approach immediately calls into question the issue of high availability. What do you do if the throttler host goes down? We can first assume it is possible to spin up a new throttler service. It may take a few moments until it's up and running, and until it has established all connections and has begun to collect data. In the interim, what do clients do? This is where a design decision must be made: do clients fail open, or do they fail closed? If no throttler is available, should clients consider themselves rejected, or should they proceed with full power? A common approach is to hold off up to some timeout and, from there on, proceed unthrottled, taking into consideration the possibility that the throttler may not be up for a while.

Another option is to run multiple, independent instances of the throttler. They could run in different availability zones, all oblivious to each other, and so we still consider them to be singular. They will all collect the same metrics from the same servers, albeit at slightly different timings. This means two independent throttlers will overall exhibit the same behavior allowing/refusing requests, but it is possible that at any specific point in time, two throttlers will disagree with each other.

More combinations exist, such as having active-passive throttlers, with traffic always directed to the active one. The passive throttlers will be readily available should the active one step down. They will possibly be collecting metrics while passive.

It is clear that the singular approach is susceptible to a scaling problem. There's only so many connections it can maintain while running high-frequency probing.

Metrics access/API

Another issue concerns environments where the throttler cannot be allowed direct access to database and OS metrics due to security restrictions. A common solution is to set up an HTTP server, some API access point, which the throttler can check to get the host metrics. A daemon or an agent running on the host is responsible for collecting the metrics locally to the host. The throttler's work is now made simpler, as it may need to only hit a single access point to collect all metrics for a given host. However, this design introduces many complexities.

First and foremost, the addition of a new component that needs to reliably run continuously on the host. Metric collection is no longer in the hands of the throttler, and we must trust that component to grab those metrics. We then introduce an API or otherwise some handshake between the throttler and the metric collection component, which must be treated with care when it comes to upgrades and backwards compatibility.

Last but not least, we lose synchronicity and introduce multiple layers of collection polling intervals: the agent collects metrics at its own interval. For example, the agent might collect data once per second, while the throttler polls the API at its own interval, which could also be once per second. The throttler may now collect data that is up to 2 seconds stale, as opposed to up to 1 second stale in the monolithic, synchronous approach. Note that there is also a latency effect to the staleness of metrics, but we will leave this discussion to a later stage.

In adding this agent component, even if it's the simplest script to scrape and publish metrics, we've effectively turned our singular throttler into a distributed multi-component system.

Distributed throttler design

We now consider the case for a distributed throttler design, and again find that there are multiple approaches to distribution.

In the context of your environment, does it make sense for a throttler to probe hosts/services outside its availability zone? It is possible to run a throttler per AZ that only collects metrics within that AZ. Each throttler considers itself to be singular and is oblivious to other throttlers, but clients need to know which throttler to address.

A variation of the above could introduce some collaboration between the throttlers: a us-east-1 throttler can advertise its own collected metrics to a us-west-1 throttler. This lets the us-west-1 throttler grab all us-east-1 metrics in one go, and without having to have direct access to the underlying hosts or services. This is a glorified and scaled implementation of the agent architecture above, where all components are throttlers.

Or, we can do functional partitioning on our architectural elements. Some services are disjoint, and we can run different throttlers for different elements, grouped by functionality association. In this design throttlers are again independent of each other.

Going even more granular, there may be a throttler associated with any host, or with any probed service.

A granular throttler design case study

The Vitess tablet throttler combines multiple design approaches to achieve different throttling scopes. The throttler runs on each and every vttablet, mapping one throttler for each MySQL database server. Each such throttler first and foremost collects metrics from its own vttablet host and from its associated MySQL server. Then, the throttlers (or vttablet servers) of any shard, or a replication topology (primary and replicas) collaborate to represent the "shard" throttler. The throttler service on the primary server takes the responsibility for collecting the metrics from all of the shard's throttlers and aggregating them as the "shard" metrics.

Thus, a massive write to the primary is normally throttled by replication lag, a metric collected from all serving replicas. Clients consult with the primary throttler, which accepts or rejects their requests based on the highest lag among all replicas. In contrast, some operations only require a massive read, which can take place on a specific replica. These reads can pollute the replica's page cache and overload its disk I/O, causing it to lag. This will, however, have no effect on the replication performance of other replicas. The client can therefore suffice in checking the throttler on the specific replicas, ignoring any metrics from other servers. This introduces the concept of a metric's scope, which can be an entire shard or a specific host in this scenario.

Different shards represent distinct architectural elements, and there is no cross-shard throttler communication. This limits the hosts/services monitored by any single throttler to a sustainable amount.

It's important to remember that any cross-throttler communication introduces the layered collection poll interval and reduction of granularity, as discussed above.

Reducing the throttler's impact

Can the throttler itself generate load on the system? Let's avoid the infinite recursion trap of throttle-the-throttler and consider the usage pattern.

The throttler can introduce load on the system by over-probing for metric data, as well as by over-communicating between throttler nodes. Clients can introduce load by overwhelming the throttler with requests.

To begin with the low-hanging fruit, busy loops should be avoided at all times. A rejected client should sleep for a pre-determined amount of time before rechecking the throttler. Conversely, depending on the metric, a client might get a free pass for a period of time after a successful check. Consider the case for replication lag: if a client checks for lag and the lag is 0.5sec and the threshold is 5sec, then the next 4.5sec (up to metric collection granularity) are guaranteed to be successful and can be skipped.

The metrics should be collected at an appropriate granularity for the situation. We mentioned the use case for massive background jobs. A job can take a few hours to run, but there may yet be a few hours break between two jobs. During that break, there isn't strictly a need for the throttler to collect data at high rate, and likewise, no strict need for throttlers to communicate with each other at high rate. The throttler can choose to slow down based on lack of requests. It could either stop collecting metrics altogether and go into hibernation, or it might just slow down its normal pace. It would take a client checking the throttler to re-ignite the high-frequency collection of metrics.

This does come at a cost because the very first check, and likely also the next few checks, will run on stale data and potentially reject requests that would otherwise be accepted. However, we defer to the expected client retry mechanism which will induce another check, at such time that the throttler is again fully engaged and has up-to-date metrics.

Another caveat is that with a distributed throttler design, throttlers which depend on each other should be able to inform each other upon being checked. All throttlers who communicate with each other should re-ignite upon the first request to any of them.

Metric hibernation case study

Metric collection is not the only process that can hibernate. Metric generation itself can also hibernate. This may sound ludicrous at first: aren't metrics just there? Let us discuss replication heartbeats.

In Part 1, we've elaborated on the role of replication lag as the single most used throttling metric. While there are alternative techniques, it has been established in the MySQL world that the most reliable way to evaluate replication lag is by injecting timestamps on a dedicated table on the Primary server, then reading the replicated value on a replica, comparing it with the system time on said replica. This technique works well when the replicas are working well, when they are lagging, when replication is stopped, and even when replication gets broken or misconfigured.

There must be some process to routinely inject heartbeats on the Primary database server (pt-heartbeat is a popular tool to do so). You'd need to ensure heartbeats are only ever written on the Primary, and handle failovers and promotion situations.

The injection interval dictates the lag metric granularity, and you need to balance the desire to have the most granular replication lag metric with the overhead of generating those writes.

But then there is another impact to heartbeat generation using this technique: the heartbeat events are persisted in the binary logs, which are then re-written on the replicas. For some users, the introduction of heartbeats causes a significant increase in binlog generation. With more binlog events having to be persisted, more binary log files are generated per given period of time. These consume more disk space. It is not uncommon to see MySQL deployments where the total size of binary logs is larger than the actual data set. Furthermore, you may wish to retain the binary logs for an extended period of time, for recovery/auditing purposes, and you may wish to back them up. You'll need larger disks, more backup storage space, and this translates to expenses.

It thus also makes sense to avoid generating those heartbeats, or generate them much less frequently, when not absolutely needed. When no massive background job takes place, we can enjoy little to no overhead, and when there is a massive operation, the heartbeat events are but a small overhead compared with the amounts of data written to the binary logs.

Like throttler hibernation, these heartbeats must be re-ignited at the right time. Like throttler hibernation, the first few checks will read outdated heartbeats, and are most likely to be rejected. It may take a few seconds to get to a fully active operation, when the throttler has re-engaged, heartbeats re-generated, and replication is caught up with at least the very first re-generated heartbeats, and the clients must be prepared for some retries.

To be continued

In the next and final part of this series we will discuss clients, prioritization, starvation scenarios, and more.