使用rocket_db_pools连接Redis集群多节点时hmget报错的解决办法
问题分析与解决方案
问题根源
你遇到的错误码853本质是TLS握手失败,核心原因有两点:
- 当前使用的
deadpool_redis::Pool是单节点连接池,无法处理Redis集群的节点重定向逻辑; - Redis集群重定向时默认返回非TLS地址(
redis://),但客户端配置了rediss://(TLS连接),导致连接其他节点时TLS握手失败;若仅入口节点开启TLS、其他节点未配置,也会触发该错误。
解决方案
方案一:修正客户端连接池配置(推荐)
改用集群专用连接池,强制所有节点走TLS连接:
- 修改连接池定义:
use rocket_db_pools::{deadpool_redis, Database}; #[derive(Database)] #[database("redis_tests")] pub struct TestRedisPool(deadpool_redis::ClusterPool); // 替换为集群专用连接池
- 更新Rocket.toml配置:
[default.databases.redis_tests] # 填写所有集群节点的TLS地址,用逗号分隔 url = "rediss://<node1-ip>:6379,rediss://<node2-ip>:6379,rediss://<node3-ip>:6379" # 强制启用TLS tls = true # 测试环境可临时跳过证书验证(生产环境禁用) tls_skip_verify = true
- 确保依赖版本兼容:
检查Cargo.toml中依赖版本匹配,示例配置:
redis = { version = "0.21.5", features = ["tls", "tokio-native-tls-comp", "async-std-tls-comp", "cluster"] } deadpool-redis = { version = "0.10.2", features = ["cluster", "async-std"] } rocket_db_pools = { version = "0.1.0-rc.2", features = ["deadpool_redis"] }
方案二:修改Redis集群配置(若有权限)
让所有集群节点开启TLS,并公告TLS地址,确保重定向时返回正确的rediss://格式地址:
- 每个节点的redis.conf添加以下配置:
# 启用TLS端口 tls-port 6379 # 配置证书文件路径 tls-cert-file /path/to/your/cert.pem tls-key-file /path/to/your/key.pem tls-ca-cert-file /path/to/your/ca.pem # 公告节点公网IP和TLS端口 cluster-announce-ip <node-public-ip> cluster-announce-tls-port 6379 # 可选:禁用非TLS端口,强制所有连接走TLS port 0
- 重启所有Redis节点,必要时重新执行集群初始化操作。
方案三:手动配置集群连接池(灵活定制)
如果rocket_db_pools的Database宏无法满足需求,可手动创建并挂载集群连接池:
use rocket::fairing::{Fairing, Info, Kind}; use rocket::{Build, Rocket}; use deadpool_redis::{ClusterConfig, ClusterPool}; use redis::TlsConfig; pub struct RedisClusterFairing; #[rocket::async_trait] impl Fairing for RedisClusterFairing { fn info(&self) -> Info { Info { name: "Redis Cluster Pool Initializer", kind: Kind::Ignite, } } async fn on_ignite(&self, rocket: Rocket<Build>) -> rocket::fairing::Result { // 配置集群节点和TLS参数 let config = ClusterConfig { nodes: vec![ "rediss://<node1>:6379".parse().unwrap(), "rediss://<node2>:6379".parse().unwrap(), "rediss://<node3>:6379".parse().unwrap(), ], tls: Some(TlsConfig::new().map_err(|e| rocket::fairing::Error::Custom(e.to_string()))?), ..Default::default() }; // 创建集群连接池 let pool = ClusterPool::new(config).map_err(|e| rocket::fairing::Error::Custom(e.to_string()))?; // 挂载到Rocket应用中 Ok(rocket.manage(pool)) } } // 启动Rocket时加载自定义Fairing #[launch] fn rocket() -> _ { rocket::build() .attach(RedisClusterFairing) .mount("/", routes![your_redis_handler]) }
验证方法
执行HMGET操作前,先通过CLUSTER NODES命令检查集群节点的公告地址是否为rediss://格式,确保客户端能正确识别并连接所有节点。
内容的提问来源于stack exchange,提问作者white-dog
相关产品推荐
相关产品推荐

