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);
    }
}
相关推荐
IT大白鼠2 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz2 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
lbb 小魔仙2 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
夕除2 天前
redis--018
redis
两锭子2 天前
Redis基础
redis
烟沙九洲2 天前
Redis 缓存穿透、缓存击穿、缓存雪崩
数据库·redis
字节探索2 天前
Redis 只会当缓存用?这 10 大实战场景,让你的系统快到飞起
redis·后端
于樱花森上飞舞2 天前
【Redis】哨兵详解
java·开发语言·数据库·redis
Rain的Java大神之路3 天前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
Wang's Blog3 天前
Java 接入Redis: 通用命令与键管理
java·服务器·redis