KV 内存 单线程? 别忘了数据结构
单机 10w QPS
- String
- List: 消息队列, 列表场景
- Set
- Hash
- SortedSet
基本上我们就是 9 种数据结构, SDS zpiList quickList linkedList hash...
- String: SDS 简单动态字符串
- zipList:
- 本质是通过字节数组实现的, 为什么用数组实现链表? 是因为我们一般实现链表都会使用到指针, 这样会占据额外的内存空间, 引起内存碎片, 所以使用数组占用完整的一块内存.
- 缺点就是担心连锁更新的可能. 所以适用于少量数据的场景.
- 是 list hash sortedSet 类型的底层实现结构之一.
- zipList 之后的升级: quickList 和 listPack
- 哈希表
- skipList 跳表, 为了时间复杂度: O(logN)
- 单线程仅仅是指 KV 读写的过程是单线程的.
- 越是读写快(利用内存)的场景, I/O 越快, 多线程模型越是不利.
epoll 模型是基于事件驱动, 利用多路复用的特性, 减少在等待 I/O 处理时的时间.
RDB AOF
- RDB 是快照的形式,完成数据的备份据保存到 *.rdb 文件中,这个文件是个二进制文件。
- RDB 的实现策略有两种形式, save 与 bgSave(backgroundSave).
- bgSave 的实现方式: 当需要持久化时, fork 一个子进程, 新的进程负责全程的写入, 之后替换掉原来的 rdb 文件. 实现 copy-on-write.
- AOF 是把所有对 Redis 的修改的命令都存到一个文件里,当持久化的时候读取的时候这个文件。
- AOF 同步有三种策略, yes always(数据变更则同步) everySec(指定秒数同步).
- AOF 的缺点就是文件较大, 上面的 rdb 只是一个二进制文件, 但是 AOF 则是一个文件内保存了较多的字符串.
- 惰性删除(获取时候判断是否需要删除)(主要目标是节省 CPU 资源, 因为是单线程的, 但是非常浪费内存) + 定时删除(解决惰性删除浪费内存的问题)
- 一共 8 种可以聚合分为 4 种, LRU(最少使用) 最小频率 随机 TTL
- 先了解 set
- setEx: set expire key, 有过期时间
- setNx: set not exist, 有返回值的 set key
- 看业务场景, 不重要的应用可以使用 redis 实现
- setNx
- expire key
- delete key
- 后来 redis 也有新的命令, set key value ex px nx, ex: expire, px: 毫秒 nx: 键 notExist 时存入, xx: 键 existExist 时存入, 就是把一堆 set 命令变成了一次 pipeline 操作
- 至于 什么 lua 脚本的, 就扯淡了, 建议直接换 zookeeper 或者 etcd
- 雪崩:所有 key 的失效时间都是 12 小时,那如果这时候来了大量请求,相当于 redis 什么作用都没有。
- 设置 key 失效时间都加个随机值
- 既然跟 key 失效有关,那我 key 不失效不就得了,去主动更新 redis 的数据而不是用 redis 自动失效
- 穿透:缓存与数据库中都没有的数据,但是用户还在不断地请求。像这种穿透了 redis 去给 mysql 压力,就叫穿透。
- 参数校验
- 一个 key 非常热点,不停的扛着大并发,当这一个 key 失效瞬间,就是大量的请求都到了我数据库
- 可以自己服务端缓存, 利用 Redis 的消息通知, 把 Redis 的服务端数据同步给客户端, 同样包含变更操作.