Skip to content
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

fix(plugin/rate-limiting): use redis:eval() to improve rate-limiting accuracy #10559

Conversation

giovanibrioni
Copy link
Contributor

@giovanibrioni giovanibrioni commented Mar 25, 2023

Summary

fix rate-limiting accuracy reported on issue: #5311
There is a low impact change to the current code and this implementation has better accuracy on redis policy

it is same fix made in PR #8227, but I remove sliding-window feature. Kong have no plans to add a sliding window to this plugin, Sliding window is an enterprise-only feature at this point

Checklist

  • The Pull Request has tests
  • There's an entry in the CHANGELOG

Full changelog

[it removes the race condition problem getting keys on redis. it uses the return of the increment command as the usage counter ensuring atomicity, different from the current one, which allows multiple requests to get the same value of the redis key while the counter increment is done asynchronously]

[it has an even better performance than the current plugin using the redis policy, as it does only 1 operation per request in redis (eval) instead of the two operations per request that the current one (get and incrby)]

Issue reference

Fix #5311
KAG-981

Copy link
Contributor

@hanshuebner hanshuebner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution. Can you please have a look at my comments? It would be nice to have a test that exposes the failing behavior in the previous implementation and demonstrates that the fix works. If that is too difficult to write, can you please point out how the existing tests exercise the functionality that you've changed? Thank you again, -Hans

kong/plugins/rate-limiting/policies/init.lua Outdated Show resolved Hide resolved
kong/plugins/rate-limiting/policies/init.lua Outdated Show resolved Hide resolved
@hanshuebner hanshuebner changed the title fix rate-limiting accuracy reported on issue: https://github.com/Kong… fix rate-limiting accuracy Apr 5, 2023
@hanshuebner hanshuebner added the pending author feedback Waiting for the issue author to get back to a maintainer with findings, more details, etc... label Apr 5, 2023
@hbagdi hbagdi added the author/community PRs from the open-source community (not Kong Inc) label Apr 5, 2023
@github-actions github-actions bot added changelog chore Not part of the core functionality of kong, but still needed core/clustering core/pdk core/tracing labels Apr 7, 2023
@giovanibrioni giovanibrioni force-pushed the fix/rate-limiting-accuracy-redis-without-sliding-window branch from a84a7fb to 5e29cdf Compare April 7, 2023 14:56
@github-actions github-actions bot removed changelog core/tracing chore Not part of the core functionality of kong, but still needed core/clustering core/pdk labels Apr 7, 2023
@giovanibrioni
Copy link
Contributor Author

Thank you for your contribution. Can you please have a look at my comments? It would be nice to have a test that exposes the failing behavior in the previous implementation and demonstrates that the fix works. If that is too difficult to write, can you please point out how the existing tests exercise the functionality that you've changed? Thank you again, -Hans

@hanshuebner ,
I tried to write the test in lua using coroutine to simulate the calls in parallel, but I couldn't. As I need to get the response code of each call, it seems to me that the coroutines were running sequentially and the error did not occur.
But I created a scenario using the k6 load test where you can compare the result before and after the fix.
I put it in this repo here: https://github.com/giovanibrioni/kong-plugin-rate-limiting-temp

@stale
Copy link

stale bot commented Apr 30, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Apr 30, 2023
@giovanibrioni
Copy link
Contributor Author

i've been trying to solve this problem for over 1 year. I already use this fix in my applications and it has been battle tested receiving more than 4 billion transactions per day in a productive environment. I'd like to help the rest of the community and I've made all the adjustments requested, but this slowness is annoying me. if the bot closes my PR I won't open another one.

@@ -142,4 +146,41 @@ describe("Plugin: rate-limiting (policies)", function()
end)
end

describe("redis", function()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@oowl oowl force-pushed the fix/rate-limiting-accuracy-redis-without-sliding-window branch from 18cf550 to 867edbe Compare May 29, 2023 12:51
@ADD-SP ADD-SP force-pushed the fix/rate-limiting-accuracy-redis-without-sliding-window branch from 867edbe to 9eb755e Compare May 31, 2023 07:13
@hanshuebner hanshuebner merged commit c791af2 into Kong:master May 31, 2023
samugi added a commit that referenced this pull request Oct 27, 2023
When the periodic sync to redis feature is turned on, using the
`sync_rate` configuration option, keys are incremented by steps of 2
instead of 1 for requests that arrive after the `sync_rate` interval
has expired.

This happens because after each sync, the key is loaded again from redis
and also incremented atomically (see: #10559)
however the next call to `increment` also adds 1 to its value, so
the key is incremented by 2 every time it's loaded from redis.

This fix sets a negative delta for the key when
`conf.sync_rate ~= SYNC_RATE_REALTIME` and the key was loaded from redis
in order to invalidate the next call to `increment`.
samugi added a commit that referenced this pull request Nov 7, 2023
…11859)

* fix(rate-limiting): redis async updates

When the periodic sync to redis feature is turned on, using the
`sync_rate` configuration option, keys are incremented by steps of 2
instead of 1 for requests that arrive after the `sync_rate` interval
has expired.

This happens because after each sync, the key is loaded again from redis
and also incremented atomically (see: #10559)
however the next call to `increment` also adds 1 to its value, so
the key is incremented by 2 every time it's loaded from redis.

This fix sets a negative delta for the key when
`conf.sync_rate ~= SYNC_RATE_REALTIME` and the key was loaded from redis
in order to invalidate the next call to `increment`.

Includes a small code refactor
windmgc pushed a commit that referenced this pull request Jan 24, 2024
…11859)

* fix(rate-limiting): redis async updates

When the periodic sync to redis feature is turned on, using the
`sync_rate` configuration option, keys are incremented by steps of 2
instead of 1 for requests that arrive after the `sync_rate` interval
has expired.

This happens because after each sync, the key is loaded again from redis
and also incremented atomically (see: #10559)
however the next call to `increment` also adds 1 to its value, so
the key is incremented by 2 every time it's loaded from redis.

This fix sets a negative delta for the key when
`conf.sync_rate ~= SYNC_RATE_REALTIME` and the key was loaded from redis
in order to invalidate the next call to `increment`.

Includes a small code refactor
windmgc pushed a commit that referenced this pull request Mar 7, 2024
…11859)

* fix(rate-limiting): redis async updates

When the periodic sync to redis feature is turned on, using the
`sync_rate` configuration option, keys are incremented by steps of 2
instead of 1 for requests that arrive after the `sync_rate` interval
has expired.

This happens because after each sync, the key is loaded again from redis
and also incremented atomically (see: #10559)
however the next call to `increment` also adds 1 to its value, so
the key is incremented by 2 every time it's loaded from redis.

This fix sets a negative delta for the key when
`conf.sync_rate ~= SYNC_RATE_REALTIME` and the key was loaded from redis
in order to invalidate the next call to `increment`.

Includes a small code refactor
windmgc pushed a commit that referenced this pull request Mar 8, 2024
…11859)

* fix(rate-limiting): redis async updates

When the periodic sync to redis feature is turned on, using the
`sync_rate` configuration option, keys are incremented by steps of 2
instead of 1 for requests that arrive after the `sync_rate` interval
has expired.

This happens because after each sync, the key is loaded again from redis
and also incremented atomically (see: #10559)
however the next call to `increment` also adds 1 to its value, so
the key is incremented by 2 every time it's loaded from redis.

This fix sets a negative delta for the key when
`conf.sync_rate ~= SYNC_RATE_REALTIME` and the key was loaded from redis
in order to invalidate the next call to `increment`.

Includes a small code refactor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author/community PRs from the open-source community (not Kong Inc) changelog plugins/rate-limiting size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ratelimit plugin not working as expected - kong 1.4
7 participants