一文弄懂redis分布式缓存之微博推送技术方案

1️⃣业务场景分析

  1. 关注微博
  • 登录首页展示了我关注的所有人发的微博,展示形式是列表
  • 滚动有分页加载

2.个人微博

  • 我发的微博展示在个人微博,展示形式也是列表
  • 滚动有分页加载

2️⃣ 基于redis技术方案

发微博

文章

个人微博

关注微博

用户

服务器

采用map结构保存

采用list结构保存文章id

也采用list结构保存文章id

  1. 关注微博和个人微博的展示形式都是列表,用redis的list结构存储。
  2. 滚动有分页加载,用redis的 lrange key start stop命令范围查询元素。

问题: 每个人都有2个list:一个是个人list,一个是关注list,而这2个list每次发微博都会push到个人list和关注list,这2个list存在性能的问题,就是这个list无线增长。时间久了redis数据持续膨胀。

最有效的解决方法是限制次数,常见的场景是

  • qq群,微信群限定人数
  • 百度搜索限定了搜索出来75页
  1. 限定个人微博和关注微博的长度为1000,即,发微博的时候,往个人list和关注list push完成后,把list的长度剪切为1000,具体的技术方案采用list 的ltrim命令来实现。
  • ltrim key start end截取队列指定区间的元素,其余元素都删除

3️⃣代码编写

✏️ 发微博,写入个人主页

    /**
     * push到个人主页
     */
    public void pushHomeList(Integer userId,Integer postId){
        //个人微博列表key
        String key="myPostBox:list:"+userId;
        //把该微博文章id推送到队列
        this.redisTemplate.opsForList().leftPush(key,postId);
        //限定长度,防止膨胀,截取前1000条
        if(this.redisTemplate.opsForList().size(key)>1000){
            this.redisTemplate.opsForList().trim(key,0,1000);
        }
   }
复制代码

✏️ 发微博,批量推送给粉丝

    /**
     * 发一条微博,批量推送给所有粉丝
     */
    private void pushFollower(int userId,int postId){
        SetOperations<String, Integer> opsForSet = redisTemplate.opsForSet();
        //读取粉丝集合,粉丝集合用set保存
        String followerkey=Constants.CACHE_KEY_FOLLOWER+userId;
        //千万不能取set集合的所有数据,如果数据量大的话,会卡死
        // Set<Integer> sets= opsForSet.members(followerkey);
        Cursor<Integer> cursor = opsForSet.scan(followerkey, ScanOptions.NONE);
        try{
            while (cursor.hasNext()){
                //拿出粉丝的userid
                Integer object = cursor.next();
                //该粉丝的关注列表key
                String key= "myAttentionBox:list:"+object;
                //把该文章添加到队列
                this.redisTemplate.opsForList().leftPush(key,postId);
            }
        }catch (Exception ex){
            log.error("",ex);
        }finally {
            try {
                cursor.close();
            } catch (IOException e) {
                log.error("",e);
            }
        }
    }
复制代码

✏️ 查看个人列表

    /**
     * 获取个人主页列表
     */
    public PageResult<Content> homeList(Integer userId,int page, int size){
        //分页
        PageResult<Content> pageResult=new PageResult();
        List<Integer> list=null;
        long start = (page - 1) * size;
        long end = start + size - 1;
        try {
            String key= "myPostBox:list:"+userId;
            //1.查询用户的总数
            int total=this.redisTemplate.opsForList().size(key).intValue();
            //设置总数
            pageResult.setTotal(total);
            //2.采用redis list数据结构的lrange命令实现分页查询。
            list = this.redisTemplate.opsForList().range(key, start, end);
            //3.根据文章id去redis查询明细,redis没有就去db拿
            List<Content> contents=this.getContents(list);
            pageResult.setRows(contents);
        }catch (Exception e){
            log.error("异常",e);
        }
        return pageResult;
    }
复制代码

✏️ 查看关注列表

    /**
     * 获取关注列表
     */
    public PageResult<Content> attentionList(Integer userId,int page, int size){
        PageResult<Content> pageResult=new PageResult();

        List<Integer> list=null;
        long start = (page - 1) * size;
        long end = start + size - 1;
        try {
            String key= "myAttentionBox:list:"+userId;
            //1.设置总数
            int total=this.redisTemplate.opsForList().size(key).intValue();
            pageResult.setTotal(total);
            //2.采用redis,list数据结构的lrange命令实现分页查询。
            list = this.redisTemplate.opsForList().range(key, start, end);
            //3.根据文章id去redis查询明细,redis没有就去db拿
            List<Content> contents=this.getContents(list);
            pageResult.setRows(contents);
        }catch (Exception e){
            log.error("异常",e);
        }
        return pageResult;
    }
复制代码

⛳redis分布式缓存系列文章

上一章节: redis分布式缓存(三十)一一 🚀二级缓存的高并发文章PV解决方案

  • 👍🏻:有收获的,点赞鼓励!
  • ❤️:收藏文章,方便回看!
  • 💬:评论交流,互相进步!
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务