Cassandra - 单节点批量插入性能不佳 - table
Cassandra - poor performance with batch insert in single-node with single-table
上下文
我只有一个 Cassandra 节点,本地安装在我的 PC 上 Windows 10(Core i5、16GB 内存、SSD 驱动器)。
我创建了一个 table 这样的:
CREATE KEYSPACE covid19 WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': '1'
};
CREATE TABLE covid19.cases (
pesel text,
test_date date,
result boolean,
PRIMARY KEY ((pesel), test_date)
)
WITH CLUSTERING ORDER BY (test_date DESC);
pesel
是唯一的,一个人的 10 位数 ID。
然后我生成了 10000 行样本数据,看起来像这样:
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000001', '2020-03-10', true);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000002', '2020-03-10', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000003', '2020-03-10', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000004', '2020-03-12', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000005', '2020-03-12', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000006', '2020-03-12', false);
...
最后,我使用 cqlsh 加载了数据:source 'cases.cql';
问题 1
加载 10 000 行需要 51 秒。这正常吗?
我期待 Cassandra 的插入速度超快,而这与没有事务的 SQLite 相当 (59s)。如果我在 SQLite 中用 BEGIN
& COMMIT
包装插入,这需要不到一秒钟的时间。这给我们带来了另一个问题...
问题 2
批量插入。缓慢的批量插入。到单个分区,在单个节点上。
我用 BEGIN BATCH
和 APPLY BATCH;
包装了插入内容。在那之后,source
花了很长时间,我在超过 4 分钟标记后停止测量。
是的,我知道批量插入的错误用法。据我所知,如果需要插入到不同的分区,那么使用批量插入是一种反模式,这是有道理的。这里不是这种情况。
为什么批量插入在单个节点(因此是单个分区)上这么慢?
我在这里错过了什么?
Cassandra 不是 SQLite。它没有针对此用例进行优化(运行ning 在一台机器上)。它针对水平缩放进行了优化。您可以在本地 运行 它,但通常这仅用于测试。而且我不希望它以任何形式针对 运行ning 在 Windows.
上进行优化
在 https://blog.softwaremill.com/cassandra-writes-in-depth-6ea8d7581eb
查看 Cassandra 写入的工作方式
为了更详细一点,以下是每次插入都会发生的情况:
- 将行插入 memtable,这不仅仅是追加,因为它必须保持排序
- 向 CommitLog(磁盘上的文件)追加一行。这是一个追加,没有查找,但它仍然是一个磁盘操作。
- 在某些时候会有一些刷新操作。 Memtables 写在磁盘上,其他数据计算并附加到它们(索引,布隆过滤器)。删除所有提交日志文件。
- 您的客户端代码可能不是多线程的,因此需要一些时间来获取响应并发送另一个插入。
考虑到您 运行 在您的机器上(16GB!),memtable 可能小到足以触发 10000 行的多次刷新。也可能会开始一些压缩,这取决于你已经拥有的东西。
请注意,每个步骤至少涉及一次磁盘写入。台式机 SSD 不错,但不是那么好。
我检查了生产 Cassandra 集群;它得到 2000 writes/sec,写入的平均延迟小于 1 毫秒,同时还提供 2000 reads/sec 的平均延迟为 1.5 毫秒。但这发生在 Linux 服务器上,具有 60GB RAM 和 NVME SSD。
由于额外的协调工作,批次会更糟。批处理不会对您的设置有任何改进,只有 1 个节点没有什么可协调的。参见 https://medium.com/@foundev/cassandra-batch-loading-without-the-batch-keyword-40f00e35e23e
上下文
我只有一个 Cassandra 节点,本地安装在我的 PC 上 Windows 10(Core i5、16GB 内存、SSD 驱动器)。
我创建了一个 table 这样的:
CREATE KEYSPACE covid19 WITH replication = {
'class': 'SimpleStrategy',
'replication_factor': '1'
};
CREATE TABLE covid19.cases (
pesel text,
test_date date,
result boolean,
PRIMARY KEY ((pesel), test_date)
)
WITH CLUSTERING ORDER BY (test_date DESC);
pesel
是唯一的,一个人的 10 位数 ID。
然后我生成了 10000 行样本数据,看起来像这样:
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000001', '2020-03-10', true);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000002', '2020-03-10', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000003', '2020-03-10', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000004', '2020-03-12', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000005', '2020-03-12', false);
INSERT INTO cases (pesel, test_date, result) VALUES ('0000000006', '2020-03-12', false);
...
最后,我使用 cqlsh 加载了数据:source 'cases.cql';
问题 1
加载 10 000 行需要 51 秒。这正常吗?
我期待 Cassandra 的插入速度超快,而这与没有事务的 SQLite 相当 (59s)。如果我在 SQLite 中用 BEGIN
& COMMIT
包装插入,这需要不到一秒钟的时间。这给我们带来了另一个问题...
问题 2
批量插入。缓慢的批量插入。到单个分区,在单个节点上。
我用 BEGIN BATCH
和 APPLY BATCH;
包装了插入内容。在那之后,source
花了很长时间,我在超过 4 分钟标记后停止测量。
是的,我知道批量插入的错误用法。据我所知,如果需要插入到不同的分区,那么使用批量插入是一种反模式,这是有道理的。这里不是这种情况。
为什么批量插入在单个节点(因此是单个分区)上这么慢?
我在这里错过了什么?
Cassandra 不是 SQLite。它没有针对此用例进行优化(运行ning 在一台机器上)。它针对水平缩放进行了优化。您可以在本地 运行 它,但通常这仅用于测试。而且我不希望它以任何形式针对 运行ning 在 Windows.
上进行优化在 https://blog.softwaremill.com/cassandra-writes-in-depth-6ea8d7581eb
查看 Cassandra 写入的工作方式为了更详细一点,以下是每次插入都会发生的情况:
- 将行插入 memtable,这不仅仅是追加,因为它必须保持排序
- 向 CommitLog(磁盘上的文件)追加一行。这是一个追加,没有查找,但它仍然是一个磁盘操作。
- 在某些时候会有一些刷新操作。 Memtables 写在磁盘上,其他数据计算并附加到它们(索引,布隆过滤器)。删除所有提交日志文件。
- 您的客户端代码可能不是多线程的,因此需要一些时间来获取响应并发送另一个插入。
考虑到您 运行 在您的机器上(16GB!),memtable 可能小到足以触发 10000 行的多次刷新。也可能会开始一些压缩,这取决于你已经拥有的东西。
请注意,每个步骤至少涉及一次磁盘写入。台式机 SSD 不错,但不是那么好。
我检查了生产 Cassandra 集群;它得到 2000 writes/sec,写入的平均延迟小于 1 毫秒,同时还提供 2000 reads/sec 的平均延迟为 1.5 毫秒。但这发生在 Linux 服务器上,具有 60GB RAM 和 NVME SSD。
由于额外的协调工作,批次会更糟。批处理不会对您的设置有任何改进,只有 1 个节点没有什么可协调的。参见 https://medium.com/@foundev/cassandra-batch-loading-without-the-batch-keyword-40f00e35e23e