Redis
2022-03-11 00:30:39 3 举报
AI智能生成
redis知识体系架构图
作者其他创作
大纲/内容
redis是基于C语言编写的、基于内存的高性能非关系键值对数据库,键支持字符串类型,值支持字符串、列表、集合、散列表、有序集合五种类型。另外,redis也可作为分布式锁、支持事务、持久化、LUA脚本、集群等方案
优点:读写高性能、支持数据持久化、支持事务、数据结构丰富、支持集群处理方案
缺点:基于内存容量限制,只可作为较小数据量的高性能操作和运算;不具备自动容错和恢复功能;较难支持在线扩容
优缺点
1、传统的hashMap、Guava缓存实现的是本地缓存,不支持分布式,生命周期随着JVM销毁而结束,多实例情况下容易出现缓存不一致等问题
2、高性能:直接操作内存,速度快
3、高并发:减少了大部分直接的数据库操作,基于内存的数据使得支持的请求数量更加多
为什么用redis做缓存
1、基于内存操作,存储的数据结构也是键值对,查找的时间复杂度是O(1)
2、单线程,避免了上下文切换和竞争条件,不需要考虑加锁是否锁等同步操作
3、使用IO多路复用,非阻塞IO,内核IO操作不需要彻底完成才返回用户空间,支持同一个线程内同时处理多个IO请求。(扩展:将用户Socket对应的fd注册进epoll,epoll负责监听有哪些消息到达,这样,整个过程就只有select、poll、epoll这些调用的时候才会阻塞,收发客户消息不会阻塞,这就是事件驱动(reactor模式))
4、数据结构简单,对数据的操作也简单
redis快的原因
基础概念
可存储字符串、整数、浮点数;数值型支持自增,常见场景有计数器、验证码等简单的K-V存储
String
无序集合,添加、获取、移除元素,检查元素是否在集合中、求两个集合的交集、并集、差集,随机取元素
set
有序集合,范围取值,去重排序,通过增加scope参数,适用于根据一定的条件进行排序的数据
zset
列表,可从两端压入或弹出元素,可用于消息队列、插入有序的集合
list
无序散列表,一般用于结构化数据存储
hash
数据类型
setnx命令,或官方提供的RedLock分布式锁实现
分布式锁
应用
数据类型与应用
持久化就是将内存数据写入磁盘,防止服务器宕机丢失数据
RDB:Redis DataBase,默认的持久化方式,按照一定的时间将内存的数据以快照的形式存储到硬盘,产生的数据文件为dump.rdb。通过配置文件中的save参数定义快照周期。优点是持久化方便、容灾性好,性能有保证,通过fork子进程的方式完成,主进程继续操作命令。缺点是数据安全性低,持久化周期内发生故障数据会丢失
AOF:Append Only File持久化,表示将Redis每次写命令的记录放入单独的日志文件中,重启redis时会从持久化的日志文件中恢复数据。RDB和AOF都开启时,会选择AOF恢复。优点是数据安全,缺点是文件较大,恢复速度慢
持久化
即时过期:对每个设置过期的key维护一个定时器,到期立即清除。此策略对内存友好,及时性高,但是会占用较大的CPU资源,影响响应时间和吞吐量
惰性过期:只有当访问一个key时才判定是否过期,过期就清除。可节省大量的CPU时间,却对内存非常不友好,甚至不会清除造成大量内存占用
定时过期:每隔一段时间定时扫描过期集合,发现过期就清除。是即时过期和定时过期的折中方案
过期键删除策略
不接受写入,写入报错
移除最近最少使用
随机选择性移除
全局键空间选择性移除
随机移除
移除更早过期时间
带过期时间的键空间选择性移除
内存淘汰策略
内存管理策略
事务是一个单独的隔离操作,事务中所有的命令都会被序列化、顺序执行。事务是一个原子操作,要么全部被执行,要么全部不执行。redis事务的本质是通过multi、exec、watch命令的组合,一次性、顺序性、排他性的执行一个命令队列中的一系列命令
三个阶段:1、事务开始multi;2、命令入队;3、命令执行exec
redis不支持回滚,如果一个事务中出现命令错误,那所有的命令都不会执行;如果一个事务中出现运行错误,那正确的命令会被执行。所以redis内部可保持简单高效
watch命令是一个乐观锁,可提供CAS行为,可以监控一个或多个键,一旦某个键被修改或删除,之后的事务就不会执行,可一直持续到exec命令
discard可清空事务队列,并放弃执行事务;unwatch命令可以取消watch对所有key的监控
redis事务只保证一致性和隔离性
事务
分支主题
哨兵至少需要3个实例保证自己的健壮性,本身也是分布式的,故障转移需要大部分哨兵同意,本身也是涉及到分布式选举的问题。哨兵+redis主从架构,不报账数据0丢失,只能保证redis集群的高可用性
集群监控:负责监控redis主从机器进程是否正常工作
消息通知:报告redis实例故障
故障转移:master节点挂了,自动选举转移到slave节点
配置中心:发生实例故障时,通知客户端新的master地址
功能
哨兵模式
服务端路由查询技术,官方集群方案并没有采用一致性hash方案,而是采用slot(槽)的概念,一共分为16384(16K)个槽,并采用CRC16算法计算散列值,对槽位进行取余,定位到指定的节点。因此,可将请求发送到任意一个节点,redis会转向指令,找到正确的节点
方案过程:通过hash方式进行数据分片,每个节点存储一定的哈希槽区间的数据;2、每个数据分片会存储在多个互为主从的节点上;3、先写主节点,再写从节点;4、读取数据时通过转向指令查找正确节点;5、扩容的时候需要迁移旧数据到新节点
内部通信机制:开放至少两个端口号,读写数据时6379,16379端口就是进行节点间通信的,就是cluster bus。可进行故障检测、故障转移、消息通知、配置中心等授权。cluster采用了gossip二进制协议进行高效数据交换,占用更少的网络带宽额处理时间
优缺点:有点:无中心架构,支持动态扩容,业务员透明,具备自动监控和故障转移能力,客户端只需链接集群中任意一个节点即可,高性能;缺点:只能使用0号数据库,不支持管道命令,运维较为复杂
官方redis-cluster方案
是一种基于哈市算法将redis的key进行散列的方式,通过哈市函数,特点的key会映射到特定的节点,java-redis客户端驱动jedis,支持散列功能。优点是简单,彼此独立,灵活性强;缺点是不支持动态扩展,节点结构发生变化时,每个客户端都需要进行调整
客户端分配
核心是多了一层代理组件,代理解析客户端数据,并进行正确的节点转发。特点是透明,业务解耦,存在一定的性能损耗。常见的业界开源方案有:twtter的twemproxy、豌豆荚的codis
基于代理服务器
集群方案
单机的redis能够承载的业务量都是有限的。为了支撑高并发高可用,需设计主从架构
核心机制:1、主节点写数据,从节点读数据,实现读写分离;2、主节点异步方式复制数据到从节点,或从节点周期性的确认自身复制数据;3、从节点可以链接其它的从节点;4、从节点进行复制的时候,不会阻塞主节点的工作;5、从节点进行数据复制时,不会阻塞数据读取操作,采用原有数据提供服务,复制完成重新加载会阻塞;6、从节点一般用作横向扩容,做读写分离,提升吞吐量
注意点:主节点必须开启持久化机制,防止数据清空;单个redis主从实例不宜过大,建议不超过10G,否则会导致性能下降、恢复慢等问题
主从复制原理
原理描述:1、启动一个从节点时,发送一个PSYNC命令给主节点,初次链接会触发全量复制,主节点fork后台线程,生成RDB文件;2、从节点会先写入本地磁盘,再从本地磁盘加载到内存;3、这个过程中主节点发生的写命令也会发送到从节点;4、若从节点故障断开,只会进行增量复制
redis主从架构原理
1、希望用户可以自定义扩展若干指令来完成一些特定领域的问题。2、用户可以向redis服务器发送lua脚本来执行自定义动作,获取脚本响应数据。3、redis服务器会以单线程原子性的形式执行lua脚本,保证lua脚本在执行过程中不会其它请求打断
使用 eval 指令执行lua脚本,return结果会返回客户端。如果脚本内容很长且执行频繁,每次都要传递冗长的脚本势必浪费网络流量。redis提供了 script load 和 evalsha 指令解决这个问题
script load 指令用于将客户端提供的lua脚本传递到服务器而不执行但得到唯一ID,这个ID是redis使用sha1算法得到的字符串,后序客户端可使用这个ID反复执行执行evalsha函数代码
如果脚本异常或参数错误,redis会保护主线程不会因为错误的脚本而奔溃,但脚本可能会发生部分执行的情况且无法撤销,所以要注意脚本的正确性
主线程不会奔溃的原因:lua脚本内置了pcall(f)函数(protect call),类似于try catch。它会让f函数运行在保护模式下,这个是redis的原码实现的
如果执行了一段死循环lua脚本,需要使用redis提供的script kill 指令来动态的杀死一个执行时间超时的lua脚本。默认这个时间是5秒。script-kill的重要前提是不允许杀死对内部数据进行修改的lua脚本,否则只能使用 shutdown nosave 的方式通过停止整个redis进程来停止脚本运行
script-kill原理:基于钩子函数。redis允许在内部虚拟机执行指令时运行钩子代码。
redis之lua脚本原理
为什么需要分区:拓展利用多台计算机的内存,构建更大的内存数据库;利用多核和多台计算机,扩展计算能力,扩展网络带宽。将key分发到不同的分区,有利于减少单个节点过大的问题
客户端分区:写入数据之前在客户端就决定存储或读取节点
代理分区:通过代理层,对请求进行路由
查询路由:redis-cluster官方实现方式,通过接力模式定位正确节点
分区方式
两个或两个以上的key操作通常不会被支持,比如说对集合求交集、并集,因为它们可能存储在不同的redis实例
不支持事务
运维成本增高,数据处理复杂,主要体现在备份文件的管理上
动态扩容和缩容复杂
分区的缺点
分区
分布式锁:基于redis单线程、队列串行访问模式,且多客户端对redis的链接不存在竞争关系,可以使用redis的setnx轻松实现分布式锁
redLock:redis官方提出的基于redis实现锁的方式,可保证安全、避免死锁、容错性高等特性
分布式
分区与分布式
hash算法(大量缓存重建)
一致性hash算法(自动缓存迁移)+虚拟节点(自动负载均衡)
CRC16算法(基于redis-cluster的hash槽算法)
如何实现扩容(分布式寻址算法)
缓存雪崩:大面积的缓存同一时间大量失效,导致数据库接收到大量请求而奔溃。解决方式:缓存过期时间随机、并发量不高时请求加锁排队、给缓存加上过期标识
缓存击穿:指缓存中没有但数据库中有的数据,由于并发高都往数据库中请求数据,造成数据库压力过大。与缓存雪崩不同的是,缓存击穿是指查的同一条数据。解决方式:互斥锁、热点数据不过期
缓存穿透:缓存和数据库中都没有数据,导致所有请求都落在数据库上,造成数据库短时间内承受大量的请求而奔溃。解决方案:数据正确性校验,如id<0的请求拦截、缓存和数据都取不到的数据值可以设置为null,过期时间10s、采用布隆过滤器方案(扩展:布隆过滤器:采用多个hash算法,计算元素是否存在集合中,如果其中一个hash函数得出的不再集合中,那么肯定不在集合中;所有hash函数都得出在集合中时,认定元素就在集合中。存储结构为固定大小的二进制向量或位图,hash算法得出的结果将位图指定位置置为1,即可判定重复性。https://www.zhihu.com/question/389604738)
缓存异常
通用规则:先删除缓存,再更新数据库(并发情况下还是会存在不一致问题)
升级规则:先删除缓存,再更新数据库,异步等待一段时间再删除缓存
缓存数据库双写一致性
管道技术
大数据插入方案
一般用命令keys,但会导致阻塞,可使用scan命令查找再去重
key查找方案
常见问题
Redis
0 条评论
回复 删除
下一页