如何评估数据适不适合放入Redis中?

95后程序猿小A


当项目中引入了 Redis 做分布式缓存,那么就会面临这样的问题:

  • 哪些数据应该放到缓存中?依据是什么?
  • 缓存数据是采用主动刷新还是过期自动失效?
  • 如果采用过期自动失效,那么失效时间如何制定?

正好这两周我们项目做了相关的评估,把过程记录下来和大家分享分享;当然过程中用到了很多“笨办法”,如果你有更好的办法,也希望能分享给我。


01. 项目背景

我们的项目是一个纯服务平台,也就是只提供接口服务,并没有操作页面的,项目的接口日调用量大约在 200 万次,高峰期也就 1000 万出头,因为大部分接口是面向内部系统的,所以大部分请求集中在工作日的 9 点到 21 点,高峰期的时候系统的 QPS 在 300-400 之间。


因为我们项目数据存储使用的是 MongoDB,理论上支撑这个量级的 QPS 应该是绰绰有余,但是我有这么几点观察和考虑:

MongoDB 中虽然是整合好的数据,但是很多场景也不是单条查询,夸张的时候一个接口可能会返回上百条数据,回参报文就有两万多行(不要问我能不能分页返回......明确告诉你不能);

  • MongoDB 中虽然是整合好的数据,但是很多场景也不是单条查询,夸张的时候一个接口可能会返回上百条数据,回参报文就有两万多行(不要问我能不能分页返回......明确告诉你不能);

  • 目前项目 99.95% 的接口响应时间都在几十到几百毫秒,基本可以满足业务的需要,但是还是有 0.05% 的请求会超过 1s 响应,偶尔甚至会达到 5s、10s;

  • 观察这些响应时间长的请求,大部分时间消耗在查询 MongoDB 上,但是当我将请求报文取出,再次手动调用接口的时候,依然是毫秒级返回;MongoDB 的配置一般,时刻都有数据更新,而且我观察过,响应时间长的这些接口,那个时间点请求量特别大;

  • MongoDB 查询偶尔会慢的原因我我还在确认,我现在能想到的原因比如:大量写操作影响读操作、锁表、内存小于索引大小等等,暂时就认为是当时那一刻 MongoDB 有压力;我观察过,响应时间长的这些接口,那个时间点请求量特别大,这一点就不在这里具体分析了。

虽然一万次的请求只有四五次响应时间异常,但是随着项目接入的请求越来越大,保不齐以后量变产生质变,所以还是尽量将危机扼杀在摇篮里,所以果断上了 Redis 做分布式缓存。


02. 接口梳理

下一步就是对生产环境现有接口进行统计和梳理,确定哪些接口是可以放到缓存中的,所以首先要对每一个接口的调用量有大概的统计,因为没有接入日志平台,所以我采用了最笨的办法,一个一个接口的数嘛。

  • 把工作日某一天全天的日志拉下来,我们四台应用服务器,每天的日志大概 1 个G,还好还好;

  • 通过 EditPlus 这个工具的【在文件中查找】的功能,查询每个接口当天的调用量,已上线 30 个接口,有几分钟就统计出来了,反正是一次性的工作,索性就手动统计了;

  • 一天也调不了几次的接口,就直接忽略掉了,我基本上只把日调用量上万的接口都留下来,进行下一步的分析。


03. 字典表、配置类的数据

这一类的数据是最适合放在缓存中的,因为更新频率特别低,甚至有时候 insert 了之后就再也不做 update ,如果这类数据的调用量比较大,是一定要放到 Redis 中的;

至于缓存策略,可以在更新的时候双写数据库和 Redis,也可以采用自动失效的方式,当然这个失效时间可以放得比较长一些;针对我们项目,我采用的是半夜 12 点统一失效的策略,第一因为我们系统这类数据,是夜间通过 ETL 抽取过来的,每天同步一次,第二就是我们不怕缓存雪崩,没有那么大的访问量,夜间更没有什么访问量了。


04. 明显是热点数据的数据

有一类数据,很明显就是热点数据;

我们就有一个接口,虽然是业务数据,不过数据总量只有几千条,但是每天的调用量大约在 40 万,而且更新频率不是很高,这类数据放入 Redis 中也就再适合不过了;至于缓存策略么,因为数据也是从其他系统同步过来的,根据数据同步的时间,我们最终采用一个小时的失效时间。


05. 其余数据的评估

其实前两种数据很容易就能评估出来,关键是这类数据的评估:

  • 我们有一个接口日调用量 20-30 万,量不大,但是查询和处理逻辑比较复杂;

  • 基础数据量太大,无法把所有数据都放入 Redis 中;

  • 无法把基础数据直接放入 Redis 中,因为有多重查询维度(条件);

  • 无法确定每条数据的调用频率是怎么样的,最悲观的结果,每条数据当天只调用一次,这样就没有缓存的必要了。

但是咱也不能一拍脑袋就说:“调用量挺大的,直接放到 Redis 中吧”,或者“不好评估,算了吧,别放缓存了”,做任何一个决定还是需要有依据的,于是我是这样做的:


Step 1. 把该接口当天的所有日志都找出来

几十个日志文件肯定不能一个一个翻,要么就自己写个程序把需要的数据扒出来,但是考虑到这个工作可能只做一次,我还是尽量节省一些时间吧。

依然使用 EditPlus 这个工具的【在文件中查找】的功能,在查询结果框中【复制所有内容】,花了两分钟,就把 24 万条日志找出来了。


Step 2. 把数据导入到数据库中进行下一步分析

每一条日志大概是这样的:

XXXX.log"(64190,95):2020-3-17 16:44:10.092 http-nio-8080-exec-5 INFO 包名.类名 : 请求参数:args1={"字段1":"XXX\

会点代码的大叔


会话缓存

Redis最明显的用例之一是将其用作会话缓存。与其他会话存储(例如Memcached)相比,使用Redis的优势在于Redis提供了持久性。尽管就一致性而言,维护高速缓存通常不是关键任务,但如果所有购物车会话都消失了,大多数用户将不会完全满意,现在他们会吗?

幸运的是,随着Redis多年来的发展,很容易找到有关如何正确使用Redis进行会话缓存的文档。甚至著名的电子商务平台Magento都有Redis的插件!

全页缓存(FPC)

在基本会话令牌之外,Redis提供了一个非常易于操作的FPC平台。即使在重新启动Redis实例时,也可以恢复一致性,而磁盘持久性不会使用户看到页面加载速度的降低,这是非常麻烦的从类似PHP的本地FPC更改。

再次以Magento为例,Magento提供了一个插件,可将Redis用作全页缓存后端。

同样,对于在那里的WordPress用户,WordPress有一个名为wp-redis的超赞插件,可帮助您实现前所未有的最快页面加载速度!

队列

利用Redis的内存存储引擎来执行列表和设置操作,使其成为用于消息队列的绝佳平台。对于习惯使用Redis进行推入/弹出操作与Python等编程语言中的列表进行交互的人,应该感到与Redis作为队列进行交互。

如果您对“ Redis队列”进行快速的Google搜索,您很快就会发现那里有大量的开源项目,这些项目旨在使Redis成为满足所有排队需求的出色后端实用程序。举例来说,Celery的后端就是使用Redis作为代理。

还有就是Redis的发布/订阅功能。Pub / Sub的用例确实是无限的。我见过人们将其用于社交网络连接,基于Pub / Sub事件触发脚本,甚至使用Redis Pub / Sub构建的聊天系统!

排行榜/计数

由于Redis在内存中,因此它在递增和递减方面做得非常出色。集合和排序集合在尝试执行此类操作时也使我们的生活更轻松,而Redis恰好同时提供了这两种数据结构。因此,要从排序后的集合中抽取前10名用户(我们将其称为“ user_scores”),只需运行以下命令即可:

ZRANGE user_scores 0 10

当然,这是假设您要按增量分数对用户进行排名。如果您想同时返回用户及其分数,则可以运行以下命令:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games有一个使用Ruby的惊人示例,该示例使用了Redis作为其数据存储区的排行榜,可以在此处找到。

像这些都是Redis平常常见的使用场景,如果是在这些场景下,Redis可以很好Hold机器性能并提高它,这时候你就可以选择把数据放入到Redis去,这是一个非常明智的选择。


大魔王Hacker


一个非常好的问题。我是工作多年的Web应用架构师,来回答一下这个问题。欢迎关注我,了解更多IT专业知识。


Redis是一个高性能的key-value数据库,常用于搭建缓存系统,提高并发响应速度。除了用作缓存系统,Redis还可以用在很多业务场景中。


以最近开发的中央厨房订单管理系统为例,在设计订单流转信息模块时,使用了Redis保存当前待处理和待配送的订单信息,流转结束后不需要持久化保存。使用Redis优点如下:

1,支持数据恢复

如果直接将订单流转信息保存到内存,虽然读写效率高,但是有两个问题,一是占用不必要的内存资源,二是当服务重启或者发生故障时,数据不能恢复,需要订单派发系统重新发送订单,显然使用Redis的方案更好。

2,支持集群化扩展

为了支持服务集群化部署,服务不应该包含状态数据。将订单流转信息保存到Redis中后,数据集中存放,多个服务共享Redis存储,而且实现了数据更新时的自动同步。当生产环境中业务量增加时,Redis集群也能方便的扩展。

3,那么使用MySQL呢?

相比MySQL,Redis是一个高性能的NoSQL数据库,读写效率更高,支持高并发响应,简单轻量,部署维护方便,更符合这个应用场景。


一个典型的Web服务数据层往往是MySQL和Redis并存的,MySQL数据库保存持久化信息,Redis保存高频率读写但是需要独立存储的热数据,程序运行过程中的临时数据则直接在内存中。需要平滑高峰期负载时,引入消息队列,比如ActiveMQ。

常见架构示意图如下:


急速马力快de源码客


非常有兴趣回答这个问题。

Redis是目前最为流行的分布式缓存的解决方案,其凭借其出色的性能深受大家的欢迎。虽然Redis自身也提供了发布/订阅相应的功能,不过相对缓存来说,受欢迎程度就不那么高了。接下来,我来回答题主问题,说明样的数据适合放入Redis中(可以延伸到:何种类型的数据适合进行缓存处理)。

一、静态数据

最常见的就是各种参数、字典,这类数据往往在维护后数据量就恒定了,而且在系统运行过程中基本都是查询类型的操作。

在缓存算法方面,因为其数据量比较固定,而且不需要有过期的设定,所以这类数据不需要对其缓存算法(FIFO/LFU/LRU)有过多的要求,存下来就可以了。

在缓存策略方面,通常会选择Cache-Aside作为这类数据的缓存策略,应用有限读取缓存中的数据,如果数据不存在则从数据库中进行读取,读取后同步到缓存当中(在应用程序中通常会通过面向切面的方式来实现)。但是Cache-Aside并不能确保缓存和数据库的一致性(AB线程在查询数据库时数据发生了改变,导致A线程拿到的是a数据,B线程拿到的是b数据,那么很难保证AB线程最后put到缓存中的数据是最后更新的数据)。此外,通常会在应用启动时或提供人工操作的功能进行缓存预热,来防止缓存穿透。

二、临时数据

这一类数据最大的特点是时效性很强,并且不需要进行持久化。我们常见的Session、Token、以及各种验证码等。

在缓存算法方面,没有过多要求(缓存算法基本都是在空间恒定的情况下并且有优先顺序才会讨论的),但是需要考虑Redis分配内存的大小,必要时可以考虑持久化或者限流。

这类数据往往是由应用程序直接对缓存进行操作的。

三、热点数据

缓存热点数据的特征是并发查询非常多,例如商品信息,这类数据是动态变化的。

在缓存算法方面,通常会使用LFU/LRU或一些相关算法作为缓存算法,除了算法本身需要斟酌外,热点数据的定义也是一个非常值得研究的问题。

在缓存策略方面,或许Read-Through是个不错的选择。此外,还需要结合具体情况来制定相应防止缓存异常(穿透、击穿、雪崩)的策略,常见的有缓存预热、分级缓存、限流等等。


以上就是我的一个看法,关于算法和策略的选择上需要结合实际情况进行,但是缓存本身的意义是不变的:

1、减轻数据库压力(读写分离可以分担一些读的压力,但是还是远远不够);

2、临时性存储。

基于此,评估数据是否进行缓存的核心思想以及重要指标就是:在场景中对数据的查询操作对数据库的影响程度。

我是一名程序员,更多内容请关注:空心小窝头

空心小窝头


判断数据是否放入Redis的方法,我说下自己的理解。

Redis的特点是内存存储,所以它主要适合的是独立、速度快、适合频繁访问/修改、常作为快速缓存替代SQL。

什么样的数据适合放入Redis中呢?这里没必要扯什么数据类型、什么业务等等虚的概念。从它的特点中能看出,所有不适合把数据放入SQL数据库、同时又不方便本地缓冲的场景数据,都适合放入Redis中。

因此,如果目标数据既需要高速缓存,又需要独立存在于程序之外:比如防止服务重启(包括且不限于升级、错误、重启)等造成数据丢失,或者多个服务共享此数据,这时就可以放入Redis中。因为Redis的稳定性是可期的,同时网络接口又允许多个服务器同时访问。

因此所有要求使用Redis的场景,都有重要的特征,即高速和独立存储。基于这个需求,创造出来的业务概念即哪些所谓的 热点业务数据、高速数据镜像、共享缓存等等,也就好理解了。

下图就是实际业务中的一种场景,即为了帮SQL抗流量。重复的查询和快速的更新由Redis抗下,而SQL只做持久化。

希望能帮到有类似问题的朋友。朋友们,望不吝赐赞啊!


物联网技术沙龙


高频,原子数据不大,适合redis


分享到:


相關文章: