您现在的位置是:网站首页 > 心得笔记

redis中string的常见业务场景(1)

盛悦2025-02-1995人围观
简介本文将介绍不同数据类型下的常见业务场景(缓存+计数器+分布式锁+限流+session存储)

一. string类型


1.数据结构

redis的string数据结构是一种基础的键值对类型。

SET key value - 设置指定key的值。如果key已经存在,这个命令会更新它的值。
SET myKey "myValue"

GET key - 获取与key关联的值。

GET myKey


DEL key - 删除指定的key
DEL myKey

INCR key - 将key中的数值增加1。如果key不存在,它将首先被设置为0。

INCR myKey

DECR key - 将key中的数值减少1。

DECR myKey

2.场景应用

    2.1.缓存功能

    string类型常用于缓存经常要访问的数据,以提高接口响应速度和降低数据库的压力。

    衍生问题redis作为缓存使用时,如何避免数据的不一致性问题

    解决方案1:队列+重试机制

    采用队列和重试机制实现数据库和缓存间数据的最终一致性。

    基本思路:

    1.更新数据库数据
    当应用程序需要对数据进行更新时,首先更新数据库中的数据。
    数据库更新操作完成后,记录该操作的信息,包括操作类型、操作的数据ID等。
    
    2.将操作信息放入消息队列
    将数据库操作信息封装成消息,并放入消息队列中。
    消息队列可以选择高可靠性的消息中间件,如RocketMQ、Kafka等。
    
    3. 异步消费消息并处理缓存
    创建一个异步的消费者服务,从消息队列中读取消息。
    根据消息中的操作类型和数据ID,对缓存进行相应的操作。例如,如果消息是删除操作,则尝试删除缓存中对应的数据。
    可使用supervisor监听。
    
    4. 实现重试机制
    如果缓存操作失败(如删除缓存失败),则将该消息重新放入消息队列中,并设置一个重试次数或重试间隔。
    消费者服务在读取消息时,会检查消息的重试次数或重试间隔,如果未达到限制,则重新尝试对缓存进行操作。
    如果重试多次后仍然失败,则可以将该消息记录到日志中,并通知相关开发人员进行处理。

    解决方案2:基于订阅binlog的异步更新缓存

    通过监听MySQL的binlog日志,异步消费者消费日志并更新到Redis;

    读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
    这样一旦MySQL中产生了新的写入、更新、删除等操作,就可以把binlog相关的消息推送至Redis,
    Redis再根据binlog中的记录,对Redis进行更新。
    这里的消息推送工具可以采用第三方:kafka、rabbitMQ等来实现推送更新Redis。

     

    2.2.计数器

    利用INCRDECR命令,String类型可以作为计数器使用,适用于统计如网页访问量、商品库存数量等 。

    衍生问题:通过redis实现博客的文章浏览次数

    解决方案使用Redis的INCR命令原子性地递增文章的浏览次数,定期将浏览次数同步到数据库,用于历史数据分析。


    2.3.分布式锁

    通过SETNX命令(仅当键不存在时设置值),String类型可以实现分布式锁,保证在分布式系统中的互斥访问 。

    衍生问题在分布式系统中,如电商的秒杀活动或库存管理,如何确保同一时间只有一个进程或线程可以修改共享资源,以避免数据不一致的问题。

    解决方案使用Redis的SETNX命令实现分布式锁的获取和释放,通过Lua脚本确保释放锁时的原子性,并在执行业务逻辑前尝试获取锁,业务逻辑执行完毕后确保释放锁,从而保证在分布式系统中对共享资源的安全访问。

    $lockCacheKey = config('cache.prefix').':agent_batch_apply:'.$agentId;
    //选择数据库
    Redis::select(2);
    $orderLock = Redis::setnx($lockCacheKey, 1);//为1,则表示获取锁成功,为0表示锁已被其他进程持有
    if($orderLock === 0){ //锁失败
        // 防止死锁
        if(Redis::ttl($lockCacheKey) == -1){
            Redis::expire($lockCacheKey, 10);
        }
        throw new CommonException("请勿重复提交!");
    }
    Redis::expire($lockCacheKey, 10);//设置过期时间
    //TODO 业务逻辑


     2.4.限流

    使用EXPIRE命令,结合INCR操作,可以实现API的限流功能,防止系统被过度访问 。

    衍生问题:在高流量期间,接口收到大量并发请求,这可能会导致后端服务压力过大,甚至崩溃,怎么限流

    解决方案:请求计数+设置过期时间+检查请求频率

    1.请求计数:每次API请求时,使用INCR命令对特定的key进行递增操作。
    2.设置过期时间:使用EXPIRE命令为计数key设置一个过期时间,过期时间取决于限流的时间窗口(例如1秒)。
    3.检查请求频率:如果请求计数超过设定的阈值(例如每秒100次),则拒绝新的请求或进行排队


   2.5.共享session

   在多服务器的Web应用中,用户在不同的服务器上请求时能够保持登录状态,实现会话共享。

   衍生问题分布式架构中,如何实现session共享

   解决方案:使用Redis的String类型来集中存储和管理用户session信息。

1.存储session:当用户登录成功后,将用户的唯一标识sessionid和用户信息序列化后存储在redis。
2.验证session:每次用户请求时,通过请求中的session ID从Redis获取session信息,验证用户状态。
3.更新Session:用户活动时,更新Redis中存储的session信息,以保持其活跃状态。
4.过期策略:设置session信息在Redis中的过期时间,当用户长时间不活动时自动使session失效。

 3.注意事项

1.String类型的值可以是任何形式的文本或二进制数据,最大容量为512MB 。
2.在使用String类型作为计数器时,应确保操作的原子性,避免并发访问导致的数据不一致 。
3.使用分布式锁时,要注意锁的释放和超时机制,防止死锁的发生 。
4.存储对象时,应考虑序列化和反序列化的成本,以及数据的压缩和安全性 。
5.在使用String类型作为缓存时,需要合理设置过期时间,以保证数据的时效性 。