Redisson 框架详解

目录

一.为什么要使用分布式锁?

[二.Redisson 的基本使用:](#二.Redisson 的基本使用:)

[1.添加 Redisson 依赖:](#1.添加 Redisson 依赖:)

[2.在 application.yml 配置 Redis:](#2.在 application.yml 配置 Redis:)

[3. 创建 Redisson 客户端:](#3. 创建 Redisson 客户端:)

(1)单节点模式:

(2)集群模式:

4.注入RedissonClient:

[5.使用 Redisson 存储和获取值:](#5.使用 Redisson 存储和获取值:)

三.配置集群连接池:

[1. Redisson 集群连接池配置项:](#1. Redisson 集群连接池配置项:)

[2. 配置 Redis 集群的连接池:](#2. 配置 Redis 集群的连接池:)

四.如何在Boot项目中使用Redission实现分布式锁?

[1.引入 Redisson 依赖:](#1.引入 Redisson 依赖:)

[2.配置 Redisson:](#2.配置 Redisson:)

[3.在 Spring Boot 中注入 RedissonClient:](#3.在 Spring Boot 中注入 RedissonClient:)

4.使用分布式锁:


Redisson 是一个基于 Redis 的高效 Java 客户端,封装了 Redis 的大部分功能,提供了更为丰富和高效的操作接口,能够帮助开发者更便捷地进行分布式缓存、分布式锁、分布式集合 等操作。它不仅支持 Redis 的基本操作,还提供了更多的高级功能,如分布式锁、分布式集合、分布式计数器等,可以大大简化分布式应用的开发。

一.为什么要使用分布式锁?

分布式锁是解决 分布式系统中的资源竞争问题 的一种有效机制。在高并发分布式系统中,多个服务节点可能同时访问同一资源(如数据库、文件系统等)。这种竞争可能导致数据的不一致性、重复操作、死锁等问题,因此,使用分布式锁来保证同一时刻只有一个节点能够访问共享资源,从而确保系统的正确性和稳定性。

在单机系统中,当多个线程访问共享资源时,操作系统通常使用互斥锁(如 Java 中的 synchronizedReentrantLock)来保证同一时刻只有一个线程能访问该资源。而在分布式系统中,资源通常分布在多个服务实例或节点 上,单纯的本地锁(如 synchronized)无法跨节点进行协调,因此需要分布式锁来确保不同节点间的同步。

使用分布式锁的方式:

  • 所有节点都尝试获取锁,如果一个节点获得了锁,它将执行任务。
  • 其他节点则会等待或者跳过执行该任务,避免重复执行。
    使用场景:
  1. 防止多次执行相同的任务
  2. 确保分布式系统中资源的独占访问
  3. 控制并发数量

二.Redisson 的基本使用:

1.添加 Redisson 依赖:

在项目中使用 Redisson,首先需要添加 Redisson 的 Maven 依赖:

XML 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.16.1</version> <!-- 请根据最新版本替换 -->
</dependency>

2.在 application.yml 配置 Redis:

XML 复制代码
# 单节点
redisson:
  address: redis://127.0.0.1:6379
# 集群
redisson:
  cluster:
    addresses: 
      - redis://127.0.0.1:7000
      - redis://127.0.0.1:7001
      - redis://127.0.0.1:7002

3. 创建 Redisson 客户端:

Redisson 提供了两种方式来创建客户端:单节点模式集群模式

(1)单节点模式:

在单节点模式下,我们只需要连接到一个 Redis 实例,在配置类中:

java 复制代码
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.Redisson;

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        // 配置单节点 Redis
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer();
        serverConfig.setAddress("redis://127.0.0.1:6379");
        serverConfig.setPassword("yourpassword");
        return Redisson.create(config);
    }
}

(2)集群模式:

java 复制代码
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.ClusterServersConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.Redisson;

import java.util.List;

@Configuration
public class RedissonClusterConfig {

    // 从配置文件中读取 Redis 集群的地址
    @Value("${redisson.cluster.addresses}")
    private List<String> clusterAddresses;

    @Bean
    public RedissonClient redissonClient() {
        // 创建 Redis 配置对象
        Config config = new Config();
        
        // 配置集群
        ClusterServersConfig clusterConfig = config.useClusterServers();
        
        // 添加集群节点地址
        for (String address : clusterAddresses) {
            clusterConfig.addNodeAddress(address);
        }
        
        // 如果需要配置密码,使用 setPassword 方法
        // clusterConfig.setPassword("yourpassword");

        // 创建并返回 Redisson 客户端
        return Redisson.create(config);
    }
}

4.注入RedissonClient:

通过 @Autowired 注入 RedissonClient 到需要使用的服务类中。

java 复制代码
import org.redisson.api.RedissonClient;
import org.redisson.api.RMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RedisService {

    @Autowired
    private RedissonClient redissonClient;

    public void demoMapUsage() {
        // 获取 Redis 集群中的分布式 Map
        RMap<String, String> map = redissonClient.getMap("myMap");
        map.put("name", "Alice");
        map.put("age", "30");

        System.out.println("Name: " + map.get("name"));
        System.out.println("Age: " + map.get("age"));
    }
}

5.使用 Redisson 存储和获取值:

RBucket<String> 是 Redisson 提供的一个接口,它代表 Redis 中一个字符串类型的值。我们可以通过它来存储和获取一个键值对。

java 复制代码
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class RedisService {

    @Autowired
    private RedissonClient redissonClient;

    // 存储值
    public void setValue(String key, String value) {
        RBucket<String> bucket = redissonClient.getBucket(key); // 获取 Redis 中的指定 key
        bucket.set(value);  // 存储值
    }

    // 获取值
    public String getValue(String key) {
        RBucket<String> bucket = redissonClient.getBucket(key); // 获取 Redis 中的指定 key
        return bucket.get(); // 获取存储的值
    }
}

三.配置集群连接池:

在使用 Redisson 配置 Redis 集群时,我们可以通过配置连接池来管理连接的数量、连接的超时时间等。Redisson 提供了灵活的配置方式来定制集群模式的连接池。

1. Redisson 集群连接池配置项:

Redisson 提供了多个与连接池相关的配置项,主要包括以下几个:

  • masterConnectionPoolSize:主节点连接池的大小(连接数量)。
  • slaveConnectionPoolSize:从节点连接池的大小(连接数量)。
  • connectionMinimumIdleSize:连接池中保持的最小空闲连接数。
  • connectionPoolSize:连接池的最大连接数。
  • idleConnectionTimeout:空闲连接的超时时间。
  • connectTimeout:连接的超时时间。
  • timeout:操作超时时间(请求的最大等待时间)。

2. 配置 Redis 集群的连接池:

application.yml 中配置连接池参数:

java 复制代码
redisson:
  cluster:
    addresses: 
      - redis://127.0.0.1:7000
      - redis://127.0.0.1:7001
      - redis://127.0.0.1:7002

    # 集群连接池配置
    master-connection-pool-size: 100      # 主节点连接池大小
    slave-connection-pool-size: 50       # 从节点连接池大小
    connection-pool-size: 200            # 总连接池大小
    connection-minimum-idle-size: 10     # 最小空闲连接数
    idle-connection-timeout: 10000       # 空闲连接超时
    connect-timeout: 3000                # 连接超时
    timeout: 5000                        # 请求超时

配置连接池是确保 Redis 集群高效运行的关键,它能够有效管理连接的数量,提高 Redis 的性能,避免频繁地创建和销毁连接。

如果我们在 application.ymlapplication.properties 文件中配置了 Redisson 的连接池参数,并且使用了 redisson-spring-boot-starter,Spring Boot 会自动读取这些配置并初始化连接池。

四.如何在Boot项目中使用Redission实现分布式锁?

在 Spring Boot 项目中使用 Redisson 实现分布式锁,主要涉及到以下几个步骤:

  1. 引入 Redisson 依赖
  2. 配置 Redisson 客户端
  3. 在 Spring Boot 中注入 RedissonClient
  4. 使用分布式锁

1.引入 Redisson 依赖:

XML 复制代码
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.16.1</version> <!-- 请根据最新版本替换 -->
</dependency>

2.配置 Redisson:

java 复制代码
redisson:
  # Redis 集群配置
  cluster:
    # 集群节点地址,多个节点地址用逗号分隔
    nodes:
      - redis://127.0.0.1:7000
      - redis://127.0.0.1:7001
      - redis://127.0.0.1:7002
      - redis://127.0.0.1:7003
      - redis://127.0.0.1:7004
      - redis://127.0.0.1:7005
    # Redis 密码(如果有密码的话)
    password: yourpassword  # Redis 的密码

    # 连接池配置
    connection-pool-size: 100            # 连接池大小
    connection-minimum-idle-size: 10     # 最小空闲连接数
    idle-connection-timeout: 10000       # 空闲连接超时(毫秒)
    connect-timeout: 3000                # 连接超时(毫秒)
    timeout: 5000                        # 请求超时(毫秒)
    retries: 3                           # 在获取连接时的最大重试次数
    retry-interval: 1000                 # Redis 集群模式下的超时时间
    wait-timeout: 3000                   # 最大等待连接的时间(毫秒)
    subscription-mode: false             # 集群模式下是否启用超时管理
    threads: 16                          # 线程池大小

3.在 Spring Boot 中注入 RedissonClient:

在 Spring Boot 中,我们可以通过 @Autowired 注入 RedissonClient,然后在服务类中使用它进行 Redis 操作。

java 复制代码
import org.redisson.api.RLock;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class RedisWithLockService {

    @Autowired
    private RedissonClient redissonClient;

    // 锁的名称
    private static final String LOCK_KEY = "myLock";

    // 存储到 Redis 中的键
    private static final String REDIS_KEY = "userBalance";

    // 分布式锁处理业务逻辑
    public void updateBalance(String userId, double newBalance) {
        // 获取分布式锁
        RLock lock = redissonClient.getLock(LOCK_KEY);

        try {
            // 尝试获取锁,最多等待 10 秒,锁自动释放时间为 30 秒
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 锁获取成功,执行 Redis 操作
                System.out.println("Lock acquired, updating balance...");

                // 获取当前用户的余额
                double currentBalance = getUserBalanceFromRedis(userId);
                System.out.println("Current balance: " + currentBalance);

                // 更新余额(模拟业务逻辑)
                double updatedBalance = currentBalance + newBalance;
                System.out.println("Updated balance: " + updatedBalance);

                // 将新的余额存储回 Redis
                setUserBalanceToRedis(userId, updatedBalance);

            } else {
                System.out.println("Unable to acquire lock for updating balance.");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 确保释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    // 获取用户余额(从 Redis 中)
    private double getUserBalanceFromRedis(String userId) {
        RBucket<Double> bucket = redissonClient.getBucket(REDIS_KEY + ":" + userId);
        return bucket.isExists() ? bucket.get() : 0.0; // 如果值存在则获取,如果没有则返回 0
    }

    // 更新用户余额(存入 Redis)
    private void setUserBalanceToRedis(String userId, double balance) {
        RBucket<Double> bucket = redissonClient.getBucket(REDIS_KEY + ":" + userId);
        bucket.set(balance);  // 存储新的余额
    }
}

4.使用分布式锁:

RedisLockService 中定义了 processWithDistributedLock 方法,调用时,Redisson 将确保在同一时刻只有一个进程/线程可以进入锁的保护区域。

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RedisWithLockController {

    @Autowired
    private RedisWithLockService redisWithLockService;

    // 模拟调用分布式锁更新用户余额的接口
    @GetMapping("/updateBalance")
    public String updateBalance(@RequestParam String userId, @RequestParam double amount) {
        redisWithLockService.updateBalance(userId, amount);
        return "Balance update request received for user: " + userId;
    }
}

通过访问下面接口地址:

java 复制代码
http://localhost:8080/updateBalance?userId=user1&amount=100

查看后端返回数据。

总结:

  • Redisson 提供了丰富的 API 用于存储和获取 Redis 中的值。你可以通过 RBucket 等数据结构操作 Redis 中的数据。
  • 使用 分布式锁 可以确保在多个服务实例之间协调对共享资源(如 Redis 中的数据)的访问。
  • Redisson 的分布式锁非常适合用来保护 Redis 中的临界资源,避免高并发访问导致的数据不一致问题。
相关推荐
fat house cat_18 天前
Redisson看门狗机制
java·redission
A Everyman20 天前
Redisson分布式限流器
java·redis·分布式·限流器·redission·分布式限流
weixin_438335404 个月前
【代码】Redisson 分布式锁
redis·分布式·redission
weixin_438335404 个月前
redisson RMap和RMapCache的区别
redis·redission
gaog2zh4 个月前
0101DNS TCP fallback on UDP query timeout disabled-redission-中间件
中间件·redission
橡 皮 人7 个月前
Redis第18讲——Redis和Redission实现延迟消息
redis·面试·延迟队列·redission
applebomb9 个月前
jetcache 2级缓存模式实现批量清除
jetcache·cache·redission·ccframe
applebomb10 个月前
JustAuth扩展:支持自动获得回调域名、使用redission作为Cache
java·springboot·redission·justauth
来自宇宙的曹先生1 年前
Redission从入门到入门
分布式锁·redission