Mongodb 选择/配置数据库以实现高吞吐量、可靠、一致的写入吞吐量,并牺牲延迟

Mongodb 选择/配置数据库以实现高吞吐量、可靠、一致的写入吞吐量,并牺牲延迟,mongodb,postgresql,couchdb,throughput,database,Mongodb,Postgresql,Couchdb,Throughput,Database,我正在开发具有以下特征的实时应用程序: 数百个客户端将同时插入行/文档,每个客户端每隔几秒钟插入一行 大部分只附加;几乎所有的行/文档一旦插入,就永远不会更改 只有当数据被刷新到磁盘时,客户机才应该看到成功,然后读写一致性应该保持不变 客户端愿意在几秒钟内等待确认,等待的时间足以进行多次磁盘查找和写入 RAM中的数据太多(排除了Redis等选项)。但是很久以前写的行很少被访问,所以不把它们放在内存中是可以接受的 理想情况下,这些写入不应阻止读取 键值存储可以,但至少需要一个可靠的自动递增索引

我正在开发具有以下特征的实时应用程序:

  • 数百个客户端将同时插入行/文档,每个客户端每隔几秒钟插入一行
  • 大部分只附加;几乎所有的行/文档一旦插入,就永远不会更改
  • 只有当数据被刷新到磁盘时,客户机才应该看到成功,然后读写一致性应该保持不变
  • 客户端愿意在几秒钟内等待确认,等待的时间足以进行多次磁盘查找和写入
  • RAM中的数据太多(排除了Redis等选项)。但是很久以前写的行很少被访问,所以不把它们放在内存中是可以接受的
  • 理想情况下,这些写入不应阻止读取
  • 键值存储可以,但至少需要一个可靠的自动递增索引
换句话说(和tl;dr),客户机可以容忍延迟,但它们需要大量可信任的写入吞吐量—比“一次写入就是一次磁盘操作”的吞吐量还要高

我设想的数据库将实现如下内容:接受TCP连接的数量(理论上受文件描述符数量的限制),在内存中缓冲这些写操作,尽可能经常地将它们的批记录到磁盘(以及对自动递增索引的更新),并且仅在相关磁盘写入操作完成时才响应这些TCP连接。或者,它可以像懒洋洋地编写数据库一样简单,发布一条消息,表明它已经完成了磁盘写入(客户机等待懒洋洋的响应,然后等待写入消息报告成功)

我认为,对于如此高的延迟容忍度,这并不是要求太多。我可以想象其他人也有这个问题,比如金融公司,他们不能承受数据丢失的代价,但可以承受延迟对任何一个客户的响应


任何经过战斗测试的数据库解决方案,如Postgres、CouchDB/Couchbase或MongoDB,是否支持这种操作模式?

PostgreSQL应该非常适合这种工作负载;您指定的几乎所有内容都在其正常功能集中。Pg是ACID兼容的,支持组提交以减少同步开销,写入程序不阻止读卡器,并且它使用操作系统进行缓存,因此它自然倾向于只在内存中保留热数据集

“客户愿意在几秒钟内等待确认 -足够长的时间,可以进行多个磁盘查找和写入”

如果考虑PostgreSQL,您的应用程序非常适合于一个非常大的应用程序,这将极大地提高写吞吐量。您不能使用
synchronous\u commit=off
,因为您需要在回复之前确认提交,但您可以将提交排队几秒钟以节省同步成本

如果将Pg用于此类作业,则需要调整检查点,以确保检查点不会暂停I/O。确保bgwriter正在积极写入脏缓冲区。确保autovaccum经常运行—您没有从表中删除,但索引仍然需要维护,表统计信息也需要维护

如果你期望大量的数据,你的查询通常有一个时间元素,考虑第一年的1个月的块,把所有超过12个月的所有事物合并成一年中划分的表。Pg只有有限的内置分区(使用继承和约束排除将其拼凑在一起),因此您必须使用触发器手动/编写脚本,但它可以完成这项工作

见:


正是我想要的答案!我对文档中提到的
感到有点不快,因为无论此设置如何,每次刷新时都会写入所有挂起的提交数据,因此通过增加此参数来增加延迟实际上会提高性能的情况很少见
——但我假设我的用例是那些“罕见”的情况之一?无论如何,我需要对此做大量的阅读和测试/调优,但这看起来很有希望。@b当然,在做出任何决定之前,您需要进行测试和基准测试。我发现文件中的这一点有点不清楚;我怀疑这可能是指任何非延迟提交都会导致延迟提交刷新到磁盘。我会对你的结果感兴趣。@b顺便说一句,对于这种工作负载,你能做的最好的一件事就是确保你的存储有非常快的同步。在写回模式下具有电池备份缓存的RAID控制器是最便宜的选择。你不会相信这有什么不同。好的SAN是更昂贵的选择。无论您做什么,都不要在EC2之类的设备上运行这种工作负载。如果将RAID控制器与BBU一起使用,则它们并不完全相同;在pgsql通用邮件列表上进行基准测试或询问。如果使用BBU,请定期测试您的BBU,以确保电池仍能正常工作。