- 缓存
- 分布式锁
- 分布式Session
- 排行榜
- 限流 TODO
- 计数器
- 验证码
- Strings
- Lists
- Sets
- Hashes
- Sorted sets
- Streams
- Geospatial indexes
- Bitmaps
- Bitfields 位域
- HyperLogLog
- 惰性删除
- 定期删除
- allkeys/volatile-lru:最久没有使用
- allkeys/volatile-lfu:最不经常使用
- allkeys/volatile-random
- volatile-ttl:快要过期
- no-eviction
- RDB:文件小、恢复快、可靠性低(数据丢失)
- AOF:文件大、恢复慢、可靠性高
TODO:Redis 4.0混合持久化
TODO
TODO
槽 (slot):集群的整个数据库被分为16384个槽,每个主节点都持有一部分槽,键属于哪个槽:CRC16(key) % 16384
- 内存存储,数据读写快
- 基于IO多路复用技术实现的文件事件处理器,使用单个线程也能高效地处理客户端请求
- 设计优秀,如:为每种数据类型提供不同的数据结构、哈希表的渐进式rehash等
- 系统瓶颈通常来源于内存和网络带宽,不在于CPU
- 单线程模型的优势:功能实现简单、没有线程切换开销、没有锁竞争
- 可以通过多实例充分利用多核CPU
- Redis 4.0:LAZY FREEING,使用BIO thread异步处理耗时的删除操作,如:UNLINK、FLUSHDB ASYNC
- Redis 6.0:THREADED I/O,使用I/O threads并发读写Socket和协议解析
相对更优的更新策略:先更新数据库,再删除缓存
缓存不一致的情况:
- Case1:并发读写时,缓存失效且读请求被写请求打断,导致读请求向缓存中写入了过期数据
- Case2:删除缓存失败,导致缓存中保留了过期数据
- Case3:数据库主从同步延时,数据被更新后还未同步到从库,读请求读从库读到了过期数据,并写入缓存中
解决方案:
- Case1:延时双删,第一次删除避免写请求过程中出现不一致,第二次删除避免写请求完成后出现不一致
- Case2:删除失败重试,通常引入MQ异步重试,保证最终删除成功
- Case3:通过监听从库的binlog,执行删除操作
终极解决方案:
- 可以接受短暂不一致:设置合理的过期时间
- 必须强一致:不使用缓存
- 数据读取流程:本地缓存 -> 远程缓存 -> 数据库
- 数据更新流程:更新数据库 -> 删除远程缓存 -> 依赖MQ发布删除消息到每一个服务实例 -> 删除本地缓存
- 缓存穿透:大量请求系统不存在的数据,解决方案:
- 缓存null值
- 使用布隆过滤器
- 缓存雪崩:大量缓存同时过期,解决方案:
- 离散化缓存过期时间
- 缓存击穿:热点缓存的失效,解决方案:
- 读数据库和加载缓存时加分布式锁,其它线程等待
- 永不过期,缓存一致性通过其它方式保证,如定期更新、监听binlog
- 主从结构:增加从实例,分摊读请求
- 集群:增加key(key-1/key-2/...),将数据保存到多台分片实例上,分摊读请求
- 增加本地缓存,拦截读请求