本地C#代码连接AWS DocumentDB超时问题求助
本地通过MongoDB Compass搭配SSH隧道能成功连接AWS DocumentDB集群,但使用C#代码连接时出现超时错误,无法建立连接。
所用代码
var settings = MongoClientSettings.FromUrl(new MongoUrl("mongodb://master:password@abc-mongo.cluster-xyzxyz.eu-central-1.docdb.amazonaws.com:27017/database?ssl=false&readpreference=secondaryPreferred")); var client = new MongoClient(settings); var database = client.GetDatabase("database"); var databases = client.ListDatabases().ToList();
错误信息
30000ms后选择服务器超时,使用的选择器为CompositeServerSelector{ Selectors = ReadPreferenceServerSelector{ ReadPreference = { Mode : SecondaryPreferred } }, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }。客户端集群状态视图:{ ClusterId : "1", Type : "Unknown", State : "Disconnected", Servers : [{ ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/abc-mongo.cluster-xyzxyz.eu-central-1.docdb.amazonaws.com:27017" }", EndPoint: "Unspecified/abc-mongo.cluster-xyzxyz.eu-central-1.docdb.amazonaws.com:27017", ReasonChanged: "Heartbeat", State: "Disconnected", ServerVersion: , TopologyVersion: , Type: "Unknown", HeartbeatException: "MongoDB.Driver.MongoConnectionException: 打开服务器连接时发生异常。
---> System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (10060): 连接尝试失败,因为连接方在一段时间后没有正确响应,或者已建立的连接失败,因为连接的主机未能响应。
核心问题是:Compass能连是因为配置了SSH隧道,而C#代码没做这个配置——AWS DocumentDB默认只允许VPC内部访问,本地机器必须通过SSH跳板机(比如EC2实例)建立端口转发才能连接。
方案1:手动建立SSH隧道(快速测试)
在本地终端执行以下命令(保持终端打开),把DocumentDB的端口转发到本地27017端口:
ssh -i "你的密钥文件.pem" -L 27017:abc-mongo.cluster-xyzxyz.eu-central-1.docdb.amazonaws.com:27017 ec2-user@你的跳板机公网IP
然后修改C#代码的连接字符串,把目标地址改成localhost:
var settings = MongoClientSettings.FromUrl(new MongoUrl("mongodb://master:password@localhost:27017/database?ssl=false&readpreference=secondaryPreferred")); var client = new MongoClient(settings); var database = client.GetDatabase("database"); var databases = client.ListDatabases().ToList();
运行代码,若能成功连接,说明问题确实出在缺少SSH隧道。
方案2:代码内集成SSH隧道(持久化方案)
如果不想每次手动建隧道,用SSH.NET NuGet包在代码里自动建立SSH连接:
- 安装NuGet包:
Install-Package SSH.NET
或者通过NuGet包管理器搜索SSH.NET安装。
- 修改代码,先建立SSH隧道再连接MongoDB:
using System; using MongoDB.Driver; using Renci.SshNet; class Program { static void Main() { // SSH跳板机配置 string sshHost = "你的跳板机公网IP"; int sshPort = 22; string sshUsername = "ec2-user"; // 根据跳板机系统调整,比如Ubuntu用ubuntu string sshKeyPath = "你的密钥文件.pem"; // 端口转发配置 int localPort = 27017; string remoteHost = "abc-mongo.cluster-xyzxyz.eu-central-1.docdb.amazonaws.com"; int remotePort = 27017; using (var sshClient = new SshClient(sshHost, sshPort, sshUsername, new PrivateKeyFile(sshKeyPath))) { sshClient.Connect(); if (!sshClient.IsConnected) { Console.WriteLine("SSH连接失败"); return; } // 启动本地端口转发 var forwardedPort = sshClient.AddForwardedPortLocal(localPort, remoteHost, remotePort); forwardedPort.Start(); // 连接MongoDB var mongoUrl = new MongoUrl("mongodb://master:password@localhost:27017/database?ssl=false&readpreference=secondaryPreferred"); var mongoSettings = MongoClientSettings.FromUrl(mongoUrl); var mongoClient = new MongoClient(mongoSettings); try { var databases = mongoClient.ListDatabases().ToList(); Console.WriteLine("连接成功,数据库列表:"); foreach (var db in databases) { Console.WriteLine(db["name"]); } } catch (Exception ex) { Console.WriteLine($"MongoDB连接错误:{ex.Message}"); } finally { forwardedPort.Stop(); sshClient.Disconnect(); } } } }
额外注意事项
- 确保跳板机安全组允许你的本地IP访问22端口;
- 确保DocumentDB安全组允许跳板机的私有IP访问27017端口;
- 如果DocumentDB开启了SSL(默认开启),需将连接字符串中的
ssl=false改为ssl=true,并配置SSL验证:
mongoSettings.SslSettings = new SslSettings { EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12, // 若要严格验证,需导入AWS根证书,此处为简化暂时跳过验证 ServerCertificateValidationCallback = (sender, cert, chain, errors) => true };
内容的提问来源于stack exchange,提问作者mrd

