数组结构
String、Map、Set、ZSet、List
持久化
AOF:追加日志持久化操作,将写命令追加到一个文件的末尾。redis重启时,执行这些操作。更可靠。不会出现数据丢失的问题。写入硬盘的频率配置:每秒同步、每写入命令同步、禁止同步
RDB:快照持久化,将某个时间点的数据以二进制的形式保存到硬盘上。可以定时/手动触发/自动触发。生产的文件比AOF小,恢复速度快,适合备份和灾难恢复。操作的是虚拟内存的页表,只拷贝页表,两份页表指向同一个物理内存。
AOF优先级更高,重启时会优先AOF,如果AOF文件损坏,使用RDB
主从复制
主从复制包括全量复制,增量复制两种。一般当slave第一次启动连接master,或者认为是第一次连接,就采用全量复制,
全量复制流程如下:
1.slave发送sync命令到master。
2.master接收到SYNC命令后,执行bgsave命令,生成RDB全量文件。
3.master使用缓冲区,记录RDB快照生成期间的所有写命令。
4.master执行完bgsave后,向所有slave发送RDB快照文件。
5.slave收到RDB快照文件后,载入、解析收到的快照。
6.master使用缓冲区,记录RDB同步期间生成的所有写的命令。
7.master快照发送完毕后,开始向slave发送缓冲区中的写命令;
8.salve接受命令请求,并执行来自master缓冲区的写命令
增量复制:
主从服务器在完成第一次同步后,就会基于长连接进行命令传播。
连接可能断开,
重新连接上后slave会发送自己的复制偏移量和环形缓冲区给master
在主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入到 repl_backlog_buffer 缓冲区里,因此 这个缓冲区里会保存着最近传播的写命令。
如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式;
相反,如果判断出从服务器要读取的数据已经不存在
repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式。
哨兵模式
哨兵模式,在独立的哨兵节点上运行哨兵进程
sentile 主进程,监控各个节点的状态,执行故障转移
monitor 哨兵进程,监控主节点和从节点的情况,并通知其他哨兵进程
judge 哨兵进程 根据预设的阈值,判断是否要将主节点下线
failover 哨兵进程,将选举出来的从节点设置为主节点,并通知其他节点更新配置信息
工作原理
启动时,哨兵会选举出一个主节点,每个哨兵节点向其他节点发出命令,当票数大于一半时就成为领导者。
节点监控,发送命令周期性的检查主从节点的状态,如果发现主节点不可用,触发一次故障转移。
故障转移:
1、过滤已下线的从节点
2、选择优先级最高
3、选择和主节点复制最完整的从节点
联系客户端新的主节点位置,让客户端能和新的主节点建立连接。
监控从节点,有问题就下线,没问题再上线。
缓存一致性
1、延时双删:先删除redis、再更新mysql,过几百毫秒后又删除一次redis。保证将第一次删除redis和更新mysql之间产生的脏数据删除
2、队列+重试机制
先更新mysql,如果删除redis失败,将删除操作发送到mq,过一会再删除,重试删除操作。这样做对业务代码侵入大。
3、基于订阅binlog的同步机制,
1、更新mysql,mysql将操作写入binlog
2、提取binlog,发送到mq,mq发送后再操作一次redis
缓存击穿、缓存穿透、缓存雪崩
缓存击穿:redis热点数据过期,请求直接打到mysql
解决:热点数据不设置过期时间,防止缓存击穿
缓存穿透:redis没有这个key,数据库也没有,导致数据库负载过大
如果数据库也没有的数据,在缓存做一个空的值,防止缓存穿透
布隆过滤器:它由初始值为0的位图数组和N个哈希函数组成。一个对一个key进行N个hash算法获取N个值,在比特数组中将这N个值散列后设定为1,然后查的时候如果特定的这几个位置都为1,那么布隆过滤器判断该key存在。
缓存雪崩:缓存在某个时间点失效/崩溃,大量请求打到后端服务器,后端数据库也崩溃。导致服务不可用
热key
可预知的:凭借业务经验,进行预估哪些是热key,通过批量加载和预先访问热门数据,将热key提前加载到内存中。
不可预知的:通过Daas平台查看热点key的分析和监控。一般不用monitor命令什么的,因为公司不让。
热key的危害
1、流量集中,可能使某台机器宕机
2、缓存击穿,引起db雪崩
热key的方案
1、使用二级缓存,GuavaCache等,但是会有缓存一致性问题需要维护。
2、让热key分散到不同机器上
3、热key拆分,把热key再根据业务细分。
在生成 RDB期间,Redis 可以同时处理写请求么?
可以的,Redis提供两个指令生成RDB,分别是save和bgsave。
如果是save指令,会阻塞,因为是主线程执行的。
如果是bgsave指令,是fork一个子进程来写入RDB文件的,快照持久化完全交给子进程来处理,父进程则可以继续处理客户端的请求。
redis_86">redis哈希冲突
redis对哈希冲突的处理方式类似hashmap,相同hash值的放在一个链表里
为什么Redis 6.0 之后改多线程呢?
Redis6.0之前,Redis在处理客户端的请求时,包括读socket、解析、执行、写socket等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。
Redis6.0之前为什么一直不使用多线程?使用Redis时,几乎不存在CPU成为瓶颈的情况, Redis主要受限于内存和网络。例如在一个普通的Linux系统上,Redis通过使用pipelining每秒可以处理100万个请求,所以如果应用程序主要使用O(N)或O(log(N))的命令,它几乎不会占用太多CPU。
redis使用多线程并非是完全摒弃单线程,redis还是使用单线程模型来处理客户端的请求,只是使用多线程来处理数据的读写和协议解析,执行命令还是使用单线程。
这样做的目的是因为redis的性能瓶颈在于网络IO而非CPU,使用多线程能提升IO读写的效率,从而整体提高redis的性能。
Redisson
要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。