1. redis 简介
redis 是内存型 NoSQL 数据库,因其使用内存存储,性能优越,其读写速度远超其他类型的数据库。
1.1 redis 的应用场景
- 缓存:使用 redis 存储一些常用的主要数据可以提升响应速度(redis 和数据库的数据一致性)
- 高速读写场合:在高频次读写操作时,数据库的响应就会显著降低。而这时,使用 redis 进行高速读写,在读写结束时,异步将数据写入数据库中
2.redis 的数据类型和基本操作
2.1 redis 的数据类型
- String(二进制安全,可以存储任何数据,例如 jpg 或其他序列化字节,最大存储 512MB)
1 | update or (create if not exist) |
- Hash
1 | update or (create if not exist) field |
- List(按照插入顺序排序)
1 | 队列 |
- Set(String 的无序集合)
1 | add |
- Zset(有序集合,通过关联分数从而有序)
1 | zadd [key] [score] [member1] |
2.2 发布订阅(消息通信模式)
- 一个或多个客户端通过
subscribe [channel_key]
订阅频道 - 服务端通过
publish [channel_key] [msg]
发布消息,每个订阅的客户端都会受到消息
1 | client1 |
2.3 事务
和数据库业务不同,redis 事务非原子性,且事务中某个操作失败,不会回滚,也不会停止事务
1 | 开启事务 |
2.4 数据备份和恢复
……
2.5 Redis 管道
……
3. Reids 淘汰策略
当内存超出物理内存限制,就会使用 swap 或虚拟内存,这都是和磁盘进行交换,会导致 redis 的性能大打折扣。
所以生产环境中,都会设置maxmemory
参数限制 redis 最大占用。当 redis 内存占用超过maxmemory
后,新的数据无法写入,
redis 提供了几种淘汰策略,清理数据用于存放新的数据。
- noeviction(default): 不可写入新的数据,也不会丢弃数据
- volatile-lru: 淘汰具有过期时间且最近最少使用的 key
- allkeys-lru: 淘汰最近最少使用的 key
- volatile-ttl: 淘汰具有过期时间且 ttl 最小的 key
- volatile-random: 随机淘汰具有过期时间的 key
- allkeys-random: 随机淘汰 key
3.1 近似 LRU 算法
Redis 使用近似 LRU 算法,因为 LRU 算法还需要一个链表按照访问时间顺序保存节点,这将占用大量的额外内存,
近似 LRU 算法是 Redis 在现有的数据结构基础上使用随机采样法来淘汰元素,可以达到与 LRU 算法非常近似的效果,Redis 给每个 key 增加了一个额外的小字段,长度为 24 个 bit,用于保存最后一次访问的时间戳。
3.2 随机采样
近似 LRU 算法触发是在 Redis 执行写操作时,发现内存超出 maxmemory 的值了,就会执行一次该算法,通过随机采样出 maxmemory_samples (默认值为 5) 个 key,然后淘汰掉最旧的一个 key,如果淘汰后内存还是超出 maxmemory,那就继续随机采样淘汰,直到低于 maxmemory。
采样的数据根据 maxmemory-policy 的设置决定,如果是 allkeys,在所有的字典 key 中进行采样,如果是 volatile,则在具有过期时间 key 的字典中采样,采样的数量根据 maxmemory_samples 配置得来,采样数量越大,近似 LRU 算法的效果越接近严格 LRU 算法,
同时在 Redis3.0 中,还增加了一个淘汰池数组,大小是 maxmemory_samples,在每一次淘汰循环中,新的采样出来的 key 会和淘汰池中的 key 进行融合,淘汰掉最旧的一个 key,然后将剩余最旧的 key 列表放入淘汰池,等待下次循环。
4. Redis 集群
主从复制
sentinel 模式(哨兵)
cluster 模式
5. Redis 特殊数据结构的底层实现
5.1 Set
intset
hashtable
使用 hash 中 key 的唯一性来确定 set 中值不会重复
5.2 ZSet
当满足以下两个条件使用 ziplist,反之则使用 skiplist
- zset 元素数量少于 128
- zset 的所有元素字长都<= 64 字节
ziplist
skiplist