You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助Spring Data Redis让Redis集群只读Lua脚本在从节点执行?

解决方案

方案1:手动指定从节点执行只读Lua脚本

Spring Data Redis的ReadFrom配置确实仅对标准只读命令生效,因为Lua脚本默认会被路由到主节点。你可以通过直接获取从节点连接来执行只读Lua脚本:

  • 从Redis连接工厂中获取集群连接,过滤出所有从节点地址
  • 选择目标从节点,创建专用连接执行脚本
  • 最后释放连接避免资源泄漏

示例代码:

@Autowired
private RedisConnectionFactory connectionFactory;

public Object executeReadOnlyLuaScriptOnReplica(String script, List<String> keys, Object... args) {
    ClusterConnection clusterConn = (ClusterConnection) connectionFactory.getConnection();
    try {
        // 过滤出所有从节点
        Set<RedisNode> replicaNodes = clusterConn.clusterGetNodes().stream()
                .filter(node -> node.getType() == RedisNode.NodeType.REPLICA)
                .collect(Collectors.toSet());
        
        if (replicaNodes.isEmpty()) {
            throw new RuntimeException("No replica nodes available");
        }
        
        // 选取第一个可用从节点(可自行扩展负载均衡逻辑)
        RedisNode replicaNode = replicaNodes.iterator().next();
        RedisClusterNode clusterNode = new RedisClusterNode(replicaNode.getHost(), replicaNode.getPort());
        
        // 向指定从节点执行脚本
        return clusterConn.execute(clusterNode, script.getBytes(), keys, args);
    } finally {
        clusterConn.close();
    }
}

方案2:利用Lettuce客户端临时切换ReadFrom策略

如果你的Spring Data Redis底层使用Lettuce客户端,可以通过原生连接临时切换ReadFrom策略,执行脚本后再恢复原配置:

@Autowired
private RedisTemplate<String, Object> redisTemplate;

public Object executeLuaScriptOnReplica(String script, List<String> keys, Object... args) {
    return redisTemplate.execute((RedisCallback<Object>) connection -> {
        LettuceConnection lettuceConn = (LettuceConnection) connection;
        StatefulRedisClusterConnection<String, String> nativeConn = lettuceConn.getNativeConnection();
        
        // 保存原有ReadFrom配置
        ReadFrom originalReadFrom = nativeConn.getReadFrom();
        try {
            // 临时切换为优先从节点读取
            nativeConn.setReadFrom(ReadFrom.REPLICA_PREFERRED);
            // 执行Lua脚本
            return nativeConn.sync().eval(script, ScriptOutputType.VALUE, keys.toArray(new String[0]), args);
        } finally {
            // 恢复原有配置
            nativeConn.setReadFrom(originalReadFrom);
        }
    });
}

方案3:创建专用只读RedisTemplate

配置一个专门用于只读操作的RedisTemplate,指定其连接工厂的ReadFrom为REPLICA_PREFERRED,仅用它执行只读Lua脚本:

  1. 配置专用Lettuce连接工厂
@Bean
public LettuceConnectionFactory replicaPreferredConnectionFactory(RedisClusterConfiguration clusterConfig) {
    LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
            .readFrom(ReadFrom.REPLICA_PREFERRED)
            .build();
    return new LettuceConnectionFactory(clusterConfig, clientConfig);
}

@Bean(name = "replicaRedisTemplate")
public RedisTemplate<String, Object> replicaRedisTemplate(LettuceConnectionFactory replicaPreferredConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(replicaPreferredConnectionFactory);
    // 配置序列化器
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return template;
}
  1. 使用专用模板执行脚本
@Autowired
@Qualifier("replicaRedisTemplate")
private RedisTemplate<String, Object> replicaRedisTemplate;

public Object executeReadOnlyLuaScript(String script, List<String> keys, Object... args) {
    DefaultRedisScript<Object> redisScript = new DefaultRedisScript<>(script, Object.class);
    return replicaRedisTemplate.execute(redisScript, keys, args);
}

注意:此方案仅适用于完全只读的Lua脚本,如果脚本包含写操作,会因从节点不允许写操作而执行失败。

内容的提问来源于stack exchange,提问作者Kostas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:08:20