关于codis对于原redis过期事件解决方案

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);
                            }
                   },"[email protected]*__:expired");
         }

当监听过期key时,则redis将此key通过pub/sub来发送事件。

由于codis不支持的命令包含了pub/sub,则codis不再支持此监听事件。

2.     解决方案

2.1.  采用java的DelayQueue解决

DelayQueue介绍:Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed元素。如果延迟都还没有期满,则队列没有头部,并且 poll将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS)方法返回一个小于等于 0 的值时,将发生到期。即使无法使用 takepoll移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。

代码如下:

public class RedisEvent<K, V> implements Runnable{
    public DelayQueue<DelayItem<Pair<K, V>>> q = new DelayQueue<DelayItem<Pair<K, V>>>();
    public void run() {
        while (true){
            DelayItem<Pair<K, V>> delayItem = null;
            try {
                delayItem = q.take();
                if (delayItem != null) {
                    // 超时对象处理
                    Pair<K, V> 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<String, String> re = new RedisEvent<String, String>();
        //过期key,value
        Pair<String, String> pair1 = new Pair<String, String>("key1", "value1");
        //2秒过期
        DelayItem<Pair<String,String>> d1 = new DelayItem<Pair<String,String>>(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<Pair<String,String>> delayItem = re.q.poll();
        System.out.println(delayItem);
        Pair<String, String> pair =delayItem.getItem();
        System.out.println("key : " + pair.first + ", value : " + pair.second);

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

    }

输出结果:

null
null
[email protected]
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, release或者bury操作;delete之后,job从系统消亡,之后不能再获取;release操作可以重新把该job状态迁移回READY(也 可以延迟该状态迁移操作),使其他的consumer可以继续获取和执行该job;有意思的是bury操作,可以把该job休眠,等到需要的时候,再将休 眠的job kick回READY状态,也可以deleteBURIED状态的job。正是有这些有趣的操作和状态,才可以基于此做出很多意思的应用,比如要实现一个循环队列,就可以将RESERVED状态的 job休眠掉,等没有READY状态的job时再将BURIED状态的job一次性kick回READY状态。

优点:不需要自己实现,使用第三方queue

缺点:

1. Beanstalkd目前没有提供主从同步+故障切换机制,在应用中有可能成为单点的风险。在实际应用中,可以使用数据库为job提供持久化存储。

2. 需要花费成本学习第三方queue

2.3.  使用数据库实现

将过期key,value放入数据库中,使用线程定时扫描数据库。

启动三个线程:

线程1:根据过期时间,扫描状态为delay且过期时间已到的事件,将状态改为ready

线程2:处理状态为ready的事件,将ready状态改为done

线程3:删除done状态的事件

优点:数据持久化,不会丢失事件数据

缺点:线程定时扫描,过期事件存在延迟处理

2.4.  使用redis实现(推荐)

由于codis不支持pub/sub,则重新添加redis服务,此服务只用来做过期事件处理

优点:实现方式与原来相同,不需要修改任何代码

缺点:需要添加机器来做redis服务,主备需采用keepalive等处理

时间: 2024-11-13 04:34:37

关于codis对于原redis过期事件解决方案的相关文章

Redis Sentinel环境下的Key过期事件消息订阅

一.Redis Sentinel Sentinel是Redis 2.8之后官方发布的HA解决方案,通过Sentinel可以保障整个Redis系统的高可用性.当Redis系统中的Master在异常情况下停止服务后,若干Sentinel会及时察觉并主观判断Master down(Subjectively Down),并且随后由一定数量的Sentinel共同确定Master确实客观已down(Objectively Down),这个时候Sentinel们会选举出一个新的Master继续提供服务.Red

Codis——分布式Redis服务的解决方案

Codis——分布式Redis服务的解决方案 之前介绍过的 Twemproxy 是一种Redis代理,但它不支持集群的动态伸缩,而codis则支持动态的增减Redis节点:另外,官方的redis 3.0开始支持cluster. codis和twemproxy最大的区别有两个: codis支持动态水平扩展,对client完全透明不影响服务的情况下可以完成增减redis实例的操作: codis是用go语言写的并支持多线程,twemproxy用C并只用单线程. 后者又意味着:codis在多核机器上的性

redis的分布式解决方案--codis

codis是豌豆荚开源的分布式服务器,目前处于稳定阶段. 原文地址:https://github.com/wandoulabs/codis/blob/master/doc/tutorial_zh.md Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所

Codis 替换 Redis 集群 解决方案

Codis: Redis 集群解决方案 Codis 由四部分组成: Codis Proxy (codis-proxy) Codis Manager (codis-config) Codis Redis (codis-server) ZooKeeper 1. 首先安装 go 语言  需安装1.0 以及之前的版本 https://code.google.com/p/go/ wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.t

redis中key过期事件

刚到新公司一个月左右,有个新需求,想做定时任务,比如在用户注册时间的3天后推送用户一条消息. 从刚开始脑子里面闪现的数据库轮询,立马否定掉(浪费资源),再到linux系统的定时任务,但是当用户量过大时,肯定不行. 最后想着redis如果key过期了,能不能监听触发一个事件,这样便可以不用时刻的查询是否到了发送消息的时间,从而节省资源. 最终找到了 redis的key过期事件.通过监听redis的过期时间,在过期时触发一个事件,从而通过这个事件做其他事情. 操作步骤(liunx系统): 1.找到r

redis学习笔记——Redis过期键的删除策略

Redis过期键的删除策略 对于过期键一般有三种删除策略 定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作: 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键:如果没有过期,那就返回该键: 定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键.至于删除多少过期键,以及要检查多少个数据库,则由算法决定. 下面我们来看看三种策略的优缺比较: 定时删除策略对内存是

Nginx源码分析—过期事件和惊群事件的处理

过期事件:每个事件的date域都是一个结构体ngx_connection_t结构体,表示对应的连接.对于一个结构体struct epoll_event 中的data.ptr成员存储的是ngx_connection_t连接,这里使用Instance标志位来标识,下面就配合ngx_epoll_process_events方法说明他的用法. Data.ptr (void* )((uintptr_t) c  |  ev->instance); 这事添加事件的使用对ptr进行的初始化. 那么在检查的时候怎

虚拟机centOS中安装Redis,主机Redis Destop Manager不能访问虚拟机Redis server的解决方案

今天在学些redis的时候碰到个问题,发现主机Redis Destop Manager不能访问虚拟机Redis server的解决方案,找了一些网上的资料,原因可能有两个,整理记录下来: 1. Redis.conf文件中打开了 # By default Redis listens for connections from all the network interfaces# available on the server. It is possible to listen to just on

Redis数据存储解决方案

1.背景1.1 Redis简介 官方网站:http://redis.io/,Redis是REmote DIctionary Server的缩写. Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作由VMware主持.它跟 memcached 类似,不过数据可以持久化,而且支持的数据类型很丰富.它在保持键值数据库简单快捷特点的同时,又吸收了部分关系数据库的优点.从而