redis生产使用场景(一):并行流+二级缓存

本文主要介绍 redis 缓存在线上的使用场景

由于业务的特殊性,在生产库用户表中,大概有 50 多万的测试用户,在真实业务计算中,要把测试用户给筛选掉,所以在计算前,需要把测试用户加载到 redis 缓存中,并构建本地缓存。

查询数据库

为了提高查询效率,先得到最大主键ID,以每次查询5000 条提前构建好批次范围,并采用并行查询的方式。

     long maxUserId = odsUserDAO.getMaxUserId(); // 查询最大 id
     // 构建批次范围列表
     List<LinkedList<Long>> pagingIntervalList = new ArrayList<>();

     //初始化分页列表
     for(long leftBoundary = 0; leftBoundary < maxUserId; leftBoundary += 5000){
         LinkedList<Long> pagingInterval = new LinkedList<>();
         long rightBoundary = leftBoundary + 5000;
         if(rightBoundary >= maxUserId){
             pagingInterval.add(leftBoundary);
             pagingInterval.add(maxUserId + 1);
             pagingIntervalList.add(pagingInterval);
             break;
         }

         pagingInterval.add(leftBoundary);
         pagingInterval.add(rightBoundary);
         pagingIntervalList.add(pagingInterval);
     }

     //并行加载测试学生
     Set<Long> testUserIdSet = pagingIntervalList
             .parallelStream()
             .map(pagingInterval -> odsUserDAO.incrementGetTestUser(pagingInterval.peekFirst(), pagingInterval.peekLast()))
             .flatMap(List::stream)
             .map(o -> o.getId())
             .collect(Collectors.toSet());

分页查询 sql

<select id="incrementGetTestUser" resultMap="BaseResultMap">
    select  <include refid="Base_Column_List"/>
    from user
    where (account_type ='TEST'
    or name like '%test%'
    or name like '%TEST%'
    or name like '%测试%'
    or status <![CDATA[ <> ]]> 'NORMAL')
    and id between #{pagingStartIdx} and #{pagingEndIdx}
    and status = 1
  </select>

写回缓存

private static volatile Set<Long> testUserLocalCache = null; //全局变量

testUserLocalCache = testUserIdSet; //本地缓存
String[] testUserIdArray = testUserIdSet
        .parallelStream()
        .map(String::valueOf)
        .toArray(String[]::new);
redisCluster.sadd("test_user_data", testUserIdArray); //redis缓存

查询缓存

在处理业务时,如果该用户是测试数据,则跳过。

private static volatile Set<Long> testUserLocalCache = null; //全局变量
 
public boolean isTestUser(Long userId){
        if (testUserLocalCache == null || testUserLocalCache.isEmpty()){
            boolean isRemoteTestUserCacheExists = redisCluster.exists("test_user_data");
            if(!isRemoteTestUserCacheExists){
                throw new RuntimeException("failed to hit test user remote cache, cause test user never preload");
            }

            // 如果本地缓存为空,则构建
            synchronized(this){
                if (testUserLocalCache == null || testUserLocalCache.isEmpty()){
                    Set<String> testUserSet = redisCluster.sscanAll("test_user_data"); //采用 sscan 游标方式查询
                    testUserLocalCache = testUserSet
                            .parallelStream()
                            .map(Long::valueOf)
                            .collect(Collectors.toSet());
                }
            }
        }
        //从本地缓存查询数据
        return testUserLocalCache.contains(userId);
    }

总结

由于业务性质及生产机器配置够高,缓存不设置过期时间,只是在下次计算前,先清除缓存即可,再构建本次新的缓存。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值