为什么用一致性哈希
比如我们对数据取模决定存放的机器,比如有3台机器4%3=1,再加一台机器4%4=0,查不到原来数据了。
一致性哈希算法
是一种分布式算法,常用于负载均衡。Memcached client也选择这种算法,解决将key-value均匀分配到众多Memcached server上的问题。
它要做的是:对象通过算法判断连哪台机器
它不再是每台机器去保存一个连续的资源段,而是让每台机器都保存多个区域的部分资源段。
如果保证队列不重复消费
1.使用唯一id做幂等,生产者生成一个唯一id,消费者用这个id做key去redis中或mysql中做幂等校验。
数据结构
string SDS动态字符串 结构体包含三个属性
len 当前字符串的长度
free 当前剩余的空间
buf[] char数组保存当前字符串
空间分配原则:当小于1M时按倍分配,当大于1M时每次额外多分配1M空间
hash结构
定义字典结的结构体
diciType 结构本
rehash的数组,用于保存两张hash表的,通常只有一个数组有值
是否进行rehash
存储数据的结构体
key
value
还有一个链表解决key的冲突情况
扩容:扩容的新hash是原来的两倍
缩容:当第一个数组的个数,小于第一个数据长的10%就会缩容
rehash:在渐进式rehash过中,所有的,增删改查都可能会操作两个表,查找会先从表一查,没有再去表二查;更新和删除会同时操作两个表;添加只有添加到第二个表
为什么要渐进式:避免了大的hash复制会堵塞进程,redis是单进程的。
list
双向列表
set/zset
zset满足下面两个条件时用ziplist:一、保存的元素少于128个二、所有元素的大小都小于64字节。
否则用skiplist
ziplist(压缩表)
是一系列连续内存组成的存储结构,数据有一个一个有entry节点组成,并从大到小排序

zlbytes:表的长度
zltail:最后节点的偏移量,方便pop和反向遍历
zllen:节点的数量
zlend:表的结尾

prevlength:上一个节点的长度,方便遍历。
data:当前节点的数据
skiplist(跳表)
zset结构体包含一个字典和一个跳表。

字典:保存成员和值.
跳表:保存值,用于范围查询。由底层跳跃表和上次节点的跳表组成
redis
基本类型
string,hash,list,set,zset(sortd set)
watch+multi机制
watch监控一个key,multi开启事物并把以下操作加到队列里,exec执行前会检查watch监控的key是否有变化,如果有变量就取消队列里的操作,否则就提交队列里的操作
CAS比较和交换
两个线程同时修改一个数据,都先监控初始值,谁先改动,提交的时候对比初始值,不跟初始值一样就放弃操作
主从同步
全量同步:一般发生在从机初始化的时候
1.主机会先生成一个RDB快照,在这期间写和修改操作主机会写到缓存里
2.从机收到快照后,会把数据加载到自己的内存里
3.主机发送完快照,再把缓冲区的命令也发给从机,然后从机再执行新收到的命令
增量同步:
主机每执行一条写操作,都向从机发送一条同样的命令,从机接受并执行
redis队列和kafka队列对比
1.redis是key,kafka是topic
2.kafka的一个队列可以有多个分片/子队列,redis不能。
3.如果一个队列数据特别大,redis性能没有kafka好
4.redis操作相对简单
5.redis队列没有异常处理机制,取出来如果执行失败就没有了,没有ack确认的机制
持久化方式
RDB(存的是二进制):
fork创建一个子进程,然后子进程负责将快照写入硬盘。
优点:每次快照会成生一个完整的数据文件,可以保存多个时间点的快照,RDB恢复数据快
缺点:因为是定时的,在崩溃的时候可能会丢失数据
AOF(存的是命令):
会将执行的写命令写到AOF文件末尾。
优点:比较安全,丢失数据风险小,AOF文件记录的是命令易读可修改
缺点:文件大会占更多的空间,数据恢复慢
三种写入方式:1 同步写回,每个操作都会同步写入
2每秒写回,每隔一秒把缓存的命令写入
3 操作系统控制的写回,写的AOF的缓冲区有系统决定什么时候写入AOF文件
Strgin底层是怎么存的
SDS,扩展的收缩机制
HashMap底层是怎么存的
一个dict,两个dictht,一个dictEntry(bucket)
垃圾回收机制
惰性删除:不主动删除,当用户访问已经过期的对象的时候才删除
定时任务删除:定时执行,当发现过期时删除对应的键
缓存穿透
缓存和数据库都没有,
1.数据库未查到的也可以设置一个时间端的空redis值
2.布隆过滤器
缓存击穿
在缓存过期的那一刻有大量的请求过来,然后这些请求直接查到了数据库上
1.热点数据可以设置一个很长的过期时间,如果有变更后台去更新
缓存血崩
缓存大面积过期,导致大量请求直接查询数据库
1.设置不同的过期时间
2.后台更新缓存逻辑
redis为什么快
1.绝大数操作都是内存操作,避免了磁盘IO的耗时。
2.单进程模式,避免了多进程的上下文切换和cpu竞争的一些耗时
3.采用多路复用非堵塞io
4.支持主从模式,能分散读写压力
同时有多个子系统去set一个key
不推荐用事务,对于redis集群操作事务不一定会生效,数据可能是分片存储的
1.分布式锁拿到锁才去执行
2.要求顺序,B先写了一个3:00的数据,A发现自己的早于B就不更新
3.采用队列
原子性
1.一个指令是不能再分的,要么成功要么失败
2.单线程的
3.事务保证批量操作的原子性
有序列表的实现
内部实现依赖两种数据结构:ziplist(压缩列表) 和 skiplist(跳表)
zadd时redis会检查使用那种结构。
满足以下条件会创建ziplist:1.zset_max_ziplist_entries 大于0,2.元素的member长度小于zset_max_ziplist_value的配置;否则会创建skiplist
满足以下条件的ziplist会转成skiplist:1.ziplist所保存元素的长库超过zset_max_ziplist_entries的配置,2.新添加member的长度大于zset_max_ziplist_value的配置
扩容机制
String:当冗余空间不足中就加倍扩容
高可用
主从模式,主从从:部署方便,不能自动迁移故障
哨兵模式:哨兵的数量要是奇数个,可以自己迁移故障。
集群模式:
数据持久化rdb+aof
redis为什么快
1.数据都存在内存里,绝大多数据操作都是内存操作
2.采用单线程,避免的多线程的上下文切换,和多线程下共享资源锁的竞争
3.采用epoll io多路复用技术,可以同时处理多个io流。