由于大型墓碑扫描,如何避免 Cassandra 读取失败?
How to avoid Cassandra read failure, due to large tombstone scans?
我使用 Apache Spark 从 Cassandra 读取数据,它在后台执行基于令牌范围的扫描。但是,最近我在从我的 Cassandra table.
读取数据时看到很多失败
读取失败,原因如下:
Caused by: com.datastax.driver.core.exceptions.ReadFailureException: Cassandra failure during read query at consistency LOCAL_ONE (1 responses were required but only 0 replica responded, 1 failed)
at com.datastax.driver.core.exceptions.ReadFailureException.copy(ReadFailureException.java:85)
at com.datastax.driver.core.exceptions.ReadFailureException.copy(ReadFailureException.java:27)
at com.datastax.driver.core.DriverThrowables.propagateCause(DriverThrowables.java:37)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:245)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:68)
当我检查系统日志时,我发现了以下问题:
ERROR [ReadStage-1] 2020-04-09 10:25:59,701 StorageProxy.java:1896 - Scanned over 100001 tombstones during query 'SELECT * FROM my_keyspace.my_table WHERE token(id) > -5868586221781016365 AND token(id) <= -5347313590141106513 LIMIT 5000' (last scanned row partion key was (my_key_1)); query aborted
错误日志很简单,由于墓碑扫描导致读取失败。
我不明白的是,我 运行 从事同一份 Spark 工作已有一年多了,但从未遇到过这个问题。但是,那是次要的。首先我想知道如何解决这个问题?
可以为未传递的列值创建墓碑,因为我使用 Cassandra Insert Json 功能来插入文档。确认 ,此方法将创建墓碑。
我该如何解决这个问题?基于非空值创建多个插入查询是一个复杂的选项。
在我看来,即使插入虚拟值也是不切实际的。从这些 table 中读取数据的所有客户端都需要进行更改。
我个人认为,如果某个列在 JSON 中不存在,Cassandra 永远不应该为该列创建墓碑。
解决这个问题的其他方法是什么?
你有几种可能性:
- 不要将数据作为 JSON 插入,而是在应用程序中解析 JSON,并使用
unset
而不是缺失值插入数据(默认情况下,look to docs) - 您可以通过将 JSON 映射到 POJO 并使用还支持用 unset
替换空值的对象映射器来简化您的工作。这是最好的方法,因为墓碑会影响所有应用程序和 Cassandra 本身。但真正的解决方案将取决于您的用例——您是只插入新数据,还是同时更新现有数据?在后一种情况下,您需要确保覆盖以前的数据
- 减小 Spark 应用程序中的页面大小以在一页中读取更少的行。这由
spark.cassandra.input.fetch.size_in_rows
参数 described in docs 调节。如果您将 DSE 与 DSE Analytics 一起使用,您可能需要禁用连续分页
我使用 Apache Spark 从 Cassandra 读取数据,它在后台执行基于令牌范围的扫描。但是,最近我在从我的 Cassandra table.
读取数据时看到很多失败读取失败,原因如下:
Caused by: com.datastax.driver.core.exceptions.ReadFailureException: Cassandra failure during read query at consistency LOCAL_ONE (1 responses were required but only 0 replica responded, 1 failed)
at com.datastax.driver.core.exceptions.ReadFailureException.copy(ReadFailureException.java:85)
at com.datastax.driver.core.exceptions.ReadFailureException.copy(ReadFailureException.java:27)
at com.datastax.driver.core.DriverThrowables.propagateCause(DriverThrowables.java:37)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:245)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:68)
当我检查系统日志时,我发现了以下问题:
ERROR [ReadStage-1] 2020-04-09 10:25:59,701 StorageProxy.java:1896 - Scanned over 100001 tombstones during query 'SELECT * FROM my_keyspace.my_table WHERE token(id) > -5868586221781016365 AND token(id) <= -5347313590141106513 LIMIT 5000' (last scanned row partion key was (my_key_1)); query aborted
错误日志很简单,由于墓碑扫描导致读取失败。
我不明白的是,我 运行 从事同一份 Spark 工作已有一年多了,但从未遇到过这个问题。但是,那是次要的。首先我想知道如何解决这个问题?
可以为未传递的列值创建墓碑,因为我使用 Cassandra Insert Json 功能来插入文档。确认
我该如何解决这个问题?基于非空值创建多个插入查询是一个复杂的选项。
在我看来,即使插入虚拟值也是不切实际的。从这些 table 中读取数据的所有客户端都需要进行更改。
我个人认为,如果某个列在 JSON 中不存在,Cassandra 永远不应该为该列创建墓碑。
解决这个问题的其他方法是什么?
你有几种可能性:
- 不要将数据作为 JSON 插入,而是在应用程序中解析 JSON,并使用
unset
而不是缺失值插入数据(默认情况下,look to docs) - 您可以通过将 JSON 映射到 POJO 并使用还支持用unset
替换空值的对象映射器来简化您的工作。这是最好的方法,因为墓碑会影响所有应用程序和 Cassandra 本身。但真正的解决方案将取决于您的用例——您是只插入新数据,还是同时更新现有数据?在后一种情况下,您需要确保覆盖以前的数据 - 减小 Spark 应用程序中的页面大小以在一页中读取更少的行。这由
spark.cassandra.input.fetch.size_in_rows
参数 described in docs 调节。如果您将 DSE 与 DSE Analytics 一起使用,您可能需要禁用连续分页