Почему экспорт таблицы Cassandra с pycassa возвращает меньше строк, чем с помощью CQL SELECT - PullRequest
0 голосов
/ 11 февраля 2020

Мне было поручено обновить установку Cassandra с миллионами записей с версии 2.1 до 3.11 (последняя версия). Чтобы усложнить ситуацию, существуют некоторые внутренние проблемы форматирования с неправильно кодированными значениями UTF8.

Я исправил проблемы с UTF8, изменив каждый валидатор на тип Byte, так что, по крайней мере, теперь все записи видимы (то есть не вызывают ошибки формата) , Но у меня возникают проблемы при экспорте данных в файлы CSV:

  1. Команда CQL SELECT, либо в cql sh, либо в сценарии через драйвер DataStax, была бы очевидным решением. Но операторы SELECT имеют LIMIT по умолчанию, равный 10 000, и я прочитал, что изменение этого значения на намного большее приведет к всевозможным ошибкам, и фактически документация рекомендует, чтобы он не был установлен более чем на 2 000 000. Так что это исключенный подход CQL.

  2. Утилита dsbulk будет следующим выбором. Но когда я попробовал это на тестовой таблице, он вывел строки выходных байтов в странной кодировке, которую я не мог понять.

Так что мне пришлось вернуться к Плану 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)

This выдает около 700 строк, но когда я запускаю «SELECT COUNT (*) FROM complete» в cql sh, получается около 1300 строк. Я проверил вывод, используя WinMerge, и отсутствующие записи являются блоком с большими значениями ключа. Похоже, драйвер pycassa / Thrift по какой-то причине пропускает более свежие записи? !!

Есть идеи?

- = - = - = - = - = - = - = - = - = - = - =

В ответ на первый комментарий Алекса Отта:

Большое спасибо за ваш быстрый ответ Алекс.

Схема таблицы:

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 со старым значением, которое я не могу произвольно увеличить или исключить - SELECTs отсутствуют по этой причине!

Моя вторая проблема заключается в том, что он выводит большие двоичные объекты в формате гиббери sh, например:

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?

...