在分布式系统架构中,Redis 凭借其超高的性能、丰富的数据结构和灵活的部署方式,成为分布式缓存领域的事实标准。作为一款开源的内存数据存储,Redis 不仅能作为缓存使用,还能承担消息队列、分布式锁、计数器等多种角色。本文将从基础用法到高级特性,全面解析 Redis 的实战技巧,帮助开发者构建高效、可靠的 Redis 应用。
Redis(Remote Dictionary Server)是一款基于内存的键值对存储系统,其核心优势使其在众多缓存产品中脱颖而出:
Redis 的典型应用场景包括:
# 下载最新稳定版wget https://download.redis.io/releases/redis-7.2.4.tar.gztar xzf redis-7.2.4.tar.gzcd redis-7.2.4# 编译安装makemake install# 启动服务redis-server redis.conf# 客户端连接redis-cli -h localhost -p 6379
# 拉取镜像docker pull redis:7.2.4# 启动容器docker run -d --name redis -p 6379:6379 \ -v /data/redis/conf:/etc/redis \ -v /data/redis/data:/data \ redis:7.2.4 redis-server /etc/redis/redis.conf# 进入容器docker exec -it redis redis-cli
Redis 的配置文件(redis.conf)中有多个关键参数需要根据实际场景调整:
# 端口号port 6379# 绑定IP,生产环境建议指定具体IPbind 0.0.0.0# 密码认证requirepass your_secure_password# 最大内存限制,建议设置为物理内存的70-80%maxmemory 4gb# 内存淘汰策略,当内存满时的处理方式maxmemory-policy allkeys-lru# 持久化配置save 900 1 # 900秒内至少1个键被修改则触发RDBsave 300 10 # 300秒内至少10个键被修改则触发RDBappendonly yes # 开启AOF持久化appendfsync everysec # 每秒同步一次AOF文件
常用内存淘汰策略:
Redis 提供了丰富的命令集,以下是常用数据结构的基本操作:
String 是 Redis 最基本的数据类型,可存储字符串、整数和浮点数:
# 设置键值对,过期时间30秒SET user:1 "张三" EX 30# 获取值GET user:1# 自增(整数)INCR counter:pageviews# 自减(整数)DECR counter:stock# 追加字符串APPEND user:1 "_VIP"
Hash 适合存储对象,可对对象的字段进行单独操作:
# 设置用户信息HSET user:1 name "张三" age 30 email "zhangsan@example.com"# 获取用户的name字段HGET user:1 name# 获取用户的所有字段和值HGETALL user:1# 获取用户的所有字段HKEYS user:1# 获取用户的所有值HVALS user:1# 删除用户的age字段HDEL user:1 age
List 是有序的字符串列表,可用于实现队列、栈等数据结构:
# 从左侧插入元素LPUSH queue:tasks task1 task2 task3# 从右侧弹出元素(队列模式)RPOP queue:tasks# 从左侧弹出元素(栈模式)LPOP queue:tasks# 获取列表中的元素LRANGE queue:tasks 0 -1 # 获取所有元素
Set 是无序的字符串集合,自动去重,支持交集、并集等操作:
# 添加元素SADD set:tags java python redis# 判断元素是否存在SISMEMBER set:tags java# 获取所有元素SMEMBERS set:tags# 计算两个集合的交集SINTER set:tags1 set:tags2
Sorted Set 是有序的集合,每个元素关联一个分数,可用于排行榜等场景:
# 添加元素(用户ID和积分)ZADD rank:users 100 user1 200 user2 150 user3# 获取排名前2的用户(升序)ZRANGE rank:users 0 1 WITHSCORES# 获取排名前2的用户(降序)ZREVRANGE rank:users 0 1 WITHSCORES# 增加用户积分ZINCRBY rank:users 50 user1
Redis 提供两种持久化方式,可单独使用或结合使用:
RDB(Redis Database)通过创建内存数据的快照来实现持久化:
# 手动触发RDB快照SAVE # 同步操作,阻塞主线程BGSAVE # 异步操作,后台执行
AOF(Append Only File)通过记录所有写操作来实现持久化:
# 开启AOF(在redis.conf中配置)appendonly yes# AOF同步策略appendfsync always # 每次写操作都同步(最安全,性能最差)appendfsync everysec # 每秒同步一次(平衡安全和性能)appendfsync no # 由操作系统决定何时同步(性能最好,安全性最差)
混合持久化结合了 RDB 和 AOF 的优点,AOF 文件头部包含 RDB 数据,尾部包含增量的 AOF 日志:
# 开启混合持久化(在redis.conf中配置)aof-use-rdb-preamble yes
主从复制实现了数据的多副本存储,提高了数据安全性和读操作性能:
从节点配置文件:
# 配置主节点地址和端口replicaof master_ip master_port# 如果主节点有密码认证masterauth master_password
或通过命令动态配置:
# 在从节点执行REPLICAOF master_ip master_portCONFIG SET masterauth "master_password"
哨兵(Sentinel)用于监控主从集群,实现自动故障转移:
# 监控主节点,名称为mymaster,quorum为2(至少2个哨兵同意才判定主节点下线)sentinel monitor mymaster master_ip master_port 2# 判定主节点下线的超时时间(毫秒)sentinel down-after-milliseconds mymaster 30000# 故障转移的超时时间(毫秒)sentinel failover-timeout mymaster 180000# 同时最多有1个从节点同步新的主节点sentinel parallel-syncs mymaster 1
redis-sentinel sentinel.conf
Redis Cluster 用于实现大规模部署,通过数据分片提高存储容量和并发处理能力:
cluster-enabled yescluster-config-file nodes.confcluster-node-timeout 5000
redis-cli --cluster create \ node1_ip:node1_port \ node2_ip:node2_port \ node3_ip:node3_port \ node4_ip:node4_port \ node5_ip:node5_port \ node6_ip:node6_port \ --cluster-replicas 1
其中--cluster-replicas 1表示每个主节点有 1 个从节点。
Jedis 是 Redis 官方推荐的 Java 客户端,使用简单,功能全面。
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>4.4.6</version></dependency>
// 创建Jedis实例Jedis jedis = new Jedis("localhost", 6379);// 认证jedis.auth("your_password");// String操作jedis.set("user:1", "张三");String userName = jedis.get("user:1");// Hash操作Map<String, String> userInfo = new HashMap<>();userInfo.put("name", "李四");userInfo.put("age", "25");jedis.hset("user:2", userInfo);String userAge = jedis.hget("user:2", "age");// 关闭连接jedis.close();
// 连接池配置JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(100); // 最大连接数poolConfig.setMaxIdle(20); // 最大空闲连接数poolConfig.setMinIdle(5); // 最小空闲连接数poolConfig.setTestOnBorrow(true); // 获取连接时测试连接是否可用// 创建连接池JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379, 2000, "your_password");// 从连接池获取连接try (Jedis jedis = jedisPool.getResource()) { // 执行操作 jedis.set("test:key", "test_value");}
Spring Data Redis 简化了 Redis 在 Spring 应用中的使用,提供了模板类和注解支持。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>
@Configurationpublic class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); // 设置Key序列化器 StringRedisSerializer keySerializer = new StringRedisSerializer(); template.setKeySerializer(keySerializer); template.setHashKeySerializer(keySerializer); // 设置Value序列化器(使用Jackson2JsonRedisSerializer) Jackson2JsonRedisSerializer<Object> valueSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); valueSerializer.setObjectMapper(mapper); template.setValueSerializer(valueSerializer); template.setHashValueSerializer(valueSerializer); template.afterPropertiesSet(); return template; }}
@Servicepublic class UserService { @Autowired private RedisTemplate<String, Object> redisTemplate; public void saveUser(User user) { // 存储用户信息 redisTemplate.opsForValue().set("user:" + user.getId(), user, 1, TimeUnit.HOURS); // 存储用户ID到集合 redisTemplate.opsForSet().add("users", user.getId()); } public User getUser(Long id) { return (User) redisTemplate.opsForValue().get("user:" + id); } public Set<Object> getAllUserIds() { return redisTemplate.opsForSet().members("users"); }}
利用 Redis 的 SET NX 命令实现分布式锁,解决分布式系统中的并发问题:
public class RedisDistributedLock { private RedisTemplate<String, Object> redisTemplate; private String lockKey; private String lockValue; // 用于标识锁的持有者,避免误释放 private int expireTime = 30; // 锁的过期时间(秒) public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate, String lockKey) { this.redisTemplate = redisTemplate; this.lockKey = lockKey; this.lockValue = UUID.randomUUID().toString(); } // 获取锁 public boolean tryLock() { return redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expireTime, TimeUnit.SECONDS); } // 释放锁(使用Lua脚本保证原子性) public boolean unlock() { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) " + "else " + "return 0 " + "end"; Long result = (Long) redisTemplate.execute( new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), lockValue ); return result != null && result > 0; }}
基于 Redis 的计数器实现接口限流,控制单位时间内的请求次数:
public class RedisRateLimiter { private RedisTemplate<String, Object> redisTemplate; private int maxRequests; // 单位时间内最大请求数 private int period; // 时间周期(秒) public RedisRateLimiter(RedisTemplate<String, Object> redisTemplate, int maxRequests, int period) { this.redisTemplate = redisTemplate; this.maxRequests = maxRequests; this.period = period; } // 检查是否允许请求 public boolean</doubaocanvas>
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。