日常踩坑_关于cassandra使用了count(1)又又又超时了

发布时间 2023-09-14 13:24:58作者: Dean_001

背景提要

由于习惯了用Mysql和Oracle这种数据库,切换到Cassandra之后真是踩了一系列的坑
本来是一个简单的请求,I just want 简简单单求个表的总行数
而表也不是什么千万级别的大表,just 只是小小的几千条数据而已,然而cassandra非常给面子,本应该在千万级别查询才出的错,出现在了我一张千行数据的小表上
ReadTimeout: Error from server: code=1200 [Coordinator node timed out waiting for replica nodes' responses] message="Operation timed out - received only 0 responses." info={'received_responses': 0, 'required_responses': 1, 'consistency': 'ONE'}

解决

其实也不算是彻底解决,只是对于我当下可以解决(不过尝试了两千万数据,也可以计数,只是稍微慢一点)
原本的cql: select count(1) from keyspaceName.table_name;
完整的ssh command:sudo -u dean cqlsh 127.0.0.1 --ssl -u cassandra -ppassword -e 'use keyspaceName; select count(1) FROM table_name;' |grep -A2 count | xargs| awk '{print $NF}' 这条命令会最终直接输出行数

修改后的cql:copy keyspaceName.table_name(primary_key) to '/dev/null';
完整的ssh command: sudo -u dean cqlsh 127.0.0.1 --ssl -u cassandra -ppassword -e "copy keyspaceName.table_name(primary_key) to '/dev/null';" | sed -n 5p | sed 's/ .*//'

浅浅解析一下这条命令吧
cqlsh 127.0.0.1 --ssl -u cassandra -ppassword -e "copy keyspaceName.table_name(primary_key) to '/dev/null';

*  cqlsh 是 Cassandra Query Language Shell 的命令行工具,用于与 Cassandra 数据库交互。
*  127.0.0.1 是Cassandra sever
*  --ssl 是连接到 Cassandra 数据库的通信将通过 SSL/TLS 进行加密
*  -u cassandra -ppassword 是登录Cassandra数据库的用户及密码
*  -e 后跟的是实际的 CQL 查询字符串
*  copy keyspaceName.table_name(primary_key) to '/dev/null' 是要执行的 CQL 查询。它指定了要从keyspaceName下的 table_name 表中导出数据,但仅包括指定的 primary_key列,并将结果导出到 /dev/null,这实际上是将结果丢弃。
*   |:这是管道操作符,它将前一个命令的输出传递给下一个命令。
*  sed -n 5p:
     sed 是流编辑器,用于处理文本流的文本处理工具。
     -n 选项用于关闭默认的输出,只输出经过处理的文本。
     5p 是 sed 命令,它表示仅打印第五行。

*   |:再次使用管道操作符,将前一个命令的输出传递给下一个命令。
*   sed 's/ .*//':
    这是另一个 sed 命令,用于处理前一个命令的输出。
    's/ .*//' 是一个替换命令,它会将输入文本中的第一个空格及其后的所有字符替换为空字符串。这样可以提取第五行的第一个单词或字符串。

这条命令最终输出的就是表的总行数了

其他失败的无用尝试

1、网上大批量出现的是第一种更改request timeout的时间
即在cassandra server上更改cassandra.yaml里的如下参数

      sudo nano /etc/cassandra/cassandra.yaml
      # How long the coordinator should wait for read operations to complete
      read_request_timeout_in_ms: 50000
      # How long the coordinator should wait for seq or index scans to complete
      range_request_timeout_in_ms: 100000
      # How long the coordinator should wait for writes to complete
      write_request_timeout_in_ms: 20000
      # How long the coordinator should wait for counter writes to complete
      counter_write_request_timeout_in_ms: 50000
      # How long a coordinator should continue to retry a CAS operation
      # that contends with other proposals for the same row
      cas_contention_timeout_in_ms: 10000
      # How long the coordinator should wait for truncates to complete
      # (This can be much longer, because unless auto_snapshot is disabled
      # we need to flush first so we can snapshot before removing the data.)
      truncate_request_timeout_in_ms: 600000
      # The default timeout for other, miscellaneous operations
      request_timeout_in_ms: 100000

      # How long before a node logs slow queries. Select queries that take longer than
      # this timeout to execute, will generate an aggregated log message, so that slow queries
      # can be identified. Set this value to zero to disable slow query logging.
      slow_query_log_timeout_in_ms: 5000

然后搭配 cqlsh --request-timeout=60000 使用
但实际上,当我手动执行cql时发现,实际返回readTimeout错误返回时花费的时间并没有超过timeout的设置值,
也就是说实际问题不是给cassandra运行cql的时间太短,而是cassandra根本无法正常执行该cql,所以实际需要从cql本身入手,而非超时设置上

2、关于如何正常计数,cassandra给出的官方解答是增加一列计数列counter
我本身没有去尝试这个计数列,因为我的表是一个比较老的表,牵涉很多,增加额外的一列用来计数是一个非常不合理的更改
其次,稍微了解了一下cassandra的这个计数列,该列实际是需要自己手动进行行数的增减的,这非常的不人性化

3、网上提出了可以使用第三方工具或库去进行计数,比较推荐的是 cassandra-count(一个开源小工具)和 使用Cassandra的JMX接口获取总数
cassandra-count:github开源项目cassandra-count
该工具安装运行还是挺简单的,但后续安装之后一直报找不到NoHostAvaliable,没有进一步的研究
但该工具去计算计数时,实际会消耗一些资源,降低性能,所以谨慎选择

Cassandra的JMX接口获取总数(实际配置过程略有些复杂,以下步骤供诸君参考)

* 启用 JMX 监控:
    首先,确保您已经启用了 Cassandra 的 JMX 监控功能。这通常需要在 Cassandra 配置文件中进行配置。查找并编辑  `cassandra-env.sh`  或 `cassandra.in.sh`(取决于Cassandra 版本),并确保以下行没有被注释掉:
    JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.port=<JMX_PORT>" 
    将 `<JMX_PORT>` 替换为您希望用于 JMX 连接的端口号。

* 重启 Cassandra: 在修改了配置后,重启 Cassandra 以应用更改。
* 使用 JMX 客户端: 使用 JMX 客户端工具(例如 JConsole、VisualVM 或编程语言中的 JMX 客户端库)连接到正在运行的 Cassandra 实例的 JMX 端口。需要提供连接信息,包括主机名和端口号。
* 浏览 MBeans: 连接到 Cassandra 的 JMX 后,浏览 MBeans(管理 Bean)树以查找与表相关的统计信息。通常,Cassandra 的表信息存储在 MBeans 的 `org.apache.cassandra.db` 部分下。
* 查询表的总行数
  在 MBeans 中找到与表相关的 MBean,查看其属性以获取总行数(RowCount)。通常,表的 MBean 名称可能与表的 keyspace 和表名相关

为什么Cassandra不能进行有效的count计数

在不断的尝试获取一个有效的行数时不停的跳坑,让我对于cassandra的怨气达到了巅峰,为什么一个数据库的能设计成只是求一个行数都如此艰难的地步
1、数据分布和分片
cassandra是分布式架构嘛,所以cassandra将数据分布在了多个节点上,并且使用了分片(sharding) 来处理大量的数据,这意味着数据分散存储在了不同的节点上,要计算总行数时,就需要从所有节点检索并汇总计数,这期间涉及到了网络通信和数据传输,导致了查询变得非常耗时

2、分布式一致性
cassandra强调分布式系统中的高可用性和分区容忍性,为了实现这些目标,cassandra采用的是分布式一致性模型,这意味着在多个节点之间的数据一致性需要经过复杂的协调和通信,这增加了查询的延迟

3、数据模型
Cassandra的数据模型是面向列族(Column Family)的,而不是传统的关系型数据库,这种数据模型适用于高度分布式和横向扩展的场景,但不像传统关系型数据库会优化count查询

4、没有内置索引
Cassandra没有内置的用于计算总行数的索引,这意味着要执行 count 查询,通常需要扫描全表或分区,这在大型表上非常耗时

总之,就是希望cassandra会优化吧

跳坑结束,祝你开心!