Redis全面指南:数据类型、高可用配置与缓存问题解决方案
Redis全面指南:数据类型、高可用配置与缓存问题解决方案
一、Redis概述与应用场景
Redis(Remote Dictionary Server)是一个开源的基于内存的键值存储系统,支持多种数据结构,读写性能可达10万+ QPS1,8。主要应用场景包括:
- 缓存热点数据:减轻数据库压力
- 会话存储:分布式Session共享
- 排行榜:利用Zset实现实时排名
- 分布式锁:通过SETNX命令实现
- 消息队列:基于List/Stream实现
二、核心数据类型与命令详解
1. 五种基础数据结构
数据类型 | 结构 | 常用命令 | 应用场景 |
---|---|---|---|
String | 二进制安全字符串 | SET key value , GET key , INCR key , SETEX key 10 value |
计数器、分布式锁 |
Hash | 字段-值映射表 | HSET user name John , HGETALL user , HINCRBY user age 1 |
存储对象属性 |
List | 双向链表 | LPUSH list 1 , RPOP list , LRANGE list 0 -1 |
消息队列、时间轴 |
Set | 无序唯一集合 | SADD tags Java , SINTER tags1 tags2 , SMEMBERS tags |
标签系统、共同好友 |
Zset | 带权重的有序集合 | ZADD rank 95 Alice , ZRANGE rank 0 10 , ZREVRANK rank Bob |
排行榜、延时队列 |
Java操作示例(Jedis):
// String操作
jedis.set("counter", "100");
jedis.incr("counter");
// Hash操作
Map<String, String> user = new HashMap<>();
user.put("name", "John");
user.put("age", "30");
jedis.hset("user:1001", user);
// Zset操作
jedis.zadd("leaderboard", 95.0, "Alice");
Set<String> topUsers = jedis.zrevrange("leaderboard", 0, 10);
###2. 高级数据结构
1.Geospatial(地理空间)
```bash
GEOADD cities 116.40 39.90 Beijing
GEODIST cities Beijing Shanghai km
2.HyperLogLog(基数统计)
PFADD uv 192.168.1.1 192.168.1.2
PFCOUNT uv
3.Bitmap(位图)
SETBIT login:2025-06-30 1001 1 # 用户1001登录
BITCOUNT login:2025-06-30 # 当日登录用户数
三、持久化与主从复制配置
1. 持久化策略
方式 | 触发机制 | 配置示例 | 特点 |
---|---|---|---|
AOF | 记录写命令 | appendonly yes | 数据更安全,文件较大 |
RDB | 定时快照 | save 900 1 | 二进制紧凑,恢复快 |
2. 主从复制配置(Linux)
主服务器配置(/etc/redis/redis.conf)
bind 0.0.0.0
requirepass master_password
从服务器配置:
bind 0.0.0.0
replicaof 192.168.1.100 6379
masterauth master_password
重启服务:
sudo systemctl restart redis-server
拓扑结构:
主节点(写入) -> 从节点1(读取)
|--> 从节点2(读取)
四、哨兵模式高可用方案
- 哨兵配置(sentinel.conf)
sentinel monitor mymaster 192.168.1.100 6379 2
sentinel auth-pass mymaster master_password
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
- Java客户端连接哨兵
JedisPoolConfig poolConfig = new JedisPoolConfig();
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.1.101:26379");
sentinels.add("192.168.1.102:26379");
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels, poolConfig);
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value"); // 自动路由到主节点
}
故障转移流程:
- 哨兵检测到主节点下线
- 哨兵集群投票选举领导者
- 领导者哨兵执行故障转移
- 切换从节点为新主节点
- 客户端更新连接信息
五、缓存问题解决方案与Java实现
- 缓存穿透(访问不存在数据)
解决方案:
- 布隆过滤器:预加载数据指纹
- 空值缓存:设置短过期时间
public String getData(String key) {
// 1. 尝试从缓存获取
String value = jedis.get(key);
if (value == null) {
// 2. 布隆过滤器校验
if (!bloomFilter.mightContain(key)) {
return null;
}
// 3. 空值缓存
jedis.setex(key, 60, "NULL");
}
return value;
}
- 缓存击穿(热点Key失效)
解决方案:
- 互斥锁:仅允许一个线程重建缓存
- 逻辑过期:异步更新缓存
public String getHotData(String key) {
String value = jedis.get(key);
if (value == null) {
// 尝试获取分布式锁
if (lock.tryLock()) {
try {
// 双重检查
value = jedis.get(key);
if (value == null) {
value = db.getData(key);
jedis.setex(key, 300, value);
}
} finally {
lock.unlock();
}
}
}
return value;
}
- 缓存雪崩(大量Key同时失效)
解决方案:
- 随机过期时间:分散失效时间点
- 多级缓存:本地缓存+Redis
- 熔断降级:Hystrix实现服务降级
// 设置随机过期时间
int expireTime = 3600 + new Random().nextInt(600); // 3600~4200秒
jedis.setex(key, expireTime, value);
六、Redis使用最佳实践
1.内存优化
maxmemory 2gb # 限制最大内存
maxmemory-policy volatile-lru # 使用LRU淘汰策略
2.管道批处理
Pipeline p = jedis.pipelined();
for (int i=0; i<1000; i++) {
p.set("key" + i, "value" + i);
}
p.sync();
3.Lua脚本保证原子性
-- 限流脚本
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local count = tonumber(redis.call('get', key) or "0")
if count + 1 > limit then
return 0
else
redis.call('INCR', key)
return 1
end
扩展建议:
- 生产环境建议使用Redis 6.0+的多线程IO模型
- 集群规模较大时采用Redis Cluster分片方案
- 监控重要指标:内存使用率、命中率、延迟