写点什么

mysql 与 redis 的选型问题实践

作者:苏格拉格拉
  • 2022-11-28
    浙江
  • 本文字数:2538 字

    阅读完需:约 8 分钟

背景

当前系统当前使用 mysql+redis 的技术架构,现需要对该系统进行重构工作,其中就需要对数据存储技术进行选型。

系统演进路线


系统重构目标


业务场景如下:

  • 该系统为油站价格优惠系统,涉及众多油站(1w+)、商品(92/95/柴油/天然气等)、渠道(端内各渠道/各大 C 共 1k+)维度,涉及价格数量共 1 亿(1wx10x1k)。

  • 优惠策略除各维度价格之外,还存在城市、全国维度等非“单点”策略。

  • 优惠策略存在周期、人群等复杂筛选条件。


具体情况如下:

  • 运营在后台配置优惠策略,数据保存在 mysql 数据库;

  • C 端用户需要获取某一门店商品价格,需要根据条件查询 mysql 数据库,并对查询结果进行匹配过滤;

  • 后因性能问题引入缓存,对各维度查询结果进行缓存;

  • 后又因缓存穿透、性能问题,演变成:C 端不读区数据库只读区缓存,运营配置完成后进行一轮异步刷缓存。


选型需求如下:

  • 以稳定性为主要目标,将系统拆分为配置域与执行域:配置域处理运营配置、数据刷新等复杂不可控的业务;

  • 策略加工后输送到运行域(即 C 端),运行域仅读取加工完的数据,进行简单的计算处理;

  • 现在需要找到一个合适的存储载体来存在这些加工好后的运营策略。系统当前运行状态下,对应的载体应该是 redis,但是作为数据存储载体,其是否合适需要进一步讨论。

分析

当前使用场景的要求

  • 查询场景:查询门店 x 商品 x 渠道维度对应的策略

  • 数据量:门店 x 商品 x 渠道,一共有 1 亿个渠道

  • qps:当前访问峰值需要支持 1wqps

redis 作为存储载体

首先,redis 作为存储载体,是最“平滑”的选择,因为系统的现状,当前位置用的就是 redis。


但是,随着系统进行拆分,以及任务加工逻辑的复杂,继续使用 redis 会面临以下问题:

  • 在执行域系统,redis 将成为唯一数据存储载体,这与 redis 本身作为缓存的定位有些不符;

  • 系统中的数据存储载体正常应该是基于磁盘的数据库,而非基于内存的缓存,虽然 redis 也支持持久化;

另外,redis 的数据查询能力较弱,无法支持 sql 查询,事务支持不完善。因为在当前场景无此要求,所以可以忽略。


当然,使用 redis 也有其优越性:

  • key-value 的结构天然适合当前场景的“定点”查询;

  • redis 基于内存,能够支持高速访问;但同时也让 redis 的成本较高(虽然在企业使用上没有这方面考量);可以水平扩展,所以容易支持大数据量,高 qps。


总结:

  • 从硬性要求考虑,redis 可以满足;

  • 但从功能定位上,把 redis 作为一个数据存储的载体,不怎么合适

mysql 作为存储载体

另外一个方案就是使用回 mysql。

一般来说,从 mysql 转到 redis 都是因为性能问题,对热点 key 进行缓存,以提升访问速度,同时降低数据库的磁盘压力。

而系统当前引入 redis 的初衷,并非是为了热点数据的性能考量,而是因为某些“不得已”的性能瓶颈。所以在 redis 中缓存的并非只是热点数据,而是全盘的 key-value。


关于“不得已”的性能瓶颈:

  • 前面的业务介绍有提到,除了门店-商品-渠道维度,还有类似“城市”、“全国”等全局维度;

  • 系统采取的方案是先查询当前维度的策略,然后再查一次城市维度的策略,最后合并到一起;

  • 随着城市维度的策略增多,数据库的响应时间出现问题,于是就因为“性能”问题引入了 redis。

上面的“优化”手段,其实并没有解决实质问题,只是将 mysql 中的“大数据量”问题换了一种形式存在:redis 中的大 key 问题。

在这之后,我们也掉到了这个坑里面;因为运营配置了较多的城市维度策略,引发了 redis 大 key(1.8M)问题,带来了一个线上故障。这也是这次重构工作的重要背景。

补充一句,在缓存出了问题之后,我们其实还可以将问题再次转移,给系统“续命”:将缓存中的 key 在应用本地再缓存一次。但这样做只会跟上一次“优化”的结果一样,给系统再一次埋下定时炸弹。


回到存储方案选型上来,通过历史我们可以得知:这个系统其实并不一定需要缓存。从线上的监控来看,mysql 的响应速度不比 redis 差太多。

那么,mysql 是否可以在当前场景作为存储方案的产品呢?


优点就不说了,直接看最为关键的两个问题:

  • 响应速度:公司内部使用了 dbproxy 优化,从监控结果上看,性能跟 redis 所差不多;

  • qps:需要添加备库以支撑 qps,当前公司可申请的最大规格无法满足 qps 要求,需要 dba 操作;

  • 数据量:需要进行分库分表,开发/维护成本较高。


总结:

  • 从硬性要求考虑,mysql 可以满足;

  • 但分库分表开发维护成本较高

redis + mysql

先不管是否可能,顺着前面的方案,采取 redis+mysql 方案会怎么样?

  • 首先,redis 的“定位”问题解决,因为有了 mysql 来作为数据存储载体;

  • 然后,因为 redis 的缓存,qps 的问题可能会有一些缓解,但不一定能打包票,还要考虑命中率及缓存可用性的问题;

  • 最后 mysql 的大数据量无法解决,还是需要分库分表。

一个 Redis 与 MySQL 之间的方案

前面我们说 redis 最大的问题是产品定位问题。那么,redis 为什么不适合作为存储载体?或者说,redis 为什么不能作为数据库替代 mysql?

我觉得核心问题是持久化能力。

  • redis 虽有 rdb、aof 两种持久化方式,但其本质是仍一个内存数据库,持久化只是用于辅助内存的读写,宕机仍存在丢失风险;

  • aof 持久化虽然可以做到跟内存同步,但也是以牺牲性能作为代价的。


所以我们要找的应该是可持久化的、方便水平扩展的数据库产品。


刚好内部自研的 fusion 可以满足这个要求:

  • 其定位介于 Redis 与 MySQL 之间,是一款基于 rocksdb 的主存储数据库,又实现了 redis 协议;

  • 部署在 ssd 之上,上层自带 cache 缓存;

  • 可支持水平扩展;

  • 内部有团队支持。


总结

数据结构:门店 x 商品 x 渠道

mysql:b+树索引组合查询可以支持,另外支持 sql 丰富的查询统计

redis:k-v 结构可以支持


qps:1wqps

mysql:需要添加备库以支撑 qps,当前公司可申请的最大规格无法满足 qps 要求,需要 dba 操作。redis:可以水平扩展


数据量

mysql:需要进行分库分表,开发/维护成本较高

redis:可以水平扩展


rt

mysql:公司内部使用了 dbproxy 优化,从监控结果上看,性能跟 redis 所差不多

redis:基于内存,快速


定位

mysql:基于磁盘,适合数据存储

redis:基于内存(有持久化做辅助),适合做缓存


结论

因为功能定位问题,不用 redis;

使用类似 mysql 的基于磁盘的数据产品,但需要解决 mysql 的两个问题;

使用 fusion,产品定位介于 mysql、redis 之间,是数据存储载体,又可以支持大数据量水平扩展、支持高 qps。

参考

redis 是否可以代替 mysql 进行数据存储?怎么样? https://www.ucloud.cn/yun/ask/77842.html

fusion https://www.dandelioncloud.cn/article/details/1496098463225057281


发布于: 刚刚阅读数: 5
用户头像

八股文难,难于上青天,看了后面忘了前面 2018-08-22 加入

https://github.com/wengyingjian

评论

发布
暂无评论
mysql与redis的选型问题实践_MySQL_苏格拉格拉_InfoQ写作社区