Redis实战(9)-有序集合SortedSet实战之再谈游戏充值排行榜(如何处理历史与异常的充值记录) - Go语言中文社区

Redis实战(9)-有序集合SortedSet实战之再谈游戏充值排行榜(如何处理历史与异常的充值记录)


概述:本系列博文所涉及的相关内容来源于debug亲自录制的实战课程:缓存中间件Redis技术入门与应用场景实战(SpringBoot2.x + 抢红包系统设计与实战),感兴趣的小伙伴可以点击自行前往学习(毕竟以视频的形式来掌握技术 会更快!) 文章所属技术专栏:缓存中间件Redis技术入门与实战

摘要:每当我们谈起缓存中间件Redis的应用场景时,我们一般都会根据其数据结构联想到对应的应用场景,有序集合SortedSet也不例外,“排行榜”一直都是与其紧密挂钩、不得不谈的其中一种实战场景!本文我们将继续再谈“游戏充值排行榜”,介绍如何去处理历史已经存在的充值记录 或者 在将充值记录塞入缓存Cache失败时如何开启后续的补偿处理措施!

内容:在上篇文章中,我们已经给各位小伙伴介绍了如何基于Spring Boot2.0 + 缓存Redis的SortedSet以实际的代码实战一种典型的业务场景“游戏充值排行榜”,在文中我们介绍了这一业务场景两大典型的核心功能模块,即“用户充值”、“获取充值排行榜”,各位小伙伴可以自行前往回顾!

然而,这世间本就没有十全十美之物,“游戏充值排行榜”这一业务场景也不例外,虽然我们基本上已经实现了该业务场景几乎所有的功能模块,但是我们却忽略了其他两种情况:

A.如果“充值排行榜”这一功能模块是增量式的需求,那么上线时如何去处理历史的用户充值记录呢?你总不能说我们的“充值排行榜”对于以往充值的用户记录不生效吧?(那样岂不令人笑掉大牙!)

B.虽然我们的代码看似完美,但是要知道Bug是无处不在的,这些Bug有的是能一眼被洞穿的,也有的是后知后觉的,“用户充值的过程”便是如此,如果用户充值后插入数据库DB成功、但是插入缓存Cache失败(DB事务不回滚的前提),那毫无疑问,最终得出来的“充值排行榜”一定是不准确的(因为我们是直接从缓存Redis中获取的)

带着这两大问题,我们给大家提供了一种并非十全十美的,但是却能保证“最终一致性”的充值排行榜的解决方案,那就是万能的定时任务调度

既然是定时任务调度,那么这个定时任务是做啥的呢?没错,它要完成的任务就是开启一个定时时钟,基于数据库DB中的“用户充值记录表”,借助数据库提供的Order By、Group By等查询得出目前为止所有有效用户的“充值排行榜”,下面我们以实际的代码进行实战。

(1)直接建立一个定时任务调度类PhoneFareScheduler,并开发相应的方法实现具体的定时任务逻辑,其完整源代码如下所示:

/**补偿机制:手机号码充值排行榜
 * @Author:debug (SteadyJack)
 * @Link: weixin-> debug0868 qq-> 1948831260**/
@Component
public class PhoneFareScheduler {
    private static final Logger log= LoggerFactory.getLogger(PhoneFareScheduler.class);

    @Autowired
    private PhoneFareMapper phoneFareMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    //时间频度设定为30min,当然啦,具体的设定要根据实际情况而定
    @Scheduled(cron = "0 0/30 * * * ?")
    public void sortFareScheduler(){
        log.info("--补偿性手机号码充值排行榜-定时任务");

        this.cacheSortResult();
    }

    @Async("threadPoolTaskExecutor")
    private void cacheSortResult(){
        try {
            ZSetOperations<String,FareDto> zSetOperations=redisTemplate.opsForZSet();

            List<PhoneFare> list=phoneFareMapper.getAllSortFares();
            if (list!=null && !list.isEmpty()){
                redisTemplate.delete(Constant.RedisSortedSetKey2);

                list.forEach(fare -> {
                    FareDto dto=new FareDto(fare.getPhone());
                    zSetOperations.add(Constant.RedisSortedSetKey2,dto,fare.getFare().doubleValue());
                });
            }
        }catch (Exception e){
            log.error("--补偿性手机号码充值排行榜-定时任务-发生异常:",e.fillInStackTrace());
        }
    }
}

值得一提的是,在该定时任务调度中我们设定的时间频率为 每30min进行执行一次任务,实现“充值排行榜”的大洗盘!也就是说,如果前端“排行榜”页面数据出现差错,那么其恢复正确的等待时间是30min(因为我们的定时任务就是前往数据库DB,查询获取得到排行榜,当然啦,其前提是保证DB中的数据是正确无误的!)

(2)其中,phoneFareMapper.getAllSortFares() 的作用就是前往数据库Mysql,通过Group By、Order By和SUM等查询得到排行榜,其完整的动态SQL如下所示:

  <!--基于数据库的补偿排名机制-->
  <select id="getAllSortFares" resultType="com.boot.debug.redis.model.entity.PhoneFare">
    SELECT
        phone,
        SUM(fare) AS fare
    FROM
        phone_fare
    GROUP BY
        phone
    ORDER BY
        fare DESC
  </select>

除此之外,@Async("threadPoolTaskExecutor") 的作用便是采用“线程池-多线程的方式异步执行定时任务”,故而我们需要作一个全局的Config,用于配置线程池-多线程的相关信息:  

/**线程池-多线程配置
 * @Author:debug (SteadyJack)
 * @Link: weixin-> debug0868 qq-> 1948831260**/
public class ThreadConfig {
    @Bean("threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(4);
        executor.setMaxPoolSize(8);
        executor.setKeepAliveSeconds(10);
        executor.setQueueCapacity(8);

        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

至此,我们已经撸完了“游戏充值排行榜”这一完整业务的“补偿机制”功能代码了,在测试之前,我们先“偷偷”在数据库表phone_fare中新增几条充值记录,代表“以前存在的历史充值记录”或者“插入DB成功,但插入缓存失败的充值记录”,如下图所示:

最后我们基于Postman测试一波吧,下面一张图足以说明一切了:

好了,本篇文章我们就介绍到这里了,建议各位小伙伴一定要照着文章提供的样例代码撸一撸,只有撸过才能知道这玩意是咋用的,否则就成了“空谈者”!

对Redis相关技术栈以及实际应用场景实战感兴趣的小伙伴可以前往debug搭建的技术社区的课程中心进行学习观看:程序员实战基地 !其他相关的技术,感兴趣的小伙伴可以关注底部debug的技术公众号,一起学习、共同成长!

补充:

1、本文涉及到的相关的源代码可以到此地址,check出来进行查看学习:https://gitee.com/steadyjack/SpringBootRedis

2、目前debug已将本文所涉及的内容整理录制成视频教程,感兴趣的小伙伴可以前往观看学习:https://edu.csdn.net/course/detail/26619

3、关注一下debug的技术微信公众号,最新的技术文章、课程以及技术专栏将会第一时间在公众号发布哦!

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u013871100/article/details/104307110
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 17:52:18
  • 阅读 ( 1427 )
  • 分类:Redis

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢