redis实现直播间评论分页查询
技术选型
直播间查询评论数据有以下特点
- 高频次查询
不断获取历史消息,接口频次查询高 - 高并发查询
同时十几万在线,QPS在十万级别 - 全局一致性
评论数据是实时读取,写入缓存,不是单向的读取,采用redis分布式缓存
数据类型选择
在数据类型选择时,符合列表特性的数据类型有
实现逻辑
- 整体逻辑
- 核心代码
- 保存
public void addCommentInfo(String content) {
// 生成id
int commentId = genKey();
// 保存mysql
commentInfoGateway.insertMysql(content);
//保存redis commentInfo
String commenInfoKey = RedisKeyUtils.getCommenInfoKey(String.valueOf(commentId));
stringRedisTemplate.opsForValue().set(commenInfoKey, JSONUtil.toJsonStr(commentInfo));
//保存直播间对应的评论数据
String commentRoomKey = RedisKeyUtils.getCommentRoomKey(commentInfoBo.getRoomId());
redisTemplate.opsForZSet().add(commentRoomKey, commenInfoKey, commentTime);
//保存时间戳对应的下标
String timeKey = RedisKeyUtils.getRoomTimeKey(commentInfoBo.getRoomId(), commentInfoBo.getCommentTime());
// 评分值相同,按照字典序排列
redisTemplate.opsForZSet().add(timeKey, commenInfoKey, 1);
}
public Set getCommentInfos( Long commentTime,Long roomId) {
String commentRoomKey = RedisKeyUtils.getCommentRoomKey(roomId);
int[] index = getIndex(index);
Set<String> rangeList = redisTemplate
.opsForZSet().reverseRange(commentRoomKey, index[0], index[1]);
return rangeList;
}
private Long[] getIndex(int page,
int pageSize,
Long commentTime,
Long roomId) {
// 前端没有传时间戳的话,默认取最近的数据
Long startIndex = 0L;
Long endIndex = (long) pageSize - 1;
//如果时间为空,就按照最新时间分页
if (soIn.getCommentTime() == null) {
startIndex = (long) (page - 1) * pageSize;
endIndex = startIndex + pageSize - 1;
return new Long[]{startIndex, endIndex};
}
//如果时间不为空,就向后位移
String roomTimeKey = RedisKeyUtils.getRoomTimeKey(s roomId, commentTime);
String commentRoomKey = RedisKeyUtils.getCommentRoomKey(roomId);
startIndex = redisTemplate.opsForZSet().reverseRank(roomKey, key);
startIndex = startIndex + (long) (page - 1) * pageSize;
endIndex = startIndex + pageSize - 1;
return new Long[]{startIndex, endIndex};
}