问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Redis是什么?架构是怎么样的?

创作时间:
作者:
@小白创作中心

Redis是什么?架构是怎么样的?

引用
CSDN
1.
https://m.blog.csdn.net/tangjieqing/article/details/144593101

Redis是一种高性能的远程字典服务,通过缓存机制有效解决了数据库查询压力问题。本文将通过一个具体场景,逐步介绍Redis的核心特性和工作原理。

假设有一个商品服务,它需要对外提供每秒1万次查询,但背后的MySQL数据库却只能提供每秒5000次查询。这种情况下,MySQL很容易被压垮。

这类大流量查询场景非常常见,比如双十一秒杀和春节抢车票。那么,有没有办法在不压垮MySQL的情况下,让商品服务支持每秒1万次查询呢?

本地缓存

我们知道,查询内存的速度比查询磁盘要快得多。如果能在商品服务的内存中申请一个字典(在Python中叫dict,在Java中叫map),将商品ID作为key,商品数据作为value,那么通过商品ID就能快速查到商品数据。

发生查询时,优先去查内存字典,如果没有结果再跑到MySQL数据库里查询,并将结果顺手放内存字典里,下次就能直接从内存里查出来。

像这样,放在服务内部的缓存,就是所谓的本地缓存。有了本地缓存的加持,真正打到MySQL的查询量就会大大减少。

远程缓存

但是,如果商品服务有多个实例,每个实例都重复缓存一份本地内存,就会有些浪费。因此,更好的解决方案是将这部分字典内存抽出来,单独做成一个服务,这就是所谓的远程缓存服务。

但是,多个商品服务通过网络去读写同一份远程缓存,会存在并发问题。为了解决这个问题,可以对外不管有多少个网络连接,收到读写命令后,都统一塞到一个线程上,在一个线程上对字典进行读写,这样并发问题和线程切换开销就完全不存在了。

多种数据类型支持

现在缓存服务里,只有一个字典类型。key和value都是字符串。但是,我们平时写代码的时候,还会用到很多其他内存里的数据结构,比如先进先出的队列(List)、用于去重的Set类型、可以做排行榜的ZSet等。因此,对字段的value进行扩展,支持这些数据结构,可以让缓存服务更强大。

内存过期策略

缓存服务支持的数据结构变多了之后,塞到内存里的数据就越来越多了,内存又小又贵,迟早扛不住。怎么办呢?可以给缓存里的数据加个过期时间,一旦数据过期,就从内存里删掉,可以很大程度缓解掉内存增长速度。

但是,不能指望每个调用方都是老实人,如果都不设置过期时间,那内存还是得炸。有解法吗?有!在内存接近上限的时候,根据一些策略删除掉一些内存。比如可以将最近最少使用的内存删掉,也就是所谓的LRU,这样不仅解决了内存过大的问题,还让redis里的数据全是热点数据。真是一箭双雕。

持久化

现在内存过大的问题是解决了。但还有个问题,mysql之所以过得那么舒服,那是因为前面有个缓存服务挡住了大部分流量。一旦缓存服务重启,那内存就全丢了,这时候流量会全都打到mysql身上,疼得它嗷嗷叫。所以我们还需要给redis加入最大程度的持久化保证。确保服务重启后不至于什么数据都没有。

于是可以在缓存服务里加个异步线程,定期将全量内存数据定期持久化到磁盘文件里,而这种将内存数据生成快照保存到文件的方式,就是所谓的RDB,Redis Database Backup。它可以每隔几分钟记录下缓存服务的全量数据,类似于游戏的"存档"。

这样就算进程挂了,重启的时候,通过加载快照文件,就能复原大部分数据。之所以说是大部分,是因为"存档"之后写入的数据可能会丢。那还有其他方式可以保留更多数据吗?有!全量数据备份当然耗时,那我们化整为零,在每次写入数据时,顺手将数据记录到文件缓存中,并每秒将文件缓存刷入磁盘,这种持久化机制叫AOF,Append Only File,服务启动时跟着文件重新执行一遍就能将大部分数据还原,最大程度保证了数据持久化。那问题就来了,AOF文件会不会很大?没事,定期重写压缩就行,比如a被依次赋值a=1,a=2,最终保留a=2就够了。

简化网络协议

刚刚提到远程缓存服务对外提供读写能力,那是对外提供的HTTP接口吗?当然不是!我们知道,HTTP是基于TCP做的通信,实现了很多笨重的特性。既然当初是为了性能,特地上的缓存服务,那就索性彻底点,抛弃HTTP,直接基于TCP做传输就好!传输协议也设计得简单点,比如只要通过TCP传入SET key value,就能完成写入。传入"GET key"就能获得对应的value。非常简洁。

那传输协议的解析需要我们自己写代码去实现吗?完全不需要,redis官方提供了一个命令行工具,redis-cli,通过它,我们可以输入一些命令,读写Redis服务器里的各种内存数据。不想用命令行也没关系,各路大神已经用各种语言将redis-cli支持的命令实现了一遍,完全不需要自己手写。

Redis是什么?

好了,到这里,当初那个简陋的远程缓存服务,就成了一个高性能,支持多种数据类型和各种缓存淘汰策略,并提供一定持久化能力的超强缓存服务,没错,它就是我们常说的Redis,全称Remote Dictionary Server,这名字就很精辟了,说白了redis就是一个远程的字典服务。

redis作为架构中最常用的提速神器,是万金油一般的存在,将它放在mysql面前挡一道查询只是最基础的用法。通过扩展插件,还能实现各种高阶玩法。比如RedisJSON支持复杂的JSON查询和更新,说白了就是内存版本的MongoDB。RediSearch支持全文搜索,说白了就是内存丐版的es。RedisGraph支持图数据库功能,类似Neo4j,RedisTimeSeries处理时间序列数据,也就是内存版InfluxDB。大有一种要在内存里将所有中间件都实现一遍的味道。

现在大家通了吗?

总结

  • Redis本质上就是一个远程字典服务,所有读写命令等核心逻辑,都在一个线程上完成。什么并发问题和线程切换开销,完全不存在!
  • Redis支持多种数据类型、内存过期策略和多种缓存失效策略,通过TCP对外提供了一套非常简单的传输协议。
  • Redis加入了最大程度的持久化保证。将数据持久化为rdb和AOF,确保服务重启后不至于什么数据都没有。
  • Redis支持多种扩展,玩法非常多,比如RediSearch和RedisJSON。

最后遗留一个问题,Redis到目前为止就是一个单机服务,高性能是有了,但高可用和可扩展性是一点没看到。这就需要聊聊主从、哨兵和集群模式了,如果大家感兴趣,下期我们聊聊这个话题。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号