24

这是我在这里的正式第一个问题;我欢迎任何/所有对我的帖子的批评,以便我可以学习如何成为一个更好的 SO 公民。

我正在审查非关系 DBMS 以存储潜在的大型电子邮件退出列表,倾向于 MongoDB 或 RethinkDB,使用它们各自的 Python 客户端库。我的应用程序的痛点是批量插入性能,因此我设置了两个 Python 脚本以将 20,000 条记录分批插入 5,000 条记录到 MongoDB 和 RethinkDB 集合中。

MongoDB python 脚本 mongo_insert_test.py:

NUM_LINES = 20000
BATCH_SIZE = 5000

def insert_records():
    collection = mongo.recips
    i = 0
    batch_counter = 0
    batch = []
    while i <= NUM_LINES:
        i += 1
        recip = {
            'address': "test%d@test%d.com" % (i, i)
        }
        if batch_counter <= BATCH_SIZE:
            batch.append(recip)
            batch_counter += 1
        if (batch_counter == BATCH_SIZE) or i == NUM_LINES:
            collection.insert(batch)
            batch_counter = 0
            batch = []

if __name__ == '__main__':
    insert_records()

几乎相同的 RethinkDB python 脚本 rethink_insert_test.py:

NUM_LINES = 20000
BATCH_SIZE = 5000

def insert_records():
    i = 0
    batch_counter = 0
    batch = []
    while i <= NUM_LINES:
        i += 1
        recip = {
            'address': "test%d@test%d.com" % (i, i)
        }
        if batch_counter <= BATCH_SIZE:
            batch.append(recip)
            batch_counter += 1
        if (batch_counter == BATCH_SIZE) or i == NUM_LINES:
            r.table('recip').insert(batch).run()
            batch_counter = 0
            batch = []

if __name__ == '__main__':
    insert_records()

在我的开发环境中,MongoDB 脚本在一秒钟内插入 20,000 条记录:

$ time python mongo_insert_test.py 
real    0m0.618s
user    0m0.400s
sys     0m0.032s

在相同的环境下,RethinkDB 脚本的执行速度要慢得多,在 2 分钟内插入 20,000 条记录:

$ time python rethink_insert_test.py
real    2m2.502s
user    0m3.000s
sys     0m0.052s

关于这两个 DBMS 的工作方式,我在这里是否遗漏了一些重要的东西?为什么 RethinkDB 在这个测试中表现如此糟糕?

我的开发机器有大约 1.2GB 的可用内存用于这些测试。

4

4 回答 4

47

RethinkDB 目前通过在服务器上一次执行单个插入来实现批量插入。由于 Rethink 将每条记录刷新到磁盘(因为它的设计首先考虑了安全性),这对像这样的工作负载产生了非常糟糕的影响。

我们正在做两件事来解决这个问题:

  1. 批量插入将通过服务器上的批量插入算法实现,以避免一次插入一个。
  2. 如果您愿意,我们将为您提供放宽持久性约束的选项,以允许高速缓存内存吸收高吞吐量插入(以换取不经常同步到磁盘)。

这绝对会在 4-12 周内修复(如果您需要尽快解决,请随时给我发送电子邮件至 slava@rethinkdb.com,我会看看我们是否可以重新确定优先级)。

以下是相关的github问题:

https://github.com/rethinkdb/rethinkdb/issues/207

https://github.com/rethinkdb/rethinkdb/issues/314

希望这可以帮助。如果您需要帮助,请随时联系我们。

于 2013-03-01T06:49:22.247 回答
6

撇开咖啡贴的内容不谈:

  1. 根据您使用的驱动程序版本以及如何配置与 mongodb 的连接,这些插入甚至可能不会被服务器确认。如果您使用的是最新版本的 Python 驱动程序,那么这些操作只是在等待来自服务器的接收确认(这并不意味着数据甚至已写入内存)。有关我所指内容的更多详细信息,请查看Mongodb 写入关注设置

  2. 在 Rethinkdb 的情况下,您可以通过并行化插入来加快速度。基本上,如果您运行多个进程/线程,您会看到速度提高。在 Mongo 的情况下,由于涉及到锁,并行性将无济于事。

话虽如此,RethinkDB 可以提高写入速度。

PS:我正在为 Rethink 工作,但以上几点是基于我对这两个系统的公正知识。

于 2013-03-01T07:55:23.213 回答
4

Pymongo 开发人员在这里 - 以防万一您不这样做,请确保您使用的是最新的 pymongo 版本,MongoClient或者MongoRepicaSetClient您的写入得到确认,而不是触发和忘记。正如@Alex 所说,它们很可能是您所需要的。

我会考虑的其他因素是:这是数据库的主要用例还是核心痛点?在做出决定之前,您可能需要考虑其他数据模式、查询数据、易用性和可维护性。

于 2013-03-01T10:08:26.947 回答
0

请原谅这个类比——但是它使我的观点非常清楚。

将贵重物品锁在保险箱中并不需要太多时间,但要做到上千次。如果您改为邮寄到银行的保险库,请考虑您的贵重物品在运往银行的过程中不安全的时间;那个包裹可能会堆满许多其他包裹——来自志同道合的存款人。有人会四处打开您的包裹,然后将其与其他物品堆放在安全的保险库中。

这就是将数据定期提交到磁盘与批量或延迟将数据写入磁盘之间的区别。这是更高的数据完整性和改进的写入性能之间的权衡。如果数据丢失无关紧要,那么不那么频繁地同步到磁盘、批量或懒惰地写入更新是完全可以接受的。做出错误的选择总有一天会咬你一口,所以要明智地选择!

于 2015-11-07T00:55:02.807 回答