Redis
Redis的编程模型
单进程单线程
为什么快
- 完全基于内存
- 结构简单
- 多路I/O复用模型
好处
- 代码清晰,简单
- 无加锁消耗,和死锁问题
- 无进程线程切换CPU消耗
坏处
- 无法发挥多核性能,可通过多部署实例
数据类型及应用场景
- string(字符串): 基本的数据存储单元,可以存储字符串、整数或者浮点数。一个键最大能存储 512MB。
- 底层实现采用了 SDS(Simple Dynamic String,简单动态字符串) 结构,就是预申请不同大小的长度。
- 表示整数,Redis 会将其编码为 int 类型。
- 长度 ≤ 44 字节的字符串,Embstr 编码。
- hash(哈希):一个键值对集合,可以存储多个字段。每个哈希最多可以存储 2^32 - 1 个键值对。模拟session的效果。
- ziplist:<512字段,内存紧凑,适合小数据量场景。
- hashtable:操作高效,适合大数据量或高频读写场景。
- list(列表):一个简单的列表,可以存储一系列的字符串元素。列表最多可以存储 2^32 - 1 个元素。
- quicklist:统一使用快速列表,将多个 ziplist 节点通过双向链表连接。
- set(集合):一个无序集合,可以存储不重复的字符串元素。
- 均为整数且元素数量<512,使用 intset 以节省内存。
- 当集合包含非整数元素或元素数量较多时,转为 hashtable。
- zset(sorted set:有序集合): 类似于集合,但是每个元素都有一个分数(score)与之关联。游戏积分排名。
- 底层采用压缩表ziplist(元素少于128)或跳表skiplist和哈希表的数据结构实现。
- 位图(Bitmaps):基于字符串类型,可以对每个位进行操作。每日签到记录(偏移量表示日期)。
- 超日志(HyperLogLogs):用于基数统计,可以估算集合中的唯一元素数量。UV统计。
- 地理空间(Geospatial):用于存储地理位置信息。查找附近的商家、司机。
- 发布/订阅(Pub/Sub):一种消息通信模式,允许客户端订阅消息通道,并接收发布到该通道的消息。
- 流(Streams):用于消息队列和日志存储,支持消息的持久化和时间排序。
- 模块(Modules):Redis 支持动态加载模块,可以扩展 Redis 的功能。
过期策略以及内存淘汰机制
定期删除+惰性删除策略
定期删除: 100ms随机抽取key检查 惰性删除: 获取某个key,检查是否过期
内存淘汰策略(内存不足)
- noeviction 报错
- allkeys-lru 移除最近最少使用 推荐
- allkeys-random 随机删除
部署
- Master-Slave模式,主宕机,从变为主,哨兵模式
- 集群分片(哈希Slot)
- 对每个键计算 CRC16(key) % 16384,得到其所属槽。
- 每个节点维护槽与节点的映射关系。
- 客户端缓存槽分配信息,直接请求目标节点;若节点返回 MOVED 错误,则更新缓存并重试。
- 主节点宕机时,从节点通过选举升级为主节点。
哨兵模式的缺点
- 哨兵宕机,故障转移失效
- 应用端需要先访问哨兵才能访问主库
主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:
- 海量数据存储问题
- 高并发写的问题
持久化
- RDB 数据快照
- AOF 命令顺序执行
主从同步策略
主从刚刚连接的时候,进行全量同步(RDB);全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步
其他开源软件模型
- Nginx 多进程单线程
- Memcached 单进程多线程模型
String和Hash(ziplist),什么情况下用Hash更省内存。
- 哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
- 哈希对象保存的键值对数量小于 512 个;