redis深度历险-读书笔记

redis数据结构

  • string
    采取分配冗余空间的方式减少内存频繁分配
    当字符串长度少于1MB,扩容都是成倍扩展
    当字符串长度大于1MB,每次只会多扩1MB
    字符串长度最大为512MB
    字符串由多个字节组成,每个字节由8bit组成,就是bitmap(位图)数据结构

  • list
    相当于java中的LinkedList
    redis底层存储的是quicklist 快速链表
    数据量少的时候是ziplist,数据量大的时候改成quicklist
    quicklist就是多个ziplist连在一起

  • hash
    redis的hash只能是字符串,
    rehash是渐进式rehash
    在渐进式rehash时,会保留新旧两个hash结构,查询会同时查询两个hash结构,然后在定时任务中渐渐将旧的结构的数据迁移到新的结构

  • set
    低层是hashset

  • zset
    类似于java的soreset和hashmap的结合体

分布式锁

分布式锁需要设置和超时为原子命令
set a a expire 5 nx
超时问题:如果加锁和释放锁之间逻辑执行太长,超出了锁的超时限制,建议分布式锁下的程序执行时间尽量短
解决办法:将set的value设置成随机值,避免别的线程将自己的锁释放,确保当前线程占有的锁不会被其他线程释放掉
除非这个锁是因为到期了而被释放

  • 可重入性
    如果一个锁支持同一个线程同时加锁,那么这个锁就是可重入的
    如果redis要支持可重入锁,需要对客户端的set方法进行包装,使用ThreadLocal变量存储当前持有锁的计数
    尽量避免使用可重入锁

延时队列

实现阻塞队列: 使用blpop和brpop取出数据,没有数据的时候阻塞
队列空了:可以使用阻塞指令,但是要注意超时的情况, 可以使用轮询的方式,比较耗性能,可以加sleep让cpu降下来

分布式锁冲突处理: 1.直接抛异常 2.sleep后重试 3.将请求转移到延迟队列,稍后重试

延时队列: 通过zset有序列表实现,将消息序列化成zset的value,到期时间设置为score,然后用多个线程轮询到期的任务

位图

用于用户签到类业务,365天只需要365bit
位图的数组是自动扩展的,如果设置的某个偏移位超出了现有内容范围,则自动将数组进行零扩充
setbit s 1 1
getbit s 1

Scan

因为keys * 容易导致阻塞,所以用scan替代keys
scan 0 match a* count 1000

大key扫描

如果key太大,会导致数据迁移卡顿
如果需要扩容的时候,会一次性申请一块大的内存,会导致卡顿,
如果key被删除,会一次性回收一块大的内存,也会导致卡顿

  • 扫描大key

redis单线程

1.基于内存
2.多路复用:select系列事件轮询api,非阻塞io

  • 指令队列:客户端指令通过队列顺序处理
  • 响应队列
  • 定时任务

redis持久化

使用操作系统的多进程Copy On Write机制进行
RDB: fork一个子进程做持久化,当父进程修改数据,会先拷贝一份出来修改
所以在子进程建立后,数据是不会变化的
AOF: redis会先执行指令再保存日志
AOF重写: 开辟一个子进程对内存遍历,转换成一系列redis操作指令,序列化到一个新的AOF日志文件,序列化完成后,再将增量AOF日志追加,完成后替换旧的AOF文件

  • redis4.0增加混合持久化,重启的时候先加载rdb的内容,然后再加载aof日志,代替了之前的AOF全量文件重放

redis集群

redis主从同步是异步的,不满足一致性
主节点修改数据后会立即返回,从节点会尽量追赶主节点,redis保证数据最终一致性

  • 增量同步
    主节点将指令记录在本地的buffer中,然后异步将buffer同步到从节点
    从节点一边执行同步指令流,一边向主节点反馈自己同步到哪里了
  • 快照同步
    首先在主节点执行一次bgsave
    将当前内存数据全部都保存到磁盘文件中
    再将快照传到从节点
    从节点加载完成后再通知主节点进行增量同步

sentinel(哨兵)

当主节点挂掉,会选一个最优从节点变成主节点
客户端先连接sentinel,通过sentinel查询主节点的地址,然后和主节点进行数据交互
当主节点发生故障,客户端会向哨兵重新获取主节点地址

codis


codis默认将所有key划分为1024个槽位,首先对客户端传过来的key进行crc32运算计算hash值,再将hash后的整数值对1024取余就是槽位

  • 自动迁移:
    增加新的redis实例后,遍历指定slot下所有key,Codis通过SLOTSSCAN扫描出待迁移槽位所有key,然后挨个迁移每个key到新的redis节点

  • 自动均衡
    在系统空闲的时候观察每个redis实例对应的slot数量,如果不平衡会自动进行迁移

  • codis集群配置中心使用zookeeper

  • 执行mget

redis cluster

redis cluster由最少3个节点组成
每个节点负责一部分数据
三个节点连接成对等的集群
一共分成16384个槽
Redis集群,要保证16384个槽对应的node都正常工作,如果某个node发生故障,那它负责的slots也就失效,整个集群将不能工作。
为了增加集群的可访问性,官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。这时,如果主节点失效,Redis Cluster会根据选举算法从slave节点中选择一个上升为主节点,整个集群继续对外提供服务,Redis Cluster本身提供了故障转移容错的能力。

从节点过期策略

从节点不会进行定期扫描,从节点对过期处理是被动的
主节点在key过期后会在AOF写入一个del命令,然后同步到从节点

字符串

字符串叫sds
sds结构:

长度短时,用embstr存储
长度超过44字节,用raw形式存储

list

单个ziplist为8kb,如果超出会新建一个ziplist

posted @ 2021-08-25 12:02  余***龙  阅读(131)  评论(0编辑  收藏  举报