skiplist 少听到,从他来拓展一下。
zset 使用的数据结构,大概长这样,
显而易见,他比链表查询速度快。 node 节点大概长这样。
typedef struct zskiplistNode {
// 成员(Member)
sds ele; // SDS 是 Redis 的字符串类型
// 分值(Score)
double score;
// 多级指针(Forward)
struct zskiplistNode **backward; // 反向指针(可选,用于双向遍历)
struct zskiplistLevel {
struct zskiplistNode *forward; // 指向下一节点
unsigned int span; // 跨度(可选,用于计算排名)
} level[]; // 柔性数组,层数可变
} zskiplistNode;
typedef struct zskiplist {
struct zskiplistNode *header, *tail; // 头节点和尾节点
unsigned long length; // 节点数量
int level; // 当前最大层数
} zskiplist;
一个数据的sds 可能存在与skiplist 的多层list 上; 插入数据时 node 中的level决定了该节点存在与哪些层的list 上。 删除时逐层删除该层list 上的节点, 调整前后节点的 双向指针。 他不需要保持树高度平衡, 没了AVL, 节省性能啊
拓展一下:
SDS: redis 自己实现的string , 拓展了c的string 去掉了c中结尾的“\0”
ziplist: redis 中的压缩链表, 它里面的node 叫做entry , 每个entry 记录自己的长度,entry里没有前后节点指针, 即所谓压缩。entry 中记录了前一个节点的长度, 从而实现了遍历, 前向 next =curr+pre_len; 后向 next = curr -pre_len
锁: set nx ex 设置锁 ,秒杀抢购锁住库存, 在锁的时候加上自己的uuid, 只能解自己uuid的锁; redis 默认只写到master 节点, 如果此时down机 那么 slave 没同步会导致锁不住,那么对所有节点检查写入成功,redlock组件干的事了。
zset 实现排行榜, 时间戳 滑动窗口限流,姓名排序,电话排序,电话簿,好友列表
incr, decr 发号 计数
list 消息队列
持久化: AOF 和 RDB ; rdb 用于主从复制,备份恢复等,save 60 1000 60s 内写1000次哪怕是同一个 调用bgsave非阻塞写。 AOF append only file ,有always,everysec 和 no ; 对比下 innodb wal 的三种刷盘策略 : 1 每个trx提交写log,2每个trx提交写 page cache , 0 每个trx 提交写 redo log buffer ;混合持久化,触发aof时写格式变成二进制,否则为aof的日志;
redis 与mysql: 先写redis 再删redis; 若先删redis 则延迟双删;保证最终一致性。
热key : 单key缓存失效时击穿, 用双重检查锁,在key过期时加锁处理
雪崩:多key集中过期雪崩,多key失效时间随机,或预热。
穿透:redis 和 sql都不存在,大量请求到db,那让redis 缓存下不存在的,
bitmap: 用到签到,打卡场景不错
set : 共同好友 ;大量数据的时候 用neo4j 或布隆过滤器; 抽奖人,
大key :超过xx量认为是大key,拆分大key或者开启惰性删除,不开的话删除会阻塞,别用keys 获取了,用scan 扫
惰性删除: 过期了不会立即删,下次被访问时再删。
定期删除: 100ms随机抽取部分设置了过期时间的key,删除其中的过期的key;用unlink交给异步删比del删不阻塞主线程;
主动清理: 内存使用超过maxmemory 触发; 清理设置了过期时间的 ; 清理所有键;不清理的话写OOM读没问题; rand,lru,lfu ,ttl 三种清理策略
lru: 最近一段时间内的访问次数, 可能干掉这段时间前的热key,
lfu: 访问次数, 历史访问的热key 可能一直留着, 需要基于时间给次数做衰减 从而干掉冷数据
与memcached区别: mem 无持久化,支持的数据类型少。
单线程处理读写,多线程处理异步io:epoll 多路复用所以能单线程到10wqps;开多个节点利用机器CPU;
可用性架构:单主从切换时需要介入,哨兵单主了同步会慢,而且主挂哨兵选主的时间内会访问失败,集群是多主从了,相当于一主分片到了多主,并发高了,出问题的概率小了
集群分片: crc(key) mod 16384 = slot , 看slot 配置在哪个主
object encoding key 查看底层数据结构
127.0.0.1:6379> SET mykey "hello"
OK
127.0.0.1:6379> OBJECT ENCODING mykey
"embstr"
127.0.0.1:6379> LPUSH mylist 1 2 3
(integer) 3
127.0.0.1:6379> OBJECT ENCODING mylist
"quicklist"
127.0.0.1:6379> ZADD myzset 1 "one" 2 "two" 3 "three"
(integer) 3
127.0.0.1:6379> OBJECT ENCODING myzset
"skiplist"