Redis概念
1.架构
1.1 内存操作
1.2 底层数据结构
底层数据结构一共有6种,分别是,简单动态字符串,双向链表,压缩列表,哈希表,跳表和整数数组

1.3 非阻塞I/O多路复用
单个线程高效处理多个连接请求,尽量减少网络 IO 的时间消耗
1.4 单线程
多线程在执行过程中需要进行 CPU 的上下文切换,redis基于内存,CPU不是瓶颈。
很多个模块组成,如网络请求模块、索引模块、存储模块、高可用集群支撑模块、数据操作模块等。
Redis中只有网络请求模块和数据操作模块是单线程的,而其他的如持久化存储模块、集群支撑模块等是多线程的。
Reids6之后,网络请求模块改成多线程
2.集群
1.twemproxy,大概概念是,它类似于一个代理方式,使用方法和普通Redis无任何区别,设置好它下属的多个Redis实例后,使用时在本需要连接Redis的地方改为连接twemproxy,它会以一个代理的身份接收请求并使用一致性hash算法,将请求转接到具体Redis,将结果再返回twemproxy.使用方式简便(相对Redis只需修改连接端口),对旧项目扩展的首选。
问题: twemproxy自身单端口实例的压力,使用一致性hash后,对Redis节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。
2. codis, 目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新hash节点。
3. Redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。
4.在业务代码层实现,起几个毫无关联的Redis实例,在代码层,对key进行hash计算,然后去对应的Redis实例操作数据。这种方式对hash层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。
3.持久化
3.1 RDB

Redis DataBase,RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb.通过配置文件中的save参数来定义快照的周期。
优点:
- 只有一个文件dump.rdb,方便持久化。
- 容灾性好,一个文件可以保存到安全的磁盘。
- 性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是10最大化。使用单独子进程来进行持久化,主进程不会进行任何10操作,保证了redis的高性能
- 相对于数据集大时,比AOF的启动效率更高。
缺点:
1.数据安全性低。RDB 是间隔段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
3.2 AOF

Append only fle,特久化方式:是指所有的命令行记录以redis命令请求协议的格式完全持久化存储保存为aof文件。将Redis执行的每次写命令记录到单独的日志文件中。当重启Redis会重新将持久化的日志中文件恢复数据。当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复
优点:
- 数据安全,aof持久化可以配置appendfsyno属性,有always,每进行一次命令操作就记录到aof文件中一次。
- 通过append模式写文件,即使中途服务器宕机,可以通过redis-check-aof工具解决数据一致性问题。
- AOF机制的rewrite模式。AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall)
缺点: - AOF文件比RDB文件大,且恢复速度慢。
- 数据集大的时候,比rdb启动效率低。
俩种持久化的优缺点是什么 - AOF文件比RDB更新频率高,优先使用AOF还原数据。AOF比RDB更安全也更大
- RDB性能比AOF好
- 如果两个都配了优先加载AOF
3.3 选择
- 一般来说,如果想达到足以媲美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。在这种情况下,当Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF
文件保存的数据集要比RDB文件保存的数据集要完整。 - 如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用RDB持久化。
- 有很多用户都只使用AOF持久化,但并不推荐这种方式,因为定时生成RDB快照(snapshot)非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使
用RDB还可以避免AOF程序的bug. - 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
3.4 扩容
- 如果Redis被当做缓存使用, 使用一致性哈希实现动态扩容缩容。
- 如果Redis被当做一个持久化存储使用,必须使用固定的keys-to-nodes映射关系, 节点的数量一旦确定不能变化。否则的话(即Redis节点需要动态变化的情况),必须使用可以在运行时进行数据
再平衡的一套系统,而当前只有Redis集群可以做到这样。
4.redis的过期策略以及内存淘汰机制
Redis可以对存储在Redis中的缓存数据设置过期时间。
比如我们获取的短信验证码一般十分钟过期,我们这时候就需要在验证码存进Redis时添加一个key的过期时间
但是这里有一个需要格外注意的问题就是:并非key过期时间到了就一定会被Redis给删除。
4.1 定时删除
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;
但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
4.2 定期删除
Redis默认是每隔100ms就随机抽取一些设置了过期时间的Key,检查其是否过期,如果过期就删除。
为什么是随机抽取而不是检查所有key?因为你如果设置的key成千上万,每100毫秒都将所有存在的key检查一遍,会给CPU带来比较大的压力。
4.3 惰性删除
定期删除由于是随机抽取可能会导致很多过期Key到了过期时间并没有被删除。
所以用户在从缓存获取数据的时候,redis会检查这个key是否过期了,如果过期就删除这个key。这时候就会在查询的时候将过期key从缓存中清除。
4.4.内存淘汰机制
仅仅使用定期删除+惰性删除机制还是会留下一个严重的隐患:
如果定期删除留下了很多已经过期的key,而且用户长时间都没有使用过这些过期key,导致过期key无法被惰性删除,从而导致过期key一直堆积在内存里
最终造成Redis内存块被消耗殆尽。
那这个问题如何解决呢?这个时候Redis内存淘汰机制应运而生了。Redis内存淘汰机制提供了6种数据淘汰策略:
仅仅使用定期删除+惰性删除机制还是会留下一个严重的隐患:如果定期删除留下了很多已经过期的key,而且
用户长时间都没有使用过这些过期key,导致过期key无法被惰性删除,从而导致过期key- -直堆积在内存里,最终
造成Redis内存块被消耗殆尽。那这个问题如何解决呢?这个时候Redis内存淘汰机制应运而生了。Redis内存淘汰
机制提供了6种数据淘汰策略:
- volatile-lru: 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰。
- volatile-tt1: 从已设置过期时间的数据集中挑选将要过期的数据淘汰。
- volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
- allkeys-lru: 当内存不足以容纳新写入数据时移除最近最少使用的key。
- allkeys-random:从数据集中任意选择数据淘汰。
- noenviction (默认) :当内存不足以容纳新写入数据时,新写入操作会报错
4.5 过期时间和永久有效分别设置
expire和persist命令。
4.6 过期的数据怎么处理
除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
- 定时去清理过期的缓存;
- 当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
5.线程模型
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file eventhandler)
它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。
因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。
文件事件处理器使用IO多路复用(multiplexing) 程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
被监听的套接字准备好执行连接应答(accept) 、读取(read) 、写入(write) 、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用IO多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与redis服务器中其他同样以单线程方式运行的模块进行对接,这保持了Redis 内部单线程设计的简单性。
6.事务
1.不支持回滚 失败继续执行剩下的
2.一个命令错误 所有命令都不执行
3.运行错误,正确命令执行
- MULTI 开启事务,返回ok,命令被放入队列
- EXEC 执行所有事务块的命令,返回所有命令的返回值
- DISCARD 清空事务队列,放弃执行事务
- WATCH 为Redis事务提供check-and-set行为,监控多个键,一个键被修改删除,之后事务不会执行
7.缓存优化
7.5 缓存更新
缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择),我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:
(1)定时去清理过期的缓存;
(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!
7.6 缓存降级
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。
降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
以参考日志级别设置预案:
(1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
(2)警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,
并发送告警;
(3)错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的
最大阀值,此时可以根据情况自动降级或者人工降级;
(4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。
服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。
8.数据结构
- string
- hash
- set
基于 set 玩儿交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集 - list
- zset

浙公网安备 33010602011771号