-
Notifications
You must be signed in to change notification settings - Fork 730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NEW] Prevent endless replication loop by throttling write commands #1649
Comments
@lschmidtcavalante-sc Thanks for starting this issue. I think operationally it makes sense to introduce a mechanism to avoid the endless replication loop. I've a few questions on this.
|
|
@hpatro just wanted to add to point # 2 above that we use this functionality when ValKey is used as a cache and in that context a write failure is preferred instead of a OOM crash. |
Yeah. the blocking mechanism already exists in the system so we could leverage that. |
By "this solution is good" I meant this proposal ( |
That's right but in the same place we don't want to make changes where client is unable to handle the server response. |
Can you point me to the implementation of this client blocking mechanism (both server and client side)? PS: Also, it is my goal to contribute CPU throttling to Valkey and it would re-use this |
I couldn't find any documentation for it but here is the code link. There is nothing much to do on client side.
Sure. I've not wrapped around my head around |
Sort of a duplicate of #872, but this one has some more traction so we can maybe use this one moving forward. (Most of the issue is actually here though redis/redis#12844) I overall like this idea. As was mentioned, blocking is one such option, but doesn't work well for caching workloads. Although, typically caching workloads are doing mostly reads and not writes, so blocking the client may be a better approach here. We might independently want to add a new throttled error code that clients can opt-in to handling. |
@madolson we already have this code in our branch and @lschmidtcavalcante-sc can send a proposed PR shortly if we are aligned on the new optional error code approach. |
Yeah, please feel free to open the PR as a draft (doesn't need to be perfect) since I think that is a good place to finalize the discussion. I think we'll want to discuss client compatibility story as well. @valkey-io/core-team Would also like your input about adding a new throttled or blocking code instead of disconnecting the replica*. |
I like the idea of throttling. If we make the config an enum instead of bool, we can make it open to add blocking (like CLIENT PAUSE WRITE) too later. Other use of thottling can be CPU or the number of pending commands to handle. |
Shared proposed implementation at #1672 |
For CPU throttling I started a new issue at #1688 |
@madolson @zuiderkwast @hpatro what do you guys think about #1672 which adds a new "-THROTTLED" error to prevent primary node slowdowns and allow configuring caching clusters to throttle instead of fail. |
@ovaiskhansc We're in the process of releasing 8.1 release candidate, so we're a bit distracted about that. Once that's out the door we'll be a little more responsive about the PR. Appreciate the patience! |
No worries at all. 8.1 is an important release for us as we are planning to deploy that (+ these protections) at Snap |
I am onboard with this proposal. Generally speaking, I think blocking clients on replication backlog overflow is a breaking change. The convention has been encoding the blocking behavior explicitly in the command, such as |
My two cents: |
I like -THROTTLED. We can maybe refine the exact error message later. I think the word throttle can mean to slow down, so maybe rate limiting is a better term? We can also encode some message about how long to wait before trying again I think we need a config and a CLIENT CAPA. If we only throttle clients that report that they support throttling, we can assume that they behave correctly and don't immediately resend the commands. They should wait some time before resending them, or delegate to the application code behind. If it's a web API, it can return Blocking however is quite bad in a real-time application with latency requirements and even in say a website or mobile app, you wouldn't want things to just hang. An error and retrying later is much better. Then the application can handle this in a suitable way, either delaying and retying or pushing back the throttling to the end user. Another reason to not block/delay commands is that it can make command queue up. Subsequent non-write commands sent on the same connection (AKA pipelined) get blocked too, the client buffers grow, client eviction kicks in... It doesn't seem great to me. |
@hpatro you have a point about |
I also don't mind some mechanism to indicate some form of backoff. I had put up that thought in the PR (#1672 (comment)). Yeah, I was trying to highlight CAPA at an individual error would be a bit too much. |
Not really sure how this is a breaking change. From the client side it just looks like the server is slow. Maybe also worth mentioning that for short bursts, the blocking time won't be that long. If we temporarily exceed the limit we will start blocking until we can drain the replica.
I think we need a better strategy though. It's important to remember that devops folks are not the same as application developers. If an application developer is not prepared to handle this new
This gives operators and managed services a softer lever. Clients can 'opt' in by sending the capability but aren't required to do so. I also really don't like error modes which only surface during other failure modes. You don't want to experience a new error only when you are under memory pressure. One mitigation could be that clients could be required to support this capability when connecting. |
The problem/use-case that the feature addresses
The problem of endless replication loop is described here https://redis.io/blog/the-endless-redis-replication-loop-what-why-and-how-to-solve-it/, but it can be summarized as: in cases where the replica is slow to consume the replication buffer (for example, busy retrieving the initial snapshot of the database), said buffer can overflow triggering the synchronization process to start from scratch again.
Description of the feature
Implement a feature flag (say
write-throttling
) that once enabled evaluates each incoming write request:THROTTLED
error;This way the endless replication loop is avoided at the cost of dropping some requests.
Alternatives you've considered
There are currently two solutions to endless replication loop:
These solutions will continue to exist and the proposed
write-throttling
is not expected to be enabled by default.The text was updated successfully, but these errors were encountered: