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实现即可
最后更新于