Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[RateLimiter] Always store SlidingWindows with an expiration set#44996
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
stof commentedJan 12, 2022
I think the purpose was precisely to reduce the storage size |
Seldaek commentedJan 12, 2022
It does not seem to have any effect though, so I think it was mostly there to exclude the FYI here is the full output with igbinary: You can see it is quite a bit shorter with __serialize, but it's much more with the RateLimiter classes because somehow the serialized output includes the property names with full class name every time, it's extremely wasteful: One example from my prod redis server: |
Seldaek commentedJan 12, 2022
Nyholm commentedFeb 4, 2022
Oh no, you are very correct. This is indeed a bug. I’m not sure about your solution. I think there is a good reason why we didn’t set a new expectation time, Ie we don’t want to move the window. (Yes, it is “sliding” but we need a clear start and end of each window which is defined by the cache item) I need to give this a second look asap to confirm. (I’m currently traveling and my computer broke down) |
Seldaek commentedMar 1, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@Nyholm ping here? I'd be happy to get this resolved at some point, as our redis keeps filling up right now :) Thanks to the bug right now, the cache item doesn't expire ever if you hit more than once. So either the way I see it, either:
So the fix seems correct to me (it would only change the last bit of the last bullet point above), but maybe I misunderstood something of course. |
Seldaek commentedMar 16, 2022
Rebased/retargetted to 5.4 as 5.3 is now EOL |
Nyholm commentedMar 17, 2022
Please let me delay this week too. I have an open source session planned on Sunday. If I fail to come back then just ignore me. Sorry for being unavailable. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
fabpot commentedMar 26, 2022
Any news here? |
wouterj left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Thanks!
It does not seem to have any effect though, so I think it was mostly there to exclude the cached property
Indeed, I don't think storage size was considered here.
src/Symfony/Component/RateLimiter/Tests/Policy/SlidingWindowTest.php OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
5d96d1d to5336906Comparefabpot commentedMar 29, 2022
Thank you@Seldaek. |
Seldaek commentedMar 29, 2022
I tested the patch with the latest changes from@nicolas-grekas and the good news is it does work well doing: instead of: So much more efficient storage, and SETEX instead of SET 👍🏻 Bad news is the migration path is a bit broken (like you get a fatal error..) if it reloads existing data which was serialized with __sleep and tries to unserialize using the new __unserialize. I'll send a follow-up PR. |
wouterj commentedMar 29, 2022
thanks for the quick checking in a real app :) |
Seldaek commentedMar 29, 2022
Here#45876 |
…che (Seldaek)This PR was merged into the 5.4 branch.Discussion----------Add BC layer to handle old objects already present in cache| Q | A| ------------- | ---| Branch? | 5.4| Bug fix? | yes| New feature? | no <!-- please update src/**/CHANGELOG.md files -->| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->| Tickets | Refs#44996| License | MIT| Doc PR | symfony/symfony-docs#... <!-- required for new features -->When reloading an old RateLimiter instance from cache with the new code I did get an exception because windowEndAt was a string and getHitCount does windowEndAt - intervalInSeconds, and string - int fails.The reason is the new code assigns the id to windowEndAt via:``` $pack = key($data); $this->windowEndAt = $data[$pack];```I dumped $this and $data in __unserialize just FYI and you get this:```object(Symfony\Component\RateLimiter\Policy\SlidingWindow)[959] private 'id' => null private 'hitCount' => int 0 private 'hitCountForLastWindow' => int 0 private 'intervalInSeconds' => null private 'windowEndAt' => null``````array (size=5) '�Symfony\Component\RateLimiter\Policy\SlidingWindow�id' => string 'login_per_ip-127.0.0.1' (length=22) '�Symfony\Component\RateLimiter\Policy\SlidingWindow�hitCount' => int 2 '�Symfony\Component\RateLimiter\Policy\SlidingWindow�intervalInSeconds' => int 60 '�Symfony\Component\RateLimiter\Policy\SlidingWindow�hitCountForLastWindow' => int 0 '�Symfony\Component\RateLimiter\Policy\SlidingWindow�windowEndAt' => float 1648544909.4762```I only tested the code in real conditions for SlidingWindow, but I do believe/hope the same applies for the other two policies.Commits-------f039ee6 Add BC layer to handle old objects already present in cache
Seldaek commentedApr 6, 2022
Confirmed to work in prod now with 6.0.7 🥳 Thanks again everyone. |
Uh oh!
There was an error while loading.Please reload this page.
See#44995 for more details. The short story is that this code causes the cache item to be overwritten without TTL in
symfony/src/Symfony/Component/RateLimiter/Storage/CacheStorage.php
Lines 31 to 37 in6bffe41
So our redis DB is filling up with rate limiter data, which is not the expected outcome. I couldn't really figure out why the logic was the way it was so it seems safe for me to remove this, but maybe I missed something.
As a related side note, implementing __serialize/__unserialize in SlidingWindow and co would be good as it would reduce the storage requirements in the cache from 400 bytes to 100 bytes per rate limiter stored. I'm happy to help with that just let me know, I am not sure if there was a good reason not to implement this or if storage size was simply not a consideration. I see __sleep is implemented but that does not seem to help here, not sure what the purpose is/was.