杰瑞科技汇

Java MongoDB集群如何搭建与配置?

MongoDB 集群基础(重要)

在连接之前,必须理解 MongoDB 集群的几种常见架构,因为你的 Java 连接字符串会根据架构的不同而变化。

Java MongoDB集群如何搭建与配置?-图1
(图片来源网络,侵删)

a) 副本集

这是最常见的高可用性架构,它由多个数据节点组成,其中一个主节点(Primary)负责处理所有写操作,其余为从节点(Secondary)负责复制主节点的数据并提供读操作。

  • 特点:自动故障转移,如果主节点宕机,副本集会自动从从节点中选举一个新的主节点。
  • Java 连接:你需要连接到副本集中的至少一个成员(最好是所有成员的地址),驱动会自动发现集群中的所有成员(主、从、仲裁者)并进行智能路由。

b) 分片集群

用于解决数据量和请求量巨大的问题,它通过将数据水平切分并分布到不同的服务器(分片)上来实现扩展。

  • 组成
    • Shard Servers (分片):存储实际数据。
    • Config Servers (配置服务器):存储集群的元数据(数据分片在哪个分片上)。
    • Query Routers (路由器):最常见的是 mongos,客户端连接它,它会查询配置服务器,然后将请求路由到正确的分片。
  • Java 连接:你不需要连接到每个分片,你只需要连接到一个或多个 mongos 路由器即可,驱动会与 mongos 通信,mongos 负责后续的路由。

Java 驱动核心:MongoClient

在 Java 中,我们使用 MongoClient 类来连接 MongoDB,对于集群,关键在于如何正确配置它的 MongoClientSettings

关键配置点:

  1. applyToClusterSettings:这是配置集群连接的核心。

    Java MongoDB集群如何搭建与配置?-图2
    (图片来源网络,侵删)
    • hosts(List<ServerAddress>):指定集群中所有节点的地址,对于副本集,这是所有副本集成员的地址;对于分片集群,这是所有 mongos 路由器的地址。
    • requiredReplicaSetName(String)(仅副本集) 指定副本集的名称,这是驱动区分不同集群的关键。
    • mode(ClusterConnectionMode):指定集群模式,通常是 MULTIPLE(连接多个节点)。
  2. applyToSocketSettings:配置网络套接字。

    • connectTimeout(Duration):连接超时时间。
    • readTimeout(Duration):读取超时时间。
  3. applyToSslSettings:如果集群启用了 TLS/SSL,必须配置此项。

    • enabled(boolean):启用 SSL。
    • invalidHostNameAllowed(boolean):是否允许无效的主机名(生产环境建议为 false)。
    • context(SSLContext):提供自定义的 SSL 上下文。
  4. credential:认证配置。

    • Credential 对象包含了用户名、认证数据库、密码和认证机制(如 SCRAM-SHA-1, SCRAM-SHA-256, PLAIN 等)。

连接字符串 vs. Builder 模式

虽然可以使用传统的连接字符串,但强烈推荐使用 Builder 模式,因为它更清晰、更易于维护,并且能更好地利用 Java 驱动的最新功能。

连接字符串 示例 (不推荐)

  • 副本集mongodb://user:pass@host1:27017,host2:27017,host3:27017/mydb?replicaSet=myReplSet&authSource=admin
  • 分片集群mongodb://user:pass@mongos1:27017,mongos2:27017/mydb?authSource=admin

Builder 模式 (强烈推荐)

下面我们使用 Builder 模式来构建不同集群的连接。


完整 Java 代码示例

确保你的 pom.xml 中有最新的 MongoDB Java 驱动依赖:

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>4.11.1</version> <!-- 请使用最新版本 -->
</dependency>

示例 1:连接副本集

假设你的副本集名为 myReplSet,成员为 rs1.example.com:27017, rs2.example.com:27017, rs3.example.com:27017,用户为 clusterUser,认证数据库为 admin

import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import java.util.Arrays;
import java.util.List;
public class MongoReplicaSetConnectionExample {
    public static void main(String[] args) {
        // 1. 定义集群节点列表
        List<ServerAddress> hosts = Arrays.asList(
            new ServerAddress("rs1.example.com", 27017),
            new ServerAddress("rs2.example.com", 27017),
            new ServerAddress("rs3.example.com", 27017)
        );
        // 2. 定义认证凭据
        MongoCredential credential = MongoCredential.createCredential(
            "clusterUser", 
            "admin", 
            "your_password".toCharArray()
        );
        // 3. 构建 MongoClientSettings
        MongoClientSettings settings = MongoClientSettings.builder()
                .applyToClusterSettings(builder -> 
                    builder.hosts(hosts) // 设置集群节点
                           .requiredReplicaSetName("myReplSet") // 【关键】设置副本集名称
                )
                .credential(credential) // 设置认证
                .applyToSslSettings(builder -> builder.enabled(true)) // 如果启用SSL
                .build();
        // 4. 创建 MongoClient
        try (MongoClient mongoClient = MongoClients.create(settings)) {
            System.out.println("成功连接到 MongoDB 副本集!");
            // 5. 获取数据库和集合进行操作
            MongoDatabase database = mongoClient.getDatabase("testdb");
            System.out.println("获取数据库 'testdb' 成功。");
            // 可以执行一些CRUD操作...
            // database.getCollection("myCollection").insertOne(new Document("name", "Java Driver"));
            System.out.println("操作完成。");
        } catch (Exception e) {
            System.err.println("连接 MongoDB 失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

示例 2:连接分片集群

假设你的 mongos 路由器地址为 mongos1.example.com:27017, mongos2.example.com:27017

import com.mongodb.MongoClientSettings;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import java.util.Arrays;
import java.util.List;
public class MongoShardedClusterConnectionExample {
    public static void main(String[] args) {
        // 1. 定义 mongos 路由器列表
        List<ServerAddress> hosts = Arrays.asList(
            new ServerAddress("mongos1.example.com", 27017),
            new ServerAddress("mongos2.example.com", 27017)
        );
        // 2. 定义认证凭据
        MongoCredential credential = MongoCredential.createCredential(
            "shardedUser", 
            "admin", 
            "your_sharded_password".toCharArray()
        );
        // 3. 构建 MongoClientSettings
        // 注意:对于分片集群,不需要 requiredReplicaSetName
        MongoClientSettings settings = MongoClientSettings.builder()
                .applyToClusterSettings(builder -> 
                    builder.hosts(hosts) // 设置 mongos 路由器
                )
                .credential(credential) // 设置认证
                .applyToSslSettings(builder -> builder.enabled(true)) // 如果启用SSL
                .build();
        // 4. 创建 MongoClient
        try (MongoClient mongoClient = MongoClients.create(settings)) {
            System.out.println("成功连接到 MongoDB 分片集群!");
            // 5. 获取数据库和集合进行操作
            MongoDatabase database = mongoClient.getDatabase("shardeddb");
            System.out.println("获取数据库 'shardeddb' 成功。");
            // 执行操作...
            // database.getCollection("myShardedCollection").insertOne(new Document("key", "value"));
            System.out.println("操作完成。");
        } catch (Exception e) {
            System.err.println("连接 MongoDB 失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

最佳实践

  1. 使用连接池MongoClient 内部已经实现了高效、可配置的连接池,你应该为整个应用程序创建一个 MongoClient 的单例实例,并在整个应用生命周期中复用它,而不是为每个请求都创建一个新的,不要调用 mongoClient.close(),除非你的应用即将关闭。

  2. 启用 TLS/SSL:在生产环境中,MongoDB 集群必须通过 TLS/SSL 加密通信,以保护数据在传输过程中的安全。

  3. 正确配置超时:为网络连接和读写操作设置合理的超时时间,以防止因网络问题导致的应用程序线程长时间阻塞。

  4. 处理 MongoTimeoutException:当集群发生故障转移或网络抖动时,你的应用程序可能会遇到 MongoTimeoutExceptionMongoCommandException,你的应用逻辑应该能够优雅地处理这些异常,例如通过重试机制。

  5. 使用现代 API:尽量使用 com.mongodb.client 包下的新 API(如 MongoClient, MongoDatabase, MongoCollection),而不是旧的 com.mongodb.Mongo

  6. 监控:监控你的 MongoDB 集群和 Java 应用程序的连接情况,关注连接池的使用情况(活跃连接数、空闲连接数等),以及慢查询和错误率。


特性 副本集 分片集群
连接目标 副本集的所有成员 一个或多个 mongos 路由器
关键配置 requiredReplicaSetName("...") 无需此配置
驱动行为 自动发现主从节点,读写分离 依赖 mongos 进行路由
连接字符串 mongodb://.../db?replicaSet=myReplSet mongodb://.../db
Builder 模式 builder.requiredReplicaSetName(...) 仅设置 hosts

通过遵循以上指南,你可以构建出健壮、可靠且高效的 Java 应用程序来连接和操作 MongoDB 集群,核心在于正确配置 MongoClientSettings,并遵循单例 MongoClient启用 SSL 的最佳实践。

分享:
扫描分享到社交APP
上一篇
下一篇