Redis 核心功能全解析:功能描述、应用场景与 Java 实战

Redis 核心功能全解析:功能描述、应用场景与 Java 实战

本文将全面覆盖 Redis 核心功能,从功能本质、应用场景到Java项目实战代码逐一解析,所有代码可直接复用,互相探讨

我将主要从数据结构、内存管理、持久化、分布式锁、主从复制、发布/订阅、哨兵、集群、布隆过滤器、性能优化、事务、Lua 脚本、Geo 地理信息 等全方位的介绍 Redis

Redis 核心功能

一、基础数据结构

Redis 核心基础是5种原生数据结构,是所有高级功能的底层支撑,Java项目种通过Redis客户端直接操作。

1.字符串

Redis 最基础的数据类型,二进制安全(可存储文本、图片Base64等),支持字符串拼接、自增自减、过期时间设置等操作,value最大长度512MB。
应用场景

复制代码
缓存单个值:如用户信息JSON串、商品详情 
计数器:文章阅读量、接口调用次数 
分布式限流:基于自增 + 过期时间
分布式锁的基础实现:setnx + expire

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisStringDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 缓存用户信息(JSON格式)
    public void cacheUserInfo(String userId, String userJson) {
        // 设置key过期时间为1小时
        stringRedisTemplate.opsForValue().set("user:info:" + userId, userJson, 1, TimeUnit.HOURS);
    }

    // 2. 计数器(文章阅读量自增)
    public Long incrementArticleViewCount(String articleId) {
        String key = "article:view:count:" + articleId;
        // 自增1,不存在则默认从0开始
        return stringRedisTemplate.opsForValue().increment(key, 1);
    }

    // 3. 分布式限流(单位时间内接口最大调用次数)
    public boolean limitApiCall(String userId, String apiName, int maxCount, long period) {
        String key = "limit:api:" + userId + ":" + apiName;
        // 自增1,返回当前值
        Long currentCount = stringRedisTemplate.opsForValue().increment(key, 1);
        // 第一次调用时设置过期时间
        if (currentCount != null && currentCount == 1) {
            stringRedisTemplate.expire(key, period, TimeUnit.SECONDS);
        }
        // 超过最大次数则限流
        return currentCount != null && currentCount <= maxCount;
    }
}

2.哈希(Hash)

键值对集合(field-value),类似Java的HashMap,支持单个field增删改查,也可批量操作,适合存储结构化数据。
应用场景

复制代码
存储对象类数据:如用户基本信息、商品属性 
购物车:key为用户ID,field为商品ID,value为数量
配置项存储:如系统参数,field为参数名

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;

@Component
public class RedisHashDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 存储用户基本信息(结构化数据)
    public void saveUserInfo(String userId, String username, String phone, String email) {
        String key = "user:hash:" + userId;
        // 批量设置field-value
        stringRedisTemplate.opsForHash().putAll(key, Map.of(
                "username", username,
                "phone", phone,
                "email", email
        ));
        // 单独修改某个field
        stringRedisTemplate.opsForHash().put(key, "phone", "13800138000");
    }

    // 2. 购物车操作(添加商品、修改数量、删除商品)
    public void addCartItem(String userId, String productId, int quantity) {
        String key = "cart:" + userId;
        // 商品数量自增(不存在则默认0,自增后为quantity)
        stringRedisTemplate.opsForHash().increment(key, productId, quantity);
    }

    public void removeCartItem(String userId, String productId) {
        String key = "cart:" + userId;
        stringRedisTemplate.opsForHash().delete(key, productId);
    }

    // 获取用户购物车所有商品
    public Map<Object, Object> getUserCart(String userId) {
        String key = "cart:" + userId;
        return stringRedisTemplate.opsForHash().entries(key);
    }
}

3.列表(List)

有序字符串列表(双向链表实现),支持从头部/尾部插入、删除元素,按索引访问,可实现栈(LIFO)、队列(FIFO)。
应用场景

复制代码
消息队列:简单版,如异步通知、日志收集 
最新消息列表:如朋友圈、系统公告 
排行榜:基于时间顺序的最新榜单

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;

@Component
public class RedisListDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 简单消息队列(生产者-消费者模式)
    public void sendMessage(String queueName, String message) {
        // 从列表尾部插入消息
        stringRedisTemplate.opsForList().rightPush(queueName, message);
    }

    // 消费者(阻塞获取,避免空轮询)
    public String consumeMessage(String queueName, long timeout) {
        // 从列表头部获取消息,超时返回null
        return stringRedisTemplate.opsForList().leftPop(queueName, timeout, java.util.concurrent.TimeUnit.SECONDS);
    }

    // 2. 最新公告列表(保留最近100条)
    public void addAnnouncement(String announcement) {
        String key = "announcement:latest";
        // 尾部插入新公告
        stringRedisTemplate.opsForList().rightPush(key, announcement);
        // 限制列表长度为100,超出则删除头部旧数据
        stringRedisTemplate.opsForList().trim(key, -100, -1);
    }

    // 获取最近10条公告
    public List<String> getLatestAnnouncements(int count) {
        String key = "announcement:latest";
        // 从头部开始获取前count条(0到count-1)
        return stringRedisTemplate.opsForList().range(key, 0, count - 1);
    }
}

4.集合(Set)

无序、唯一的字符串集合,支持交集、并集、差集运算,底层是哈希表,查找、添加、删除复杂度O(1)。
应用场景

复制代码
标签系统:如文章标签、商品分类 
社交关系:用户关注列表、好友列表 
去重操作:如日志去重、抽奖防重复参与 
共同好友/兴趣推荐:基于交集运算

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;

@Component
public class RedisSetDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 标签系统(给文章添加标签、查询带某标签的文章)
    public void addArticleTags(String articleId, String... tags) {
        String key = "article:tags:" + articleId;
        stringRedisTemplate.opsForSet().add(key, tags);
    }

    public Set<String> getArticlesByTag(String tag) {
        // 假设key格式为"tag:articles:标签名",存储该标签下的所有文章ID
        String key = "tag:articles:" + tag;
        return stringRedisTemplate.opsForSet().members(key);
    }

    // 2. 社交关系(添加好友、获取共同好友)
    public void addFriend(String userId, String friendId) {
        String key = "user:friends:" + userId;
        stringRedisTemplate.opsForSet().add(key, friendId);
        // 双向好友,同时添加到对方列表
        stringRedisTemplate.opsForSet().add("user:friends:" + friendId, userId);
    }

    public Set<String> getCommonFriends(String userId1, String userId2) {
        String key1 = "user:friends:" + userId1;
        String key2 = "user:friends:" + userId2;
        // 计算两个集合的交集(共同好友)
        return stringRedisTemplate.opsForSet().intersect(key1, key2);
    }

    // 3. 抽奖防重复(用户ID去重)
    public boolean joinLottery(String lotteryId, String userId) {
        String key = "lottery:participants:" + lotteryId;
        // 添加成功返回true(未参与过),失败返回false(已参与)
        return stringRedisTemplate.opsForSet().add(key, userId);
    }
}

5.有序集合(Sorted Set / Zset)

有序、唯一的字符串集合,每个元素关联一个分数(score),按分数排序,支持按分数范围、排名范围查询。
应用场景

复制代码
排行榜:如游戏积分、商品销量、文章点赞数 
带权重的消息队列:按优先级处理 
范围统计:如查询积分Top10用户、某分数段用户

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;

@Component
public class RedisZSetDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 商品销量排行榜(按销量降序)
    public void incrementProductSales(String productId, long sales) {
        String key = "rank:product:sales";
        // 分数(销量)自增,不存在则默认0
        stringRedisTemplate.opsForZSet().incrementScore(key, productId, sales);
    }

    // 获取销量TOP10商品(从高到低)
    public Set<ZSetOperations.TypedTuple<String>> getSalesTop10() {
        String key = "rank:product:sales";
        // 0-9表示前10名,desc表示降序
        return stringRedisTemplate.opsForZSet().reverseRangeWithScores(key, 0, 9);
    }

    // 2. 用户积分排行榜(查询用户排名和积分)
    public Long getUserRank(String userId) {
        String key = "rank:user:points";
        // reverseRank返回降序排名(第1名返回0)
        return stringRedisTemplate.opsForZSet().reverseRank(key, userId);
    }

    public Double getUserPoints(String userId) {
        String key = "rank:user:points";
        return stringRedisTemplate.opsForZSet().score(key, userId);
    }

    // 3. 范围查询(积分在100-500之间的用户)
    public Set<String> getUsersByPointsRange(double min, double max) {
        String key = "rank:user:points";
        return stringRedisTemplate.opsForZSet().rangeByScore(key, min, max);
    }
}

二、高级功能

1.内存管理

Redis 提供灵活的内存淘汰策略和过期时间机制,控制内存使用上限,避免内存溢出,同时自动清理过期数据。

复制代码
内存上限配置:通过 maxmemory 设置最大可用内存 
淘汰策略:如 allkeys-lru(淘汰最近最少使用的键)、volatile-lru(仅淘汰带过期时间的最近最少使用键)等 
过期时间:支持给键设置 EX(秒)、PX(毫秒)过期,底层通过过期时间字典和惰性删除 + 定期删除机制实现

应用场景

复制代码
缓存系统:自动清理过期缓存,避免缓存雪崩 
临时数据存储:如验证码、临时令牌,自动过期无需手动删除
高并发场景下控制内存占用:避免缓存过多导致OOM

Java项目配置与使用
Redis 配置文件(redis.conf)

yaml 复制代码
# 设置最大内存为4GB
maxmemory 4294967296
# 内存淘汰策略:淘汰最近最少使用的键(适用于缓存场景)
maxmemory-policy allkeys-lru
# 淘汰采样数量(默认5,值越大越精准但性能消耗略高)
maxmemory-samples 5

Java种设置过期时间(Spring Data Redis)

java 复制代码
// 1. 给String类型设置过期时间(2分钟)
stringRedisTemplate.opsForValue().set("verify:code:13800138000", "666666", 2, TimeUnit.MINUTES);

// 2. 给Hash类型设置过期时间
String userKey = "user:hash:1001";
stringRedisTemplate.opsForHash().putAll(userKey, Map.of("username", "zhangsan"));
stringRedisTemplate.expire(userKey, 1, TimeUnit.HOURS);

// 3. 批量设置过期时间(通过Pipeline优化性能)
stringRedisTemplate.executePipelined((RedisCallback<Void>) connection -> {
    for (int i = 1002; i <= 1010; i++) {
        String key = "user:hash:" + i;
        connection.hashCommands().hSet(key.getBytes(), "username".getBytes(), ("user" + i).getBytes());
        connection.expire(key.getBytes(), 3600); // 1小时过期
    }
    return null;
});

2.持久化

Redis 支持两种持久化机制,将内存中的数据写入磁盘,避免服务重启后数据丢失

复制代码
RDB(Redis Database):在指定时间间隔内生成数据集的快照(二进制文件),适合备份和大规模数据恢复 
AOF(Append Only File):记录每一条写命令(文本格式),重启时重新执行命令恢复数据,数据一致性更高

应用场景

复制代码
数据备份:如每日凌晨生成RDB快照,用于灾备 
服务重启后数据恢复:生产环境常用 RDB+AOF混合模式
跨环境数据迁移:通过RDB文件导入导出数据

Java项目配置与使用
Redis 配置文件(redis.conf)

yaml 复制代码
# ========== RDB配置 ==========
# 900秒内有1个键修改则触发快照
save 900 1
# 300秒内有10个键修改则触发快照
save 300 10
# 60秒内有10000个键修改则触发快照
save 60 10000
# 快照文件存储路径(默认当前目录)
dir ./
# 快照文件名(默认dump.rdb)
dbfilename dump.rdb

# ========== AOF配置 ==========
# 开启AOF(默认关闭,生产环境建议开启)
appendonly yes
# AOF文件名(默认appendonly.aof)
appendfilename "appendonly.aof"
# AOF同步策略:everysec(每秒同步,平衡性能和一致性)
appendfsync everysec
# 重写触发条件:当AOF文件大小是上次重写后大小的100%且大于64MB
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Java中手动触发持久化(慎用,生产环境避免频繁调用)

java 复制代码
// 手动触发RDB快照(同步,会阻塞Redis服务,建议用bgSave)
stringRedisTemplate.execute((RedisCallback<Void>) connection -> {
    connection.serverCommands().save();
    return null;
});

// 手动触发RDB快照(异步,不阻塞服务)
stringRedisTemplate.execute((RedisCallback<Void>) connection -> {
    connection.serverCommands().bgSave();
    return null;
});

// 手动触发AOF重写(异步)
stringRedisTemplate.execute((RedisCallback<Void>) connection -> {
    connection.serverCommands().bgRewriteAof();
    return null;
});

3.分布式锁

Redis 分布式锁是基于 Redis 原子操作实现的跨服务、跨进程互斥锁,用于在分布式系统中保证同一时刻只有一个线程 / 进程能访问共享资源,从而解决并发冲突(如超卖、数据错乱、重复执行等问题)。其设计核心依赖 Redis 的原子性、过期时间和唯一标识机制,是分布式系统中解决资源竞争的首选方案。
应用场景

复制代码
秒杀 / 抢购系统:防止超卖 
分布式任务调度:避免重复执行 
共享资源更新:防止数据错乱 
唯一标识生成:避免重复
长任务并发控制:防止中途锁释放

Java实战(Spring Data Redis)

java 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLockRedisson {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 可重入锁(生产最常用)
     * @param lockKey 锁Key
     * @param waitTime 最大等待时间(秒):获取锁失败时,最多等待多久
     * @param leaseTime 锁自动释放时间(秒):-1表示启用Watch Dog自动续约
     * @return 加锁是否成功
     */
    public boolean lock(String lockKey, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试加锁:waitTime秒内获取锁,获取成功后leaseTime秒自动释放
            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    /**
     * 解锁方法
     * @param lockKey 锁Key
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        // 仅释放当前线程持有的锁
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * 实战1:秒杀防超卖(短任务场景)
     */
    public boolean seckill(String productId, String userId) {
        String lockKey = "lock:seckill:" + productId;
        try {
            // 加锁:最多等待10秒,获取成功后5秒自动释放
            boolean locked = lock(lockKey, 10, 5);
            if (!locked) {
                System.out.printf("用户%s秒杀商品%s失败:获取锁超时%n", userId, productId);
                return false;
            }

            // 业务逻辑:查询库存→扣减库存→生成订单(同原生实现)
            String stockKey = "product:stock:" + productId;
            String stockStr = redissonClient.getString(stockKey);
            if (stockStr == null || Integer.parseInt(stockStr) <= 0) {
                System.out.printf("用户%s秒杀商品%s失败:库存不足%n", userId, productId);
                return false;
            }

            redissonClient.getAtomicLong(stockKey).decrementAndGet();
            System.out.printf("用户%s秒杀商品%s成功%n", userId, productId);
            return true;

        } finally {
            // 解锁
            unlock(lockKey);
        }
    }

    /**
     * 实战2:长任务处理(启用锁续约)
     */
    public boolean processLargeFile(String fileId, String userId) {
        String lockKey = "lock:file:process:" + fileId;
        try {
            // 加锁:最多等待10秒,leaseTime=-1(启用Watch Dog自动续约)
            boolean locked = lock(lockKey, 10, -1);
            if (!locked) {
                System.out.printf("用户%s处理文件%s失败:未获取到锁%n", userId, fileId);
                return false;
            }

            // 长任务执行(如文件上传、解析,模拟2分钟)
            System.out.printf("用户%s开始处理文件%s...%n", userId, fileId);
            Thread.sleep(120000);
            System.out.printf("用户%s处理文件%s成功%n", userId, fileId);
            return true;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            // 解锁
            unlock(lockKey);
        }
    }
}

4.主从复制

通过主从架构实现数据同步,主节点(Master)处理写请求,从节点(Slave)复制主节点数据并处理读请求,支持一主多从、多级从节点。

复制代码
核心作用:读写分离(提升读吞吐量)、数据备份(从节点可作为备份节点)、故障转移(主节点故障后从节点可晋升为主)
同步机制:全量同步(从节点首次连接主节点)+ 增量同步(主节点后续写操作同步到从节点)

应用场景

复制代码
高读并发场景:如电商商品详情查询、新闻列表浏览 
数据备份与容灾:从节点部署在不同机房
避免单节点压力过大:写请求集中在主节点,读请求分散到从节点)

Java项目配置与使用
Redis主从配置(无需修改Java代码,通过Redis配置实现)

主节点配置(redis-master.conf):默认无需特殊配置,只需开启端口(6379)并允许从节点连接

从节点配置(redis-slave-conf):

yaml 复制代码
# 从节点端口(避免与主节点冲突)
port 6380
# 配置主节点地址和端口
replicaof 192.168.1.100 6379
# 主节点有密码时配置
masterauth "redis123456"
# 从节点只读(默认开启,避免从节点处理写请求)
replica-read-only yes

Java中读写分离实现(Spring Data Rdis 配置)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class RedisMasterSlaveConfig {

    // 主节点连接工厂(写操作)
    @Bean("masterRedisConnectionFactory")
    public RedisConnectionFactory masterConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName("192.168.1.100");
        config.setPort(6379);
        config.setPassword("redis123456");
        
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(20);
        poolConfig.setMinIdle(5);
        
        return new JedisConnectionFactory(config, poolConfig);
    }

    // 从节点连接工厂(读操作)
    @Bean("slaveRedisConnectionFactory")
    public RedisConnectionFactory slaveConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName("192.168.1.101");
        config.setPort(6380);
        config.setPassword("redis123456");
        
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(200);
        poolConfig.setMaxIdle(50);
        poolConfig.setMinIdle(10);
        
        return new JedisConnectionFactory(config, poolConfig);
    }

    // 写操作Template(关联主节点)
    @Bean("writeRedisTemplate")
    public StringRedisTemplate writeRedisTemplate(@org.springframework.beans.factory.annotation.Qualifier("masterRedisConnectionFactory") RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }

    // 读操作Template(关联从节点)
    @Bean("readRedisTemplate")
    public StringRedisTemplate readRedisTemplate(@org.springframework.beans.factory.annotation.Qualifier("slaveRedisConnectionFactory") RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}

Java中使用读写分离

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component
public class RedisMasterSlaveDemo {

    // 写操作(主节点)
    @Resource(name = "writeRedisTemplate")
    private StringRedisTemplate writeRedisTemplate;

    // 读操作(从节点)
    @Resource(name = "readRedisTemplate")
    private StringRedisTemplate readRedisTemplate;

    // 写操作(如更新商品库存)
    public void updateProductStock(String productId, int stock) {
        String key = "product:stock:" + productId;
        writeRedisTemplate.opsForValue().set(key, String.valueOf(stock));
    }

    // 读操作(如查询商品库存)
    public String getProductStock(String productId) {
        String key = "product:stock:" + productId;
        return readRedisTemplate.opsForValue().get(key);
    }
}

5.发布订阅(Pub/Sub)

Redis原生支持发布订阅模式,生产者(Publisher)发布消息到频道(Channel),消费者(Subscriber)订阅频道并接收消息,支持多订阅者、多频道
应用场景

复制代码
实时通知:如订单状态变更通知、系统公告推送 
事件触发:如用户注册成功后触发积分赠送、短信发送

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;

@Component
public class RedisPubSubDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisMessageListenerContainer redisMessageListenerContainer;

    // 1. 生产者:发布消息到频道
    public void publishMessage(String channel, String message) {
        stringRedisTemplate.convertAndSend(channel, message);
    }

    // 2. 消费者:订阅频道(监听订单状态变更)
    @PostConstruct
    public void subscribeOrderChannel() {
        String channel = "channel:order:status";
        // 注册监听器
        redisMessageListenerContainer.addMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message, byte[] pattern) {
                // 接收消息并处理
                String messageBody = new String(message.getBody());
                String channelName = new String(message.getChannel());
                System.out.println("从频道 " + channelName + " 接收消息:" + messageBody);

                // 业务处理逻辑(如推送通知给用户)
                handleOrderStatusChange(messageBody);
            }
        }, new ChannelTopic(channel));
    }

    // 处理订单状态变更消息
    private void handleOrderStatusChange(String message) {
        // 解析消息(假设消息为JSON格式)
        System.out.println("处理订单状态变更:" + message);
    }

    // 示例:发布订单支付成功消息
    public void publishOrderPaidMessage(String orderId) {
        String message = "{\"orderId\":\"" + orderId + "\",\"status\":\"PAID\",\"time\":\"2024-01-01 12:00:00\"}";
        publishMessage("channel:order:status", message);
    }
}

6.哨兵

Redis 哨兵是主从架构的高可用解决方案,由多个哨兵节点组成集群,负责监控主从节点状态:

复制代码
故障检测:实时监控主节点是否存活,若主节点宕机,自动触发故障转移
自动故障转移:将某个从节点晋升为主节点,其他从节点切换到新主节点同步数据
配置管理:客户端通过哨兵获取主节点地址,无需硬编码主节点IP

应用场景

复制代码
生产环境主从架构的高可用保障:避免主节点故障导致服务不可用 
无人值守的故障恢复:无需人工干预切换主从

Java项目配置与使用
哨兵配置文件(sentinel.conf)

yaml 复制代码
# 哨兵节点端口(每个哨兵节点端口不同,如26379、26380、26381)
port 26379
# 监控主节点:名称(自定义)、主节点IP:端口、故障判定所需的哨兵节点数量(quorum)
sentinel monitor mymaster 192.168.1.100 6379 2
# 主节点密码(若有)
sentinel auth-pass mymaster redis123456
# 主节点无响应超时时间(默认30秒,单位毫秒)
sentinel down-after-milliseconds mymaster 30000
# 故障转移超时时间(默认180秒)
sentinel failover-timeout mymaster 180000

Java中通过哨兵连接Redis(Spring Data Redis 配置)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;

@Configuration
public class RedisSentinelConfig {

    @Bean
    public RedisSentinelConfiguration sentinelConfiguration() {
        RedisSentinelConfiguration config = new RedisSentinelConfiguration();
        // 主节点名称(需与哨兵配置一致)
        config.master("mymaster");
        // 哨兵节点集合
        Set<String> sentinelNodes = new HashSet<>();
        sentinelNodes.add("192.168.1.100:26379");
        sentinelNodes.add("192.168.1.101:26380");
        sentinelNodes.add("192.168.1.102:26381");
        config.setSentinels(sentinelNodes);
        // Redis密码
        config.setPassword("redis123456");
        return config;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory(RedisSentinelConfiguration sentinelConfig) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(200);
        poolConfig.setMaxIdle(50);
        poolConfig.setMinIdle(10);
        return new JedisConnectionFactory(sentinelConfig, poolConfig);
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}

Java中使用(与普通Redis使用方式一致,哨兵自动处理故障转移)

java 复制代码
// 无需修改业务代码,直接使用StringRedisTemplate即可
@Component
public class RedisSentinelDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public void setValue(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value, 1, java.util.concurrent.TimeUnit.HOURS);
    }

    public String getValue(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
}

7.集群(Cluster)

Redis Cluster 是分布式解决方案,将数据分片存储在多个节点(最少3主3从),每个主节点负责一部分哈希槽(共16384个),支持水平扩容和高可用。

复制代码
核心特性:数据分片(按key的哈希值分配到不同节点)、自动故障转移(主节点故障后从节点晋升)、水平扩容(新增节点后重新分配哈希槽)
优势:解决单节点内存上限问题,支持大规模数据存储和高并发访问

应用场景

复制代码
大规模数据存储:如千万级别用户的会话存储、亿级商品缓存 
超高并发场景:如电商秒杀、双11峰值流量 
需水平扩容的业务:避免单节点硬件瓶颈

Java项目配置与使用
Redis Cluster集群搭建

复制代码
每个节点配置 cluster-enabled yes(开启集群模式) 
每个节点配置 cluster-config-file nodes.conf(集群节点信息文件) 
通过 redis-cli --cluster create 命令创建集群(如3主3从)
bash 复制代码
redis-cli --cluster create 192.168.1.100:6379 192.168.1.101:6379 192.168.1.102:6379 192.168.1.103:6380 192.168.1.104:6380 192.168.1.105:6380 --cluster-replicas 1 -a redis123456

Java中连接Redis Cluster(Spring Data Redis 配置)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Arrays;
import java.util.List;

@Configuration
public class RedisClusterConfig {

    @Bean
    public RedisClusterConfiguration clusterConfiguration() {
        RedisClusterConfiguration config = new RedisClusterConfiguration();
        // 集群节点列表(只需配置主节点,从节点会自动发现)
        List<String> clusterNodes = Arrays.asList(
                "192.168.1.100:6379",
                "192.168.1.101:6379",
                "192.168.1.102:6379"
        );
        config.setClusterNodes(clusterNodes);
        // 最大重定向次数(默认3)
        config.setMaxRedirects(3);
        // Redis密码
        config.setPassword("redis123456");
        return config;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory(RedisClusterConfiguration clusterConfig) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(300);
        poolConfig.setMaxIdle(100);
        poolConfig.setMinIdle(20);
        // 开启集群模式支持
        return new JedisConnectionFactory(clusterConfig, poolConfig);
    }

    @Bean
    public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}

Java中使用 Redis Cluster(支持所有基础操作,自动处理分片)

java 复制代码
@Component
public class RedisClusterDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 存储用户会话(自动分片到对应节点)
    public void saveUserSession(String sessionId, String userInfo) {
        String key = "session:" + sessionId;
        stringRedisTemplate.opsForValue().set(key, userInfo, 2, java.util.concurrent.TimeUnit.HOURS);
    }

    // 获取用户会话(自动路由到存储该key的节点)
    public String getUserSession(String sessionId) {
        String key = "session:" + sessionId;
        return stringRedisTemplate.opsForValue().get(key);
    }

    // ZSet操作(排行榜,自动分片)
    public void incrementRank(String rankKey, String member, double score) {
        stringRedisTemplate.opsForZSet().incrementScore(rankKey, member, score);
    }
}

8.布隆过滤器(Bloom Filter)

Redis 4.0+ 支持布隆过滤器插件(redisbloom),是一种空间高效的概率性数据结构,用于判断一个元素是否在集合中。

复制代码
核心特性:查询效率高(O(k),k为哈希函数个数)、空间占用小,存在误判率(不会漏判,可能把不存在的元素判定为存在)
原理:通过多个哈希函数将元素映射到位图的多个位置,标记为1;查询时若所有映射位置都是1,则可能存在,否则一定不存在

应用场景

复制代码
缓存穿透防护:过滤不存在的key,避免请求穿透到数据库) 
大数据量去重:如日志去重、爬虫URL去重
黑名单校验:如垃圾邮件地址、恶意IP黑名单

Java项目配置与使用
Redis 布隆过滤器安装(需先安装插件)

bash 复制代码
# 下载redisbloom插件
git clone https://github.com/RedisBloom/RedisBloom.git
cd RedisBloom
make
# 启动Redis时加载插件
redis-server --loadmodule /path/to/redisbloom.so

Java中使用布隆过滤器(基于 Jedis客户端,Spring Data Redis 需扩展)

java 复制代码
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import javax.annotation.Resource;

@Component
public class RedisBloomFilterDemo {

    @Resource
    private JedisPool jedisPool;

    // 布隆过滤器初始化(指定key、预计元素个数、误判率)
    public void initBloomFilter(String filterKey, long expectedInsertions, double falseProbability) {
        try (Jedis jedis = jedisPool.getResource()) {
            // BF.RESERVE 命令:创建布隆过滤器
            jedis.executeCommand("BF.RESERVE", filterKey, String.valueOf(falseProbability), String.valueOf(expectedInsertions));
        }
    }

    // 添加元素到布隆过滤器
    public void addToBloomFilter(String filterKey, String element) {
        try (Jedis jedis = jedisPool.getResource()) {
            // BF.ADD 命令:添加单个元素
            jedis.executeCommand("BF.ADD", filterKey, element);
            // 批量添加:BF.MADD filterKey elem1 elem2 elem3
            // jedis.executeCommand("BF.MADD", filterKey, "elem1", "elem2", "elem3");
        }
    }

    // 检查元素是否在布隆过滤器中
    public boolean existsInBloomFilter(String filterKey, String element) {
        try (Jedis jedis = jedisPool.getResource()) {
            // BF.EXISTS 命令:返回1表示可能存在,0表示一定不存在
            Long result = (Long) jedis.executeCommand("BF.EXISTS", filterKey, element);
            return result != null && result == 1;
        }
    }

    // 缓存穿透防护示例(查询商品前先检查布隆过滤器)
    public String getProductById(String productId) {
        String cacheKey = "product:info:" + productId;
        String filterKey = "bloom:filter:product";

        // 1. 先检查布隆过滤器,不存在则直接返回null(避免穿透到DB)
        if (!existsInBloomFilter(filterKey, productId)) {
            return null;
        }

        // 2. 布隆过滤器认为存在,查询Redis缓存
        String productInfo = stringRedisTemplate.opsForValue().get(cacheKey);
        if (productInfo != null) {
            return productInfo;
        }

        // 3. 缓存未命中,查询数据库(此处省略DB查询逻辑)
        String dbProductInfo = "从DB查询到的商品信息";

        // 4. 存入Redis缓存
        stringRedisTemplate.opsForValue().set(cacheKey, dbProductInfo, 1, java.util.concurrent.TimeUnit.HOURS);

        return dbProductInfo;
    }
}

9.事务(Transaction)

Redis事务是一组命令的集合,支持 MULTI(开启事务)、EXEC(执行事务)、DISCARD(取消事务)、WATCH(乐观锁)命令:

复制代码
核心特性:批量执行命令(要么全部执行,要么全部不执行,无部分执行),但不支持回滚(Redis事务是"弱事务) 乐观锁:通过 WATCH
监控键,若事务执行前键被修改,则事务取消执行

应用场景

复制代码
原子性操作组合:如扣减库存 + 增加订单数 
避免并发修改冲突:如秒杀场景下的库存扣减

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;

@Component
public class RedisTransactionDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 原子操作:扣减库存+增加销量(无乐观锁,适合低并发场景)
    public void deductStockAndAddSales(String productId, int num) {
        stringRedisTemplate.execute(session -> {
            // 开启事务
            session.multi();

            // 1. 扣减库存(假设库存key为product:stock:xxx)
            String stockKey = "product:stock:" + productId;
            session.opsForValue().decrement(stockKey, num);

            // 2. 增加销量(假设销量key为product:sales:xxx)
            String salesKey = "product:sales:" + productId;
            session.opsForValue().increment(salesKey, num);

            // 执行事务,返回结果列表
            List<Object> results = session.exec();
            // results.get(0) 是decrement的结果,results.get(1) 是increment的结果
            return results;
        });
    }

    // 乐观锁实现:秒杀场景下的库存扣减(避免超卖)
    public boolean seckillWithOptimisticLock(String productId, String userId, int num) {
        String stockKey = "product:stock:" + productId;
        String orderKey = "seckill:order:" + productId + ":" + userId;

        // 使用RedisCallback执行底层命令,支持WATCH
        return stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> {
            // 1. 监控库存键(乐观锁)
            connection.watch(stockKey.getBytes());

            // 2. 查询当前库存
            byte[] stockBytes = connection.get(stockKey.getBytes());
            if (stockBytes == null) {
                connection.unwatch();
                return false; // 商品不存在
            }

            int currentStock = Integer.parseInt(new String(stockBytes));
            if (currentStock < num) {
                connection.unwatch();
                return false; // 库存不足
            }

            // 3. 开启事务
            connection.multi();

            // 4. 扣减库存
            connection.decrBy(stockKey.getBytes(), num);

            // 5. 记录订单(标记用户已购买)
            connection.set(orderKey.getBytes(), "1".getBytes());

            // 6. 执行事务(若库存被其他线程修改,exec返回null)
            List<Object> results = connection.exec();

            // 7. 事务执行成功则返回true,否则返回false
            return results != null && !results.isEmpty();
        });
    }
}

10.Lua脚本

Redis支持嵌入 Lua 脚本执行,脚本中的命令会被原子化执行(中途不会被其他命令打断),支持调用Redis命令API,可实现复杂的原子逻辑

复制代码
核心优势:原子性(避免多命令并发冲突)、减少网络开销(多命令合并为一个脚本调用)、灵活扩展(实现Redis原生不支持的复杂逻辑)

应用场景

复制代码
复杂原子操作:如秒杀库存扣减 + 订单创建 + 日志记录 
自定义数据结构操作:如基于ZSet实现带过期时间的排行榜
分布式锁的高级实现:如带过期时间的互斥锁

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component
public class RedisLuaScriptDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 秒杀场景:原子执行"库存检查+扣减+订单创建"
    public boolean seckillWithLua(String productId, String userId, int num) {
        // Lua脚本:先检查库存,库存充足则扣减并记录订单,返回1;否则返回0
        String luaScript = """
                local stockKey = KEYS[1]
                local orderKey = KEYS[2]
                local num = tonumber(ARGV[1])
                local userId = ARGV[2]
                
                -- 检查用户是否已购买(防重复下单)
                local hasOrdered = redis.call('get', orderKey .. ':' .. userId)
                if hasOrdered then
                    return 0
                end
                
                -- 检查库存
                local currentStock = tonumber(redis.call('get', stockKey))
                if not currentStock or currentStock < num then
                    return 0
                end
                
                -- 扣减库存
                redis.call('decrby', stockKey, num)
                
                -- 记录订单(设置1小时过期)
                redis.call('setex', orderKey .. ':' .. userId, 3600, '1')
                
                return 1
                """;

        // 执行Lua脚本:KEYS为键列表,ARGV为参数列表
        Long result = stringRedisTemplate.execute(
                new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
                java.util.List.of("product:stock:" + productId, "seckill:order:" + productId), // KEYS
                String.valueOf(num), userId // ARGV
        );

        return result != null && result == 1;
    }

    // 2. 分布式锁:基于Lua脚本实现"加锁+过期时间"原子操作
    public boolean acquireLock(String lockKey, String lockValue, long expireTime) {
        // Lua脚本:如果锁不存在则设置锁和过期时间,返回1;否则返回0
        String luaScript = """
                local lockKey = KEYS[1]
                local lockValue = ARGV[1]
                local expireTime = tonumber(ARGV[2])
                
                if redis.call('setnx', lockKey, lockValue) == 1 then
                    redis.call('expire', lockKey, expireTime)
                    return 1
                end
                return 0
                """;

        Long result = stringRedisTemplate.execute(
                new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
                java.util.List.of(lockKey),
                lockValue, String.valueOf(expireTime)
        );

        return result != null && result == 1;
    }

    // 3. 分布式锁:基于Lua脚本实现"解锁(仅删除自己的锁)"原子操作
    public boolean releaseLock(String lockKey, String lockValue) {
        // Lua脚本:只有锁存在且值匹配时才删除,避免误删其他线程的锁
        String luaScript = """
                local lockKey = KEYS[1]
                local lockValue = ARGV[1]
                
                if redis.call('get', lockKey) == lockValue then
                    redis.call('del', lockKey)
                    return 1
                end
                return 0
                """;

        Long result = stringRedisTemplate.execute(
                new org.springframework.data.redis.core.script.DefaultRedisScript<>(luaScript, Long.class),
                java.util.List.of(lockKey),
                lockValue
        );

        return result != null && result == 1;
    }
}

11.Geo 地理信息

Redis 3.2+ 原生支持Geo数据类型,用于存储地理位置信息(经纬度),支持距离计算、范围查询、附近的人等操作

复制代码
核心命令:GEOADD(添加地理位置)、GEODIST(计算两点距离)、GEORADIUS(根据坐标查询范围内的点)、GEORADIUSBYMEMBER(根据成员查询范围内的点)

应用场景

复制代码
附近的人/商家:如外卖商家推荐、社交软件附近好友 
地理位置距离计算:如两地距离、配送范围判断 
区域筛选:如查询某城市范围内的景点

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.domain.geo.GeoDistance;
import org.springframework.data.redis.domain.geo.GeoResults;
import org.springframework.data.redis.domain.geo.Metric;
import org.springframework.data.redis.domain.geo.Point;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component
public class RedisGeoDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 添加地理位置(如外卖商家)
    public void addMerchantLocation(String merchantId, double longitude, double latitude) {
        GeoOperations<String, String> geoOps = stringRedisTemplate.opsForGeo();
        // GEOADD key 经度 纬度 成员
        geoOps.add("geo:merchant", new Point(longitude, latitude), merchantId);
    }

    // 2. 计算两个商家之间的距离(单位:千米)
    public double calculateMerchantDistance(String merchantId1, String merchantId2) {
        GeoOperations<String, String> geoOps = stringRedisTemplate.opsForGeo();
        // GEODIST key 成员1 成员2 单位(km/m/mi/ft)
        GeoDistance distance = geoOps.distance("geo:merchant", merchantId1, merchantId2, Metric.KILOMETERS);
        return distance != null ? distance.getValue() : 0;
    }

    // 3. 附近的商家查询(根据用户坐标,查询5公里内的商家,按距离排序)
    public GeoResults<org.springframework.data.redis.domain.geo.GeoLocation<String>> findNearbyMerchants(double userLongitude, double userLatitude, double radiusKm) {
        GeoOperations<String, String> geoOps = stringRedisTemplate.opsForGeo();
        // GEORADIUS key 经度 纬度 半径 单位 WITHDIST WITHLATLNG ASC
        return geoOps.radius(
                "geo:merchant",
                new Point(userLongitude, userLatitude),
                new Distance(radiusKm, Metric.KILOMETERS),
                org.springframework.data.redis.domain.geo.GeoRadiusCommandArgs.newGeoRadiusArgs()
                        .includeDistance() // 包含距离
                        .includeCoordinates() // 包含经纬度
                        .sortAscending() // 按距离升序排序
        );
    }

    // 4. 根据商家查询附近的用户(如配送员查找附近下单用户)
    public GeoResults<org.springframework.data.redis.domain.geo.GeoLocation<String>> findUsersNearMerchant(String merchantId, double radiusKm) {
        GeoOperations<String, String> geoOps = stringRedisTemplate.opsForGeo();
        // GEORADIUSBYMEMBER key 成员 半径 单位 WITHDIST
        return geoOps.radius(
                "geo:user",
                merchantId,
                new Distance(radiusKm, Metric.KILOMETERS),
                org.springframework.data.redis.domain.geo.GeoRadiusCommandArgs.newGeoRadiusArgs()
                        .includeDistance()
                        .sortAscending()
        );
    }
}

12.HyperLogLog

Redis原生支持的概率性数据结构,用于高效统计集合的基数(不重复元素个数),占用内存极小(无论数据量多大,仅需约12KB)

复制代码
核心特性:内存高效(适合超大数据量技术统计),存在极小误差(约0.81%),不存储具体元素,仅统计基数

应用场景

复制代码
网站UV统计:每日访问独立用户数 
接口调用独立IP统计 
商品被浏览的独立用户数统计

Java实战(Spring Data Redis)

java 复制代码
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component
public class RedisHyperLogLogDemo {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    // 1. 统计网站UV(每日独立用户)
    public void recordWebsiteUV(String date, String userId) {
        String key = "uv:website:" + date;
        // PFADD 命令:添加用户ID到HyperLogLog
        stringRedisTemplate.opsForHyperLogLog().add(key, userId);
    }

    // 2. 获取每日UV数量
    public long getWebsiteUV(String date) {
        String key = "uv:website:" + date;
        // PFCOUNT 命令:统计基数(独立用户数)
        return stringRedisTemplate.opsForHyperLogLog().size(key);
    }

    // 3. 合并多个日期的UV(如统计本周UV)
    public long mergeWeeklyUV(String weekKey, String... dailyKeys) {
        // PFMERGE 命令:合并多个HyperLogLog到一个key
        stringRedisTemplate.opsForHyperLogLog().union(weekKey, dailyKeys);
        // 统计合并后的基数
        return stringRedisTemplate.opsForHyperLogLog().size(weekKey);
    }

    // 4. 接口独立IP统计
    public void recordApiIp(String apiName, String ip) {
        String key = "uv:api:" + apiName;
        stringRedisTemplate.opsForHyperLogLog().add(key, ip);
    }

    public long getApiUniqueIpCount(String apiName) {
        String key = "uv:api:" + apiName;
        return stringRedisTemplate.opsForHyperLogLog().size(key);
    }
}

13.Stream

Redis 5.0+ 引入的高性能消息队列数据结构,支持持久化、消费组、消息确认、回溯消费等特性,功能媲美专业消息队列(如RabbitMQ)

复制代码
核心特性:消息持久化(基于AOF/RDB)、消费组模式(支持多消费者负载均衡)、消息ID自增(保证顺序)、消息确认(ACK)机制

应用场景

复制代码
高可靠消息队列:如订单创建、支付回调通知 
日志收集:按时间顺序存储日志,支持回溯查询 
异步任务处理:如订单超时取消、短信发送

Java实战(基于 Jedis 客户端)

java 复制代码
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.StreamEntry;
import redis.clients.jedis.StreamEntryID;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class RedisStreamDemo {

    @Resource
    private JedisPool jedisPool;

    // 1. 生产者:发送消息到Stream
    public String sendMessage(String streamKey, Map<String, String> message) {
        try (Jedis jedis = jedisPool.getResource()) {
            // XADD 命令:添加消息到Stream,自动生成消息ID(如1699999999999-0)
            StreamEntryID entryId = jedis.xadd(streamKey, null, message);
            return entryId.toString();
        }
    }

    // 2. 消费者组:创建消费组(首次使用时创建)
    public void createConsumerGroup(String streamKey, String groupName) {
        try (Jedis jedis = jedisPool.getResource()) {
            // XGROUP CREATE 命令:创建消费组,从最新消息开始消费($表示最新)
            jedis.xgroupCreate(streamKey, groupName, new StreamEntryID("$"), true);
        }
    }

    // 3. 消费者:从消费组获取消息并确认
    public void consumeMessageFromGroup(String streamKey, String groupName, String consumerName) {
        try (Jedis jedis = jedisPool.getResource()) {
            while (true) {
                // XREADGROUP 命令:从消费组获取消息,阻塞10秒(0表示无限阻塞)
                Map<String, List<StreamEntry>> messages = jedis.xreadGroup(
                        groupName, consumerName,
                        1, // 每次获取1条消息
                        10000, // 阻塞10秒
                        false, // 不重复获取已确认的消息
                        Map.of(streamKey, StreamEntryID.UNRECEIVED_ENTRY) // 获取未消费的消息
                );

                if (messages == null || messages.isEmpty()) {
                    continue;
                }

                // 处理消息
                List<StreamEntry> streamEntries = messages.get(streamKey);
                for (StreamEntry entry : streamEntries) {
                    String messageId = entry.getID().toString();
                    Map<String, String> message = entry.getFields();

                    // 业务处理逻辑(如处理订单消息)
                    System.out.println("处理消息:" + messageId + ",内容:" + message);

                    // 确认消息(ACK):XACK 命令
                    jedis.xack(streamKey, groupName, entry.getID());
                }
            }
        }
    }

    // 4. 普通消费者:非消费组模式(适合单消费者)
    public void consumeMessage(String streamKey) {
        try (Jedis jedis = jedisPool.getResource()) {
            StreamEntryID lastId = StreamEntryID.LAST_ENTRY; // 从最后一条消息开始消费
            while (true) {
                Map<String, List<StreamEntry>> messages = jedis.xread(
                        1,
                        10000,
                        false,
                        Map.of(streamKey, lastId)
                );

                if (messages == null || messages.isEmpty()) {
                    continue;
                }

                List<StreamEntry> streamEntries = messages.get(streamKey);
                for (StreamEntry entry : streamEntries) {
                    System.out.println("普通消费者处理消息:" + entry.getFields());
                    lastId = entry.getID(); // 更新最后消费的消息ID
                }
            }
        }
    }

    // 示例:发送订单消息
    public void sendOrderMessage(String orderId, String userId, String amount) {
        Map<String, String> message = new HashMap<>();
        message.put("orderId", orderId);
        message.put("userId", userId);
        message.put("amount", amount);
        message.put("status", "PENDING");
        sendMessage("stream:order", message);
    }
}
相关推荐
xie_pin_an2 小时前
Redis 核心命令速查表
数据库·redis·缓存
苦学编程的谢3 小时前
Redis_11_类型补充+命令补充+RESP
数据库·redis·缓存
hzk的学习笔记3 小时前
Redisson 和 Jedis 的区别
数据库·redis·缓存
无心水3 小时前
【中间件:Redis】5、Redis分布式锁实战:从基础实现到Redisson高级版(避坑指南)
redis·分布式·中间件·redisson·后端面试·redis分布式锁·分布式系统
无心水4 小时前
【中间件:Redis】3、Redis数据安全机制:持久化(RDB+AOF)+事务+原子性(面试3大考点)
redis·中间件·面试·后端面试·redis事务·redis持久化·redis原子性
陈果然DeepVersion5 小时前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问
spring boot·redis·微服务·ai·智能客服·java面试·rag
有梦想的攻城狮13 小时前
通过Lettuce实现PB3格式对象在Redis中的存储与查询
数据库·redis·缓存·pb3