验证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

相关文章

Python在二进制文件中进行数据搜索的实战指南

《Python在二进制文件中进行数据搜索的实战指南》在二进制文件中搜索特定数据是编程中常见的任务,尤其在日志分析、程序调试和二进制数据处理中尤为重要,下面我们就来看看如何使用Python实现这一功能吧... 目录简介1. 二进制文件搜索概述2. python二进制模式文件读取(rb)2.1 二进制模式与文本

SQL Server 中的表进行行转列场景示例

《SQLServer中的表进行行转列场景示例》本文详细介绍了SQLServer行转列(Pivot)的三种常用写法,包括固定列名、条件聚合和动态列名,文章还提供了实际示例、动态列数处理、性能优化建议... 目录一、常见场景示例二、写法 1:PIVOT(固定列名)三、写法 2:条件聚合(CASE WHEN)四、

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

JAVA SpringBoot集成Jasypt进行加密、解密的详细过程

《JAVASpringBoot集成Jasypt进行加密、解密的详细过程》文章详细介绍了如何在SpringBoot项目中集成Jasypt进行加密和解密,包括Jasypt简介、如何添加依赖、配置加密密钥... 目录Java (SpringBoot) 集成 Jasypt 进行加密、解密 - 详细教程一、Jasyp

通过DBeaver连接GaussDB数据库的实战案例

《通过DBeaver连接GaussDB数据库的实战案例》DBeaver是一个通用的数据库客户端,可以通过配置不同驱动连接各种不同的数据库,:本文主要介绍通过DBeaver连接GaussDB数据库的... 目录​一、前置条件​二、连接步骤​三、常见问题与解决方案​1. 驱动未找到​2. 连接超时​3. 权限不

linux实现对.jar文件的配置文件进行修改

《linux实现对.jar文件的配置文件进行修改》文章讲述了如何使用Linux系统修改.jar文件的配置文件,包括进入文件夹、编辑文件、保存并退出编辑器,以及重新启动项目... 目录linux对.jar文件的配置文件进行修改第一步第二步 第三步第四步总结linux对.jar文件的配置文件进行修改第一步进

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

Navicat连接Mysql8.0.11出现1251错误的解决方案

《Navicat连接Mysql8.0.11出现1251错误的解决方案》在重装电脑并安装最新版MySQL后,Navicat和Sqlyog连接MySQL时遇到的1251和2058错误,通过将MySQL用户... 目录Navicat连接mysql8.0.11出现1251错误原因分析解决问题方法有两种总结Navic

Python连接Spark的7种方法大全

《Python连接Spark的7种方法大全》ApacheSpark是一个强大的分布式计算框架,广泛用于大规模数据处理,通过PySpark,Python开发者能够无缝接入Spark生态系统,本文给大家介... 目录第一章:python与Spark集成概述PySpark 的核心优势基本集成配置步骤启动一个简单的