简介
- 存储在内存
- K - V 存储
- 只有一个工作线程 worker,串行处理, 多个任务间无序
- 有多个io thread(6.x 以上提供)
- 通过 epoll 实现多路复用
- 整体流程 通过epoll 确定就绪io -> 读 io (io 线程) -> 处理 (worker) -> 写io (io 线程 返回值)
V 类型
String
- 数据格式为二进制数组
- 该二进制数组字节码安全,客户端给啥存啥
- 所有数据类型以文本存储(如:int double)
- incr decr 只能操作数值型文本
- incr decr 操作成功之后,该值会标识为 int, Object encoding key 会返回 int
- bitmap, 二进制操作.默认1个字节(自动扩充 0000 0000), 通过 setbit (从左向右下标) 1 (修改的值, 0/1) 1, get key 为 0100 0000 (ascii 码) 结果为 '@'
List
- 双向链表,key 存储了头和尾
- lpush rpush 代表放入顺
- lpop rpop 同向实现栈,异向实现队列
- lrange rrange 实现数组
- -1代表最后一个元素,-2 代倒数第二个元素, lrange 0 -1 代表从左往右 取出全部元素
Hash
- v 结构 为 k-v (java 的 HashMap)
Set
- 无序,去重 (java 的set)
- 用 hashtable 实现
- srandmember key 取出数量 (正数 负数), 正数去重 负数允许重复
- 交集 并集 差集 等
zSet
- 有序set
- 添加元素,给出分值
- 当 server.zset_max_ziplist_entries(默认128) > 0时 且 元素member 长度 < server.zset_max_ziplist_value(默认64) 时为zipList,否则为跳表
- 当 元素个数 > server.zset_max_ziplist_entries > 或者 元素member 长度 > server.zset_max_ziplist_value 转化为跳表
跳表说明
- 下层数据必须包含上层的全部数据 (第二层的数据 第一层必须有)
- 添加数据时,在插入第一层链表后,会生成一个随机数,该随机数为该数据的层数
- 层数每+1 概率减少 50% , 第二层的概率为50% 第三层为 25% 以此类推,最高ZSKIPLIST_MAXLEVEL(5.x 为 64)
- redis并不要求上层链表相对下层链表有规律(比如隔 N 个 跳一个,下图中第二层极端情况下可以是 0 1 2 3 4 5 6 7)
- 头结点不存储元素,且层数为 ZSKIPLIST_MAXLEVEL
- 查找元素时,head 先找到有元素的最高层
- 当元素< 查找元素时,向同层右方继续查找
- 当元素>查找元素时 || 为nul (不在最底层) ,想下层右方查找
- 当元素为nul时 && 在最底层时,返回nul
- 当元素=查找元素时,返回该元素对应的最底层元素值
- 比如 查找5 ,元素最高层为3,先比较4,然后比较第三层 nul ,再比较6,再比较5,最后返回5
数据持久化
4.32版本前只能开启一种,默认是rdb
4.32开始,首先根据rdb恢复快照,再根据aof增量恢复
rdb 快照
恢复数据快,会缺失数据
save 时间(秒),启用后数据库只包含一个文件
aof 日志
恢复速度慢,有冗余
appendonly no/yes
- appendfsync always 每次操作都持久化一次(降级为mysql?)
- appendfsync everysec (默认) 每秒持久化一次
- appendfsync no 不持久化
redis 集群 (一般组合使用)
主从复制(AP)
解决单点故障问题,数据同步,节点间数据是全量的
- 支持强一致性(会破坏可用性)
- 默认是弱一致性
cluster模式
分治分片解决容量,压力,瓶颈问题, 节点存储的是部分数据
- 客户端实现分片算法(根据规则存储到不同的redis)
- proxy 代理层实现分片
- 集群自身实现分片 (%16384)