Redis
2021-06-02 19:59:05 3 举报
AI智能生成
redis
作者其他创作
大纲/内容
Redis
Redis架构
主从架构
核心机制
redis replication的核心机制
主从架构的核心原理
当启动一个slave node 重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node 第一次连接的master node,那么会出发一次full resynchronization开始full resyncronization的时候,master会启动一个后台线程,开始生成一份RDB快照i文件,同还会将从客户端收到的所有写命令缓存到内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后在从本地磁盘加载到内存中,然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。slave node 如果跟master node有网络故障,断开了连接,会自动重连接,master如果发现有多个alave node 都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有alave node
主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份master node会在内存中常见能与i个backlog。master和slave都会保存一个replica offset还有一个masterid,offset就是保存在backlog中的,如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制但是如果没有找到对应的offset,那么就会执行一次resynchronization
无磁盘化复制
过期key处理
redis 哨兵模式
主要功能
集群监控,负责监控redis master 和slave进程是否正常工作
消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报告通知给管理员
故障转移,如果master node挂掉了,会自动转移到slave node 上
配置中心,如果故障转移发生了,通知clent客户端新的master地址
分布式
1、故障转移时,判断一个master node 是宕机了,需要大部分的哨兵都同意才行,涉及刀片了分布式选举的问题
即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单机的,那就完蛋了
核心知识
1、哨兵至少需要三个实例,来保证自己的健壮性
2、哨兵 + redis 主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
3、对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
数据丢失
异步复制导致的数据丢失
脑裂导致的数据丢失
解决异步复制和脑裂导致的数据丢失
底层原理
sdown和odown
哨兵机制的自动那个发现机制
slave配置的自动纠正
salve -> master 选举算法
瓶颈
如果你的数据量很少,主要是承接高并发高性能的场景,比如你的缓存一般就是几个G,哪单机就足够了
replication 一个master、多个slave,要几个salve跟你的额要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证中架构的高可用性,就可以了
redis cluster
介绍
cluster
自动将数据进行分片,每个master上放一部分数据提供内置的高可用支持,部分master不可用时,还是可以继续工作的
cluster 端口
每个redis 要放开两个端口,比如一个是6379,另外一个就是加10000的端口号,比如1637916379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线,cluster bus的通信,用来进行检测,配置更新,故障转移授权cluster bus 用了另外一种二进制的协议,主要用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间
hash slot算法
核心原理-节点内部通信
基础通信原理
节点间采取gossip协议进行通信
10000端口
交换的信息
gossip协议
ping消息深入
redis 回收算法
redis是会在数据达到一定程度之后,超过了一个最大的限度之后,就会将数据进行一定的清理,从内存中清理掉一些数据Redis默认情况下就是使用LRU策略的,因为内存是有限的LRU:least Recently userd 最近最少使用算法将最近一段时间内,最少使用的一些数据,给干掉,比如说有一个key,在最近1个小时内,只被访问了一次,还有一个key在最近1个小时内,被访问了1万次
缓存清理设置
maxmermory,设置redis用来存放数据的最大的内存大小,一旦超出这个内存大小之后,就会立即使用LRU算法清除掉部分数据对于64bit的机器,如果maxmemory设置为0,那么就默认不限制内存的使用,直到耗尽机器中所有的内存位置maxmemoiry-policy,可以设置内存达到最大闲置后,采取什么策略来处理
清理策略
可以通过maxmemory-policy key 来设置内存达到最大内存后,采取什么策略来处理volatile-lru -> 根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。allkeys-lru -> 根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。volatile-lfu -> 根据LFU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。allkeys-lfu -> 根据LFU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。volatile-random -> 随机删除过期键,直到腾出足够空间为止。allkeys-random -> 随机删除所有键,直到腾出足够空间为止。volatile-ttl -> 根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。noeviction -> 不会删除任何数据,拒绝所有写入操作并返 回客户端错误信息,此 时Redis只响应读操作。
缓存设计
缓存更新
1、先删除redis中的缓存2、更新mysql 的数据3、查询的时候在增加redis的缓存
缓存穿透
描述
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
缓存击穿
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
1、设置热点数据永远不过期。
2、接口限流与熔断,降级。重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些 服务 不可用时候,进行熔断,失败快速返回机制。
3、布隆过滤器。bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小
4、加互斥锁
雪崩击穿
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
3、设置热点数据永远不过期。
预防措施
事前
事中
事后
数据类型
String
数据结构:key-value
常用操作:set、get、decr、incr、mget回、msetnc加锁
应用场景:incr点赞计数器
hash
数据结构:Hashmap
常用操作:hget、hset、hgetall
应用场景:数据对象存储、session、短网址追踪、更新博客
list
数据结构:双向链表,可重复有序集合
常用操作:lpush、rpush、lpop、rpop、lrange
应用场景:消息队列类型,阻塞式发送邮件、lrange:分页查询、数据id保存
set
数据结构:value永远为null的Hashmap不可重复无序集合
常用操作:sadd、spop、snenbers、sunion
其它扩展判断某个成员是否在一个set集合内
应用场景:粉丝、关注、抽奖、投票、UV、多个关键词搜索商品
其他扩展-交集、并集、差集
Z-Set
数据结构:使用HashMap和跳跃表(Skiplis)来保证数据的存储和有序不可重复有序集合
常用操作:zadd、zrange、zrem、zcard
子主题
geo
数据结构:
常用操作:geoadd、georadiusByMember、geodist
应用场景:附近人、用户到商家的距离
sorted set
数据结构:zSet
常用操作:zadd、zincrby、zrevrangeWithScores、zrevrangeBySoreWithScores
应用场景:音乐排行榜、商品推荐
Redis持久化意义
1、是做灾难恢复、数据恢复,也可以归类到高可用的一个环节里面去,比如你redis整个挂了,然后redis就不可用了,你要做的事情是让redis 变得可用,或者尽快得可用
2、大量的请求过来,缓存全部无法命中,在redis里根本找不到护具,这个时候就死定了,缓存雪崩问题,所有请求,没有在redis 命中,就会去mysql数据库这种数据源头去找,一下子这么多请求,mysql可能也会挂了
3、redis持久化做好,备份和恢复方案做到企业及的程度、那么即使你的redis故障了,也可以通过备份数据,快速恢复,一旦恢复立即对外提供服务
Redis持久化RDB
优点
1、RDB会经过一段时间复制一份数据快照,这种数据快照非常适合做冷备,能够快速将完整文件发送到一些远程的redis中
2、RDB时 redis依然对外提供读写服务,性能影响非常小,可以让redis保持高性能,redis主进程只是fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
3、相对于AOF持久化机制来说,redis通过RDB文件恢复的更快,在redis重启时能更快恢复redis可用
缺点
1、redis发生故障的时候,RDB可能会丢失数据,因为RDB是每隔5分钟备份一次快照,或者更长时间,那么这期间的数据就会丢失
2、RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别的大,可能会导致客户端提供的服务暂停数毫秒,或者数秒
配置
工作流程
模拟实验
Redis持久化AOF
1、AOF可以更好的保护数据不丢失,一般AOF会每隔1秒通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
2、AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破碎,也很容易修复
3、AOF文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写,因为在rewrite log的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来,在创建新的日志的同时,老的日志文件还是照常写入,当新的merge后的日志文件ready的时候,在交换新老日志文件即可
4、AOF日志文件的命令通常可读,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall 命令清空了所有数据,只要这个时候后台rewiter还没有发生,那么就可以离职拷贝AOF文件,把最后一条fulshall 命令删除掉。
1、对于同一份数据来说,AOF的文件要比RDB数据快照更大
2、AOF开启后,支持的QPS会比RDB支持写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,每秒一次fsync性能还是很高的
3、通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来,所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多
4、唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢,还要做冷备,定期的备份,不太方便,可能要自己手写复杂的脚本去做,做冷备不太合适
1、AOF持久化,默认是关闭的,默认是打开RDB持久化,appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓,打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写os cahce的,然后每隔一定时间在fsycn一下
2、而且即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为AOF数据比较完整
3、可以配置AOF的fsync策略,有三种策略可以选择,一种是每次写入一条数据执行一次fsync,一种是每隔一秒执行和一次fsync,一种是不主动执行fsync
always:每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常差,吞吐量很低,确保将redis里的数据一条都不丢,那就只能这样了
mysql -> 内存策略,大量磁盘,QPS到多少,一两K,QPS,每秒钟的请求数量redis -> 内存,磁盘持久化,QPS到多少,单机,一般来说,上万QOS没问题
everysec 每秒将 os cache中数量fsync到磁盘,这个最常用的,生成环境一般都这么配置,性能很高,QPS还是可以上万的
no:仅仅redis负责将数据写入os cache 就撒手不管了,然后后面os 自己会时不时有自己的策略将数据刷入磁盘,不可控了
1、开启appendonly yes,kill -9 杀掉redis进程,重新启动redis 进场,发现数据被恢复回来了,就是AOF文件中恢复回来的redis进程启动的时候,直接会从appendonly.aof 中加载所有的日志,把内存中数据恢复回来
2、redis进程启动的时候,直接就会从appendonly.aof中加载所有的日志,把内存中的数据恢复回来redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存的算法清理掉
3、redis中的数据会不断淘汰掉旧的数据,只有常用的数据会被保留在redis 内存中,其他的数据会被redis用缓存清除算法清除掉
AOF rewrite
redis中的数据其实是有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉redis中数据会不断淘汰掉旧的数据,只有一部分常用数据会自动保存在redis内存中所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀到很大很大 所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了;redis内存只剩下10万;基于内存中当前的10万数据构建一套最新的日志到aof中,覆盖之前的老日志;确保AOF日志文件不会太大
1、redis fork一个子进程2、子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写日志3、redis主流程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件4、子进程写完新的日志文件之后,redis主进程将内存中的新日志再此追加到新的AOF文件中5、 用新的日志文件替换掉旧的日志文件
RDB VS AOF
区别
1、RDB也可以做冷备,生成多个文件,每个文件都代表了某一个时刻的完整的数据快照2、AOF也可以坐冷备,只有一文件,但是可以,每隔一定的时间,会copy一份这个文件出来
2、RDB,每次写,都是直接写redis内存,只是在一定的时候 ,才会将数据写入磁盘中AOF,每次都是要写文件的,虽然可以快速些人 os cache中,但是还是有一定的时间开销的,速度肯定比RDB略慢一些
3、AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,未恢复出来内存中的所有数据的RDB,就是一份数据文件,恢复的时候,直接拉取到内存中既可
同时工作
1、不要仅仅使用RDB,因为那样会导致你丢失很多数据
2、也不要仅仅使用AOF,因为那样会有两个问题,第一通过AOF做冷备,没有RDB做冷备,来的恢复速度快第二、RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
3、综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同的成都的冷备,在AOF文件都丢失或损坏的不可用的时候,还可用RDB来进行快速的数据恢复
0 条评论
回复 删除
下一页