一、持久化
Redis 的数据 全部存储 在 内存 中,如果 突然宕机,数据就会全部丢失,因此必须有一套机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的 持久化机制,它会将内存中的数据库状态 保存到磁盘 中
创新互联建站长期为上1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为临猗企业提供专业的
做网站、网站建设,
临猗网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。
AOF(Append Only File - 仅追加文件) 它的工作方式非常简单:每次执行 修改内存 中数据集的写操作时,都会 记录 该操作。假设 AOF 日志记录了自 Redis 实例创建以来 所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例 顺序执行所有的指令,也就是 「重放」,来恢复 Redis 当前实例的内存数据结构的状态
执行流程
- 命令追加:将redis的写命令追加到缓冲区aof_buf
- 文件写入和同步:根据策略 将aof_buf种的内容同步到硬盘,appendsync 参数支持always、no、everysec
- 文件重写:定期重写AOF文件,达到压缩的目的
- 手动触发:手动执行bgrewriteaof
- 自动触发:配置参数 auto-aof-rewrite-min-size等等
- 优点
- AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,因为这个模式是只追加的方式,所以没有任何磁盘寻址的开销,所以很快,有点像Mysql中的binlog,当redis重启时再次执行AOF文件中的命令来恢复数据
- 取决于AOF日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据
- 缺点
- 一样的数据,AOF文件比RDB还要大
- AOF开启后,Redis支持写的QPS会比RDB支持写的要低,他不是每秒都要去异步刷新一次日志嘛fsync,当然即使这样性能还是很高
- 数据恢复比较慢,不适合做冷备
是最简单的 Redis 持久性模式。当满足特定条件时,它将生成数据集的时间点快照,例如,如果先前的快照是在2分钟前创建的,并且现在已经至少有 100 次新写入,则将创建一个新的快照。此条件可以由用户配置 Redis 实例来控制,也可以在运行时修改而无需重新启动服务器。快照作为包含整个数据集的单个 .rdb 文件生成,将当前进程中的数据生成快照保存到硬盘中,当redis 重新启动时,可以读取快照文件恢复数据
操作系统多进程 COW(Copy On Write) 机制 拯救了我们。Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,简单理解也就是基于当前进程 复制 了一个进程,主进程和子进程会共享内存里面的代码块和数据段
- RDB文件
- 二进制文件
- 会进行压缩
- 可以通过rdbtools分析RDB文件
- 触发条件
- 手动触发
- 手动执行bgsave 命令会创建一个子进程,由子进程来负责创建RDB文件
- bgsave命令执行过程中,只有fork子进程会阻塞
- 自动触发
- 最常见的就是在配置文件中通过save 指定sconds秒内至少发生次变化,会触发bgsave
- 执行shutdown命令时,自动执行RDB持久化
- 优点
- 他会生成多个数据文件,每个数据文件分别都代表了某一时刻Redis里面的数据,这种方式,有没有觉得很适合做冷备,完整的数据运维设置定时任务,定时同步到远端的服务器,比如阿里的云服务,这样一旦线上挂了,你想恢复多少分钟之前的数据,就去远端拷贝一份之前的数据就好了
- RDB对Redis的性能影响非常小,是因为在同步数据的时候他只是fork了一个子进程去做持久化的,而且他在数据恢复的时候速度比AOF来的快
- 缺点
- RDB都是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判
- RDB在生成数据快照的时候,如果文件很大,客户端可能会暂停几毫秒甚至几秒,你公司在做秒杀的时候他刚好在这个时候fork了一个子进程去生成一个大快照,哦豁,出大问题
二、淘汰策略
FIFO (First In First Out)先进先出策略,先进去的被淘汰
LRU (Least Recently Used) 最近最久未使用策略,优先淘汰最久未使用的,热点数据
LFU (Latest Frequently Used) 最不经常使用策略,优先淘汰一段时间内使用次数最少的数据
- noeviction 策略:noeviction表示不淘汰数据,当缓存数据满了,有新的写请求进来,Redis不再提供服务,而是直接返回错误
- 根据过期时间的淘汰策略(volatile-random、volatile-ttl、volatile-lru、volatile-lfu 四种策略是针对已经设置了过期时间的键值对。到键值对的到期时间到了或者Redis内存使用量达到了maxmemory阈值,Redis会根据这些策略对键值对进行淘汰)
- volatile-ttl 在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除
- volatile-random 就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
- volatile-lru 会使用 LRU 算法筛选设置了过期时间的键值对。
- volatile-lfu 会使用 LFU 算法选择设置了过期时间的键值对。
- 所有数据范围内的淘汰策略(allkeys-lru、allkeys-random、allkeys-lfu 这三种策略淘汰的数据范围扩大到所有的键值对,无论这些键值对是否设置了过期时间,筛选数据进行淘汰的规则是:)
- allkeys-random 策略,从所有键值对中随机选择并删除数据;
- allkeys-lru 策略,使用 LRU 算法在所有数据中进行筛选。
- allkeys-lfu 策略,使用 LFU 算法在所有数据中进行筛选。
LRU 策略的核心思想:如果一个数据刚刚被访问,那么这个数据肯定是热数据,还会被再次访问
LRU算法即是最近最常使用算法,由于LRU会使用一个链表去维护使用的数据列表,当使用的数据越多,其移动元素时就会越耗时,这不可避免地会影响到Redis主线程。为此Redis对lru算法做了些简化,以减轻淘汰数据对缓存性能的影响
- Redis 中的 LRU 策略,会在每个数据对应的 RedisObject 结构体中设置一个 lru 字段,用来记录数据的最近访问时间戳
- 在redis决定淘汰数据时,会随机挑选N个数据,把它们作为一个候选集合
- 比较这N个数据的lru字段,把最小的时间戳给筛选出去,从缓存中淘汰
- 当再次淘汰数据时,reidis需要挑选数据进入第一次淘汰时创建的候选集合
- 当有新数据进入候选集,当数据达到maxmemory-samples 时,将最小的值给淘汰掉
这样Redis不用为所有的数据维护一个大链表,也不用在每次数据访问时都移动链表,提升了缓存的性能
通过该命令可以设置挑选的候选集合数 CONFIG SET maxmemory-samples N
三、过期策略
- 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量
- 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存
- 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key
Redis中同时使用了惰性过期和定期过期两种过期策略
Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据
过期键删除策略和内存淘汰机制之间的关系:
- 过期键删除策略强调的是对过期健的操作,如果有键过期了,而内存还足够,不会使用内存淘汰机制,这时也会使用过期键删除策略删除过期键。
- 内存淘汰机制强调的是对内存的操作,如果内存不够了,即使有的键没有过期,也要删除一部分,同时也针对没有设置过期时间的键
四、缓存场景
- 缓存雪崩
- 指的是由于数据没有被加载到缓存中,或者缓存数据在同一时间大面积失效(过期),又或者缓存服务器宕机,导致大量的请求都到达数据库,当发生缓存雪崩时,数据库无法处理这么大的请求,导致数据库崩溃
- 解决办法:
- 在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好了,这样可以保证数据不会在同一时间大面积失效
- 也可以进行缓存预热,避免在系统刚启动不久由于还未将大量数据进行缓存而导致缓存雪崩
- 为了防止缓存服务器宕机出现的缓存雪崩,可以使用分布式缓存,分布式缓存中每一个节点只缓存部分的数据,当某个节点宕机时可以保证其它节点的缓存仍然可用
- 为了防止缓存在同一时间大面积过期导致的缓存雪崩,可以通过观察用户行为,合理设置缓存过期时间来实现
- 缓存穿透
- 指的是对某个一定不存在的数据进行请求,该请求将会穿透缓存到达数据库
- 解决办法:
- 布隆过滤器
- 对这类请求进行过滤
- 对这些不存在的数据缓存一个空数据
- 缓存击穿
- 指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库
- 解决办法:
- 布隆过滤器
- 原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你return就好了,存在你就去查了DB刷新KV再return
- 缓存一致性
- 缓存使用姿势
- 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃
- 事中:本地 cache 缓存 + Hystrix 限流+降级,避免MySQL被打死
- Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据
五、高可用
同步策略:你启动一台slave 的时候,他会发送一个psync命令给master ,如果是这个slave第一次socket连接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后master会把内存里面缓存的那些新命名都发给slave
其他问题:
- 数据传输过程中断网或者服务器挂了:传输过程中有什么网络问题啥的,会自动重连的,并且连接之后会把缺少的数据补上的
- 延迟与不一致问题:可以设置salve-serve-stale-data为no
- 数据过期问题:从节点不会主动删除数据,而是由主节点控制从节点中过期数据的删除
- 复制超时问题:复制超时会导致复制中断,释放连接,可以调整repl-timeout参数控制超时时间
优点:
- 主机会自己将数据 同步到从机,可以进行读写分离
- 读写分离降低Master读压力,由Master去写
缺点:
- Redis不具备自动容错和恢复功能,主机和从机宕机都会导致前段读写失败,需要等机器重启或手动切换
- 主机宕机,宕机前有部分数据未能及时同步时,会引起数据不一致,降低系统的可用性
- 如果多个Slave断线了,需要重启的时候,尽量不要同一时间段进行重启,因为多个Slave重启,和主机全量同步,会导致Master IO 剧增从而宕机
主从模式下,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这种方式并不推荐,实际生产中,我们优先考虑哨兵模式。这种模式下,master 宕机,哨兵会自动选举 master 并将其他的 slave 指向新的 master
在主从模式下,redis 同时提供了哨兵命令redis-sentinel,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵进程向所有的 redis 机器发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例
哨兵可以有多个,一般为了便于决策选举,使用奇数个哨兵。哨兵可以和 redis 机器部署在一起,也可以部署在其他的机器上。多个哨兵构成一个哨兵集群,哨兵直接也会相互通信,检查哨兵是否正常运行,同时发现 master 宕机哨兵之间会进行决策选举新的 master
哨兵模式的作用
- 集群监控:负责监控 Redis master 和 slave 进程是否正常工作
- 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员
- 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上
- 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址
优点:
- 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有
- 主从可以自动切换,系统更健壮,可用性更高
缺点
- 具有主从模式的缺点,每台机器上的数据是一样的,内存的可用性较低
- Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂
- 集群模式
Redis集群采用去中心化的思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点进行操作,就像操作单一Redis实例一样,不需要任何代理中间件,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node
- 为什么需要集群
- 提高并发量,单台redis 能够支持10w qos
- 降低数据量,单台redis 服务器内存大概在16G-256G之间,分散数据存储,降低服务器存储压力
当我们的存取的 Key 到达的时候,Redis 会根据 crc16 的算法对计算后得出一个结果,然后把结果和 16384 求余 数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作,总槽数为:16384(2^14),如果有3台master,那么每台负责5461个槽(16384/3)
- 一致性hash算法
- 一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对2^ 32-1取模,什么意思呢简单来说,一致性Hash算法将整个Hash值控件组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1取模(即哈希值是一个32位无符号整型)
- 一致性hash算法主要应用于分布式存储系统中,可以有效地解决分布式存储结构下普通余数Hash算法带来的伸缩性差的问题,可以保证在动态增加和删除节点的情况下尽量有多的请求命中原来的机器节点
- 数据倾斜:
- 一致性Hash算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器,此时必然造成大量数据集中到Node 2上,而只有极少量会定位到Node 1上
- 为了解决数据倾斜问题,一致性Hash算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node 1#1”、“Node 1#2”、“Node 1#3”、“Node 2#1”、“Node 2#2”、“Node 2#3”的哈希值,于是形成六个虚拟节点
- 集群扩缩容
- 缩容
- 迁移槽
- 忘记节点:通过cluster forget 通知其他的节点
- 扩容
- 启动新节点
- 使用cluster meet 命令将新节点加入到集群
- 迁移槽和数据:添加新节点后,需要将一些槽和数据从旧节点迁移到新节点
- 投票选举
- slave 的 priority 设置的越低,优先级越高
- 同等情况下,slave 复制的数据越多优先级越高
- 相同的条件下 runid 越小越容易被选中
总结:
主从模式:一主多从,读写分离,分担主节点压力,master宕机需要手动选主
哨兵模式:一主多从,哨兵监控主节点状态,投票选主
集群模式:多主多从,可以使数据分区,去中心化,减少单机 压力
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
本文名称:Redis实践-创新互联
当前路径:
http://6mz.cn/article/dccchg.html