之前不停听说redis,但一直很好奇不知道是什么。借着这篇文章,简单的了解一下。希望能说明白以下三个问题:
1. redis是什么?
2. redis有什么优点?优点从何而来?
3. redis的一些问题
一、redis是什么?
第一句话redis是数据库
Redis全称是Remote Dictionary Server,远程数据服务,是一种内存高速缓存数据库,维持key-value结构,是一个用C语言编写的开源数据库,目前最新的版本是7.0。开源代码在:https://github.com/redis/redis
redis在数据库分类中属于NoSql数据库,下面简单介绍下NoSql
NoSql(no only SQL)数据库,泛指非关系型数据库。第一个想到的问题应该是既然有了SQL为什么还会有NoSql的存在呢?
NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。相比于结构型的SQL,非关系型存储的数据是半结构化的,这就意味着计算机在读入内存中有更少的规则,读入速度更快。不过这个也不是说非结构化就更好,非结构型和结构型数据库各有优点,数据结构越完整读写的速度越慢,但是提供的功能越强大。
相比于SQL数据库来说,Redis 数据库没有“表”的概念,它是通过不同的数据类型来实现存储数据的需求,不同的数据类型能够适应不同的应用场景,从而满足开发者的需求。上面说redis维持了key-value的结构,但也有限制,理论上 Redis 的每个 key、value 的大小不超过 512 MB
redis的地位可不低,是目前最流行的一种NoSql数据库。既然是数据库其实就是存储数据用的,那为何redis能收到各方面的青睐呢?这就是下面要介绍的内容呀!
redis官网:https://redis.io/
二、redis有什么优点?
这部分的内容阐述方式,是先介绍redis的优点,然后围绕每条优点来详细介绍redis的实现,分析如何提供功能的。
redis的优点总结起来:
1.速度快
2.持久性
3.redis有丰富的数据结构,应用场景多
4.安全性高
1.为什么速度快?
1)基于内存做操作
速度快可以说是redis最重要的一个特点,传统的数据库都是把数据存储在磁盘中,每次操作从磁盘上读写数据。众所周知,磁盘IO是非常慢的,而redis以内存为存储介质,而不是磁盘,读写效率很高。redis会把数据直接写在内存中,但定期会向磁盘进行更新。不过对于使用者来说就是操作内存
2)单进程单线程
redis的实现使用了单进程单线程,这样在处理的时候没有进程/线程切换的上下文开销(累计起来是一笔可观的时间),因为只有一个线程,更不会发生死锁这种极端耗时好资源的情况。不过这里指的单线程指的是网络请求的单线程,用一个线程处理网络连接。在其他方面也会有线程做操作。
3)使用非阻塞的多路复用IO模型
redis本身还是CS的结构,客户端的网络请求以socket的形式发过来,可能有多个客户端连接请求。但redis处理网络请求的只有一个线程,这里就是用IO多路复用
ps:对IO多路复用做个简单介绍,正常处理多个连接需要多个进程/线程分别处理,但多个进程/线程在切换时由上下文开销。IO多路复用就是用把不同请求放到队列里,然后由单个进程去处理,减少开销。
在redis中IO多路复用底层实现基于select,poll这种IO多路复用方法实现的。
4)主从配置
主从配置就是定期会将数据库的内容复制到一个从节点上,这样的话,可以实现读写分离。同时进行数据的读取和更新,从节点仅提供读操作,主节点提供写操作。对于读多写少的状况,可给主节点配置多个从节点,从而提高响应效率。只要最后节点间进行数据一致性保持就可以。读写分离比那种同时间只读只写的情况可快了太多。
2.为什么持久?
从上面了解到redis是基于内存存储结构的,内存是DRAM,每次关机就是刷新内容,那它是怎么保持持久性的呢?
其实redis的存储分为内存存储、磁盘存储和log文件三部分,重启后,虽然内存里的数据没有,但Redis可以从磁盘重新将数据加载到内存中,这些可以通过配置文件对其进行配置,正因为这样,Redis才能实现持久化。但另一个问题就来了:是咋把数据写到磁盘里的?为了防止发生数据丢失,有一个内置的持久性模块,它会在给定的情况下将内存状态写入磁盘上的转储文件,转储文件在系统启动时加载,一旦启动并运行,数据就可用于操作,所以,没有数据丢失。这个持久化模块和redis的持久化策略有关,redis有两种策略:
1)RBD策略(默认策略)
RDB策略就是快照,可以理解成备份。快照会把内存中的数据保存到一个 dump.rdb 的文件中,这个文件在磁盘上。快照保存一般是定时的,不过每当有大的修改时就会快照保存。工作原理简单说一下:当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程会负责将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write。
2)AOF策略
AOF不像RDB那样去直接存储数据,AOF会把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,是命令的集合。在重启的时候进行一次命令回放,然后就可以恢复到之前的状态。
两个策略相比而言,当 Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。不过AOF也有缺点,它的文件体积很大,回放时间也长、初始化的时间可能会更长些。不过两种方式都保证了数据的正确持久存储。
3.丰富的数据结构,应用场景多
redis底层支持的五种数据类型:String,Hash,List,Set,ZSet。基于五种数据类型又有多种数据结构。因为其支持多种数据结构,应用场景丰富,也被称为数据结构数据库。
虽然只有5种数据类型,但是有两大好处:一方面五种类型已经可以满足存储各种数据结构体的需要;另外一方面数据类型少,使得规则就少,需要的判断和逻辑就少,这样读/写的速度就更快。这也是快的一个原因。
下面对五种数据类型进行下简单介绍吧(把一切的数据都当成字符串,这是一种数据库的设计思想):
(1)String :key是字符串,value是数字、字符串,或者jpg 图片或者序列化的对象。String 类型的值最大能存储 512M。
(2)Hash是一个键值的集合。Redis 的 Hash 是一个 String 的 Key 和 Value 的映射表,Hash 特别适合存储对象。
(3)List 列表是简单的字符串列表,按照插入顺序排序。支持左右添加元素。还提供了操作某一段的 API,可以直接查询或者删除某一段的元素。底层双向链表实现。
(4)Set 是 String 类型的无序集合。集合是通过 hashtable 实现的。Set 中的元素是没有顺序的,而且是没有重复的。作用:自动去重,判断是否在列表中。从Key-value角度看,所有value都是NULL。
(5)Zset 和 Set 一样是 String 类型元素的集合,且不允许重复的元素。和 Set 相比,Zset提供了排序功能,实现的原理是关联了一个 Double 类型权重的参数 Score,使得集合中的元素能够按照 Score 进行有序排列,Redis 正是通过score值来为集合中的成员进行从小到大的排序。适用于需要有序且不重复时可以使用。底层实现上Redis Sorted Set 的内部使用 HashMap 和跳跃表(skipList)来保证数据的存储和有序,HashMap 里放的是成员到 Score 的映射。而跳跃表里存放的是所有的成员,排序依据是 HashMap 里存的 Score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。
应用场景当然有很多啦,但其实我没用过,理解的也不是很深刻,简单做下记录:
1.缓存,临时存储
2.消息队列
3.计数
参考:Redis 16 个常见使用场景_Young丶的博客-CSDN博客_redis使用场景
4.安全性高:
安全性其实是数据库应该保障的首要因素,毕竟希望读取的是正确的数据,否则再快也没用,redis执行所有操作都是原子操作,不会有乱序执行造成的结果差异化,这样就可以保证安全性,这也对高并发场景有天然的优势。
还有一点就是主从配置,通过配置从节点备份。保证当主节点即使损坏时数据安全性也有保障(单点故障问题)。主从配置一般需要结合哨兵模式。那为什么需要哨兵呢?
主从配置情况下,主节点挂掉以后要选择一个从节点成为新的主节点。要对外修改很多东西,通知系统中各节点新的主节点信息。这个过程需要人工参与,为了避免人工,引入哨兵。哨兵会监控主节点状态,在主节点挂掉时,自动选择从节点成为新主节点然后在系统中广播信息,代替人工操作过程.
哨兵有具体的实现原理(简单说):有很多个哨兵,哨兵会定期ping一下各节点,各节点接受信息后返回。如果哨兵没收到主节点的返回值(主观下线),就会告诉别的哨兵去ping它,如果达到一定数量没有回复(客观下线),就选取新主节点
基本就是下面这个原理图:
图源:Redis是什么-电子发烧友网 (elecfans.com)
当然Redis支持主从模式,可以配置集群,这样更利于支撑起大型的项目,这也是Redis的一大亮点
那redis这么好,是不是就没有什么问题呢?当然也不是,下面介绍下redis常见的几个问题:
三、redis的常见问题
Redis常见问题1:雪崩
概念:在高并发下,缓存层无法处理请求,所有的请求会涌向存储层,短时间内的高并发请求可能会导致存储层挂机,称之为“Redis雪崩”。
原因1:缓存中大量数据同时过期
原因2:缓存层死机了
解决方案:随机设置失效时间,避免大面积失效情况发生/用集群,这个缓存坏了能换一个
Redis常见问题2:缓存穿透
概念:多次访问那些redis里没有,数据库也没有的数据。导致数据库搜索压力过大,因为redis没有,所以无法拦截,直接穿透到数据库而得名
解决方法:对情况进行识别,然后拦截
Redis常见问题3:缓存击穿
概念:热点数据一直在被高并发访问,突然失效了,大量请求直接给到数据库,数据库崩了
解决方法:设置热点数据永久不失效
参考:Redis的雪崩,击穿,穿透详解_童先森的blog的博客-CSDN博客_redis击穿
还有一个问题就是redis是基于内存的,众所周知内存相比磁盘来说空间很少,那满了怎么办,找个时候就需要淘汰策略。
redis有六种淘汰策略:
1)noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
2)allkeys-lru:从所有key中使用LRU算法进行淘汰(LRU算法:即最近最少使用算法)
3)volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
4)allkeys-random:从所有key中随机淘汰数据
5)volatile-random:从设置了过期时间的key中随机淘汰
6)volatile-ttl:在设置了过期时间的key中,淘汰过期时间剩余最短的
不过redis也不是万能的,具体情况还是要具体分析,redis毕竟是缓存机制,如果项目对于缓存要求是强一致性,就不要使用redis。选择一个合适的数据库,灵活多变才是真理。
理论学习总是浅尝辄止,还是要使用才能深刻理解原理。
参考资料:Redis是什么-电子发烧友网 (elecfans.com)
因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!