cassandra - 为什么使用 pycassa 导出的 Cassandra 表返回的行数少于通过 CQL SELECT 导出的行数
问题描述
我的任务是将包含数百万条记录的 Cassandra 安装从 2.1 版升级到 3.11 版(最新)。更复杂的是,错误编码的 UTF8 值存在一些内部格式问题。
我通过将每个验证器更改为字节类型来修复 UTF8 问题,因此至少现在所有记录都是可见的(即不会触发格式错误)。但我无法将数据导出到 CSV 文件:
在 cqlsh 中或通过 DataStax 驱动程序在脚本中的 CQL SELECT 命令将是显而易见的解决方案。但是 SELECT 语句的默认 LIMIT 为 10,000,我已经读过将其更改为更大的值会导致各种错误,实际上文档建议它不能设置为超过 2,000,000。所以排除了 CQL 方法。
dsbulk 实用程序将是下一个选择。但是当我在测试表上尝试这个时,它以我无法理解的奇怪编码产生了输出字节字符串。
所以我不得不求助于Plan C,也就是使用Pycassa驱动来导出数据。然而,这又引发了另一个问题——它读取的记录数量大约是 CQL 看到的数量的一半!我的问题是为什么?!
这是我的 python2 pycassa 脚本(其输出旨在与 SQL SELECT 的输出相同,以进行比较):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Python 2 Script to export raw CQL byte output of 'complete' or 'partial' column familes from Cassandra 2.1.x tables
#
# For small table exports, the CQL SELECT statement in table_export2.sh is fine. But SELECT has a default LIMIT of
# 10,000 and a zero LIMIT (meaning none) cannot be specified, and even if it could the process would hang and fall
# over in a heap if millions of rows had to be exported.
#
import sys
import os
import re
import codecs
import collections
import binascii
import pycassa
from pycassa.pool import ConnectionPool
from pycassa.columnfamily import ColumnFamily
cass_node = sys.argv[1] if len(sys.argv) >= 2 else ''
namespace = sys.argv[2] if len(sys.argv) >= 3 else ''
col_fam = sys.argv[3] if len(sys.argv) >= 4 else ''
if col_fam not in [ 'complete', 'partial' ]:
print("Usage: python compart.py {cassandra_host_name} {cassandra_namespace_name}" +
" { complete | partial } [ {CQL_file_name} ]")
sys.exit(1)
file_path = sys.argv[4] if len(sys.argv) == 5 else ''
write_file = sys.stdout if file_path == '' else open(file_path, 'w')
# Export rows
#
# Text file /etc/cassandra/conf/cassandra.yaml must include:
#
# start_rpc: true
# rpc_port: 9171
#
pool = ConnectionPool(namespace, [ cass_node + ':9171' ], \
credentials={'username': 'cassandra', 'password': 'cassandra'} )
table = pycassa.ColumnFamily(pool, col_fam)
print " key | column1 | value"
print "----------+------------------------------------------------------------------------------+-------"
for fk, fv in table.get_range(start='', finish=''):
key = binascii.hexlify(fk)
if type(fv) == type(collections.OrderedDict()):
for column1 in fv.keys():
value = fv[column1]
if value != '':
value = binascii.hexlify(value)
print '%9s |%77s |%6s' % ('0x' + key, '0x' + binascii.hexlify(column1), '0x' + value)
这会产生大约 700 行,但是当我在 cqlsh 中运行“SELECT COUNT(*) FROM complete”时,大约有 1300 行。我使用 WinMerge 检查了输出,丢失的记录是具有较大键值的块。所以看起来 pycassa/Thrift 驱动程序由于某种原因错过了最近的记录?!
有任何想法吗?
-=-=-=-=-=-=-=-=-=-=-=
回应 Alex Ott 的第一条评论:
非常感谢您及时回复亚历克斯。
表架构是:
CREATE TABLE app2_uat.complete (
key blob,
column1 blob,
value blob,
PRIMARY KEY (key, column1)
) WITH COMPACT STORAGE
AND CLUSTERING ORDER BY (column1 ASC)
AND caching = '{"keys":"ALL", "rows_per_partition":"NONE"}'
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'}
AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND dclocal_read_repair_chance = 0.0
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = 'NONE';
我试过的 dsbulk 命令是:
dsbulk unload -u cassandra -p cassandra -h '["172.31.44.160"]' -query "SELECT * from app2_uat.complete;"
我对这种方法的第一个问题是它使用了糟糕的旧 CQL SELECT 及其 LIMIT ,我无法随意增加或消除它 - SELECT 出于这个原因!
我的第二个问题是它以乱码格式输出 blob,例如:
key,column1,value
MTU4,Yy0xNTgyZmYxYzkwMGYxNzQ0ZmFhOWVlOGRkZWQxOTM2OGI3MA==,IA==
MTU4,Yy0xNThhMmYyNDliMWJhOWI0YWVmOTc4OTM5ZjE0NzZmNGFjNQ==,IA==
MTU4,Yy0xNThjODJmZGYyZDIyMjk0YWFjODBhNjQ5Y2NiZGZhMDk5Mg==,IA==
OTQ=,Yy05NDRhYjYyM2YxODMzNDQwM2M5MmNmOTc0ZWJkNjRiZmY0,IA==
MTE3,Yy0xMTc3OTEzNWE0OTNlYjU0YzU1YTNjMTdhNzc5YTk2ZTM1ZQ==,
MTE3,Yy0xMTdiYzQ2ZmNhNTc1ZmQ0MDk3YmQ0NTYxODdhMzQxYTQ1Ng==,
NTg=,Yy01ODZmZmVhNTczYjRjNzQwNGJiYjFjNzM2MzMxNTM5Mzhj,
NTg=,Yy01ODhjMmI3ZWJjNWYwNjQ1OGQ5NGMwNDljOWI1OGRiYjk0,
我与 CQL(和我的 pycassa 脚本)产生的十六进制输出无关:
key | column1 | value
----------+------------------------------------------------------------------------------+-------
0x36 | 0x632d3632373566376561633136323131653338343730303230303839646531306266 | 0x20
0x36 | 0x632d3633383563356632633136323131653339636363303230303839646531306266 | 0x20
0x36 | 0x632d3634363737643663633136323131653362346135303230303839646531306266 | 0x20
0x36 | 0x632d3635353933303361633136323131653361326137303230303839646531306266 | 0x20
0x36 | 0x632d3636326264653836633136323131653362323363303230303839646531306266 | 0x20
0x36 | 0x632d3637306662343934633136323131653361616439303230303839646531306266 | 0x20
0x36 | 0x632d3637663931376230633136323131653361623963303230303839646531306266 | 0x20
0x36 | 0x632d3638636164373061633136323131653339396134303230303839646531306266 | 0x20
你能想到为什么 pycassa 不会输出在 CQL 中可见的记录块的任何原因吗?
解决方案
推荐阅读
- code-coverage - 如何将 coverage.svg 限制在一个阶段或从一个阶段删除覆盖率报告?
- flutter - 我可以使用颤振的 TabBar 来过滤卡片列表吗?
- youtube-api - API 密钥如何在 3rd 方应用程序中分发和使用?
- visual-studio-code - VS Code ssh 远程未在新选项卡中打开文件
- amazon-ecs - Amazon ECS,容量提供商无法提供所需容量
- reactjs - 使用箭头键导航/选择 ag-grid 表行
- javascript - 在 iFrame 或其他替代方案中自动播放取消静音 YouTube 视频
- c - 将 mremap(..., MREMAP_FIXED) 与 valgrind 一起使用
- mysql - MySQL JSON 数组列按值计数
- javascript - JavaScript Jest 测试使用 fetch() 并从 JSON 数据中获取“未定义”