数据使用Redis缓存还是类变量缓存分析

业务场景

        业务方提出一个根据配置规则进行调查问卷信息推送的业务,有点类似QQ弹出的游戏调查问卷,问卷配置内容包括当日最大提醒次数、回答后不再提醒天数等一些配置参数信息。配置包括临时规则、默认规则。每天的订单数据平均有40W,实际符合规则的会在10W左右。数据会存在高峰期,大致为早上、晚上、凌晨三个时间段。

需求分析

   配置读取

        1. 首先从数据量来看,当一次订单数据进来时,系统不能每次都去查数据库得到配置信息,然后去过滤当前订单是否满足推送规则。因此需要走缓存处理。

        2.  说到缓存,大多数人第一反应是Redis,但因为配置可能会动态调整,因此缓存不能永久不变,设置多久过期时间也是一个问题,那么Redis这时候真的符合业务要求吗。答案是不符合的,不管设置多久的过期时间都不会满足临时规则的添加,可能会有疑惑是我设置当新增时候就把Redis缓存清空不就行了,但是这个业务特殊地方就是配置和推送服务并不在一块,这也很好理解,配置是属于对内基础业务,推送服务是属于对外业务。

        3. 不用Redis缓存,那怎么解决又想要缓存,这时能考虑的解决方案就是使用类变量去存储配置数据,加上定时刷新机制确保数据一致。

  提醒数据信息

        1. 当日提交数据这个可以利用Redis缓存去处理用户的提交数据信息,

        2. 多少天内间隔,这个可以存入Redis数据,过期时间和配置中设置的间隔时间一致,只是Redis的存储的数据个数会比较多,但因为存的都是数值信息,且有过期时间并不会导致数据累加。也可以通过类变量去保存数据信息,但是考虑到数据库的日增长量,读取数据库的压力会越来越大,因此使用Redis缓存作为提醒数据信息缓存。

    高峰期问题 

           因数据存在高峰期时间,因此配置数据和业务方约定好尽量提前设置好配置,同时用户提交的数据可以通过队列或者多线程异步处理,保证接口及时响应,因问卷信息并不影响实际业务,只是做统计使用,可以在提交中不设置事务以及防重复校验,重复提交校验可以放数据库层去校验,比如加上唯一索引

需求场景实现

   配置读取

          1. 定时器实现

@Slf4j
@Component
public class MemberManager {

    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);

    @Autowired
    private MemberServiceManager memberServiceManager;

    /**
     * 使用@PostConstruct注解,确保Servlet实例化后就已经把数据加载完了
     */
    @PostConstruct
    public void loadMember() {
        //设置定时执行间隔,这个假设是加载数据一
        scheduledExecutorService.schedule(this::loadVipMember, 50, TimeUnit.MILLISECONDS);
        //这里假设加载数据二
        scheduledExecutorService.schedule(this::loadNormalMember, 50, TimeUnit.MILLISECONDS);
    }

    /**
     * 加载VIP会员数据,这里是临时写的一个接口,理解一下就行
     */
    private void loadVipMember(){
        IMemberService memberService = memberServiceManager.getMemberService(MemberLevelServiceConstants.VIP_MEMBER);
        memberService.loadMemberInfo();
    }

    /**
     * 加载普通会员数据
     */
    private void loadNormalMember(){
        IMemberService memberService = memberServiceManager.getMemberService(MemberLevelServiceConstants.NORMAL_MEMBER);
        memberService.loadMemberInfo();
    }

}

2. 加载数据Service实现,Service实现是通过策略模式,因不同的规则对应的加载数据可能不一样

@Slf4j
@Component
public class MemberServiceManager {

    @Autowired
    private Map<String, IMemberService> handleMap;


    public IMemberService getMemberService(String name) {
       return handleMap.get(name);
    }

}

public class MemberLevelServiceConstants {

    public static final String REGISTER_MEMBER = "registerMemberService";

    public static final String NORMAL_MEMBER = "normalMemberService";

    public static final String VIP_MEMBER = "vipMemberService";

}
@Slf4j
@Service(MemberLevelServiceConstants.VIP_MEMBER)
public class MemberVipServiceImpl implements IMemberService {

    private List<String> memberList = new ArrayList<>();

    @Override
    public void loadMemberInfo() {
        System.out.println("当前Service" + MemberLevelEnum.VIP.getName());
        memberList.add("VIP会员:张三");
    }


    @Override
    public List<String> getMemberInfo() {
        return memberList;
    }
}

3. 测试实际效果

总结

        缓存并不一定就得使用Redis,Redis并不是一定适合全部的业务场景,使用Redis还需要保证数据库和缓存的一致性,在分布式系统下,这个会增加系统的代码复杂度,使用类变量缓存,只需要保证服务读取的数据库是一致的,服务可以通过多数据源来控制所需要的数据库,使用Redis还有一个问题是如果规则结构类型发生改变,Redis的数据存储可能不支持这个结构类型,Redis理解应该只是作为一个旁路缓存使用。当然使用类变量去存数据,还有一个问题就是数据的刷新时间如何控制,这里需要结合实际的业务去设置,因此当一个实际业务到了手上时,不应该理所当然的去分析,而应结合实际场景分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Redis 缓存数据可以在某些场景下提高应用程序的性能和响应速度。以下是使用 FastAPI 和 Redis 进行缓存的基本步骤: 1. 安装 Redis 客户端库 ``` pip install aioredis ``` 2. 在应用程序中引入 Redis 客户端 ```python import aioredis redis = await aioredis.create_redis_pool('redis://localhost') ``` 3. 在需要缓存数据的地方将数据储到 Redis 中 ```python await redis.set('key', 'value', expire=60) # 设置过期时间为60秒 ``` 4. 在需要获取数据的地方从 Redis 中获取数据 ```python value = await redis.get('key') ``` 完整的示例代码如下: ```python import aioredis from fastapi import FastAPI app = FastAPI() redis = None @app.on_event("startup") async def startup_event(): global redis redis = await aioredis.create_redis_pool('redis://localhost') @app.on_event("shutdown") async def shutdown_event(): redis.close() await redis.wait_closed() @app.get("/") async def read_root(): value = await redis.get('key') if value is None: value = "Hello, Redis!" await redis.set('key', value, expire=60) return {"message": value} ``` 在这个示例中,我们创建了一个名为 `redis` 的全局变量使用 `aioredis` 库来创建 Redis 连接池,并在应用程序启动事件中初始化它。在应用程序关闭事件中我们关闭 Redis 连接池并等待连接关闭。 在根路径的 GET 请求中,我们首先从 Redis 中获取 `key` 对应的值。如果值不在,则设置默认值并将其储到 Redis 中。然后返回结果作为响应。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值