redis主从架构利用lettuce实现读写分离

redis主从架构利用lettuce实现读写分离

背景

随着业务流量越来越大,原先所有流量都访问redis主库,给主库造成了很大的压力

目标

在不影响业务的前提下,减轻redis主库压力

现状

当前redis的部署架构是一主一从,从库只是承担了备份的角色,资源有很大的闲置

方案

如果从库也能承担一部分线上流量,那么主库的压力自然就会减轻;方案理论上可行

问题

项目使用的lettuce + spring-boot-starter-data-redis做redis访问

lettuce本身是支持主从模式的访问的,奈何spring-boot-starter-data-redis对于redis哨兵和redis集群模式都有很好的支持,对于主从没有支持

代码分析

入口

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

只看上面的import部分,默认会LettuceConnectionConfiguration会生效,接着看下这个文件

redisConnectionFactory会创建最终的RedisConnectionFactory,再看createLettuceConnectionFactory方法,可以发现对哨兵(sentinel)和集群(cluster)是天然支持的,具体怎么配置这里先略过

我们再看LettuceConnectionFactory,这里重点关注afterPropertiesSet方法

再看下createConnectionProvider方法

最终会走到最后一行的最后一条语句new StandaloneConnectionProvider((RedisClient)client, codec, readFrom));

再看StandaloneConnectionProvider,重点看getConnection方法

当connectionType=StatefulConnection时,会走到masterReplicaConnection方法

继续往下追,会走到MasterReplica.connectAsyncSentinelOrAutodiscovery方法

最终走到AutodiscoveryConnector,重点关注initializeConnection方法

可以发现返回的StatefulRedisMasterReplicaConnection对象中,channerWriter是MasterReplicaChannelWriter;重点看write方法,大部分redis操作都走到这个方法

重点在CompletableFuture<StatefulRedisConnection<K, V>> future = (CompletableFuture) masterReplicaConnectionProvider .getConnectionAsync(intent);

其中有一行需要注意;if (readFrom != null && intent == Intent.READ) 块中的内容

可以发现,当遇到读请求且readFrom不为空时,会有选择节点的策略

所以要实现读写分离,我们只需要保证走到这里时,readFrom是从从库选择节点的策略就行

其中内置的ReadFrom.REPLICA_PREFERRED即可满足要求

接下来需要解决的是如何保证走到这里时readFrom不为空,实际上这里无法直接通过配置完成,具体可以看RedisProperties,里面没有定义这个字段,接下来,我们向上回溯可以发现

LettuceConnectionConfiguration.getLettuceClientConfiguration此时可以通过新增LettuceClientConfigurationBuilderCustomizer去设置readFrom,整个推理过程不在描述

因此,我们只需要增加一个LettuceClientConfigurationBuilderCustomizer实现即可

最后更新于