Redis学习笔记(十)——过期时间、访问限制与缓存

过期时间

之前应该提到过redis的特性之一是可以设置键的超时时间。命令是expire。

EXPIRE命令返回1表示成功,返回0表示键值不存在或设置失败。

同时这里还有一个比较常用的命令是ttl,用于查看一个键还有多久时间会被删除。返回的是剩余时间(秒数)。

这里就不贴代码了,有一点需要说明的是,ttl命令在键不存在或被删除之后,会返回-2,在没有为键设置生存时间(即永久存在,建一个键之后的默认情况)时返回的是-1。大家可以亲自操作一把。

如果想要把一个设置过过期时间的键取消过期时间设置,则需要使用persist命令。

这里需要说明一点的是,除了使用persist命令外,使用set、getset命令为键赋值,也会同时消除键的生存时间,如果需要可以重新使用expire命令为键设置生存时间。而其他对键的操作命令(如incr、lpush、hset、zrem)都不会影响键的生存时间。

expire命令的单位是秒,而且这个参数必须为整数,如果需要更精准的时间的话,需要使用pexpire命令设置,其单位为毫秒,同理也需要用pttl命令来看键的剩余毫秒数。当然使用expire命令设置的过期时间也是可以用pttl看键的剩余毫秒数的。

访问限制

有时候我们会有一个需求是需要限制一个用户对一个资源的访问频率,我们假定一个用户(用IP作为判断)每分钟对一个资源访问次数不能超过10次。

我们可以使用一个键,每次用户访问则把值加1,当值加到10的时候,我们设定键的过期时间为60秒,并且禁止访问。这时候下次访问发现值为10,则不让访问了,然后60秒后键被删除,这时候再次创建键。这样就可以解决,但是其实这样时间并不精准,问题还是挺大的。

我们还有一个方案:使用队列。前面的章节也说到了,使用列表类型可以用作队列。

我们设定一个队列rate.limiting.192.168.1.1(假定是这个IP),我们把每次的访问时间都添加到队列中,当队列长度达到10以后,判断当前时间与队列第一个值的时间差是否小于60,如果小于60则说明60秒内访问次数超过10次,不允许访问;否则说明可以访问,则把队列头的值删除,队列尾增加当前访问时间。

这种方法可以比较精准的实现访问限制,但是当限制的次数比较大时,这种方法占用的存储空间也会比较大。

缓存

有时候会把一些对CPU或IO资源消耗比较大的操作结果缓存起来,并设置一定时间的自动过期。比如我们设定一个微博外链的最热站点缓存放于新浪微博的首页,这样我们不可能每次访问都重新计算最热的外链站点,所以我们可以设定两小时更新一次。每次访问是判断这个键有没有,如果存在则直接返回,如果没有则通过计算把内容存入键中,并设定两小时的过期时间。

然而在很多场合这种方法会很恐怖,当服务器内存有限的时候,大量使用缓存切设置生存时间过长就会导致redis占用太多内存,而redis有时候会把系统内存都吃掉,导致系统崩溃。但是设置时间过短又会导致缓存的命中太低。

所以我们最好的办法是设定缓存的淘汰规则。这种方式比较适用于将redis用作缓存系统的时候比较好。

具体就是:修改配置文件中的maxmemory参数,限制redis的最大内存,当超出后会按照maxmemory-policy参数指定的策略删除不需要的键,直到redis占用的内存小于设定值。

规则

说明

volatile-lru

使用LRU算法删除一个键(只对设置了生存时间的键)

allkeys-lru

使用LRU算法删除一个键

volatile-random

随机删除一个键(只对设置了生存时间的键)

allkeys- random

随机删除一个键

volatile-ttl

删除生存时间最近的一个键

noeviction

不删除键,只返回错误

其中的LRU算法即是【最近最少使用】。

这里提一句,实际上redis根本就不会准确的将整个数据库中最久未被使用的键删除,而是每次从数据库中随机取3个键并删除这3个键里最久未被使用的键。上面提到的所有的随机的操作实际上都是这样的,这个3可以用过redis的配置文件中的maxmemeory-samples参数配置。

本文发表自赵伊凡BLOG

©原创文章,转载请注明来源: 赵伊凡's Blog
©本文链接地址: Redis学习笔记(十)——过期时间、访问限制与缓存

“Redis学习笔记(十)——过期时间、访问限制与缓存”的42个回复

  1. Pingback: money loans
  2. Pingback: bmi calc
  3. "我们可以使用一个键,每次用户访问则把值加1,当值加到10的时候,我们设定键的过期时间为60秒,并且禁止访问。这时候下次访问发现值为10,则不让访问了,然后60秒后键被删除,这时候再次创建键。这样就可以解决,但是其实这样时间并不精准,问题还是挺大的" 为什么说这中方式会不够精准,希望能给出写提示。谢谢! :)

    1. 不好意思,最近刚换了工作比较忙。所以一直没上这个网站看。
      因为在每次访问的时候增加1,但是是在访问到第10次的时候才计时的60秒,所以不准,其实这样只能满足访问了10次之后60秒之后不能访问而已(实际时长是60秒加他前面10次访问的时间了),而不是60秒内只能访问10次。
      这个问题只是引出下面的解决方法而已。

      1. 问个问题,我可能要给很多key设置过期时间,然而这些过期时间都是分散设置的,而且可能过期时间比较长长达几个月过期,

      2. 接上面的,没说完,就是设置这么长的过期时间还有如果具有有效期的key几百万,近千万的时候,对性能是不是个考验

        1. 首先,正常情况下,一千万key的内存使用量一般在2G左右,当然如果类型比较复杂,值又多,可能占用内存会很多。这个主要看业务场景,当然可以使用集群分片处理。另外每个key都有过期时间这个没什么问题,因为redis有专门的子进程去做定期检查。在一定程度上可以保持效率。当然如果全都有过期时间,如果有很多的键同时过期的话,不一定能立刻全部删除(定时检查删除的键是有限的,保证cpu占用不要太高)。不过redis还有个是在get之类的操作的时候判断键的有效期,失效了也会删除。

  4. Pingback: Blue Coaster33
  5. Pingback: tv online, online tv
  6. Pingback: Website
  7. Pingback: stop parking
  8. Pingback: lan penge nu 18 ar
  9. Pingback: stop parking
  10. Pingback: 3gp mobile porn
  11. Pingback: bedste laan lige nu
  12. Pingback: water ionizer
  13. Pingback: YouTube views kopen
  14. Pingback: electrician bags
  15. Pingback: locksmiths las vegas
  16. Pingback: plumbers bladder
  17. Pingback: this site
  18. Pingback: alkaline water brands
  19. Pingback: house blue
  20. Pingback: like this
  21. Pingback: ionizer loans
  22. Pingback: water ionizer
  23. Pingback: visit site
  24. Pingback: alkaline water
  25. Pingback: here
  26. Pingback: see
  27. 请教一下,上文说道incr操作不会影响key的生存时间,那是否可以这样做:新建一个键,默认值为0,过期时间为60s,每次用户访问时判断key值是否达到10,如果没有进行incr加1,如果超过则进行锁定。这样不是就能满足60s内访问超过10次后不能访问的问题了

心@帆进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注