• KeySpaceNotification 键空间通知


    KeySpaceNotification 键空间通知

    1、Redis键淘汰机制简介

    在Redis中,内存的大小是有限的,所以为了防止内存饱和,需要实现某种键淘汰策略。主要有两种方法,一种是当Redis内存不足时所采用的内存释放策略。第二种是对过期键进行删除的策略,也可以在某种程度上释放内存。

    1.1 Redis键过期淘汰的策略

    当需要进行内存释放的时候,需要用某种策略对保存的的对象进行删除。Redis有六种策略:

    volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

    volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰

    volatile-random:从已设置过期时间的数据集中任意选择数据淘汰

    allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

    allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

    no-enviction(驱逐):禁止驱逐数据

    2、KeySpaceNotification功能

    2.1 开启KeySpaceNotification功能

    默认情况下,该功能是关闭的,因为该功能消耗部分CPU。开启该功能需要修改redis的配置文件。

    当前需要修改的配置的机器有两台:Redis1、Redis2

    配置文件的路径均为: /etc/redis

    clip_image002

    图1 Redis1中需要修改的配置文件

    clip_image004

    图2 Redis2中需要修改的配置文件

    2.2 修改配置文件

    1. 使用vi 6379.conf 进入文件;

    clip_image006

    图3 使用vi指令进入配置文件

    2. 输入/keyspace,回车后定位到该功能开启部分;

    clip_image008

    图4 定位keyspace

    clip_image009

    图4 查看通知功能介绍

    3. 修改配置文件为下图所示 KEA表示所有的操作都会向相应的频道中发布通知信息;

    clip_image011

    图5 修改后的配置文件

    4. 按下Esc,输入:wq! 回车保存文件;

    5. 按照上述过程将所有的配置文件。

    6. 重启Redis1、Redis2,使键空间通知功能开启。

    3、使用键空间通知功能

    3.1 实现频道的订阅

    public class jedisSubscribe {
    
    public static void main(String[] args) {
    
      Set<HostAndPort> jedisClusterNodes=new HashSet<HostAndPort>();
    
      JedisCluster cluster;
    
      cluster = new JedisCluster(RedisPool.loadServers());
    
      String host1 = "192.168.1.34";
    
      JedisPubSub jedisPubSub = null;
    
      jedisPubSub = new JedisPubSub() {
    
      /*
    
      * 常规模式:关闭订阅时触发arg0 key值 arg1 订阅数量
    
      */
    
      public void onUnsubscribe(String arg0, int arg1) {
    
      }
    
      /*
    
      * 常规模式:启动订阅时触发arg0 key值 arg1 订阅数量
    
      */
    
      public void onSubscribe(String arg0, int arg1) {
    
        System.out.println("Success onSubscribe "+arg0);
    
      }
    
      /*
    
      * 常规模式:收到匹配key值的消息时触发arg0 key值arg1 收到的消息值
    
      */
    
      public void onMessage(String arg0, String arg1) {
    
        System.out.println("Get Message "+arg1);
    
        System.out.println("Get "+arg0);
    
        String key = cluster.get(arg0);
    
        System.out.println("Success "+key);
    
      }
    
      /*
    
      * 正则模式:关闭正则类型订阅时触发
    
      * arg0 key的正则表达式arg1 订阅数量
    
      */
    
      public void onPUnsubscribe(String arg0, int arg1) {
      
      }
    
      /*
    
      * 正则模式:启动正则类型订阅时触发
    
      * arg0 key的正则表达式
    
      * arg1 订阅数量
    
      */
    
      public void onPSubscribe(String arg0, int arg1) {
      
      }
    
      /*
    
      * 正则模式:收到匹配key值的消息时触发
    
      * arg0订阅的key正则表达式
    
      * arg1匹配上该正则key值
    
      * arg2收到的消息值
    
      */
    
      public void onPMessage(String arg0, String arg1, String arg2) {
      
      }
    
    };
    
      String channel4 = "__keyevent@0__:expire";//设置订阅的频道channels
    
      JedisPool jedisPool1 = new JedisPool(host1);
    
      jedisPool1.getResource().subscribe(jedisPubSub, channel4);
    
      }
    
    }

    3.2 对Redis中的键进行操作

    public static void main(String[] args) throws InterruptedException {
    
      Set<HostAndPort> jedisClusterNodes=new HashSet<HostAndPort>();
    
      JedisCluster cluster;
    
      cluster = new JedisCluster(RedisPool.loadServers());
    
      String key = "name";//设置一个key
    
      String value = "zpf";//设置该key的value
    
      cluster.set(key, value);//向redis中写入该(key,value)
    
      cluster.expire(key, 2);//设置key过期时间为2秒
    
      cluster.del(key);
    
    }
    3.3 运行结果

    clip_image013

    4.车辆信息的实时性维护

    4.1利用键空间通知的方法

    Redis会在设置过期时间的键集合中随机抽选进行键的判断,如果过期则进行删除操作,同时会向频道 __keyevent@0__:expire中过期消息,并且监听这个频道的程序会得到过期的键是哪一个键。也会向频道 __keyspace@0__:key中发布该键过期的消息,其中这里的频道根据过期的键key不同发布的频道也不同。进行删除操作时,Redis也会向频道__keyevent@0__:del和 __keyspace@0__:key中分别发布消息。

    为了维护车辆信息的实时性,需要对过期的车辆数据进行相应的删除操作,但是Redis中的删除操作只能将对应的key删除掉,这里的需求是进行网格以及其他相应的维护操作,删除操作是不相同的。因此需要再删除之前得到过期的key的值value。

    clip_image015

    clip_image017

    根据上面的描述,无法再订阅频道__keyevent@0__:expire接收到通知的时候得到过期键的值value。为了实现借助Redis的删除功能需要在该频道接收到信息之前得到要过期的key的值value。但是这样的话又成了对redis的判断操作。为了实现得到过期键的value,可以通过在得到该数据并进行设置过期时间的时候提前构造一个map<key,value>其中key为车牌,value为车牌+原始信息的value。这样在频道__keyevent@0__:expire接收到通知时,就可以使用map得到相应的value值。

    4.2 使用该方法造成的问题

    构造map时,需要对每一辆车进行判断,如果车牌key不在此map中时,需要将该信息放入map中;如果车牌key存在此map中,需要更新map。那么存储该map需要占用额外的存储空间。

    5.参考资料

    http://redis.io/topics/notifications

    https://cnodejs.org/topic/5577b493c4e7fbea6e9a33c9#5577e266c4e7fbea6e9a3449

    http://redisdoc.com/topic/notification.html#id1

    http://blog.csdn.net/caishenfans/article/details/44902651

    https://github.com/antirez/redis/issues/594

  • 相关阅读:
    [日常] Go语言圣经--示例: 并发的Echo服务
    [日常] Go语言圣经--示例: 并发的Clock服务习题
    [日常] Go语言圣经--接口约定习题2
    [日常] Go语言圣经--接口约定习题
    [日常] Linux下的docker实践
    [日常] Go语言圣经-指针对象的方法-bit数组习题2
    [日常] Go语言圣经-指针对象的方法-bit数组习题
    [日常] Go语言圣经-Panic异常,Recover捕获异常习题
    [日常] Go语言圣经-Deferred函数
    [日常] Go语言圣经-可变参数习题
  • 原文地址:https://www.cnblogs.com/zpfbuaa/p/5997773.html
Copyright © 2020-2023  润新知