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

Add DataStore::RedisMulti #2443

Merged
merged 3 commits into from Mar 9, 2022
Merged

Conversation

mwiencek
Copy link
Member

@mwiencek mwiencek commented Mar 8, 2022

If the DataStore::RedisMulti module is active, then DATASTORE_REDIS_ARGS may return an array ref of connection details. (How do you know if it's active? grep for DataStore::RedisMulti->new. We may revert back to plain-old DataStore::Redis if multiple instances aren't needed.)

This module is useful when Redis service needs to be migrated to a new server. We'll attempt to read from each connection in order (returning the first non-empty result), and also distribute writes to all connections. This allows time to copy any keys that don't exist on the new instance from the old instance.

@mwiencek mwiencek force-pushed the redis-multi-store branch 6 times, most recently from f03ad02 to 3dcae74 Compare March 9, 2022 01:43
@mwiencek
Copy link
Member Author

mwiencek commented Mar 9, 2022

Outside of our current type of ordeal (migrating one standalone Redis instance to another server), this likely won't be as useful if we have a multi-master Redis/KeyDB cluster in the future. But, it could be used for migrating to such a setup more easily. Or perhaps we may need to migrate from one cluster to another for some reason?

Copy link
Contributor

@yvanzo yvanzo left a comment

Choose a reason for hiding this comment

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

Indeed, having a more adaptive server for deployment is useful to help with any future maintenance operations (switching to HAProxy/KeyDB, redeploying in emergency...).

LGTMBDNT. The added tests have a good coverage.

Comment on lines +73 to +76
$redis_multi->delete('string');
is($redis_multi->exists('string'), 0, 'exists returns 0 for deleted key');
is($redis1->exists('string'), 0, 'exists returns 0 for deleted key in database 1');
is($redis2->exists('string'), 0, 'exists returns 0 for deleted key in database 2');
Copy link
Member

Choose a reason for hiding this comment

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

What should happen if you delete from $redis1 but not $redis2? Should we have a test for that case?

Copy link
Member Author

Choose a reason for hiding this comment

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

It'd only be deleted from $redis1, but any servers with RedisMulti enabled would still see the key if it exists in $redis2.

This shouldn't really happen in practice, because we'd be deploying the RedisMulti configuration on all servers at once. But there is a minor race condition where a key is set on a server with a RedisMulti configuration, and then deleted on a server that doesn't have the new configuration yet (because we're in the middle of deploying it). The only situation I can see this happening is if a user logs in and then logs out; this would have to be perfectly timed and forwarded to the right servers. In that case there may be a stale session key on the new Redis instance, but it would expire within some hours anyway.

Test-wise we do have the "string-1-only"/"string-2-only" ones here, which check that keys set in only one of the servers will be retrieved through $redis_multi (doesn't matter if they're deleted first).

Copy link
Member

Choose a reason for hiding this comment

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

Perfect then, I was just wondering if, since adding to one adds to multi, deleting from one should delete from multi :) All clear now.

These are all implemented by `DataStore::Redis`, which is currently the
only implementation of the `DataStore` role -- so as it turns out,
attributes that have `does => 'MusicBrainz::DataStore'` already expect
these to be implemented.
remove is an alias for delete, which already calls _prepare_key.
If the `DataStore::RedisMulti` module is active, then
`DATASTORE_REDIS_ARGS` may return an array ref of connection details.
(How do you know if it's active? grep for `DataStore::RedisMulti->new`.
We may revert back to plain-old `DataStore::Redis` if multiple instances
aren't needed.)

This module is useful when Redis service needs to be migrated to a new
server. We'll attempt to read from each connection in order (returning
the first non-empty result), and also distribute writes to all
connections. This allows time to copy any keys that don't exist on the
new instance from the old instance.
@mwiencek mwiencek changed the base branch from master to production March 9, 2022 16:36
@mwiencek mwiencek merged commit 98c9b89 into metabrainz:production Mar 9, 2022
@mwiencek mwiencek deleted the redis-multi-store branch March 9, 2022 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants