gpt4 book ai didi

java - 分片后MongoDB插入速度变慢

转载 作者:IT老高 更新时间:2023-10-28 13:16:20 25 4
gpt4 key购买 nike

我有一个 Mongodb 集群,其中包含一个主副本和一个辅助副本作为复制集一起运行。但随着流量的增长,我决定执行分片以获得更快的写入速度。

我根据 tutorial 对“_id”列执行了散列分片。并将数据分成两个分片。然后我进行了一些基准测试,发现在某些情况下,分片集群甚至比非分片集群还要慢。

这是测试结果。

  1. 最大吞吐量测试:使用十台机器同时运行“mongoimport”将数据加载到目标db,以测试db的最大写入速度。

    结果:

    分片集群可以插入 39500 个文档/秒。

    非分片集群可以插入 27400 个文档/秒。

  2. 单实例 mongoimport 测试:仅使用一台机器运行“mongoimport”将数据加载到目标数据库中。

    结果:

    分片集群可以插入14285个文档/秒。

    非分片集群可以插入 14085 个文档/秒。

  3. mongodb java驱动的单实例数据加载:调用mongodb java驱动的api,只使用一个实例将数据加载到目标数据库中。

    结果:

    分片集群可以插入 4630 个文档/秒。

    非分片集群可以插入 17544 个文档/秒。

第一次测试的结果非常合理。你将 db 分片成一个 2-shard 集群,吞吐量增加了大约 50%,一切都很完美,万岁!

第二个测试有点道理。吞吐量大致相同,但瓶颈可能在数据加载器方面,毕竟我们只使用一个实例加载数据。

但是第三个测试真的让我很烦。分片集群比非分片集群慢得多是没有意义的。另一方面,未分片的数据库具有惊人的速度,甚至比使用 mongoimport 加载数据还要快。

用于加载数据的 java 代码粘贴在下面。我真的无法弄清楚这一点,并提前感谢所有答案。

public static void insert(String host, int port) throws FileNotFoundException,
InterruptedException, ExecutionException {
MongoClient mongoClient = new MongoClient(host, port);
mongoClient.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
MongoDatabase database = mongoClient.getDatabase("my-db");
MongoCollection<Document> collection = database.getCollection("my-collection");
Scanner scan = new Scanner(new File("my-sample-dataset"));

// Pre-load the data into the memory, so that the db load test won't be
// affected by disk I/O time.
Queue<List<String>> resource = new LinkedList<>();
for (int i = 0; i < 100; i++) {
List<String> strs = new ArrayList<>();
for (int j = 0; j < 10000; j++)
strs.add(scan.nextLine());
resource.add(strs);
}

System.out.println("start");
long startTime = System.currentTimeMillis();
while (!resource.isEmpty()) {
List<String> strs = resource.poll();
List<WriteModel<Document>> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(new
InsertOneModel<Document>(Document.parse(strs.get(i))));
}
collection.bulkWrite(list);
}
System.out.println("Finished loading. Time taken: " + (System.currentTimeMillis() - startTime) + "ms");
scan.close();
}

最佳答案

这是可能的罪魁祸首collection.bulkWrite(list);

在批量写入的情况下,mongos 需要将您的批处理分成更小的批处理,然后进入每个分片。

由于您没有指定批处理中文档的插入顺序,因此 MongoDB 必须遵守插入按指定顺序发生的要求。结果是当且仅当它们对应于相同的分片时,才能对连续插入进行批处理。

mongos maintains the original document order, hence only the consecutive inserts which belong to the same shard can be grouped together

例如。考虑“k”是分片键的情况。有两个分片,对应范围

[MinKey, 10], (20, MaxKey]

现在假设我们批量插入以下文档:

[{k: 1}, {k: 25}, {k: 2}]

Doc1 -> Shard1, Doc2 -> Shard2, Doc3 -> Shard3

没有两个连续的文档属于同一个分片,因此调用 getLastError在这种情况下,每个文档之后都需要。

在散列键的情况下,文档将更随机地分布在分片中。即属于相同分片的文档可能更分散,因此会创建更多的批处理 分布越随机,批处理的大小越小,总批处理的数量越多, 产生的成本就越高getLastError 这实际上意味着性能较差。

FIX:指定“ordered: false”

collection.bulkWrite(list, new BulkWriteOptions().ordered(false));

这告诉数据库您并不关心严格保留插入发生的顺序。使用 "ordered: false",mongos 将为每个分片创建一个批处理,从而避免了额外的 getLastError 调用。每个批处理操作都可以同时在适当的分片上执行,而无需等待上一个批处理的 getLastError 响应。


还有,

MongoClient mongoClient = new MongoClient(host, port);

Creates a Mongo instance based on a single mongodb node and will not be able to discover other nodes in your replica-set or sharded cluster.

在这种情况下,您的所有写入请求都被路由到单个节点,该节点负责由于分片集群而负责所有额外的簿记工作。你应该使用的是

MongoClient(final List<ServerAddress> seeds)

When there is more than one server to choose from based on the type of request (read or write) and the read preference (if it's a read request), the driver will randomly select a server to send a request. This applies to both replica sets and sharded clusters.

Note : Put as many servers as you can in the list and the system will figure out the rest.

关于java - 分片后MongoDB插入速度变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42522158/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com