redis数据库(既然redis那么快,为什么不用它做主数据库?)

redis数据库(既然redis那么快,为什么不用它做主数据库?)
既然redis那么快,为什么不用它做主数据库?

这个问题得从Redis的诞生说起。

Redis的作者antirez,当年在做一个实时网站流量分析工具。这个工具需要为每个被追踪的网站维护一份访客列表,不断地往里写、不断地往外读,每秒钟几千次。MySQL扛不住这个频率,每次读写都要访问磁盘,延迟太高。antirez觉得这类数据放内存里处理才是正道,于是用C语言写了一个基于内存的键值存储,这就是Redis的原型。

所以Redis从出生的第一天起,解决的就是一个特定问题:把频繁读写的热数据放在内存里,快速存取。它不是冲着替代MySQL去的。

Redis项目有一份官方宣言,里面写到:

the main goal of the project remains the development of an in-memory database.

项目的核心目标,是做一个内存数据库。antirez自己在博客里也说过:Redis is different than other database solutions because it uses memory as main storage. It is not the right pick for big data exceeding RAM.

理解了这个定位,再来看为什么Redis不适合当主数据库,就很清楚了。

内存成本

这是最现实的问题。

一个中等规模的业务系统,数据库里几百G数据很正常。如果用MySQL,一台配了1T SSD的服务器就能装下,成本可控。换成Redis,这几百G数据要全部放进内存,一台256G内存的服务器大概要十几万,还装不下,得上好几台。

内存的单位价格大约是SSD的10到20倍。这还没算Redis集群的副本开销,主从架构下内存用量直接翻倍。

用Redis存几G的热数据,成本合理;用它存几百G的全量业务数据,纯粹烧钱。 大多数公司的技术预算不允许这么做,成本太高了。

持久化的天然缺陷

Redis提供了两种持久化方式:RDB快照和AOF日志。看起来数据能落盘,但仔细看就知道跟MySQL的持久化保障不在一个量级。

RDB是定时快照,默认配置是3600秒内有1次写操作、300秒内有100次写操作、或60秒内有10000次写操作才触发。两次快照之间如果宕机,这段时间的数据全丢。antirez自己在博客里写得很直白:

Redis snapshotting does NOT provide good durability guarantees if up to a few minutes of data loss is not acceptable.

AOF好一些,默认每秒刷盘一次(appendfsync everysec),最多丢1秒的数据。Redis配置文件里还提到一个更隐蔽的风险:当后台在做AOF重写或RDB快照时,如果开启了no-appendfsync-on-rewrite,主进程会暂停fsync,这时候宕机最多可能丢30秒的数据。配置文件原文是这么写的:

This means that while another child is saving, the durability of Redis is the same as “appendfsync no”. In practical terms, this means that it is possible to lose up to 30 seconds of log in the worst scenario (with the default Linux settings).

那把AOF设成always,每次写都刷盘行不行?可以,但性能会大幅下降,Redis最大的优势就没了。

对比MySQL,开启innodb_flush_log_at_trx_commit=1和sync_binlog=1,每个事务提交时redo log和binlog都同步刷盘。事务一旦提交成功,数据就一定在磁盘上了。这就是为什么金融系统、订单系统选MySQL或PostgreSQL,不会选Redis做主存储。

没有复杂查询能力

这个限制在实际业务中杀伤力最大。

Redis只能按key取数据。你存了一批用户信息,能按用户ID查,这没问题。但产品经理过来说,帮我查一下上个月下单超过3次、且累计金额超过1000元的用户有哪些,Redis做不了。没有SQL,没有JOIN,没有WHERE条件过滤,没有GROUP BY聚合。

MySQL里一条SQL就搞定的事,Redis需要你在写入数据的时候就提前想好所有查询模式,用不同的数据结构(有序集合、哈希、集合)把数据冗余存好。业务需求一变,查询条件一改,之前的数据结构就不好使了,得重新设计、重新灌数据。

redis数据库(既然redis那么快,为什么不用它做主数据库?)

业务系统的查询需求是动态的、多变的,而Redis的数据访问模式是写入时就固定死的。 这两者天然矛盾。

事务和数据关系

Redis的MULTI/EXEC看起来像事务,但跟关系型数据库的事务差距很大。最关键的一点:Redis没有回滚机制。一组命令提交后,如果中间某条执行出错,前面已经执行成功的命令不会撤销。在转账这种场景下,A账户扣款成功、B账户加款失败,数据就不一致了,Redis不管这事。

关系型数据库里理所当然的外键约束、级联删除、参照完整性,Redis一概没有。用户被删了,他关联的订单、收货地址、购物车数据是不是也要清理?在MySQL里用外键约束就能保证,在Redis里只能靠应用代码一个一个去处理,漏删一个就是脏数据。

当表之间的关系变得复杂,这种靠应用层维护数据一致性的方式,出错的概率会越来越高。

小结

Redis不适合当大多数业务系统的主数据库,不是因为它不够好,而是它从设计之初就不是为了这个场景而生的。antirez创造Redis是为了解决内存级别的高速读写问题,项目的核心目标是做一个内存数据库。拿它当缓存、当会话存储、当排行榜、当消息队列,都是把它用在了擅长的地方。拿它当主数据库,是在让它干一件它没打算干的事,内存成本扛不住,持久化保障不够硬,查询能力撑不起业务需求,事务和数据关系也管不了。选型的本质不是哪个更好,而是哪个更适合。

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有