antirez/redis — Issue #187: Redis slaves, while not allowed to expire keys without master input, should reply to clients consistently with the key expire information.
Author: antirez
Created: 2011-11-12 10:52:34+00:00
State: open
Labels: more design needed, non critical bug

Facts:

* Redis slaves don't expire keys actively, since the wait for a DEL form the master.
* Expiration was centralized in order to allow clients to write to keys with an expire set without time dependent inconsistencies in 2.2.
* Redis master will expire keys in two ways: incrementally in background, sampling random keys. In a lazy way when the key is accessed, so that even if the key was not already expired in the Redis cron we expire it as soon as a client will try to access it.

The above points are good and make the Redis expire semantic simpler from the point of view of the append only file and replication.

However consider this: a Redis master could have 50 million keys with an expire set, however all the keys but just one have the expire set in the future. The only key with a short expire is unlikely to be found by random sampling, but if a client will access this key, the key will be evicted by the lookupKey...() function and everything will work as expected.

But if a client will try to access this key in a slave it will found it existing: lookupKey...() can't expire keys in a slave.

How to fix that?
---

The obvious way to fix this issue is to make the slave more aware of what it is doing. It could simply compute if the key is expired so that lookupKey...() will return NULL and the client will be non existing from the point of view of the client request, even if the salve will not evict the key form the database, waiting for the DEL from the master instance in order to do so. This way we don't have time dependent behaviors when the slave receives, for example, an SUNIONSTORE command that has that key on its arguments (the key may not be already expired on the master since the two host timers may not be perfectly synchronized, or because there is a delay in the replication link, and so forth).

This fix is just one line and trivial, but there are a few problems with it:

1) Lookup functions are also called by commands doing work that depends on the fact the key exists or not to create new keys or new state inside the database, like SUNIONSTORE. This would require a new lookupKey... interface where the caller can say if the key is going to be used just for a read only command or to use the key content to alter the state of the data set.
2) From the point of view of Lua scripting the behavior should always be that keys exist if not evicted with an explicit DEL from the master.

This requires a refactoring of the internal API, so for now it is considered a post-3.0 stuff, but it is better to write it down and think about ways to resolve this issue in the future.