- redis/
- 使用StackExchange.Redis安全设置密钥,同时允许删除
使用StackExchange.Redis安全设置密钥,同时允许删除
使用StackExchange.Redis安全设置密钥,同时允许删除,redis,stackexchange.redis,Redis,Stackexchange.redis,我试图将Redis用作SQL数据库前面的缓存。在高层,我希望实施以下操作:
从Redis读取值,如果不存在,则通过查询SQL生成值,并将其推送到Redis,这样我们就不必再次计算该值
将值写入Redis,因为我们刚刚对SQL数据库进行了一些更改,并且我们知道我们可能已经缓存了它,但它现在无效
删除值,因为我们知道Redis中的值现在已经过时,我们怀疑没有人会想要它,但是现在重新计算太多了。我们可以让下一个执行操作1的客户再次计算
我面临的挑战是,如果我尝试使用StackExchange.Redi
我试图将Redis用作SQL数据库前面的缓存。在高层,我希望实施以下操作:
从Redis读取值,如果不存在,则通过查询SQL生成值,并将其推送到Redis,这样我们就不必再次计算该值
将值写入Redis,因为我们刚刚对SQL数据库进行了一些更改,并且我们知道我们可能已经缓存了它,但它现在无效
删除值,因为我们知道Redis中的值现在已经过时,我们怀疑没有人会想要它,但是现在重新计算太多了。我们可以让下一个执行操作1的客户再次计算
我面临的挑战是,如果我尝试使用StackExchange.Redis实现#1和#3,那么我需要了解如何实现。如果我天真地通过简单地读取键和push来实现#1,那么在我从SQL计算值并将其推入的过程中,完全有可能发生了任何数量的其他SQL操作,并试图通过#2或#3将其值推入Redis。例如,考虑这个排序:
客户机#1希望从上面执行操作#1[读取]。它试着读钥匙,发现钥匙不在那里
客户端#1调用SQL数据库以生成值
客户机#2对SQL执行某些操作,然后执行上面的操作#2[写入]。它将一些新计算的值推送到Redis中
客户机#3运行了很长时间,在SQL中执行其他一些操作,并希望对Redis执行操作#3[Delete],因为它知道如果缓存了某个内容,则该内容将不再有效
客户端#1将其(现已过时)值推送到Redis
那么我该如何实施我的操作#1?Redis提供了一个WATCH
原语,可以在裸机上轻松实现这一点,在裸机上,我可以从客户端1上观察钥匙上发生的其他事情,但是。这里的条件操作是不够的,因为如果我试着说“只有在密钥不存在时才推”,这并不能像我上面解释的那样阻止竞争。这里是否使用了模式/最佳实践?这似乎是人们想要实现的一种相当普遍的模式
我的一个想法是,我可以使用一个单独的键,每次对主键执行某些操作时,该键都会递增,然后可以使用StackExchange.Redis的条件操作,但这似乎很困难。这看起来像是关于正确缓存失效策略的问题,而不是关于Redis的问题。为什么我这么认为-RedisWATCH/MULTI是一种乐观锁定策略,这种
锁定不适用于大多数使用缓存的情况,其中db read query可能是使用缓存解决的问题。在您的操作#3描述中,您写道:
现在重新计算工作量太大了。我们可以让下一个执行操作1的客户再次计算
因此,我们可以继续使用读取更新
案例作为更新策略。在我们继续之前,还有一些问题:
当两个客户端开始执行操作#1时会发生这种情况?它们都不能在Redis中找到值,执行SQL查询,然后都将其写入Redis。所以我们应该有一个客户端可以更新缓存的garanties
我们如何在正确的写入顺序中使用舒尔(操作3)
为什么不乐观呢
假设多个事务可以频繁地完成,而不会相互干扰。在运行时,事务使用数据资源而不获取这些资源上的锁。在提交之前,每个事务都会验证没有其他事务修改它读取的数据。如果检查显示有冲突的修改,提交事务将回滚并可以重新启动
您可以阅读OCC交易的各个阶段,但只需几句话:
如果没有冲突,则更新数据。如果存在冲突,通常通过中止事务并在仍需要更新数据时重新启动事务来解决冲突
Redis WATCH/MULTY是一种乐观锁定,因此它们无法帮助您-在尝试使用它们之前,您不知道您的缓存密钥已被修改
什么有效?
每次听别人讲述锁定时,你都会听到关于折衷、性能和一致性与可用性的对话。最后一对是最重要的
在大多数高负载系统中,可用性是赢家。这就是缓存的意思吗?通常情况下:
每个缓存键都包含一些关于值状态、版本和生命周期的元数据。最后一个不是Redis TTL-通常情况下,如果您的密钥应该在缓存中保留X时间,则为终身
在元数据有X+Y时间的情况下,有Y个时间来计算进程更新
您永远不会直接删除密钥-您只需要更新状态或生命周期
每次应用程序从缓存中读取数据时,如果应该做出决定-如果数据的状态为“有效”-请使用它。如果数据状态为“无效”,请尝试更新或使用绝对删除数据李>
如何在读取时进行更新(非常重要的是这种乐观锁定和悲观锁定的“手工”组合):
尝试设置悲观锁定(在带有SETEX-)的Redis中)李>
如果失败-返回绝对删除数据(请记住,我们仍然需要可用性)
如果成功,则执行SQL查询并写入缓存
再次从Redis读取版本,并与之前读取的版本进行比较
如果版本相同-将状态标记为“有效”
松开锁李>
如何使(您的操作#2,#3)无效:
增量缓存版本并设置状态“无效”
如果需要,更新生命周期/ttl
为什么这么难
我们总是可以从缓存中获取和返回值,很少出现缓存未命中的情况。所以我们没有缓存失效级联,然后许多进程尝试更新
一把钥匙
我们仍然订购了密钥更新
每次只需一个进程就可以实现upda