设计 | 基于 Redis 谈一谈缓存设计思想

设计 | 基于 Redis 谈一谈缓存设计思想王奇 顾问软件工程师 目前从事 PaaS 中间件服务(Redis/MongoDB/ELK 等)开发工作,对 NoSQL 数据库有深入的研究以及丰富的二次开发经验,热衷对 NoSQL 数据库领域内的最新

设计 | 基于 Redis 谈一谈缓存设计思想

王奇 顾问软件工程师

目前从事 PaaS 中间件服务(Redis/MongoDB/ELK 等)开发工作,对 NoSQL 数据库有深入的研究以及丰富的二次开发经验,热衷对 NoSQL 数据库领域内的最新技术动态的学习,能够把握行业技术发展趋势。

| 前言

前段时间跟同事一起聊到 Redis 的那些坑,不谋而合感触很深。有的时候当业务规模未达到一定瓶颈,很可能发现不了问题,例如下面的这段代码。

public static LotteryPeriod getCurrentAwardNumberPeriod(String gameId) {
    List<LotteryPeriod> periodList = getPeriodsByGameId(gameId);
    if (periodList == null) {
        return null;
    }
    Timestamp now = DateUtil.getCurrentTimestamp();
    LotteryPeriod lotteryPeriod = null;
    for (LotteryPeriod period : periodList) {
        if (period.getEndTime().before(now) && period.getAwardTime().before(now)) {
          if (LotteryAwardCache.getLotteryAward(gameId, period.getPeriod(), false) != null) {
             lotteryPeriod = period;
             break;
          }
        }
    }
    return lotteryPeriod;
}

这是一个关于期次类的一个业务,这么写乍眼看没什么问题,但由于业务类型增加,时间一久代码量超过了 3000+,接近 20 个getXXPeriod(String),Java 运行后加载了几万个 Period 实例。

| 改进思路

  • Timestamp –> Long
  • startTime, endTime….betDeadline 迭代比较 –> Timeline
  • Cache

| Period 缓存设计思想

file

Period 实体类包含以上私有属性和构造方法,系统所有有关期次的时间计算均围绕 startTime、endTime、saleStartTime、saleEndTime、awardTime、openTime 这些属性。

如果将所有期次对象按照期次顺序缓存起来,后续的计算也不方便。同时效率也是需要考虑的,如果每次用户读取某些特殊需求的期次,例如获取当前销售期次,每次都需要循环处理并判断销售开始时间、结束时间与当前时间的关系。最后,Timestamp 的比较在 Redis 缓存里面不能直接计算,这样导致很多计算需要将数据传输到本地后再进行,计算的算法效率也不一定有 Redis 高。

基于上述几点考虑做以下设计:将每一个时间维度按照 Redis 缓存的 SortedSet 结构保存,Timestamp 转化为 Long 作为 SortedSet 的 score 存储,member 则为 periodId;为了提高用户访问效率,将每个特定需求的期次信息直接使用 Redis 缓存 String 结构保存,即将对象转化为字节数组保存;为保证这些数据时效性,设置合理的过期时间并且定时刷新这些数据。

file

一级缓存

总计有五种时间轴(TimelineEnum 枚举类)—— START_TIME、END_TIME、SALE_START_TIME、SALE_END_TIME、OPEN_TIME。

每种时间轴使用 SortedSet 结构保存,初始化的时候载入最新一定数量的期次,一般是未来 N 天以及过去 M 天,这里的数量主要保证追号功能和最近开奖号码功能显示正常即可。时间轴对应的时间属性转化为 Long 后作为 SortedSet 的 score,periodId 则为 member,这样每条时间轴均按照对应时间属性从小到大排序,获取满足小于或者大于某个时间点的期次列表使用 Redis 命令即可方便获取。

file

系统提供periodRedisService.refreshTimeline(gameId)按照指定彩种刷新所有的 Timeline,提供periodRedisService.rebuildTimeline(gameId)按照指定彩种重建所有的 Timeline,此方法会先删除所有 Timeline 的 Key 再刷新。

二级缓存

总计有以下系统需要访问对象(PeriodEnum 枚举类)—— CURRENT_PERIOD、CURRENT_PERIODS、TODAY_PERIODS、CURRENT_SALE_PERIOD、NEXT_SALE_PERIOD、LAST_10AWARD_PERIOD、FUTURE_3DAY_PERIOD、LAST_OPEN_PERIOD、RECENT_3PERIODS、LAST_100AWARD_PERIOD。

每种对象使用 String 结构保存,定时刷新这些已经过期的缓存。系统提供 periodRedisService.refreshPeriodInfo(gameId) 按照指定彩种刷新所有的这些缓存信息,提供 periodRedisService.refreshExpirePeriodInfo(gameId) 按照指定彩种刷新所有的 Key。

| 改善后

@Override
public List<GamePeriod> getCurrentPeriods(Long gameId) {
    String key = RedisConstant.getPeriodDetailKey(gameId, RedisConstant.CURRENT_PERIOD);
    List<GamePeriod> list = redisService.hessian2Get(key);
    if (GameCache.getGame(gameId).getGameType() != Game.GAME_TYPE_TRADITIONAL) {
        list = resetRedisTimeline(gameId, RedisConstant.CURRENT_PERIOD, list);
    }
    return (list == null || list.isEmpty()) ? null : list;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5904.html

(0)
上一篇 2023-04-21
下一篇 2023-04-21

相关推荐

  • Python字符串格式化:让输出更加美观优雅

    Python字符串格式化:让输出更加美观优雅Python中的字符串格式化是一种非常强大的工具,它可以将字符串中的变量替换为具体的值,并且可以格式化输出,使得输出的结果更加美观和优雅。本文将从多个方面对Python字符串格式化进行介绍和阐述。

    2024-01-01
    122
  • 提高Python代码效率的利器,CDW Returns详解

    提高Python代码效率的利器,CDW Returns详解Python作为一门高级编程语言,通常用于快速开发。但是随着数据量的增大和程序的复杂度增加,Python代码的效率常常会成为程序性能提升的瓶颈。因此,在编写Python代码时,需要使用一些工具来提高代码效率。

    2024-01-07
    107
  • mysql新手入门_MySQL数据库教程

    mysql新手入门_MySQL数据库教程前面写了几篇前序学习,可以去先了解看看噢!! 此篇为续篇之终四,话不多说,上货!! MySQL 一. 约束与策略 1.主键自增策略 通常情况下,主键基本都是id。 Id赋值: 随机32位字符串:va…

    2023-02-18
    149
  • MySQL数据库菜鸟教程(一)

    MySQL数据库菜鸟教程(一)1、MySQL安装?Windows系统:(解压文件)下载地址:https://dev.mysql.com/downloads/file/?id=496745?解压后进入文件夹,找到bin文件下两个可…

    2023-03-31
    164
  • innodb_buffer_pool_instances_MySQL datediff

    innodb_buffer_pool_instances_MySQL datediff今天日志出现异常,一步一步debug发现SQL语句返回值出错,进一步发现是max()函数返回出错。点击跳转解决办法,赶时间的朋友可以去获得答案。当然我还是希望大伙看看原由。 select max(HT

    2023-05-24
    159
  • python esb_elasticsearch 教程

    python esb_elasticsearch 教程python elasticsearch_dsl模块 在整理elasticsearch_dsl模块过程中,着实让我头大。 个人感觉就是资料太少而且很乱,不成体系,接口很多,没有规范。 此文凑合着看,以

    2023-04-18
    160
  • mysql双机热备和负载均衡_数据库 读写分离

    mysql双机热备和负载均衡_数据库 读写分离全部的readHost与stand by writeHost参与select语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且M1与 M2互为主备),正常情况下,M2,S1,…

    2023-03-24
    141
  • 用Python创建NumPy数组,进一步进行数据分析和处理

    用Python创建NumPy数组,进一步进行数据分析和处理在Python中,NumPy是一个重要的科学计算库,主要用于处理大型多维数组和矩阵运算。它基于C语言开发,可以提供高效的数据处理能力,并且可以与其他的科学计算库(如SciPy、pandas等)相互配合,实现更加强大的数据分析和处理能力。

    2024-02-08
    96

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注