Redis实践(4.2)SpringBoot 测试主从连接池

Redis
placeholder image
admin 发布于:2023-05-28 09:02:27
阅读:loading

前文中使用SpringBoot Data Redis项目集成了Redis的主从架构接入,本篇主要来测试一下整合后从项目中配置的Redis连接池是否生效的实现,虽然配置了有连接池参数,仅仅只是参数配置而已,事实上它确实是生效了吗?所以本文将使用代码来验证验证使用RedisTemplate的连接池工作机制,详见下文。

1.application.yml

lettuce:
  pool:
	enabled: true
	max-active: 8   #最大连接数据库连接数,设 -1 为没有限制
	max-idle: 8     #最大等待连接中的数量,设 0 为没有限制
	max-wait: 10s  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
	min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
	time-between-eviction-runs: 10s #空闲连接回收时间

【说明】

(1)此处配置只包含一小部分配置,完整的application.yml前文已给出全量;

(2)enabled参数并非此处控制是否使用连接池的关键;

(3)需要结合前文中的RedisConfiguration代码,构造LettuceConnectionFactory时写模式未设置setShareNativeConnection为false,读模式设置了;

2.测试代码

package cn.chendd.redis;

/**
 * Redis连接池测试,验证使用RedisTemplate的连接池工作机制
 * @author chendd
 * @date 2023/5/19 16:39
 */
public class ReadisConnectionPoolTest extends BaseTest {

    /*@Resource(name = RedisConstants.READ1_STRING_REDIS_TEMPLATE)
    private StringRedisTemplate stringRedisTemplate;*/

    /**
     * 累计循环10000个线程,观察getClientList的参数值
     */
    @Test
    public void poolStringRedisTemplate() throws InterruptedException {
        int count = 100;
        int number = 100;
        CountDownLatch countDownLatch = new CountDownLatch(count * number);
        AtomicInteger total = new AtomicInteger();
        for (int j = 1 ; j <= count ; j++) {
            Runnable runnable = () -> {
                StringRedisTemplate stringRedisTemplate = RedisUtils.getReadStringRedisTemplate();
                List<RedisClientInfo> clientList;
                String message;
                for (int i = 1; i <= number; i++) {
                    clientList = stringRedisTemplate.getClientList();
                    message = MessageFormat.format("第 {0} 个线程,共有 {1} 个客户端连接" , total.addAndGet(1) , clientList.size());
                    System.out.println(message);
                    countDownLatch.countDown();
                }
            };
            new Thread(runnable).start();
        }
        System.out.println("主线程准备等待...");
        countDownLatch.await();
        System.out.println("主线程执行完毕...");
    }

}

3.结果验证

(1)使用连接池,验证连接池效果生效,代码运行共计输出9个客户端连接,除了代码中最大的8个连接外,猜测Redis主从复制策略也占用了其中一个,生效结果参考如下图所示:

验证连接池生效.gif

(连接池生效)

(2)不使用连接池,验证不使用连接池效果生效,代码运行共计输出2个客户端连接,同样猜测Redis主从复制策略占用一个,测试代码中10000个线程共享同一个实例,参考效果如下图所示:

验证不使用连接池.gif

(连接池不生效)

(3)通过代码debug分析出,当共享本地连接(shareNativeConnection=true)后clientConfiguration的实例类型为DefaultLettuceClientConfiguration,不使用连接池实现,参考如下图所示:

image.png

(4)通过代码debug分析出,当共享本地连接(shareNativeConnection=false)后clientConfiguration的实例类型为DefaultLettucePoolingClientConfiguration,包含了有poolConfig连接池参数,参考如下图所示:

image.png

4.知识点

(1)使用@Resource注入的对象存在连接池策略,使用RedisUtils工具类也同样存在,它们只是获得RedisTemplate类型实例,具体的与Redis交互还在其内部;

(2)受LettuceConnectionFactory的setShareNativeConnection设置影响,决定是否使用线程池;

(3)只有在线程较多的场景多线程才会启用,线程并发不高的情况默认一个客户端连接够处理响应的话不会触发连接池;

(4)getClientList获取的是当前Redis的客户端连接个数,等同于redis命令“client list”或“info clients”;

(5)示例获取到的Redis客户端连接个数要多于此处线程池配置的个数,因为它获取到的并不是当前程序进程内的连接个数,而是Redis服务器上的全部连接个数,受“redis-cli”命令连接影响,同时若开启了主从策略也会多占用一个连接。即:getClientList = 当前进程启用个数(<=max-active) + redis-cli打开的连接个数 + redis-server主从或集群内部的连接;


 点赞


 发表评论

当前回复:作者

 评论列表


留言区