一、Redis简介

Redis是开源的、高性能的key-value数据库。

Redis数据类型包括:String、Hash、List、Set、Zset、Bitmap、Geospatial、HyperLogLog、Stream。

Bitmaps是Redis2.2.0版本新增的,即位图,是一串连续的二进制数组(0和1),可以通过偏移量(offset)定位元素。表示某个元素的值或者状态,时间复杂度为O(1)。由于bit是计算机中最小的单位,使用它进行存储将非常节省空间,特别适合一些数据量大且使用二值统计的场景。它的底层是基于String类型实现的。应用场景例如签到打卡,每一个用户一天的签到用一个bit位就能表示,一个月的签到情况用31个bit位,一年用366个bit位,不用复杂的集合类型就可以。

HyperLogLog是Redis在2.8.9版本添加的,用来做基数统计算法的数据结构。如统计网站的UV(Unique Vister-独立访客)。HLL是从Loglog算法派生的概率算法,用于确定非常大的集合的基数,而不需要存储其所有值。当然有小于0.81%的误差,但是对于UV统计来说可以忽略。简单来说,HyperLogLog提供不精确的去重计数。

GEO是Redis在3.2版本新增的,地理位置定位(底层使用zset实现),用于存储地理位置信息(经度、维度、名称),并对存储的信息进行操作。

Stream是5.0版本新增的数据类型,Redis专门为消息队列设计的数据类型。支持消息持久化、支持自动生成全局唯一ID、支持ack确认消息模式、支持消费组模式等,让消息队列更加稳定和可靠。

二、Redis快的原因

1、基于内存的实现。

Redis 是基于内存的一个数据库,内存读写速度非常快,数据存放在内存中,响应时间大约是100纳秒,这是Redis 每秒万亿级别访问的重要基础。

2、合理的线程模型。

2.1、Redis 是单线程。

避免CPU不必要的上下文切换和竞争锁的消耗。当然缺点就是如果某个命令执行时间过长(例如hgetall),会造成阻塞。Redis 是面向快速执行场景的数据库,所以要慎用smembers和lrange、hgetall等命令。

Redis 6.0引入多线程提速,不过它的执行命令操作内存仍然是个单线程。

2.2、I/O多路复用。

Redis使用epoll机制。

3、合理的数据编程。Redis支持多种数据类型。

String:若存储数字,使用int类型编码;若存储非数字,小于等于39字节的字符串使用embstr;大于39字节的用raw编码。

List:若列表的元素个数小于512个,列表每个元素的值都小于64字节(默认),使用ziplist编码,否则使用linkedlist编码。

Hash:哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable编码。

Set:如集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码。

Zset:当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码。

4、高效的数据结构。

SDS简单动态字符串、哈希、跳跃表skiplist、压缩列表ziplist。

5、虚拟内存机制。

Redis直接自己构建VM机制。暂时把不经常放的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其他需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中,冷数据保存到磁盘中。

三、Redis优缺点

3.1、优点:

1、性能高。读速度是110000次/s,写速度是81000次/s。

2、原子性。所有操作都是原子性,且支持对多个操作合并后的原子执行。

3、丰富的数据类型。

4、丰富的特性。支持publish/subscribe、通知、key过期等等特性。

3.2、缺点:

1、受物理内存限制。可以通过集群模式弥补。

2、存在数据一致性问题。存在主从一致问题、缓存数据库一致性问题。解决主从一致性问题,可以使用分布式锁,Redisson提供multiLock方案解决主从一致性问题。解决缓存数据库一致性问题,可以在每次写操作时,更新缓存中数据。

3、在线扩容困难。Redis在集群容量达到上线时,在线扩容变得非常复杂,这限制了其他大规模数据处理场景的应用。

4、存在缓存穿透、击穿和雪崩问题。解决方案包括,使用布隆过滤器来预防缓存穿透、使用分布式锁来处理缓存击穿、错开缓存失效时间以避免缓存雪崩。

5、缺乏自动容错和恢复功能。增加哨兵自动恢复故障。

6、数据类型限制。Redis数据类型相对有限,不支持所有的数据类型,可能限制某些场景下的应用。

四、应用实例

我在网上找了一篇个人觉得很不错的博文,访问地址如下:【Redis从头学-13】Redis哨兵模式解析以及搭建指南_redis搭建哨兵模式-CSDN博客

五、pipeline和lua脚本

1、pipeline(管道)。

批量处理数据。一次性返回所有结果集,对这个结果集进行批量处理,考验处理结果集的能力。一个pipeline的命令集被redis服务器执行的时候,有可能redis服务器会执行其他客户端传来的redis命令。一些异常情况尽可能发生,所以说使用pipeline一般会做一些异常捕获和处理。因此事实上管道不具有原子性。管道更适用于管道中的命令之间没有关系,不需要事务的原子性,但需要提高程序响应速度的场景。

pipeline通过减少客户端与redis的通信次数来实现降低往返延时时间,而且pipeline实现的原理是队列,队列原理是先进先出,这样可以保证数据的顺序性。

通俗来讲,pipeline就是把一组命令打包,然后一次性通过网络发送到redis,同时将执行的结果批量返回。

2、lua脚本。

lua脚本会将多个命令和操作当成一个命令在redis中执行,即执行该脚本期间,不会被其他命令或者脚本打断。因此lua脚本具有原子性,可以替代multi和exec的事务功能。当然,也正因如此,不宜在lua脚本中进行过大开销操作,避免影响后续其他请求的正常执行。因此lua脚本适合于相对简单的事务场景。

lua脚本的好处如下:1) lua脚本作为一个整体执行,中间不会被打断,具有原子性。2)可以把多条命令一次性打包,可以减少网络开销。3)lua脚本可以常驻redis内存,使用时可以直接拿来复用,减少代码量。

六、Redis持久化方案及优缺点。

1、aof。

对每条写入命令进行日志记录。

优点:数据可靠,丢失较少;持久化过程代价较低。

缺点:aof文件过大,数据恢复慢。

2、rdb。

将某一时刻的内存快照,以二进制的方式写入磁盘。

优点:rdb文件小,数据恢复快。

缺点:数据丢失较多,持久化过程代价较高。

3、混合持久化。

rdb文件小加载快但丢失多,aof文件大加载慢但丢失少。混合持久化是吸收rdb和aof两者优点的一种持久化方案。aof-rewrite的时候实际持久化的内容是rdb,等持久化后,持久化期间修改的数据以aof的形式附加到文件的尾部。混合持久化实际上是在aof-rewrite基础上进行优化,所以需要先开启aof-rewrite。

七、高可用性方案

1、主从复制。可实现高并发(读),典型部署方案为一主二从。

2、哨兵模式。可实现高可用,典型部署方案为一主二从三哨兵。

3、cluster集群。可同时支持高可用(读和写)、高并发,典型部署方案为三主三从。

redis高可用方案对比
redis主从复制 redis哨兵 redis集群
主要目的 数据备份与读写分离 高可用性和故障自动切换 高并发和数据分散处理
架构 一个主节点和多个从节点 监控主从结构并自动切换 多个主节点,数据分片
数据复制 主节点到从节点 监控并管理主从复制 每个主节点管理自己的数据集
故障转移机制 手动或哨兵自动切换 自动故障转移 自动处理节点故障
可伸缩性 有限,依赖主节点 为主从结构增加高可用性 高,因为数据分布式处理
使用场景 数据备份和读扩展 关键应用的高可用性 大规模应用的高性能需求
设置复杂度 相对简单 中等,需要配置哨兵 复杂,需要规划数据分区

八、Redis数据淘汰策略

1、no-enviction。

永不回收的策略。当内存达到限制时返回错误,并且客户端尝试执行使用更多内存的命令。

2、allkeys-lru。

尝试从数据集(server.db[i].dict)中回收最近最少使用的数据,使得新添加的数据有空间存放。

3、volatile-lru。

从已设置过期时间的数据集(server.db[i].expires)中回收最近最少使用的数据。

4、allkeys-random。

从数据集(server.db[i].dict)中随机回收数据。

5、volatile-random。

从已设置过期时间的数据集(server.db[i].expires)中随机回收数据。

6、volatile-ttl。

从已设置过期时间的数据集(server.db[i].expires)中回收将要过期的数据。

九、注意事项

1、脑裂。

当某个主节点所在的机器突然脱离正常网络,不能与其他的从节点连接,但实际上主节点还在运行,这时候哨兵就会认为主节点宕机了,然后开启选举,将其他从节点推举为新节点,这时集群中会出现两个主机。

2、多哨兵模式下的下线。

主观下线(sdown),sentinel发现Redis节点未在规定时间(down-after-milliseconds)内做出响应,则认为该节点主观下线。适用于所有节点。

客观下线(odown),sentinel监控的master节点发生故障时,哨兵至今通过is-master-down-by-adddr命令相互交流,并进行投票,当超过一定票数(quorum)的sentinel都认为master下线,则为客观下线。只适应主节点。

3、IO多路复用的三种机制。

select:使用轮询方式,每次调用select时,都需要遍历所有的文件描述符,检查其状态是否就绪。有固定大小的文件描述符集合,有限制,通常默认为1024。select使用fd_set数据结构来存放文件描述符集合。

poll:select的改进方式。解决select文件描述符数量限制问题。poll使用了一个保存文件描述符和事件的数据结构。并且每次调用时只需要遍历就绪的文件描述符,这样效率比select高一些。但是当文件描述符数量较大时,仍然需要遍历整个文件描述符集合。

epoll:epoll使用内核事件回调机制,当有事件就绪时,内核会直接将就绪的事件通知给用户空间,避免了每次都遍历所有的文件描述符。

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐