0
点赞
收藏
分享

微信扫一扫

【redis】使用redis有序集合实现按照时间淘汰算法


一、需求描述

1. 将活跃用户的时间在有序集合中用时间戳储存

2. 淘汰超过1分钟没有活跃的用户

3. 将查询活跃的用户返回

二、代码实现

/**
* 在线观众榜缓存类
* @author Marion
* @date 2021/5/25 10:52
*/
@Service
public class AudienceRankCache {

@Autowired
private StringRedisTemplate redisTemplate;

/**
* 淘汰时间(秒)
*/
public static final int rejectTime = 60;

public static class CacheKey {
/**
* stat缓存前缀
*/
public static final String CACHE_PREFIX = "stat:rank:";
/**
* 有资产变化的主播
*/
public static final String ACTIVE_ANCHOR = CACHE_PREFIX + "active:anchor";

public static String getActiveAnchor() {
return ACTIVE_ANCHOR;
}
}

public void addActiveAnchor(long uid, long timestamp) {
String key = CacheKey.getActiveAnchor();
redisTemplate.opsForZSet().add(key, String.valueOf(uid), timestamp);
}

/**
* 查询主播排行榜饭团有变化的主播
*/
public List<Long> getActiveAnchor() {
String key = CacheKey.getActiveAnchor();
Set<String> uidSet = redisTemplate.opsForZSet().reverseRange(key, 0, -1);
if (uidSet != null && uidSet.size() > 0) {
return uidSet.stream().map(Long::valueOf).collect(Collectors.toList());
}
return new ArrayList<>();
}

/**
* 【定时任务】执行淘汰检测
*/
public void checkRejectedAudience() {
String key = CacheKey.getActiveAnchor();
Set<ZSetOperations.TypedTuple<String>> tuples = redisTemplate.opsForZSet().rangeWithScores(key, 0, -1);
if (tuples != null && tuples.size() > 0) {
// 从最早的时间开始判断,如果超过60s则删除,不超过60s退出循环
long now = System.currentTimeMillis();
// 批量淘汰,如果数据量过多则可以使用pipeline
List<String> removeUid = new ArrayList<>();

for (ZSetOperations.TypedTuple<String> tuple : tuples) {
if (tuple.getScore() == null) {
redisTemplate.opsForZSet().remove(key, tuple.getValue());
}
//如果最早的时间没有过期,则退出循环
if (tuple.getScore() + rejectTime * 1000L > now) {
break;
}
removeUid.add(tuple.getValue());
}

if (removeUid.size() > 0) {
redisTemplate.opsForZSet().remove(key, removeUid);
}
}
}

}

定时任务方法

/**
* 定时任务
* 启动后5秒执行,间隔5秒执行
*/
@Scheduled(initialDelay = 5000, fixedDelay = 5000)
private void checkRejectedAudience() {
audienceRankCache.checkRejectedAudience();
}

 

举报

相关推荐

0 条评论