为什么与 MongoDB、Redis 和 MySql 相比,Apache Cassandra 的写入速度如此缓慢?

6
我最近开始为客户尝试一些noSQL的原型。他们有一个实时应用程序,进行大量插入操作,但较少读取(目前正在使用MySql,并希望尝试一些noSQL解决方案)。
在周末,我尝试了Cassandra 2.0、MongoDB 2.4.9和Redis与普通的Mysql 5.5数据库进行比较。所有这些都在我的Windows i3核心2.30 GHz/8GB RAM笔记本电脑上运行,所以没有高端机器。
表结构如下简单。虽然这是MySQL的DESC,但Cassandra具有相同的结构,在MongoDb中存储为JSON/BSON,但具有相同的结构和索引。它有两个索引(oneway_id和twoway_id)适用于所有三个数据库。 结构(对于所有四个数据库)
+--------------+---------------------+
| Field        | Type                |
+--------------+---------------------+
| tmstamp      | bigint(20) unsigned |
| field_1      | bigint(20) unsigned |
| field_2      | varchar(64)         |
| field_3      | varchar(64)         |
| field_4      | tinyint(3) unsigned |
| field_5      | bigint(20) unsigned |
| field_6      | varchar(25)         |
| field_7      | varchar(15)         |
| field_8      | varchar(15)         |
| field_9      | varchar(15)         |
+--------------+---------------------+

数据库/环境详情

  • MySql 5.6(64位)带有mysql java connector 5.1.28
  • Apache Cassandra 2.0带有datastax 2.0 Java驱动程序
  • MongoDB 2.4.6带有mongo Java驱动程序2.12.0
  • Redis 2.8.17运行在Linux机器上
  • Oracle Java 1.6(64位)
  • Microsoft Windows 7(64位)
  • Intel i3 core 2.30 GHz处理器
  • 8GB RAM

创建了一个简单的Java测试用例,以下是我得到的结果(虽然数字不一致,但延迟基本相同):

100,000条记录

  • MySql 1000,000 - 46秒
  • Cassandra - 54秒
  • MongoDb - 2秒

500,000条记录

  • MySql 1000,000 - 142秒
  • Cassandra - 299秒
  • MongoDb - 41秒

1,000,000条记录

  • MySql 1000,000 - 349秒
  • Cassandra - 699秒
  • MongoDb - 51秒
  • Redis - 34秒

我的问题是,为什么Cassandra对于这样一个小而简单的表插入需要这么长时间?

在Cassandra中,我尝试了内联循环SQL插入和批量插入。有趣的是,批量插入需要更长的时间。我遵循的文档是:

http://www.datastax.com/dev/blog/client-side-improvements-in-cassandra-2-0

我不想使用asyncExecute,因为它无法给出确切的插入时间。

我使用的批量插入如下(比正常插入需要更长时间)

PreparedStatement ps = session.prepare("INSERT INTO some_table (val_1, val_2, val_3, val_4) VALUES (?, ?, ?, ?)");
BatchStatement batch = new BatchStatement();

//for loop start
batch.add(ps.bind(uid, mid1, title1, body1));
//for loop end

session.execute(batch);

我使用insert的内联循环如下:

String sqlInsert = "INSERT INTO some_table (val_1, val_2, val_3, val_4) VALUES (";

// for loop start

sqlInsert += uid+", "+", "+mid1+", "+title1+", "+body1+")";
session.execute(sqlInsert);

// for loop end

现在为什么Cassandra比MySQL慢,更重要的是 - 为什么 MongoDB比Cassandra快得多?我真的希望我做错了什么?

是否有一种方法可以像MongoDB一样直接向Cassandra插入JSON/BSON对象?我猜这可能会让它更快?能否请一些专家帮助我解决这个问题?如果没有答案,我会得出结论:MongoDB比Cassandra更好!

1个回答

17

你的代码正在使用串行插入。每次插入都必须等待前一个插入完成并返回确认后,下一个才能开始。这是一种不好的基准测试方法,任何可以处理多个传入连接的数据库都不应该这样做。如果您真的不想使用 execute_async(正确的方法),那么您应该编写一个多线程压力测试程序,以便插入操作不会阻塞(在客户端方面)并且您真正受到Cassandra节点的限制。基本上,您看到的是您的客户端程序运行的速度,而不是数据库的能力。

有趣的博客文章要点:

http://www.datastax.com/dev/blog/how-not-to-benchmark-cassandra

只有两个原则可以正确进行负载生成:

1. 给Cassandra足够的工作量 2. 在单独的机器上生成工作负载

就是这样!但经常出现错误,从在同一台笔记本电脑上运行的单线程客户端的极端情况,到Python全局解释器锁定的更微妙问题。像二分搜索一样,构建一个好的负载生成器似乎非常困难。如果可能的话,避免自行开发,并使用经过实战考验的工具。


谢谢。你说的都很好。但是我以同样的方式将数据插入到其他数据库(MySQL和MongoDB)中,它们的性能比Cassandra要好得多。我会阅读那篇博客文章并重新审视你的答案。看起来非常有趣! - avijendr
2
你没有使任何数据库饱和,因此需要调整测试方法。这些数据库被设计为处理多个并发操作,而您目前进行的任何测试都将更多地衡量您的代码而不是数据库。一个类比就是试图通过在每个搜索引擎上一次运行100000个查询来找出Google或Yahoo是否能够处理更多负载,并查看哪个最快地完成了查询。实际上,您正在测量的是客户端与互联网的交互,而不是Google或Yahoo后端的性能/吞吐量。 - RussS
测量是交互的过程,当它在本地运行时怎么样?你是认真的吗?我已经使用了多线程插入。但我要重申的是,在插入方面,MongoDB和Mysql的性能比Cassandra更好。对于10000个插入或者说100000个插入(通过X个线程),所花费的时间,延迟比MySQL或MongoDB慢得多。这就是我的观点!顺便说一下,MongoDB、Mysql或Cassandra都没有进行任何调优。我已经阅读了很多文章,关于Cassandra的插入操作,没有太多的性能调优可以做。 - avijendr
在Stackoverflow上发表评论是一件“PINTA”的事情,因为它有字符限制!我很快会更新问题,并提供更多的发现。 - avijendr
我会重申一下,因为可能我没有表达清楚。你有两个主要问题。你的驱动程序正在与数据库本身竞争资源。客户端正在等待操作系统在插入之间执行阻塞操作。 - RussS
3
单机环境下最快的数据库不一定是在1000台机器的集群中最快的数据库。 - JohnC

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