又是一篇关于姿势的文章,为什么是”又”呢?因为上个星期刚写完一篇关于Apache Commons Pool的正确使用姿势的文章,点击此处阅读。

Redis为我们提供便利的同时,我们也要善待里面的数据

Redis是我们数据的保管者,我们可以随时存随时取,大的小的,重要的不重要的,它都毫无怨言的帮我们保存着,甚至有些时候,我们变得很懒,存东西进去的时候顺便还贴张纸:“过了一个星期就帮我扔了吧”,对于这些,Redis也都默默的接受了(谁叫Antirez把redis设计的这么好呢)。

这次要写的就是关于这张留言纸的事。

Redis提供了一套“美好”的过期数据清理机制:

  • 主动过期: Redis对数据是惰性过期,当一个key到了过期时间,Redis也不会马上清理,但如果这个key过期后被再次访问,Redis就会主动将它清理掉

  • 被动过期: 如果过期的Key一直没被访问,Redis也不会一直把它放那不管,它会每秒10次的执行以下的清理工作:

    • 随机从所有带有过期时间的Key里取出20个
    • 如果发现有过期的,就清理
    • 如果这里有25%的Key都是过期的,就继续回到第一步再来一次

这套过期机制设计的很赞,可以这样理解:如果当前有超过1/4的Key过期的话,就不停地清理,直到只剩下1/4不到的Key是要过期的为止,然后就慢慢地随机抽查着清理。

现在我们再说说对待Redis数据的姿势问题。

先看一个现象,某段程序每天24小时的跑着,但时不时地出现拿不到连接的错误:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)
...
at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
at com.dianping.cat.annotation.CatTransaction.doServerAround(CatTransaction.java:70)
at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy102.getRecommendedMediaList(Unknown Source)
at com.restful.MediaController.getMediaList(MediaController.java:139)
at sun.reflect.GeneratedMethodAccessor53.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.filter.HttpHeaderValidator.doFilter(HttpHeaderValidator.java:198)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.filter.CorrelationFilter.doFilter(CorrelationFilter.java:40)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:87)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1756)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1715)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.NoSuchElementException: Unable to validate object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:506)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at redis.clients.util.Pool.getResource(Pool.java:48)
... 82 more

这个错误是因为JedisPool拿到一个连接后,调用 jedis.ping() 方法没有得到正确的返回”pong”消息,而出现这个问题时,并不是traffic的高峰期,redis的cpu不高,于是程序员很快就怀疑到网络上,难道有”丢包”?

但跑了几天,发现出错的时间固定在某几个时间点(如晚上9点~10点),莫非是扫地阿姨每天定时在机房打扫卫生,碰着网线了?(有时候不得不佩服程序员的想象力)

然而在一个夜黑风高的晚上,程序员的脑子在这个时候一般是最清醒的,这时告警短信又来了,打开redis监控,像在唯品会上逛街一样,对着redis的各项监控数据逛啊逛,突然,看到有几条Expires的数据,当时的表情只能用看到关注了几天的商品上标了大大”0.1折”时的表情来形容。

接下来的事情,想必大家也都猜到个七七八八了,当然是下单抢购支付了,脑子里一系列的运算,掐指一算: “这个时间点正好有一大批key过期”,而且都是大的Set集合,每个都有几十万的数据,再一算: “Redis里的大部分需要过期的key就是这些key”。

于是,答案有了,Redis进行被动过期清理时,发现怎么随机,都有超过1/4的Key都是过期的,就忙着不停的删啊删,再加上又都是大集合的删除,O(N)的操作复杂度,无奈,等redis删完时,客户端那边的命令都等超时了

原因找到了,如何解决?看业务场景吧,对于我们的场景,做法是将过期时间设长一点,然后把这些可以删掉的Key标记一下,丢到一个后台线程那里分页删Set里的数据,这样就算redis再做过期操作,也不会用太多的时间来删除。

最后,稍稍总结下,对于大个的集合对象,放redis的时候需要额外注意,如果想依赖redis的过期,可能会造成过期时短暂的redis block

所以,要善待redis数据,比如不用了就自己清理掉,不要等着redis来帮你。

http://neway6655.github.io/redis/2015/12/19/%E5%96%84%E5%BE%85Redis%E9%87%8C%E7%9A%84%E6%95%B0%E6%8D%AE.html

善待Redis里的数据--Unable to validate object的更多相关文章

  1. 转载:善待Redis中的数据

    Redis是我们数据的保管者,我们可以随时存随时取,大的小的,重要的不重要的,它都毫无怨言的帮我们保存着,甚至有些时候,我们变得很懒,存东西进去的时候顺便还贴张纸:"过了一个星期就帮我扔了吧 ...

  2. 解决:Redis:java.util.NoSuchElementException: Unable to validate object at

    在Java使用Redis的过程中遇见了一个问题, redis.clients.jedis.exceptions.JedisConnectionException: Could not get a re ...

  3. redis异常Redis:java.util.NoSuchElementException: Unable to validate object at

    前两天项目上线的时候遇到了redis的一个问题,在测试环境的时候项目运行正常,项目一上线redis便开始抛异常. redis.clients.jedis.exceptions.JedisConnect ...

  4. 第三百节,python操作redis缓存-其他常用操作,用于操作redis里的数据name,不论什么数据类型

    python操作redis缓存-其他常用操作,用于操作redis里的数据name,不论什么数据类型 delete(*names)根据删除redis中的任意数据类型 #!/usr/bin/env pyt ...

  5. scrapy基础知识之 处理Redis里的数据:

    数据爬回来了,但是放在Redis里没有处理.之前我们配置文件里面没有定制自己的ITEM_PIPELINES,而是使用了RedisPipeline,所以现在这些数据都被保存在redis的xx:items ...

  6. 向Redis里存入数据

    实现思路:1.    从Redis缓存获取URL统计网址清单2.    逐条拼凑SQL统计语句,暂时不能支持批量计算,因为按单个网址统计.3.    发送到HIVE JDBC执行SQL并等待返回结果4 ...

  7. Spring整合Redis时报错:java.util.NoSuchElementException: Unable to validate object

    我在Spring整合Redis时报错,我是犯了一个很低级的错误! 我设置了Redis的访问密码,在Spring的配置文件却没有配置密码这一项,配置上密码后,终于不报错了!

  8. 从redis数据库取数据存放到本地mysql数据库

    redis数据库属于非关系型数据库,数据存放在内存堆栈中,效率比较高. 其存储数据是以json格式字符串存储字典的,而类似的关系型数据库无法实现这种数据的存储. 在爬取数据时,将数据暂存到redis中 ...

  9. Redis 如何导出数据

    Redis是一款支持多种数据类型的Key-Value数据库. 这里介绍下如何从Redis中导出数据. 数据是如何存储的?. Redis中是把数据保存到内存中的,但是它也会定期的把数据写会到硬盘中. R ...

随机推荐

  1. C# System.AppDomain类

    进程是存在独立的内存和资源的,但是AppDomain仅仅是逻辑上的一种抽象.一个process可以存在多个AppDomain.各个AppDomain之间的数据时相互独立的.一个线程可以穿梭多个AppD ...

  2. DeflateStream类

    DeflateStream是另外一种压缩与解压缩流,使用方法与GZipStream类似,而且压缩之后的带下也差不多. 一.属性 BaseStream 获取对基础流的引用. CanRead  获取一个值 ...

  3. javascript代码混淆原理

    https://www.google.com/search?biw=1440&bih=729&q=javascript%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7 ...

  4. redhat6.3 64位更新源(使用网易源)全过程记录

    本篇博客参考:http://chinaxiaoyu.diandian.com/post/2013-01-24/40046529897.首先在浏览器中输入http://tel.mirrors.163.c ...

  5. 更新ORACLE数据时遇到锁死情况的处理

    我们在操作数据库的 时候,有时候会由于操作不当引起数据库表被锁定,这么我们经常不知所措,不知怎么给这些表解锁,在pl/sql Developer工具的的菜单“tools”里面的“sessions”可以 ...

  6. 3 x 8 = 23(火了)

    颜回爱学习,德性又好,是孔子的得意门生.一天,颜回去街上办事,见一家布店前围满了人.他上前一问,才知道是买布的跟卖布的发生了纠纷. 只听买布的大嚷大叫:「三八就是二十三,你为啥要我二十四个钱?」颜回走 ...

  7. Can you solve this equation?(二分)

    Can you solve this equation? Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Ja ...

  8. TRIZ系列-创新原理-32-改变颜色原理

    改变颜色原理的详细描写叙述例如以下:1)改变物体或其环境的颜色:2)改变物体或其环境的透明度:3)对于难以看到的物体或过程.使用颜色加入剂来观測.4)假设已经使用了这样的加入剂,那么使用发光跟踪或原子 ...

  9. wso2esb源码编译总结

    最近花了两周的空闲时间帮朋友把wso2esb的4.0.3.4.6.0.4.7.0三个版本从源码编译出来了.以下是大概的一些体会. wso2esb是基于carbon的.carbon是个基于eclipse ...

  10. 远程调试weinre的使用

    一.用途 *鉴于在浏览器调试移动端页面无法准确反映移动端实际情况并无法高效调试,故常常使用远程调试工具通过电脑连接手机进行调试,常用远程调试方式: 1.chrome连接安卓机远程调试 2.Mac连接苹 ...