Spring/Mongo问题:无法连接副本集主节点但可连接从节点
我的Java应用能连接到Mongo副本集的两个Secondary实例,但连不上Primary,错误日志如下:
org.springframework.dao.DataAccessResourceFailureException: Timed out after 90000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}. Client view of cluster state is {type=REPLICA_SET, servers=[{address=mongo2:27019, type=REPLICA_SET_SECONDARY, roundTripTime=3.5 ms, state=CONNECTED}, {address=mongo3:27020, type=REPLICA_SET_SECONDARY, roundTripTime=5.5 ms, state=CONNECTED}, {address=mongo1:27018, type=UNKNOWN, state=CONNECTING}]
我用Colima Docker搭建副本集的命令如下:
# 拉取官方Mongo镜像 docker pull mongo:4.2 # 创建网络 docker network create my-mongo-cluster # 启动Mongo节点 docker run -d --net my-mongo-cluster -p 27018:27018 --name mongo1 mongo:4.2 mongod --replSet rs0 --port 27018 docker run -d --net my-mongo-cluster -p 27019:27019 --name mongo2 mongo:4.2 mongod --replSet rs0 --port 27019 docker run -d --net my-mongo-cluster -p 27020:27020 --name mongo3 mongo:4.2 mongod --replSet rs0 --port 27020 # 配置hosts sudo vim /etc/hosts # 添加以下行 127.0.0.1 mongo1 mongo2 mongo3 # 初始化副本集 docker exec -it mongo1 mongo -port 27018 config={"_id":"rs0","members":[{"_id":0,"host":"mongo1:27018"},{"_id":1,"host":"mongo2:27019"},{"_id":2,"host":"mongo3:27020"}]} rs.initiate(config)
可能的原因及解决办法
1. 副本集节点地址不匹配
Mongo副本集初始化时,节点会向集群报告容器内部地址(比如mongo1:27018),但Java应用是通过127.0.0.1:27018访问的,地址不一致导致无法连接Primary。
解决步骤:
- 进入mongo1容器查看当前副本集配置:
docker exec -it mongo1 mongo --port 27018 rs.conf() - 修改配置为客户端可访问的地址:
var cfg = rs.conf(); cfg.members[0].host = "127.0.0.1:27018"; cfg.members[1].host = "127.0.0.1:27019"; cfg.members[2].host = "127.0.0.1:27020"; rs.reconfig(cfg, {force: true}); - 等待集群重新选举后,用
rs.status()确认节点状态。
2. Colima网络或端口映射问题
Colima的端口映射可能未生效,导致Java应用无法访问mongo1的27018端口。
解决步骤:
- 检查端口是否正常监听:
lsof -i :27018 - 测试本地直接连接mongo1:
mongo --host 127.0.0.1 --port 27018 - 若连接失败,重启Colima:
colima stop && colima start
3. Java客户端连接配置错误
确保连接字符串包含所有节点并指定副本集名称:
// 正确示例 String mongoUri = "mongodb://127.0.0.1:27018,127.0.0.1:27019,127.0.0.1:27020/?replicaSet=rs0";
不要只配置Secondary节点,也不能遗漏replicaSet参数。
4. 本地防火墙拦截
临时关闭防火墙测试连接:
# macOS sudo pfctl -d # Linux sudo systemctl stop firewalld
若连接恢复,再添加对应端口的放行规则。
内容的提问来源于stack exchange,提问作者Akhilesh Pandey

