逻辑过期策略+异步更新机制提高接口的高可用性的实践

后端爬虫爬取数据缓存至Redis中,前端通过查询接口展现爬取数据。考虑到高并发场景下可能会导致多个客户端连接的多个线程在Redis中的数据过期时同时执行数据爬取逻辑重构缓存于Redis当中由于Redis是单线程的写操作与读操作是互斥的所以会导致接口响应时间过长并且数据爬取逻辑被多个线程冗余执行多次完全是没必要的(数据过期时只需要一个线程执行数据爬取逻辑更新缓存即可)。

目标:优化接口响应速度,解决多线程同时更新缓存的问题,提升用户体验。

行动:采用逻辑过期+异步更新策略

代码:

新闻查询接口    

@Override
    public List<Object> getNewList() {
        //获取当前时间戳
        long currentTime = System.currentTimeMillis();
        //获取缓存中的新闻数据逻辑过期时间戳
        Long baiduNewsExpires = RedisUtil.getExpiresFromRedis("BaiduNewsExpires");
        //获取缓存中的新闻数据 key为新闻标签+逻辑过期时间戳
        List<Object> NewList = RedisUtil.getDataFromRedis("BaiduNews"+baiduNewsExpires);
        //现在时间>=设置过期时间说明数据过期
        if (NewList.isEmpty()||currentTime>=baiduNewsExpires ) {
            //线程尝试获取锁获取不到直接返回旧数据
            if(lock.tryLock()){
                try {
                    //异步更新开启一个线程loadRedis 重构缓存数据-新闻
                    new Thread(new LoadNewsToRedisTask(1L)).start();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    //释放锁
                    lock.unlock();
                }
            }
            return NewList;
        }
        return NewList;
    }

 缓存重构线程任务

public void run() {
        //线程尝试获取锁获取到则执行缓存更新逻辑否则线程执行完毕
        //此操作是为了保证只有一个线程执行更新操作防止多个线程同时执行缓存更新操作造成空间浪费
        if(lock.tryLock()){
            try {
                //逻辑过期时间戳转换
                Expires=System.currentTimeMillis()+ (Expires * 60 * 1000);
                //爬虫
                List<Object> NewList = BaiduProcessor.spiderBaidu();
                //缓存更新数据
                RedisUtil.saveDataToRedis(NewList, "BaiduNews"+Expires);
                //逻辑过期数据保存
                RedisUtil.saveDataToRedis(Expires, "BaiduNewsExpires");
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

结果:

将新闻爬取数据缓存至Redis,并采用逻辑过期策略结合异步更新机制,系统接口的高可用性
得到了有效保障。优化后,接口响应速度从679ms大幅提升至17ms,显著提升了系统性能。

对于Redis中的过期数据我们可以使用LRU算法数据淘汰策略来优化缓存空间占用,且它能保证缓存中的数据都是热点数据

逻辑过期策略主要是为了解决 Redis 缓存使用中遇到的一些问题而设计的。当平常使用 Redis 缓存时,会出现这样的场景:Redis 的 key 到过期时间后,总是需要到数据库里面去查一遍数据再 set 回 Redis,若数据库响应比较慢,就会造成用户等待;若并发比较大,还有可能给数据库造成巨大的压力,甚至导致服务不可用 [^5]。 与常见的过期策略不同,逻辑过期策略并非真正删除过期的 key,而是在数据结构里额外存储一个逻辑过期时间字段。当访问这个 key 时,先检查逻辑过期时间,若已过期,就开启一个异步线程去更新缓存数据,同时返回旧数据,这样就避免了直接去数据库查询带来的等待问题和可能出现的高并发压力。这种策略可以保证用户请求的快速响应,提升系统的性能和稳定性。 ```python # 示例代码,模拟逻辑过期策略 import time import threading # 模拟 Redis 缓存 redis_cache = { "key": { "data": "example data", "expire_time": time.time() + 60 # 假设过期时间为 60 秒后 } } def check_and_update(key): global redis_cache current_time = time.time() if current_time > redis_cache[key]["expire_time"]: # 开启异步线程更新缓存 threading.Thread(target=update_cache, args=(key,)).start() return redis_cache[key]["data"] def update_cache(key): global redis_cache # 模拟从数据库获取新数据 new_data = "new example data" new_expire_time = time.time() + 60 redis_cache[key] = { "data": new_data, "expire_time": new_expire_time } # 模拟用户访问 data = check_and_update("key") print(data) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值