• Redis开发规范


    总体要求

    Redis主要用于缓存处理,加快读取效率,但在使用过程中需要注意合理的使用,一般存储全局配置数据和一些访问非常频繁的较为静态的数据,另外注意过期时间控制,减少资源的不必要消耗。

    key名设计

    hpfm:fnd:profile
    
    user:{uid}:friends:messages:{mid} 简化为 u:{uid}:fr:m:{mid}
    

    value设计

    set user:1:name tom
    set user:1:age 19
    set user:1:favor football
    
    1. Redis操作
      建议使用Spring提供的RedisTemplate对象进行操作,项目中进行一定的封装,是操作和使用保持一致的风格,便于后续的维护。

    先操作缓存,还是先操作数据库

    希望保证操作缓存和操作数据库的原子性,要么同时成功,要么同时失败。这演变为一个分布式事务的问题,保证原子性十分困难,很有可能出现一半成功,一半失败。

    1.先操作数据库,再操作缓存

    正常情况下:
    (1) 先操作数据库,成功;
    (2) 再操作缓存(delete或者set),也成功

    如果第一步就失败,可以返回调用方50X,不会出现数据不一致。但如果这两个动作原子性被破坏:第一步成功,第二步失败,会导致,数据库里是新数据,而缓存里是旧数据,业务无法接受。

    2.先操作缓存,再操作数据库;

    正常情况下:
    (1) 先操作缓存(delete或者set),成功;
    (2) 再操作数据库,也成功;

    如果第一步就失败,也可以返回调用方50X,不会出现数据不一致。
    如果原子性被破坏,这里分了两种情况:
    (1) 操作缓存使用set
    第一步成功,第二步失败,会导致,缓存里是set后的数据,数据库里是之前的数据,数据不一致,业务无法接受。
    (2) 操作缓存使用delete
    第一步成功,第二步失败,会导致,缓存里没有数据,数据库里是之前的数据,数据没有不一致,对业务无影响。只是下一次读取,会多一次cache miss。

    3.淘汰缓存和修改缓存中的数据,有什么差别

    建议淘汰(delete)缓存,而不是更新(set)缓存:在两个并发写发生时,由于无法保证时序,此时不管先操作缓存还是先操作数据库,都可能导致数据库与缓存之间的数据不一致。

    4.缓存中的value数据一般是怎么修改的

    因此对于对象类型,或者文本类型,修改缓存value的成本较高,一般选择直接淘汰缓存(delete key)。如果还在纠结,总是淘汰缓存,问题也不大。

    5.总结

    (1) 读请求:先读cache,再读db;如果 cache hit,则直接返回数据;如果 cache miss,则访问db,并将数据set回缓存。
    (2) 更新请求:先删缓存,再操作数据库。
    (3) 如果先操作数据库,再删缓存,因为可能存在删除缓存失败的问题,可以提供一个补偿措施,例如利用消息队列。
    (4) 对于对象类型,或者文本类型,修改缓存value的成本较高,一般选择直接淘汰缓存(delete key)
    (5) 建议淘汰(delete)缓存,而不是更新(set)缓存。
    (6) 一般来说,数据最终以数据库为准,写缓存成功,其实并不算成功。
    (7) 如果对数据有强一致性要求,就不能放缓存。我们所做的一切,只能保证最终一致性。
    (8) 缓存尽量加上失效时间,可以避免永久性的脏数据。
    (9) 缓存失效时间不要一样,可以加上一个随机值,避免集体失效。否则容易导致缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。