V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
bushenx
V2EX  ›  问与答

如果要给 Mysql 设计缓存

  •  
  •   bushenx · 2021-08-15 00:25:07 +08:00 · 1602 次点击
    这是一个创建于 1195 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景

    假设需要给 Mysql 设计一套缓存机制缓存中间件采用 Redis,让查询操作先经过缓存,在缓存没有的情况下再去查表。

    问题

    Redis 缓存中应该如何存储 Mysql 的数据呢?

    问题描述

    如果采用 Redis 的 hash 结构存储 Mysql 的一条数据,将 Mysql 的 DbName-TableName 作为 Redis Hash 的 Key,那么 field 应该使用什么呢? field 使用表的 主键 ,查询语句中带有主键的查询可以查找到这条缓存,如果查询语句中 没有主键 那应该如何处理?或者这种思路是不对的什么成熟的方案可以借鉴吗?

    15 条回复    2021-08-16 10:29:33 +08:00
    yitingbai
        1
    yitingbai  
       2021-08-15 00:36:41 +08:00
    Mysql 自身就有缓存, 另外常用的 ORM 框架也带有缓存策略配合 redis 啥的, 自己实现还是很难的, 需要面面俱到, 比如你缓存了一个 sql, 记录变动你要更新缓存. 如果想学习可以去研究 orm 库的源码, 如果只是想用在项目中, 就别重复造轮子了
    sutra
        2
    sutra  
       2021-08-15 00:39:47 +08:00
    有现成的,比如 spring-data-redis 里的 RedisCache.
    sutra
        3
    sutra  
       2021-08-15 00:42:31 +08:00
    RedisCache 的默认实现方法是 cacheName::key 作为 key,序列化(可以自定义序列化和反序列化对,比如改为使用 json 格式序列化)后的数据作为 value 。不过需要注意的是,大多实现,都存在双写一致性问题。
    sutra
        4
    sutra  
       2021-08-15 00:56:05 +08:00 via iPhone
    顺便做个广告吧,刚写完的一个使用 Redis sorted set 来存储的 spring cache 实现,可以避免双写一致性问题。https://oxerr.org/spring-cache-redis-scored/zh/index.html
    sutra
        5
    sutra  
       2021-08-15 01:07:12 +08:00
    另外,从业务角度来讲,一般缓存的数据,不是直接的数据库查询的结果,而是经过一些计算后的更偏向于业务的结果。
    sutra
        6
    sutra  
       2021-08-15 01:09:43 +08:00
    关于双写一致性问题,我收藏了几篇文章:

    Cache-Aside pattern
    https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside

    分布式之数据库和缓存双写一致性方案解析
    https://www.cnblogs.com/rjzheng/p/9041659.html

    Consistency between Redis Cache and SQL Database
    https://yunpengn.github.io/blog/2019/05/04/consistent-redis-sql/
    815979670
        7
    815979670  
       2021-08-15 02:35:52 +08:00
    看具体场景把,我们这里有一个缓存思路就是
    1 把查询的 sql 转换成 md5 然后 当成 key value 是 mysql 的查询结果,
    2 如果有 key 就直接返回 value,如果没有就去数据库查询数据 然后缓存进 redis
    3 最后给缓存的数据设置一个过期时间 我们当时给的是 5 分钟
    levelworm
        8
    levelworm  
       2021-08-15 02:52:14 +08:00 via Android
    直接把常用的查询缓存在 redis 内部,保存比如三十天的量,如何?我觉得还是看什么用的最多吧,比如说查询 dau 用的最多,就直接把两个月的 dau 扔进去,每天更新一次就行了。
    vindurriel
        9
    vindurriel  
       2021-08-15 10:38:34 +08:00 via iPhone
    我觉得中间件不适合做这个 大部分读写场景不需要 少部分需要的差异又很多 key 格式 空值行为 过期时间都是变量 省不了多少事
    bushenx
        10
    bushenx  
    OP
       2021-08-15 11:03:47 +08:00 via Android
    @sutra 学习了
    bushenx
        11
    bushenx  
    OP
       2021-08-15 11:07:30 +08:00 via Android
    @yitingbai 我现在学习的是 Go 语言,Go 还是可以造很多轮子的,哈哈。
    bushenx
        12
    bushenx  
    OP
       2021-08-15 11:43:41 +08:00 via Android
    @815979670 sql 哈希这想法属实不错
    @levelworm 老铁你这法子有啥现成工具吗?
    WIN2333
        13
    WIN2333  
       2021-08-15 11:49:32 +08:00
    mysql 有自己的缓存,orm 也有,大部分情况下内存缓存就够了,具体问题具体分析,你这个太广了不适合都这么干,最后瓶颈会落在网络交互,以及 redis 的性能尤其是 redis 还是单线程处理的,缓存是应该是多级设计的
    levelworm
        14
    levelworm  
       2021-08-15 21:12:15 +08:00 via Android
    @bushenx 没。。。我也就是一说,多半自己写了
    cyrivlclth
        15
    cyrivlclth  
       2021-08-16 10:29:33 +08:00
    @yitingbai mysql8.0 还有缓存吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5425 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 03:32 · PVG 11:32 · LAX 19:32 · JFK 22:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.