Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用StackExchange.Redis安全设置密钥,同时允许删除_Redis_Stackexchange.redis - Fatal编程技术网

使用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