验证Lettuce在单连接上进行多路复用

2024-01-12 21:04

本文主要是介绍验证Lettuce在单连接上进行多路复用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 配置 RedisTemplate
  • 验证blocking操作在独立连接上进行
  • 验证单tcp连接的多路复用

redis multiplexing机制类似http2,在存在并发请求时能减少大量通讯延迟,但不支持blocking相关的操作,如BLPOP

配置 RedisTemplate

RedisTemplate自动根据操作类型,选择是在单连接上进行多路复用,还是申请新的连接/等待空闲连接

@Configuration
public class RedisTemplateConfig {@Beanpublic LettuceConnectionFactory lettuceConnectionFactory(@Value("${redis.cluster}") String address,@Value("${redis.password}") String password) {// 配置连接池管理var poolConfig = new GenericObjectPoolConfig<StatefulRedisClusterConnection<String, String>>();poolConfig.setMaxTotal(20);poolConfig.setMaxIdle(20);poolConfig.setMinIdle(2);poolConfig.setTestWhileIdle(true);poolConfig.setMinEvictableIdleDuration(Duration.ofMillis(60000));poolConfig.setTimeBetweenEvictionRuns(Duration.ofMillis(30000));poolConfig.setNumTestsPerEvictionRun(-1);// 配置客户端行为var clientConfig = LettucePoolingClientConfiguration.builder().clientOptions(ClusterClientOptions.builder().autoReconnect(true).pingBeforeActivateConnection(true).socketOptions(SocketOptions.builder().connectTimeout(Duration.ofSeconds(3)).build()).timeoutOptions(TimeoutOptions.builder().fixedTimeout(Duration.ofSeconds(3)).build()).topologyRefreshOptions(ClusterTopologyRefreshOptions.builder().enableAdaptiveRefreshTrigger(RefreshTrigger.MOVED_REDIRECT,RefreshTrigger.PERSISTENT_RECONNECTS).adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30)).build()).build()).poolConfig(poolConfig).build();// 配置集群连接信息var redisConfig = new RedisClusterConfiguration();redisConfig.setMaxRedirects(5);redisConfig.setPassword(password);String[] serverArray = address.split(",|,|;|;");// 获取服务器数组Set<RedisNode> nodes = new HashSet<>();for (String ipPort : serverArray) {nodes.add(RedisNode.fromString(ipPort));}redisConfig.setClusterNodes(nodes);return new LettuceConnectionFactory(redisConfig, clientConfig);}@Beanpublic StringRedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {return new StringRedisTemplate(lettuceConnectionFactory);}
}

验证blocking操作在独立连接上进行

实现blocking LPOP操作的方法在opsForList()里;
并发100压测期间查看客户端本地的tcp连接,可以看到和每个redis节点都建立了大量连接;
证明RedisTemplate没有选择让不同并发线程共用同一个StatefulConnection

    @Testpublic void blpop() throws Exception {long start = System.currentTimeMillis();AtomicLong err = new AtomicLong();int maxThreads = 100;Semaphore semaphore = new Semaphore(maxThreads);for (int i = 0; i < maxThreads; i++) {final int threadnum = i + 1;semaphore.acquire(1);new Thread(new Runnable() {@Overridepublic void run() {try {template.opsForList().leftPop("test" + threadnum, 2, TimeUnit.SECONDS);} catch (Exception ex) {log.error("leftPop", ex);err.addAndGet(1L);} finally {semaphore.release(1);}}}).start();}semaphore.acquire(maxThreads);long end = System.currentTimeMillis();log.info("耗时{}ms, 错误{}", end - start, err.get());}

验证单tcp连接的多路复用

发起100个线程,每个线程连续进行1000次读写操作;
执行期间查看客户端本地的tcp连接,可以看到只建立了一个和redis节点的连接;
每个线程的指令并发地在同一个tcp连接上发出和响应,一次请求+响应实际相当于http2的一路stream

@Slf4j
@EnableAutoConfiguration(exclude = { RedisAutoConfiguration.class })
@SpringBootTest(classes = { RedisTemplateConfig.class })
public class RedisTemplateTest {@AutowiredStringRedisTemplate template;@Testpublic void getSet() throws Exception {long start = System.currentTimeMillis();int maxThreads = 100;long maxMessagess = 1000;AtomicLong err = new AtomicLong();AtomicLong num = new AtomicLong();Semaphore semaphore = new Semaphore(maxThreads);for (int i = 0; i < maxThreads; i++) {final int threadnum = i + 1;semaphore.acquire(1);new Thread(new Runnable() {@Overridepublic void run() {int j = 0;try {for (; j < maxMessagess; j++) {String key = "thread" + threadnum + "test" + j;String value = "test" + j;template.opsForValue().set(key, value, 1, TimeUnit.SECONDS);assertEquals(value, template.opsForValue().get(key));}} finally {num.addAndGet(j);semaphore.release(1);}}}).start();}semaphore.acquire(maxThreads);long end = System.currentTimeMillis();double rate = 1000d * num.get() / (end - start);log.info("每秒发送并读取消息{}; 耗时{}ms, 累计发送{}", rate, end - start, num.get());}

RedisTemplate屏蔽了哪些并发命令可以共用连接的决策难点,所以不要自行使用Lettuce客户端获取连接或从连接池申请连接。

这篇关于验证Lettuce在单连接上进行多路复用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599159

相关文章

如何使用Lombok进行spring 注入

《如何使用Lombok进行spring注入》本文介绍如何用Lombok简化Spring注入,推荐优先使用setter注入,通过注解自动生成getter/setter及构造器,减少冗余代码,提升开发效... Lombok为了开发环境简化代码,好处不用多说。spring 注入方式为2种,构造器注入和setter

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

MySQL 主从复制部署及验证(示例详解)

《MySQL主从复制部署及验证(示例详解)》本文介绍MySQL主从复制部署步骤及学校管理数据库创建脚本,包含表结构设计、示例数据插入和查询语句,用于验证主从同步功能,感兴趣的朋友一起看看吧... 目录mysql 主从复制部署指南部署步骤1.环境准备2. 主服务器配置3. 创建复制用户4. 获取主服务器状态5

MySQL深分页进行性能优化的常见方法

《MySQL深分页进行性能优化的常见方法》在Web应用中,分页查询是数据库操作中的常见需求,然而,在面对大型数据集时,深分页(deeppagination)却成为了性能优化的一个挑战,在本文中,我们将... 目录引言:深分页,真的只是“翻页慢”那么简单吗?一、背景介绍二、深分页的性能问题三、业务场景分析四、

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

linux解压缩 xxx.jar文件进行内部操作过程

《linux解压缩xxx.jar文件进行内部操作过程》:本文主要介绍linux解压缩xxx.jar文件进行内部操作,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、解压文件二、压缩文件总结一、解压文件1、把 xxx.jar 文件放在服务器上,并进入当前目录#

SpringBoot中如何使用Assert进行断言校验

《SpringBoot中如何使用Assert进行断言校验》Java提供了内置的assert机制,而Spring框架也提供了更强大的Assert工具类来帮助开发者进行参数校验和状态检查,下... 目录前言一、Java 原生assert简介1.1 使用方式1.2 示例代码1.3 优缺点分析二、Spring Fr

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构