如何配置MongoDB Java驱动程序的MongoOptions以用于生产环境?

102
我一直在搜索有关配置MongoOptions的最佳实践,以便使用MongoDB Java驱动程序,并且除了API之外,我没有找到更多信息。这个搜索是在我遇到“com.mongodb.DBPortPool $ SemaphoresOut:Out of semaphores to get db connection”错误后开始的,通过增加连接/乘数,我能够解决这个问题。我正在寻找有关生产环境中配置这些选项的链接或最佳实践。
2.4驱动程序的选项包括: http://api.mongodb.org/java/2.4/com/mongodb/MongoOptions.html - autoConnectRetry - connectionsPerHost - connectTimeout - maxWaitTime - socketTimeout - threadsAllowedToBlockForConnectionMultiplier 新版本的驱动程序有更多选项,我也很感兴趣听听相关内容。
1个回答

163
更新至2.9:
  • autoConnectRetry 表示驱动程序将在意外断开连接后自动尝试重新连接到服务器。在生产环境中,通常应将其设置为 true。

  • connectionsPerHost 是单个 Mongo 实例(它是单例的,因此通常每个应用程序只有一个实例)可以与 mongod/mongos 进程建立的物理连接数量。在编写本文时,即使实际查询吞吐量很低,Java 驱动程序最终也会建立这些连接(换句话说,您将在 mongostat 中看到“conn”统计信息上升,直到它达到每个应用程序服务器的此数目)。

    在大多数情况下,没有必要将此设置得比 100 更高,但这个设置是那种需要“测试并查看”的东西。请注意,您必须确保将其设置得足够低,以使连接总数不超过

    db.serverStatus().connections.available

    在生产环境中,我们目前将其设置为 40。

  • connectTimeout。顾名思义,指驱动程序在放弃连接尝试之前等待的毫秒数。除非存在真实的、预期的机会可能成为否则成功的连接尝试的障碍,否则将超时设置为较长时间(15-30 秒)。通常情况下,如果连接尝试需要超过几秒钟的时间,您的网络基础设施就无法实现高吞吐量。

  • maxWaitTime。线程等待连接池中的连接可用的毫秒数,并在此期间抛出异常。保持默认设置。

  • socketTimeout。标准套接字超时值。设置为 60 秒(60000)。

  • threadsAllowedToBlockForConnectionMultiplier。connectionsPerHost 的乘数,表示允许等待连接变得可用的线程数量,如果池当前已耗尽。这是会导致“com.mongodb.DBPortPool$SemaphoresOut: Out of semaphores to get db connection”异常的设置。一旦此线程队列超过 threadsAllowedToBlockForConnectionMultiplier 值,它就会抛出此异常。例如,如果 connectionsPerHost 为 10,而此值为 5,则最多可以阻止 50 个线程,直到抛出上述异常。

    如果您预计会有大量的吞吐量峰值,可能会暂时增加此值。我们目前将其设置为 1500,正因为此原因。如果查询负载始终超过服务器,请相应地改进硬件/扩展情况。

  • readPreference(更新,2.8+)用于确定默认读取首选项,并替换“slaveOk”。通过类工厂方法之一设置 ReadPreference。 有关最常见设置的完整说明可在本文末尾找到

  • w. (更新于2.6+) 该值决定了写入的“安全性”。当此值为-1时,无论网络或数据库错误如何,写操作都不会报告任何错误。 WriteConcern.NONE是适用于此的预定义WriteConcern。如果w为0,则网络错误会使写操作失败,但mongo错误不会。通常将其称为“fire and forget”写,并且应在性能比一致性和耐久性更重要时使用。使用WriteConcern.NORMAL模式进行编写。

    如果您将w设置为1或更高,则认为写入是安全的。 安全写入执行写入并随后请求服务器以确保写入成功或检索错误值(换句话说,在写入后发送getLastError()命令)。请注意,直到完成此getLastError()命令,连接才会保留。由于这个原因和额外的命令,吞吐量将显着低于w <= 0的写入。对于w值为1的情况,MongoDB保证在向您发送写入的实例上成功地写入(或可验证地失败)。

    在副本集的情况下,您可以使用更高的w值,告诉MongoDB将写入发送至至少“ w”副本集成员,然后返回(或更准确地说,等待写入复制到“ w”成员)。您还可以将w设置为字符串“majority”,这将告诉MongoDB将写入执行到大多数副本集成员(WriteConcern.MAJORITY)。通常,除非需要原始性能(-1或0)或复制写入(> 1),否则应将其设置为1。高于1的值对写入吞吐量有相当大的影响。

  • fsync。在启用时强制mongo在每次写入后刷新磁盘的耐久性选项。我从未遇到过与写入积压相关的耐久性问题,因此我们在生产中默认将其设置为false。

  • j *(NEW 2.7+)*。布尔值,当设置为true时,强制MongoDB在返回之前等待成功的日志组提交。如果启用了日志记录,则可以启用此功能以获得额外的耐久性。请参阅http://www.mongodb.org/display/DOCS/Journaling,了解日志记录获取的内容(以及您可能想启用此标志的原因)。

ReadPreference ReadPreference类允许您配置查询路由到哪个mongod实例,如果您正在使用副本集。以下选项可用:

  • ReadPreference.primary():所有读取仅针对副本集的主成员。如果您需要所有查询返回一致的(最近编写的)数据,请使用此选项。这是默认设置。

  • ReadPreference.primaryPreferred() : 如果可能,所有读取都会发送到副本集中的主节点,但如果主节点不可用,则可以查询辅助节点。因此,如果主节点不可用,读取将变为最终一致性,但仅在主节点不可用时。

  • ReadPreference.secondary() : 所有读取都会发送到辅助节点,并且主节点仅用于写入。仅当您可以接受最终一致性读取时才使用此选项。可以使用其他副本集成员来增加读取性能,尽管副本集可以拥有的(投票)成员数量存在限制。

  • ReadPreference.secondaryPreferred() : 如果存在任何辅助节点,则所有读取都会发送到辅助节点。主节点仅用于写入,除非所有辅助节点都不可用。除了回退到主节点进行读取之外,这与ReadPreference.secondary()相同。

  • ReadPreference.nearest() : 读取将发送到数据库客户端可用的最近的副本集成员。仅在可以接受最终一致性读取时使用。最近的成员是客户端和各个副本集成员之间延迟最低的成员。由于忙碌的成员最终会具有更高的延迟,因此这也应该自动平衡读取负载,尽管在我的经验中,如果成员延迟相对一致,则辅助(首选)似乎更好地做到了这一点。

注意:所有上述方法都有启用标签版本的方法,它们返回TaggableReadPreference实例。有关副本集标签的完整说明可以在此处找到:Replica Set Tags


6
将socketTimeout和connectTimeout保留为默认值(无限)是否危险?如果某个连接由于某种原因挂起,你的应用程序(或者至少该线程)将永远被卡住。这些超时时间不应该设置得非常高(例如连接30秒,套接字2分钟)吗? - Idris Mokhtarzada
非常感谢你的回答,Remon。你的答案确实解决了我的问题。我有一个MongoDB集群。为了测试其性能,我编写了一个多线程Java客户端。我发现当线程数增加到200时,MongoDB会报错:文件描述符不足。我以为这是connectionPerHost的问题,所以我将它设置为非常高的值。但问题仍然存在。在阅读了你的解释之后,我知道即使查询吞吐量很低,Mongo实例仍会建立这么多的连接。因此,如果connectionPerHost设置得太高,问题会变得更糟。所以,我将它设置为50,问题得到了解决。 - wuchang
@Vico_Wu 很高兴听到这个消息。请注意,提高文件描述符限制也是一种完全可行的方法,因为拥有更多并发连接可能会提高吞吐量,因此仅基于文件描述符问题来限制它们并不理想。 - Remon van Vliet
4
听起来是一个相当受欢迎的答案。如果有人对我更新以反映最新驱动程序中的更改感兴趣,请让我知道。 - Remon van Vliet
请查看此链接以获取详细的Spring设置:http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/ - moshe beeri
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接