Redis
数据结构
- string:简单动态字符串 SDS,自创数据结构,相对 C 语言字符串多了长度和剩余记录,加速统计、防止溢出。key 和 value 都是 SDS,hash 映射在字典里,key 经 hash 保存,hash 重复拓展单向链表。
- list:双向链表。
- hash:哈希。
- sorted set:跳跃表 skiplist,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。解决了有序链表结构查找特定值困难的问题。
问题
- 缓存雪崩,大量数据同时过期(随机过期时间);
- 缓存击穿,?
- 缓存穿透,查不到就不缓存(缓存空对象、数据预热与降级、主动更新缓存);
- 高可用方案:主从复制、Cluster 集群。
- hot key:热 key 导致集群内某个单例出现性能瓶颈,从而使整个集群出现性能瓶颈。可利用集群分片机制,加前缀打散 key 使其落在 N 个单例中。
- big key:值最大 512MB。大 Key 分片后,某个实例内存用量远大于其他实例,导致内存不足,可能会拖累整个集群。而且,因为 Redis 单线程,hgetall、hmget、lrange 等操作 IO 吞吐量大,存在阻塞集群的可能性。可拆分大 key。
回收策略
一般采用 惰性删除 + 定期删除 的策略。
keys 和 scan 可以获取到已过期未回收的 key,可以用来恢复数据。keys 可能会造成服务卡顿,不推荐使用。
delete 和 expire 区别
delete 直接删除
expires 等待回收
hash 冲突和 rehash
Redis 使用了一个 hash 表来保存所有键值对,采用链式 hash 的方式解决冲突,对 hash 桶中冲突的多个元素使用一个链表保存。
当冲突链过长,会影响效率,会 rehash 增加 hash 桶的数量,减少单桶中的元素数量。
时间复杂度
https://blog.csdn.net/qq_23564667/article/details/110917900
服务端
服务启停
# 启动
redis-server /path/to/redis.conf
# 关停
redis-cli -p 7000 -a 123456 shutdown
# CentOS
systemctl start redisd
systemctl stop redisd
# Brew
brew services start redis
brew services stop redis
创建集群
启动端口不同的 redis 服务器后,执行下述创建命令
# 无副本,至少需要3个节点
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002
# 主从复制,主3从3
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
–cluster-replicas 副本数量
创建集群 Docker
for port in `seq 7000 7002`; do \
mkdir -p ${port}/conf \
&& PORT=${port} envsubst < redis-cluster.tmpl > ${port}/conf/redis.conf \
&& mkdir -p ${port}/data; \
done
#节点端口,即对外提供通信的端口
port ${PORT}
#requirepass 123456
#masterauth 123456
protected-mode no
daemonize no
#持久化模式
appendonly yes
#是否启用集群
cluster-enabled yes
#集群配置文件
cluster-config-file nodes.conf
#连接超时时间
cluster-node-timeout 5000
#集群各节点IP地址,需要填写宿主机ip
cluster-announce-ip host.docker.internal
#集群节点映射端口
cluster-announce-port ${PORT}
#集群总线端口
cluster-announce-bus-port 1${PORT}
127.0.0.1 host.docker.internal
version: "3"
x-image: &default-image redis:alpine
x-restart: &default-restart always
services:
node7000:
image: *default-image
restart: *default-restart
volumes:
- ./7000/conf:/etc/redis
- ./7000/data:/data
ports:
- "7000:7000"
command: redis-server /etc/redis/redis.conf
node7001:
image: *default-image
restart: *default-restart
volumes:
- ./7001/conf:/etc/redis
- ./7001/data:/data
ports:
- "7001:7001"
command: redis-server /etc/redis/redis.conf
depends_on:
- node7000
node7002:
image: *default-image
restart: *default-restart
volumes:
- ./7002/conf:/etc/redis
- ./7002/data:/data
ports:
- "7002:7002"
command: redis-server /etc/redis/redis.conf
depends_on:
- node7000
连接服务器
redis-cli -h 127.0.0.1 -p 6379 -c -n 0 -a 123456
- h 服务器地址
- p 端口
- n 库,等同 select 命令
- a 密码
- c 开启集群模式,redis cluster
scan 与 unlink
redis-cli -h 127.0.0.1 -p 6379 -n 0 -a 123456 --scan --pattern test*w | xargs redis-cli -h 127.0.0.1 -p 6379 -n 0 -a 123456 unlink
- scan 游标分步扫描 key,效果类似 keys 命令,但不会阻塞服务器
- unlink 异步删除,不阻塞,需要 redis 版本 4+
布隆过滤器
当一个元素被加入集合时,通过多个哈希函数将该元素映射成一个位数组中的多个位,并将这些位都置为 1。在查找时,通过同样的哈希函数将待查元素映射到位数组中的多个位,并检查这些位是否都为 1。如果都为 1,则说明待查元素很可能在集合中;如果不全为 1,则说明待查元素肯定不在集合中。
布隆过滤器是一种概率型数据结构,优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
高可用方案
主从模式(master、slave),哨兵模式(Sentinel),集群模式(Cluster)。
哨兵模式
哨兵模式是一个高可用的 redis 部署方案。哨兵负责监控 redis 主节点和从节点的状态,当主节点宕机时,哨兵会自动将某个从节点升级为主节点,并将其他从节点切换到新主节点。
redis 和 mysql 数据一致性
先更新数据库,再更新缓存
先更新缓存,再更新数据库
这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象。
先删除缓存,再更新数据库
先更新数据库,再删除缓存
理论上分析,先更新数据库,再删除缓存也是会出现数据不一致性的问题,但是在实际中,这个问题出现的概率并不高。
所以,「先更新数据库 + 再删除缓存」的方案,是可以保证数据一致性的。还可以设置较短的过期时间兜底。
但是,删除缓存可能会失败,可以通过重试机制提高成功率。