设为首页 收藏本站
查看: 925|回复: 0

[经验分享] 关于codis对于原redis过期事件解决方案

[复制链接]

尚未签到

发表于 2018-11-6 08:38:09 | 显示全部楼层 |阅读模式
1.     Redis处理过期事件方式
1.1.  Redis处理过期key方式
  Redis key过期的方式有二:被动方式和主动方式
  当clients试图访问设置了过期时间且已过期的key时,为主动过期方式。
  但仅是这样是不够的,以为可能存在一些key永远不会被再次访问到,这些设置了过期时间的key也是需要在过期后被删除的。因此,Redis会周期性的随机测试一批设置了过期时间的key并进行处理。测试到的已过期的key将被删除。典型的方式为,Redis每秒做10次如下的步骤:
  1.随机测试100个设置了过期时间的key
  2.删除所有发现的已过期的key
  3.若删除的key超过25个则重复步骤1
  此为主动方式
1.2.  Redis处理过期事件
@Test  
         public void testRedisEvent() {
  

  
                   Jedis jedis = newJedis("192.168.92.134", 8000);
  
                   jedis.psubscribe(newJedisPubSub() {
  
                            public voidonPMessage(String pattern, String channel,
  
                                               Stringmessage) {
  
                                     System.err.println(pattern);
  
                                     System.err.println(channel);
  
                                     System.err.println(message);
  
                            }
  
                   },"__keyevent@*__:expired");
  
         }
  当监听过期key时,则redis将此key通过pub/sub来发送事件。
  由于codis不支持的命令包含了pub/sub,则codis不再支持此监听事件。
2.     解决方案
2.1.  采用java的DelayQueue解决
  DelayQueue介绍:Delayed 元素的一个***阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed元素。如果延迟都还没有期满,则队列没有头部,并且 poll将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS)方法返回一个小于等于 0 的值时,将发生到期。即使无法使用 take或 poll移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。
  代码如下:
public class RedisEvent implements Runnable{  
    public DelayQueue q = new DelayQueue();
  
    public void run() {
  
        while (true){
  
            DelayItem delayItem = null;
  
            try {
  
                delayItem = q.take();
  
                if (delayItem != null) {
  
                    // 超时对象处理
  
                    Pair pair = delayItem.getItem();
  
                    System.out.println("key : " + pair.first + ", value : " + pair.second);
  
                }
  
            } catch (InterruptedException e) {
  
                e.printStackTrace();
  
            }
  
        }
  
    }
  

  
    public static void main(String[] args) throws InterruptedException {
  
        RedisEvent re = new RedisEvent();
  
        //过期key,value
  
        Pair pair1 = new Pair("key1", "value1");
  
        //2秒过期
  
        DelayItem d1 = new DelayItem(pair1, TimeUnit.SECONDS.toNanos(2));
  
        re.q.add(d1);
  
        System.out.println(re.q.poll());
  

  
        Thread.sleep(1000 * 1);
  
        System.out.println(re.q.poll());
  
        //2秒后可以拿到数据
  
        Thread.sleep(1000 * 2);
  
        DelayItem delayItem = re.q.poll();
  
        System.out.println(delayItem);
  
        Pair pair =delayItem.getItem();
  
        System.out.println("key : " + pair.first + ", value : " + pair.second);
  

  
        System.out.println(re.q.poll());
  

  
    }
  输出结果:
null  
null
  
com.eric100.delayqueue.DelayItem@5054c2b8
  
key : key1, value : value1
  
null
此方案优缺点:  优点:自己实现,简单易用,方便修改、扩展
  缺点:当过期事件过多时且过期时间过长,需要DelayQueue存放过多key,消耗jvm内存
2.2.  使用第三方queue队列实现
  需要queue支持delay job,目前了解的有:Beanstalkd,sidekiq
  Beanstalkd介绍:
  Beanstalk,一个高性能、轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Facebook Causes应用。
  Beanstalkd设计里面的核心概念:
  ◆ job
  一个需要异步处理的任务,是Beanstalkd中的基本单元,需要放在一个tube中。
  ◆ tube
  一个有名的任务队列,用来存储统一类型的job,是producer和consumer操作的对象。
  ◆ producer
  Job的生产者,通过put命令来将一个job放到一个tube中。
  ◆ consumer
  Job的消费者,通过reserve/release/bury/delete命令来获取job或改变job的状态。

  Beanstalkd中一个job的生命周期如图2所示。一个job有READY, RESERVED, DELAYED, BURIED四种状态。当producer直接put一个job时,job就处于READY状态,等待consumer来处理,如果选择延迟 put,job就先到DELAYED状态,等待时间过后才迁移到READY状态。consumer获取了当前READY的job后,该job的状态就迁移到RESERVED,这样其他的consumer就不能再操作该job。当consumer完成该job后,可以选择delete,>  优点:不需要自己实现,使用第三方queue
  缺点:
  1. Beanstalkd目前没有提供主从同步+故障切换机制,在应用中有可能成为单点的风险。在实际应用中,可以使用数据库为job提供持久化存储。
  2. 需要花费成本学习第三方queue
2.3.  使用数据库实现
  将过期key,value放入数据库中,使用线程定时扫描数据库。
DSC0000.jpg

DSC0001.jpg

  启动三个线程:
  线程1:根据过期时间,扫描状态为delay且过期时间已到的事件,将状态改为ready
  线程2:处理状态为ready的事件,将ready状态改为done
  线程3:删除done状态的事件
  优点:数据持久化,不会丢失事件数据
  缺点:线程定时扫描,过期事件存在延迟处理
2.4.  使用redis实现(推荐)
  由于codis不支持pub/sub,则重新添加redis服务,此服务只用来做过期事件处理
  优点:实现方式与原来相同,不需要修改任何代码
  缺点:需要添加机器来做redis服务,主备需采用keepalive等处理



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-631306-1-1.html 上篇帖子: redis启动时警告信息去除及简单安全设置 下篇帖子: redis sentinel 主从切换(failover)解决方案
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表