什么?我往Redis写的数据怎么没了?
大概是因为int没有因为change方法而改变原值,所以就说它传过去的是自身的值,因而叫值传递;User对象经过change方法后,对象的数据变了,就认为是因为实参和形参指向的是同一片内存空间,内存空间的数据变了就都变了,传过去的是引用所以就说对象是引用传递。这样说的侧重点是传递的东西。
首先看俩问题,然后针对这俩问题,整理一下Redis过期策略。如果你对Redis的过期策略还不了解,那么请继续。
1、我往Redis里写的数据怎么没了?
使用Redis的同学你要明白一点,你为什么用Redis?用redis的作用是什么?用redis的好处是什么?凡事多思考一下为什么,多想想背后的原因。
就在不久前有朋友跟我说过,说他们生产环境的Redis怎么经常会丢掉一些数据?写进去了,过一会儿可能就没了。我的天啊,你问这个问题就说明Redis你就没用对啊。Redis是缓存,你给当存储了用了是吧?
首先要明白一点啥叫缓存?为啥用缓存?
Redis是用内存当缓存的。内存是无限的吗?相反,内存是很宝贵而且是有限的,磁盘是廉价而且是大量的。可能一台机器就几十个G的内存,但是可以有几个T的硬盘空间。Redis主要是基于内存来进行高性能、高并发的读写操作的。
那既然内存是有限的,比如Redis就只能用10个G,你一直往里面写数据,一直写一直写最后10个G都用的差不多了,你还写会,你想想会发生什么?当然会干掉一些的数据了,然后就保留10个G的数据。你说会不会造成数据丢失?
那Redis会干掉哪些数据?保留哪些数据呢?当然是干掉不常用的数据,保留常用的数据了。
所以说,这是缓存的一个最基本的概念:数据是会过期的。要么是你自己设置个过期时间,要么是Redis自己给干掉。
所以你的Redis如果使用不当,把生产数据存到里面,又没有去持久化到mysql,那就会有丢失的可能。
2、我的数据明明都过期了,怎么还占用着内存啊?
还有一种就是如果你给key设置好了一个过期时间,你知道到一定的时间再去查这个key就没有了,但是你知道redis是怎么给你弄成过期的吗?什么时候删除掉?
如果你不知道,在实际的使用过程中你就可能会发现这么一个问题:为啥好多数据明明应该过期了,结果发现redis内存占用还是很高?那是因为你不知道Redis是怎么删除那些过期key的。
举例,Redis 内存一共是10个G,你现在往里面写了5个G的数据,然后你对这些数据全都设置了10分钟之后过期,结果10分钟之后,你再来查看看,Redis的内存使用率怎么还是50%呢?5个G的数据都过期了,我从redis里查,是查不到了,结果过期的数据为啥还占用着Redis的内存呢。
如果你连这个问题都不知道,上来就懵了,回答不出来,建议你使用Redis之前多做做功课,不然你写代码的时候,想当然的认为写进Redis的数据就一定会存在,后面导致系统各种漏洞和bug,就不好弄了。
3、问题剖析
(1)设置过期时间
set key value 过期时间(1小时)
表示set进去的key,1小时之后就没了,就失效了。
我们set key的时候,都可以给一个expire time,就是过期时间,指定这个key比如说只能存活1个小时?10分钟?这个很有用,我们自己可以指定缓存到期就失效。
如果假设你设置一批key只能存活1个小时,那么接下来1小时后,redis是怎么对这批key进行删除的?
答案是:定期删除+惰性删除
所谓定期删除,指的是Redis默认是每隔100ms就随机抽取
一些设置了过期时间的key,检查其是否过期,如果过期就删除。
为什么是随机抽取?
假设Redis里放了10万个key,都设置了过期时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,因为这样cpu负载会很高的,全都消耗在你的检查过期key上了。
所以这里可不是每隔100ms就遍历所有的设置过期时间的key,Redis如果设置成检查所有Key那将是一场性能上的灾难。所以实际上redis是每隔100ms随机抽取
一些key来检查和删除的。
但是问题是,随机抽取检测key是否过去会导致定期删除
策略可能会导致很多过期key到了时间并没有被删除掉,那咋整呢?所以Redis还有另一个策略就是惰性删除
。
惰性删除 就是说,在你获取某个key的时候,Redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。
所以并不是key到时间就被删除掉,而是你查询这个key的时候,Redis再懒惰的检查一下。
通过上述两种手段,保证过期的key一定会被干掉。
那么刚才的问题就不难理解了,就是说,你的过期key,靠定期删除没有被删除掉,还停留在内存里,占用着你的内存呢,除非你的系统去查一下那个key,才会被redis给删除掉。如果都过期了,定期删除才删了一点点,而你又没有去查,没有触发惰性删除,那么短时间内你的redis内存占用率还是会下不来。
但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,咋整?
别担心Redis还有方案:内存淘汰机制。
(2)内存淘汰策略
如果Redis的内存占用过多的时候,此时会进行内存淘汰,Redis提供如下丰富的可选策略:
1)noeviction:
当内存不足以容纳新写入数据时,新写入操作会报错。
(这个一般没人用吧,实在是太恶心了)
2)allkeys-lru:
当内存不足以容纳新写入数据时,在所有键空间中,移除最近最少使用的key
(这个是最常用的)
3)allkeys-random:
当内存不足以容纳新写入数据时,在所有键空间中,随机移除某个key。
(这个一般没人用吧,为啥要随机,把我重要的key干掉了咋整,肯定是把最近最少使用的干掉)
4)volatile-lru:
当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
(这个一般不太合适)
5)volatile-random:
当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
6)volatile-ttl:
当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
例如:Redis 里有10个key,现在内存已经满了,设置的淘汰策略是allkeys-lru
,此时Redis需要删除掉一些key来保证你可以继续写入。在这10个key中,其中1个key,最近1分钟被查询了100次,1个key,最近10分钟被查询了50次,1个key,最近1个小时被查询了1次。肯定那些最近最少使用的被干掉了。
为啥存redis的数据有时候会丢失?
很简单,你写的数据太多了,内存占满了,或者触发了什么条件,如redis使用了allkeys-lru内存淘汰策略,自动给你清理掉了一些最近很少使用的数据。
4、结语
主要整理了Redis是怎么删除过期key的(定期删除+惰性删除),以及Redis内存满的时候怎么保证后续写入操作正常进行(内存淘汰策略)。
希望对你有帮助。奥利给!!
(关注左上角公众号,第一时间阅读文章)
什么?我往Redis写的数据怎么没了?的更多相关文章
- Memcache,Redis,MongoDB(数据缓存系统)方案对比与分析
mongodb和memcached不是一个范畴内的东西.mongodb是文档型的非关系型数据库,其优势在于查询功能比较强大,能存储海量数据.mongodb和memcached不存在谁替换谁的问题. 和 ...
- 利用redis写webshell
redis和mongodb我之所见 最近自己在做一些个人的小创作.小项目,其中用到了mongodb和redis,最初可能对这二者没有深入的认识.都是所谓的“非关系型数据库”,有什么区别么? 实际上,在 ...
- Redis 如何导出数据
Redis是一款支持多种数据类型的Key-Value数据库. 这里介绍下如何从Redis中导出数据. 数据是如何存储的?. Redis中是把数据保存到内存中的,但是它也会定期的把数据写会到硬盘中. R ...
- 善待Redis里的数据--Unable to validate object
又是一篇关于姿势的文章,为什么是”又”呢?因为上个星期刚写完一篇关于Apache Commons Pool的正确使用姿势的文章,点击此处阅读. Redis为我们提供便利的同时,我们也要善待里面的数据 ...
- 转载:善待Redis中的数据
Redis是我们数据的保管者,我们可以随时存随时取,大的小的,重要的不重要的,它都毫无怨言的帮我们保存着,甚至有些时候,我们变得很懒,存东西进去的时候顺便还贴张纸:"过了一个星期就帮我扔了吧 ...
- redis写shell与ssh免密码登陆
redis-cli参数:-h :指定要连接的主机IP或域名-p :指定连接的端口-a :指定密码-r :执行指定的命令-n :数据库名-x :将最后一个参数输出为value redis写shell- ...
- $Django 路飞之显示视频,Redis存购物车数据,优惠卷生成表,优惠卷的一个领取表。(知识小回顾)
知识小回顾之json序列化问题 精髓:支持python的几种数据类型(注意不是对象,不能放对象),其次是tuple变list. ensure_ascii:默认值True,如果dict内含有non-AS ...
- Redis和mysql数据怎么保持数据一致的?
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景, ...
- 往redis中存储数据是利用pipeline方法
在redis中保存数据时,保存和设置有效时间是分开写的话,如果中间出现的异常,这会导致数据永久有效,因此就可以采用pipeline方法. # 创建redis管道对象,可以一次执行多个语句 pipeli ...
随机推荐
- 《mysql必知必会》笔记2(子查询、联接、组合查询、全文本搜索)
十四:使用子查询 1:子查询是嵌套在其他查询中的查询. 2:需要列出订购TNT2的所有客户信息,需要下面几步: a:从orderitems表中检索出包含物品TNT2的所有订单号: b:根据上一步得出的 ...
- 在window.onload中使用setTimeout
window.onload = function(){ function n(i){ alert(1); } setTimeout('n(1)',2000); } 以上代码会报错:n() is not ...
- jquery 即点即改
//在html中建立表单. <table border=""> <th>编号</th> <th>用户名</th> < ...
- UVALive - 4787 ICPC WF 2010 Tracking Bio-bots【dp】
UVa 4787 WF题果然不一样,本来想暴力搜索,数据太大了,数组都开不了.看题解也不太懂,记录一下书上的题解,以后再看: 此题是给出N*M的格子,有些地方是墙,不可走.求所有不能只通过向上或者向右 ...
- 【批量添加】-SqlBulkCopy语句 标签: sql批量添加 2015-12-20 14:39 1367人阅读 评论(33)
上篇博客我们介绍了通过拼接sql字符串的方法来对sql数据库进行批量添加,但是通过语句拼接insert语句有个缺点,就是每次最多只能添加1000条.当时我们另外一个界面也用到了批量添加,但是这个界面轻 ...
- MapReduce数据流-Partiton&Shuffle
- Spring读取配置文件,地址问题,绝对路径,相对路径
Spring在读取配置文件时,是相对于bin,或者WEB-INF的: “applicationContext.xml”就是找bin或WEB-INF及子文件夹下的文件: “/res/applicatio ...
- oracle函数 log(x,y)
[功能]返回以x为底的y的对数 [参数]x,y,数字型表达式, [条件]x,y都必须大于0 [返回]数字 [示例] select power(4,2),log(16,2),1/log(16,4) fr ...
- 认识一下ES6的Reflect和Proxy
Reflect Reflect要替代Object的很多方法, 将Object对象一些明显属于言内部的方法放到了Reflect对象上,有13个方法 Reflect.apply(target, thisA ...
- oracle 用表连接替换EXISTS
通常来说 , 采用表连接的方式比EXISTS更有效率 SELECT ENAME FROM EMP E WHERE EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT_NO ...