Redis如何批量失效key

本文介绍了一种在Redis中批量失效缓存的策略,通过维护一个时间戳字段来代替直接删除键值,解决了在好友关系模块中频繁更新缓存的问题。

Redis如何批量失效key

问题

Redis的del key命令只能删除指定key。如果要删除满足指定模式的key,则会比较麻烦。这里提供一个使用数据时间戳的方案来实现批量失效缓存

场景描述

最近在写一个好友关系模块,类似于微信的好友机制。其中有一个方法Friendship getFriendship(long userId, long targerId);是用于获取两个用户是否有权限聊天

/*只要有一个字段为true,则可以聊天*/
class Friendship{
    boolean isFriend; //用户是否添加对方为好友,a添加b为好友,但是b未必添加a为好友,场景与微信类型。
    boolean isWhite; //如果有一方是白名单用户可以直接聊天
}
复制代码

由于该方法调用比较频繁,所以决定对该数据进行缓存。既然使用缓存就要清楚什么场景下需要添加缓存,什么场景下需要失效缓存

添加缓存

什么时候添加缓存是比较明显,当一个用户查询与另外一个用户的好友关系时加入缓存

Friendship getFriendship(long userId, long targerId){
    String key = String.format("Friendship:%s_%s", userId, targerId);
    Friendship friendship = redisServer.getObject(key, Friendship.class);
    if(friendship == null){
        friendship = queryFriendship(userId, targerId);
        redisServer.setObject(key, friendship);
    }
    return friendship;
}
复制代码

失效缓存

失效缓存分为两部分

  • isFriendship 这部分是比较简单的,只要userId方删除了targerId方,则删除为Friendship:userId_targertId的key即可
  • isWhite 这部分稍微比较麻烦一点。因为这个当一个用户被添加/删除白名单时,那么所有包含该用户的key都需要删除。虽然redis提供了keys pattern的命令用于检索关键字,但这个命令并不适合在生产上使用。比如添加/删除了一个id为123的白名单用户,那么所有符合正则Friendship:123_\d+Friendship:\d+_123的键就都要失效

解决方案

其实失效缓存并不一定要删除redis数据,只要提供一个时间戳字段用于判断缓存的有效性即可。 由于白名单用户变动比较少,为了实现上的简单,这里采用失效所有好友关系缓存的方式。即删除所有符合正则Friendship:\d+_\d+的key。问题本质与删除指定用户的key一样

白名单用户变更

void updateWhitelist(long userId, int operate){
    //update whitelist

    //保存最近一次变更白名单数据的时间
    String key = "UpdateWhitelist";
    long timestamp = System.currentTimeMillis();
    redisService.setLong(key, tiemstamp);
}
复制代码

Friendship类

class Friendship{
    boolean isFriend; 
    boolean isWhite;
    long timestamp; //缓存数据时的时间戳
}
复制代码

getFriendship 方法

Friendship getFriendship(long userId, long targerId){
    //如果没有更新,默认返回0
    long updateWhitelistTimestamp = redisServer.getLong("UpdateWhitelist", 0);

    String key = String.format("Friendship:%s_%s", userId, targerId);
    Friendship friendship = redisServer.getObject(key, Friendship.class);

    //好友关系缓存不存在或者缓存时间小于白名单更新时间,则重新查询数据库
    if(friendship == null 
        || friendship.getTimestamp() <= updateWhitelistTimestamp){

        friendship = queryFriendship(userId, targerId);
        friendship.setTimestamp(System.currentTimeMillis())
        redisServer.setObject(key, friendship);
    }
    return friendship;
}
复制代码

这样当Redis缓存了两个用户好友关系数据后,有新的用户被添加进了报名单。后续的查询根据timestamp的比较就会让当前缓存失效从而获取新的数据

转载于:https://juejin.im/post/5b1e33dd6fb9a01e3d1f9ca2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值