company_banner

Битва двух якодзун, или Cassandra vs HBase. Опыт команды Сбербанка

    Это даже не шутка, похоже, что именно эта картинка наиболее точно отражает суть этих БД, и в конце будет понятно почему:



    Согласно DB-Engines Ranking, две самых популярных NoSQL колоночных базы — это Cassandra (далее CS) и HBase (HB).



    Волею судеб наша команда управления загрузки данных в Сбербанке уже давно и плотно работает с HB. За это время мы достаточно хорошо изучили её сильные и слабые стороны и научились её готовить. Однако наличие альтернативы в виде CS все время заставляло немного терзать себя сомнениями: а правильный ли выбор мы сделали? Тем более, что результаты сравнения, выполненного DataStax, говорили, что CS легко побеждает HB практически с разгромным счетом. С другой стороны, DataStax — заинтересованное лицо, и верить на слово тут не стоит. Также смущало достаточно малое количество информации об условиях тестирования, поэтому мы решили выяснить самостоятельно, кто же является королем BigData NoSql, и полученные результаты оказались весьма интересны.

    Однако прежде чем перейти к результатам выполненных тестов, необходимо описать существенные аспекты конфигураций среды. Дело в том, что CS может использоваться в режиме допускающем потерю данных. Т.е. это когда только один сервер (нода) отвечает за данные некоего ключа и если он по какой-то причине отвалился, то значение этого ключа будет потеряно. Для многих задач это не критично, однако для банковской сферы это скорее исключение, чем правило. В нашем случае принципиально иметь несколько копий данных для надежного хранения.

    Поэтому рассматривался исключительно режим работы CS в режиме тройной репликации, т.е. создание кейспейса выполнялось с такими параметрами:

    CREATE KEYSPACE ks WITH REPLICATION = {'class' : 'NetworkTopologyStrategy', 'datacenter1' : 3};

    Далее есть два способа обеспечить необходимый уровень консистентности. Общее правило:
    NW + NR > RF

    Что означает, что количество подтверждений от нод при записи (NW) плюс количество подтверждений от нод при чтении (NR) должно быть больше фактора репликации. В нашем случае RF = 3 и значит подходят следующие варианты:
    2 + 2 > 3
    3 + 1 > 3

    Так как нам принципиально важно максимально надежно сохранить данные, была выбрана схема 3+1. К тому же HB работает по аналогичному принципу, т.е. такое сравнение будет более честным.

    Необходимо отметить, что DataStax в своем исследовании делали наоборот, они ставили RF = 1 и для CS и для HB (для последней путем изменения настроек HDFS). Это действительно важный аспект, потому что влияние на производительность CS в этом случае огромное. Например, на картинке ниже показан рост времени требующегося для загрузки данных в CS:



    Тут мы видим следующее, чем больше конкурирующих потоков пишет данные, тем дольше времени это занимает. Это естественно, но важно, что при этом деградация производительности для RF=3 существенно выше. Иными словами, если мы пишем в 4 таблицы в каждую по 5 потоков (итого 20), то RF=3 проигрывает примерно в 2 раза (150 секунд RF=3 против 75 для RF=1). Но если мы увеличим нагрузку, загружая данные в 8 таблиц в каждую по 5 потоков (итого 40), то проигрыш RF=3 уже в 2,7 раз (375 секунд против 138).

    Возможно, отчасти в этом заключается секрет успешного для CS нагрузочного тестирования выполненного DataStax, потому что для HB на нашем стенде изменение фактора репликации с 2 до 3 не оказало никакого влияния. Т.е. диски не являются узким местом для HB для нашей конфигурации. Однако тут есть много и других подводных камней, потому что нужно отметить, что наша версия HB была немного пропатчена и затюнена, среды совершенно разные и т.д. Также стоит отметить, что возможно я просто не знаю как правильно готовить CS и существуют какие-то более эффективные способы работать с ней и надеюсь в комментариях мы выясним это. Но обо всем по порядку.

    Все тесты производились на железном кластере состоящем из 4 серверов, каждый в конфигурации:

    CPU: Xeon E5-2680 v4 @ 2.40GHz 64 threads.
    Диски: 12 штук SATA HDD
    java version: 1.8.0_111


    Версия CS: 3.11.5

    Параметры cassandra.yml
    num_tokens: 256
    hinted_handoff_enabled: true
    hinted_handoff_throttle_in_kb: 1024
    max_hints_delivery_threads: 2
    hints_directory: /data10/cassandra/hints
    hints_flush_period_in_ms: 10000
    max_hints_file_size_in_mb: 128
    batchlog_replay_throttle_in_kb: 1024
    authenticator: AllowAllAuthenticator
    authorizer: AllowAllAuthorizer
    role_manager: CassandraRoleManager
    roles_validity_in_ms: 2000
    permissions_validity_in_ms: 2000
    credentials_validity_in_ms: 2000
    partitioner: org.apache.cassandra.dht.Murmur3Partitioner
    data_file_directories:
    — /data1/cassandra/data # каждая директория dataN — отдельный диск
    — /data2/cassandra/data
    — /data3/cassandra/data
    — /data4/cassandra/data
    — /data5/cassandra/data
    — /data6/cassandra/data
    — /data7/cassandra/data
    — /data8/cassandra/data
    commitlog_directory: /data9/cassandra/commitlog
    cdc_enabled: false
    disk_failure_policy: stop
    commit_failure_policy: stop
    prepared_statements_cache_size_mb:
    thrift_prepared_statements_cache_size_mb:
    key_cache_size_in_mb:
    key_cache_save_period: 14400
    row_cache_size_in_mb: 0
    row_cache_save_period: 0
    counter_cache_size_in_mb:
    counter_cache_save_period: 7200
    saved_caches_directory: /data10/cassandra/saved_caches
    commitlog_sync: periodic
    commitlog_sync_period_in_ms: 10000
    commitlog_segment_size_in_mb: 32
    seed_provider:
    — class_name: org.apache.cassandra.locator.SimpleSeedProvider
    parameters:
    — seeds: "*,*"
    concurrent_reads: 256 # пробовали 64 — разницы не замечено
    concurrent_writes: 256 # пробовали 64 — разницы не замечено
    concurrent_counter_writes: 256 # пробовали 64 — разницы не замечено
    concurrent_materialized_view_writes: 32
    memtable_heap_space_in_mb: 2048 # пробовали 16 Гб — было медленнее
    memtable_allocation_type: heap_buffers
    index_summary_capacity_in_mb:
    index_summary_resize_interval_in_minutes: 60
    trickle_fsync: false
    trickle_fsync_interval_in_kb: 10240
    storage_port: 7000
    ssl_storage_port: 7001
    listen_address: *
    broadcast_address: *
    listen_on_broadcast_address: true
    internode_authenticator: org.apache.cassandra.auth.AllowAllInternodeAuthenticator
    start_native_transport: true
    native_transport_port: 9042
    start_rpc: true
    rpc_address: *
    rpc_port: 9160
    rpc_keepalive: true
    rpc_server_type: sync
    thrift_framed_transport_size_in_mb: 15
    incremental_backups: false
    snapshot_before_compaction: false
    auto_snapshot: true
    column_index_size_in_kb: 64
    column_index_cache_size_in_kb: 2
    concurrent_compactors: 4
    compaction_throughput_mb_per_sec: 1600
    sstable_preemptive_open_interval_in_mb: 50
    read_request_timeout_in_ms: 100000
    range_request_timeout_in_ms: 200000
    write_request_timeout_in_ms: 40000
    counter_write_request_timeout_in_ms: 100000
    cas_contention_timeout_in_ms: 20000
    truncate_request_timeout_in_ms: 60000
    request_timeout_in_ms: 200000
    slow_query_log_timeout_in_ms: 500
    cross_node_timeout: false
    endpoint_snitch: GossipingPropertyFileSnitch
    dynamic_snitch_update_interval_in_ms: 100
    dynamic_snitch_reset_interval_in_ms: 600000
    dynamic_snitch_badness_threshold: 0.1
    request_scheduler: org.apache.cassandra.scheduler.NoScheduler
    server_encryption_options:
    internode_encryption: none
    client_encryption_options:
    enabled: false
    internode_compression: dc
    inter_dc_tcp_nodelay: false
    tracetype_query_ttl: 86400
    tracetype_repair_ttl: 604800
    enable_user_defined_functions: false
    enable_scripted_user_defined_functions: false
    windows_timer_interval: 1
    transparent_data_encryption_options:
    enabled: false
    tombstone_warn_threshold: 1000
    tombstone_failure_threshold: 100000
    batch_size_warn_threshold_in_kb: 200
    batch_size_fail_threshold_in_kb: 250
    unlogged_batch_across_partitions_warn_threshold: 10
    compaction_large_partition_warning_threshold_mb: 100
    gc_warn_threshold_in_ms: 1000
    back_pressure_enabled: false
    enable_materialized_views: true
    enable_sasi_indexes: true

    Настройки GC:

    ### CMS Settings
    -XX:+UseParNewGC
    -XX:+UseConcMarkSweepGC
    -XX:+CMSParallelRemarkEnabled
    -XX:SurvivorRatio=8
    -XX:MaxTenuringThreshold=1
    -XX:CMSInitiatingOccupancyFraction=75
    -XX:+UseCMSInitiatingOccupancyOnly
    -XX:CMSWaitDuration=10000
    -XX:+CMSParallelInitialMarkEnabled
    -XX:+CMSEdenChunksRecordAlways
    -XX:+CMSClassUnloadingEnabled


    Памяти jvm.options выделялось 16Gb (еще пробовали 32 Gb, разницы не замечено).

    Создание таблиц выполнялось командой:

    CREATE TABLE ks.t1 (id bigint PRIMARY KEY, title text) WITH compression = {'sstable_compression': 'LZ4Compressor', 'chunk_length_kb': 64};

    Версия HB: 1.2.0-cdh5.14.2 (в классе org.apache.hadoop.hbase.regionserver.HRegion нами был исключен MetricsRegion который приводил к GC при кол-ве регионов более 1000 на RegionServer)

    Параметры non-default HBase
    zookeeper.session.timeout: 120000
    hbase.rpc.timeout: 2 minute(s)
    hbase.client.scanner.timeout.period: 2 minute(s)
    hbase.master.handler.count: 10
    hbase.regionserver.lease.period, hbase.client.scanner.timeout.period: 2 minute(s)
    hbase.regionserver.handler.count: 160
    hbase.regionserver.metahandler.count: 30
    hbase.regionserver.logroll.period: 4 hour(s)
    hbase.regionserver.maxlogs: 200
    hbase.hregion.memstore.flush.size: 1 GiB
    hbase.hregion.memstore.block.multiplier: 6
    hbase.hstore.compactionThreshold: 5
    hbase.hstore.blockingStoreFiles: 200
    hbase.hregion.majorcompaction: 1 day(s)
    HBase Service Advanced Configuration Snippet (Safety Valve) for hbase-site.xml:
    hbase.regionserver.wal.codecorg.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec
    hbase.master.namespace.init.timeout3600000
    hbase.regionserver.optionalcacheflushinterval18000000
    hbase.regionserver.thread.compaction.large12
    hbase.regionserver.wal.enablecompressiontrue
    hbase.hstore.compaction.max.size1073741824
    hbase.server.compactchecker.interval.multiplier200
    Java Configuration Options for HBase RegionServer:
    -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=256m
    hbase.snapshot.master.timeoutMillis: 2 minute(s)
    hbase.snapshot.region.timeout: 2 minute(s)
    hbase.snapshot.master.timeout.millis: 2 minute(s)
    HBase REST Server Max Log Size: 100 MiB
    HBase REST Server Maximum Log File Backups: 5
    HBase Thrift Server Max Log Size: 100 MiB
    HBase Thrift Server Maximum Log File Backups: 5
    Master Max Log Size: 100 MiB
    Master Maximum Log File Backups: 5
    RegionServer Max Log Size: 100 MiB
    RegionServer Maximum Log File Backups: 5
    HBase Active Master Detection Window: 4 minute(s)
    dfs.client.hedged.read.threadpool.size: 40
    dfs.client.hedged.read.threshold.millis: 10 millisecond(s)
    hbase.rest.threads.min: 8
    hbase.rest.threads.max: 150
    Maximum Process File Descriptors: 180000
    hbase.thrift.minWorkerThreads: 200
    hbase.master.executor.openregion.threads: 30
    hbase.master.executor.closeregion.threads: 30
    hbase.master.executor.serverops.threads: 60
    hbase.regionserver.thread.compaction.small: 6
    hbase.ipc.server.read.threadpool.size: 20
    Region Mover Threads: 6
    Client Java Heap Size in Bytes: 1 GiB
    HBase REST Server Default Group: 3 GiB
    HBase Thrift Server Default Group: 3 GiB
    Java Heap Size of HBase Master in Bytes: 16 GiB
    Java Heap Size of HBase RegionServer in Bytes: 32 GiB

    +ZooKeeper
    maxClientCnxns: 601
    maxSessionTimeout: 120000

    Создание таблиц:
    hbase org.apache.hadoop.hbase.util.RegionSplitter ns:t1 UniformSplit -c 64 -f cf
    alter 'ns:t1', {NAME => 'cf', DATA_BLOCK_ENCODING => 'FAST_DIFF', COMPRESSION => 'GZ'}


    Тут есть один важный момент — в описании DataStax не сказано, сколько регионов использовалось при создании таблиц HB, хотя это критично для больших объемов. Поэтому для тестов было выбрано кол-во = 64, что позволяет хранить до 640 ГБ, т.е. таблицу среднего размера.

    В HBase на момент проведения теста было 22 тысячи таблиц и 67 тысяч регионов (это было бы убийственно для версии 1.2.0, если бы не патч о котором сказано выше).

    Теперь что касается кода. Так как не было ясности, какие конфигурации являются более выигрышным для той или иной БД, тесты производились в различных комбинациях. Т.е. в одних тестах загрузка шла одновременно в 4 таблицы (для подключения использовались все 4 ноды). В других тестах работали с 8 разными таблицами. В некоторых случаях размер батча был равен 100, в других 200 (параметр batch — см. код ниже). Размер данных для value 10 байт или 100 байт (dataSize). Всего каждый раз записывалось и вычитывалось по 5 млн. записей в каждую таблицу. При этом в каждую таблицу писали/читали 5 потоков (номер потока — thNum), каждый из которых использовал свой диапазон ключей (count = 1 млн):

    if (opType.equals("insert")) {
        for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
            StringBuilder sb = new StringBuilder("BEGIN BATCH ");
            for (int i = 0; i < batch; i++) {
                String value = RandomStringUtils.random(dataSize, true, true);
                sb.append("INSERT INTO ")
                        .append(tableName)
                        .append("(id, title) ")
                        .append("VALUES (")
                        .append(key)
                        .append(", '")
                        .append(value)
                        .append("');");
                key++;
            }
            sb.append("APPLY BATCH;");
            final String query = sb.toString();
            session.execute(query);
        }
    } else {
        for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
            StringBuilder sb = new StringBuilder("SELECT * FROM ").append(tableName).append(" WHERE id IN (");
            for (int i = 0; i < batch; i++) {
                sb = sb.append(key);
                if (i+1 < batch)
                    sb.append(",");
                key++;
            }
            sb = sb.append(");");
            final String query = sb.toString();
            ResultSet rs = session.execute(query);
        }
    }
    

    Соответственно аналогичный функционал был предусмотрен для HB:

    Configuration conf = getConf();
    HTable table = new HTable(conf, keyspace + ":" + tableName);
    table.setAutoFlush(false, false);
    List<Get> lGet = new ArrayList<>();
    List<Put> lPut = new ArrayList<>();
    byte[] cf = Bytes.toBytes("cf");
    byte[] qf = Bytes.toBytes("value");
    if (opType.equals("insert")) {
        for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
            lPut.clear();
            for (int i = 0; i < batch; i++) {
                Put p = new Put(makeHbaseRowKey(key));
                String value = RandomStringUtils.random(dataSize, true, true);
                p.addColumn(cf, qf, value.getBytes());
                lPut.add(p);
                key++;
            }
            table.put(lPut);
            table.flushCommits();
        }
    } else {
        for (Long key = count * thNum; key < count * (thNum + 1); key += 0) {
            lGet.clear();
            for (int i = 0; i < batch; i++) {
                Get g = new Get(makeHbaseRowKey(key));
                lGet.add(g);
                key++;
            }
            Result[] rs = table.get(lGet);
        }
    }
    

    Так как в HB о равномерном распределении данных должен заботиться клиент, то функция соления ключа выглядела так:

    public static byte[] makeHbaseRowKey(long key) {
        byte[] nonSaltedRowKey = Bytes.toBytes(key);
        CRC32 crc32 = new CRC32();
        crc32.update(nonSaltedRowKey);
        long crc32Value = crc32.getValue();
        byte[] salt = Arrays.copyOfRange(Bytes.toBytes(crc32Value), 5, 7);
        return ArrayUtils.addAll(salt, nonSaltedRowKey);
    }
    

    Теперь самое интересное — результаты:



    Тоже самое в виде графика:



    Преимущество HB настолько удивительное, что есть подозрение о наличие какого-то узкого места в настройке CS. Однако гуглеж и кручение наиболее очевидных параметров (вроде concurrent_writes или memtable_heap_space_in_mb) ускорения не дало. При этом в логах чисто, ни на что не ругается.

    Данные легли по нодам равномерно, статистика со всех нод примерно одинаковая.

    Вот как выглядит статистика по таблице с одной из нод
    Keyspace: ks
    Read Count: 9383707
    Read Latency: 0.04287025042448576 ms
    Write Count: 15462012
    Write Latency: 0.1350068438699957 ms
    Pending Flushes: 0
    Table: t1
    SSTable count: 16
    Space used (live): 148.59 MiB
    Space used (total): 148.59 MiB
    Space used by snapshots (total): 0 bytes
    Off heap memory used (total): 5.17 MiB
    SSTable Compression Ratio: 0.5720989576459437
    Number of partitions (estimate): 3970323
    Memtable cell count: 0
    Memtable data size: 0 bytes
    Memtable off heap memory used: 0 bytes
    Memtable switch count: 5
    Local read count: 2346045
    Local read latency: NaN ms
    Local write count: 3865503
    Local write latency: NaN ms
    Pending flushes: 0
    Percent repaired: 0.0
    Bloom filter false positives: 25
    Bloom filter false ratio: 0.00000
    Bloom filter space used: 4.57 MiB
    Bloom filter off heap memory used: 4.57 MiB
    Index summary off heap memory used: 590.02 KiB
    Compression metadata off heap memory used: 19.45 KiB
    Compacted partition minimum bytes: 36
    Compacted partition maximum bytes: 42
    Compacted partition mean bytes: 42
    Average live cells per slice (last five minutes): NaN
    Maximum live cells per slice (last five minutes): 0
    Average tombstones per slice (last five minutes): NaN
    Maximum tombstones per slice (last five minutes): 0
    Dropped Mutations: 0 bytes

    Попытка уменьшать размер батча (вплоть до отправки поштучно) не дала эффекта, стало только хуже. Возможно, что на самом деле это действительно максимум производительности для CS, так как полученные результаты по CS похожи на те, что получились и у DataStax — порядка сотни тысяч операций в секунду. Кроме того, если посмотреть на утилизацию ресурсов, то увидим, что CS использует гораздо больше и ЦПУ и дисков:


    На рисунке показана утилизация во время прогона всех тестов подряд для обоих БД.

    Что касается мощного преимущества HB при чтении. Тут видно, что для обоих БД утилизация дисков при чтении крайне низкая (тесты на чтение это завершающая часть цикла тестирования каждой БД, например для CS это с 15:20 до 15:40). В случае HB причина понятна — большая часть данных висит в памяти, в memstore и часть закешировалась в blockcache. Что касается CS, то тут не очень ясно как она устроена, однако также утилизации дисков не видно, но на всякий случай была сделана попытка включить кэш row_cache_size_in_mb = 2048 и установлен caching = {‘keys’: ‘ALL’, ‘rows_per_partition’: ‘2000000’}, но от этого стало даже чуть хуже.

    Также стоит еще раз проговорить существенный момент про кол-во регионов в HB. В нашем случае было указано значение 64. Если же уменьшать его и сделать равным например 4, то при чтении скорость падает в 2 раза. Причина в том, что memstore будет забиваться быстрее и файлы будут флашиться чаще и при чтении нужно будет обрабатывать больше файлов, что для HB достаточно сложная операция. В реальных условиях это лечится продумыванием стратегии пресплитинга и компактификации, в частности мы используем самописную утилиту, которая занимается сборкой мусора и сжатием HFiles постоянно в фоновом режиме. Вполне возможно, что для тестов DataStax выделяли вообще 1 регион на таблицу (что не правильно) и это бы несколько прояснило, почему HB так проигрывал в их тестах на чтение.

    Предварительные выводы отсюда получаются следующие. Если допустить, что в ходе тестирования не было допущено грубых ошибок, то Cassandra похожа на колосса на глиняных ногах. Точнее, пока она балансирует на одной ноге, как на картинке в начале статьи, она показывает относительно неплохие результаты, но при схватке в одинаковых условиях проигрывает вчистую. При этом учитывая низкую утилизацию CPU на нашем железе мы научились высаживать по два RegionServer HB на хост и тем самым удвоили производительность. Т.е. с учетом утилизации ресурсов ситуация для CS получается еще более плачевная.

    Безусловно, эти тесты достаточно синтетические и объем данных, который использовался тут, относительно скромный. Не исключено, что при переходе на терабайты ситуация была бы иная, однако если для HB мы умеем грузить терабайты, то для CS это оказалось проблематично. Она зачастую выдавала OperationTimedOutException даже при этих объемах, хотя параметры ожидания отклика и так были увеличены в разы по сравнению с дефолтными.

    Надеюсь, что совместными усилиями мы найдем узкие места CS и если получится её ускорить, то в конце поста обязательно добавлю информацию об итоговых результатах.

    UPD: Были применены следующие рекомендации на настройке CS:

    disk_optimization_strategy: spinning
    MAX_HEAP_SIZE=«32G»
    HEAP_NEWSIZE=«3200M»
    -Xms32G
    -Xmx32G
    -XX:+UseG1GC
    -XX:G1RSetUpdatingPauseTimePercent=5
    -XX:MaxGCPauseMillis=500
    -XX:InitiatingHeapOccupancyPercent=70
    -XX:ParallelGCThreads=32
    -XX:ConcGCThreads=8


    Что касается настроек ОС, это достаточно долгая и сложная процедура (получать рута, ребутить сервера и т.д.), поэтому эти рекомендации не применялись. С другой стороны, обе БД в равных условиях, так что все честно.

    В части кода, сделан один коннектор для всех потоков пишущих в таблицу:
    connector = new CassandraConnector();
    connector.connect(node, null, CL);
    session = connector.getSession();
    session.getCluster().getConfiguration().getSocketOptions().setConnectTimeoutMillis(120000);
    KeyspaceRepository sr = new KeyspaceRepository(session);
    sr.useKeyspace(keyspace);
    prepared = session.prepare("insert into " + tableName + " (id, title) values (?, ?)");


    Данные отправлялись через биндинг:
    for (Long key = count * thNum; key < count * (thNum + 1); key++) {
        String value = RandomStringUtils.random(dataSize, true, true);
        session.execute(prepared.bind(key, value));
    }


    Это не оказало ощутимого влияния на производительность записи. Для надежности запустил нагрузку инструментом YCSB, абсолютно такой же результат. Ниже статистика по одному потоку (из 4х):

    2020-01-18 14:41:53:180 315 sec: 10000000 operations; 21589.1 current ops/sec; [CLEANUP: Count=100, Max=2236415, Min=1, Avg=22356.39, 90=4, 99=24, 99.9=2236415, 99.99=2236415] [INSERT: Count=119551, Max=174463, Min=273, Avg=2582.71, 90=3491, 99=16767, 99.9=99711, 99.99=171263]
    [OVERALL], RunTime(ms), 315539
    [OVERALL], Throughput(ops/sec), 31691.803548848162
    [TOTAL_GCS_PS_Scavenge], Count, 161
    [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 2433
    [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.7710615803434757
    [TOTAL_GCS_PS_MarkSweep], Count, 0
    [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 0
    [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.0
    [TOTAL_GCs], Count, 161
    [TOTAL_GC_TIME], Time(ms), 2433
    [TOTAL_GC_TIME_%], Time(%), 0.7710615803434757
    [INSERT], Operations, 10000000
    [INSERT], AverageLatency(us), 3114.2427012
    [INSERT], MinLatency(us), 269
    [INSERT], MaxLatency(us), 609279
    [INSERT], 95thPercentileLatency(us), 5007
    [INSERT], 99thPercentileLatency(us), 33439
    [INSERT], Return=OK, 10000000


    Тут видно что скорость одного потока порядка 32 тыс записей в секунду, работало 4 потока, получается 128 тыс. Кажется, большего на текущих настройках дисковой подсистемы не выжать.

    Насчет чтения интереснее. Благодаря советам камрадов его удалось радикально ускорить. Чтение осуществлялось не в 5 потоков, а в 100. Увеличение до 200 эффекта уже не давало. Также в билдер добавлено:
    .withLoadBalancingPolicy(new TokenAwarePolicy(DCAwareRoundRobinPolicy.builder().build()))

    В результате, если раньше тест показывал 159 644 ops (5 потоков, 4 таблицы, батч 100), то теперь:
    100 потоков, 4 таблицы, батч = 1 (поштучно): 301 969 ops
    100 потоков, 4 таблицы, батч = 10: 447 608 ops
    100 потоков, 4 таблицы, батч = 100: 625 655 ops

    Так как результаты лучше с батчами, прогнал аналогичные* тесты с HB:

    *Так как при работе в 400 потоков функция RandomStringUtils, которая использовалась ранее, грузила CPU на 100%, она была заменена более быстрым генератором.

    Таким образом, увеличение количества потоков при загрузке данных дает небольшой прирост производительности HB.

    Что касается чтения, тут приведены результаты нескольких вариантов. По просьбе 0x62ash выполнялась команда flush перед чтением и также приведены для сравнения несколько других вариантов:
    Memstore — чтение из памяти, т.е. до сброса на диск.
    HFile+zip — чтение из файлов, сжатых алгоритмом GZ.
    HFile+upzip — чтение из файлов без сжатия.

    Обращает на себя внимание занятная особенность — маленькие файлы (см. поле «Данные», где записи 10 байт) обрабатываются медленнее, особенно если они сжаты. Очевидно, что это так только до определенного размера, явно файл в 5 Гб не будет обработан быстрее 10 Мб, но явно указывает на то, что во всех этих тестах еще не паханное поле для исследований различных конфигураций.

    Для интереса поправил код YCSB для работы с HB батчами по 100 штук, чтобы замерить латентность и прочее. Ниже результат работы 4-х экземпляров, которые писали в свои таблицы, каждый по 100 тредов. Получилось следующее:
    Одна операция = 100 записей
    [OVERALL], RunTime(ms), 1165415
    [OVERALL], Throughput(ops/sec), 858.06343662987
    [TOTAL_GCS_PS_Scavenge], Count, 798
    [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 7346
    [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.6303334005483026
    [TOTAL_GCS_PS_MarkSweep], Count, 1
    [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 74
    [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.006349669431061038
    [TOTAL_GCs], Count, 799
    [TOTAL_GC_TIME], Time(ms), 7420
    [TOTAL_GC_TIME_%], Time(%), 0.6366830699793635
    [INSERT], Operations, 1000000
    [INSERT], AverageLatency(us), 115893.891644
    [INSERT], MinLatency(us), 14528
    [INSERT], MaxLatency(us), 1470463
    [INSERT], 95thPercentileLatency(us), 248319
    [INSERT], 99thPercentileLatency(us), 445951
    [INSERT], Return=OK, 1000000

    20/01/19 13:19:16 INFO client.ConnectionManager$HConnectionImplementation: Closing zookeeper sessionid=0x36f98ad0a4ad8cc
    20/01/19 13:19:16 INFO zookeeper.ZooKeeper: Session: 0x36f98ad0a4ad8cc closed
    20/01/19 13:19:16 INFO zookeeper.ClientCnxn: EventThread shut down
    [OVERALL], RunTime(ms), 1165806
    [OVERALL], Throughput(ops/sec), 857.7756504941646
    [TOTAL_GCS_PS_Scavenge], Count, 776
    [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 7517
    [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.6447899564764635
    [TOTAL_GCS_PS_MarkSweep], Count, 1
    [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 63
    [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.005403986598113236
    [TOTAL_GCs], Count, 777
    [TOTAL_GC_TIME], Time(ms), 7580
    [TOTAL_GC_TIME_%], Time(%), 0.6501939430745767
    [INSERT], Operations, 1000000
    [INSERT], AverageLatency(us), 116042.207936
    [INSERT], MinLatency(us), 14056
    [INSERT], MaxLatency(us), 1462271
    [INSERT], 95thPercentileLatency(us), 250239
    [INSERT], 99thPercentileLatency(us), 446719
    [INSERT], Return=OK, 1000000

    20/01/19 13:19:16 INFO client.ConnectionManager$HConnectionImplementation: Closing zookeeper sessionid=0x26f98ad07b6d67e
    20/01/19 13:19:16 INFO zookeeper.ZooKeeper: Session: 0x26f98ad07b6d67e closed
    20/01/19 13:19:16 INFO zookeeper.ClientCnxn: EventThread shut down
    [OVERALL], RunTime(ms), 1165999
    [OVERALL], Throughput(ops/sec), 857.63366863951
    [TOTAL_GCS_PS_Scavenge], Count, 818
    [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 7557
    [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.6481137633908777
    [TOTAL_GCS_PS_MarkSweep], Count, 1
    [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 79
    [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.006775305982252128
    [TOTAL_GCs], Count, 819
    [TOTAL_GC_TIME], Time(ms), 7636
    [TOTAL_GC_TIME_%], Time(%), 0.6548890693731299
    [INSERT], Operations, 1000000
    [INSERT], AverageLatency(us), 116172.212864
    [INSERT], MinLatency(us), 7952
    [INSERT], MaxLatency(us), 1458175
    [INSERT], 95thPercentileLatency(us), 250879
    [INSERT], 99thPercentileLatency(us), 446463
    [INSERT], Return=OK, 1000000

    20/01/19 13:19:17 INFO client.ConnectionManager$HConnectionImplementation: Closing zookeeper sessionid=0x36f98ad0a4ad8cd
    20/01/19 13:19:17 INFO zookeeper.ZooKeeper: Session: 0x36f98ad0a4ad8cd closed
    20/01/19 13:19:17 INFO zookeeper.ClientCnxn: EventThread shut down
    [OVERALL], RunTime(ms), 1166860
    [OVERALL], Throughput(ops/sec), 857.000839860823
    [TOTAL_GCS_PS_Scavenge], Count, 707
    [TOTAL_GC_TIME_PS_Scavenge], Time(ms), 7239
    [TOTAL_GC_TIME_%_PS_Scavenge], Time(%), 0.6203829079752499
    [TOTAL_GCS_PS_MarkSweep], Count, 1
    [TOTAL_GC_TIME_PS_MarkSweep], Time(ms), 67
    [TOTAL_GC_TIME_%_PS_MarkSweep], Time(%), 0.0057419056270675145
    [TOTAL_GCs], Count, 708
    [TOTAL_GC_TIME], Time(ms), 7306
    [TOTAL_GC_TIME_%], Time(%), 0.6261248136023173
    [INSERT], Operations, 1000000
    [INSERT], AverageLatency(us), 116230.849308
    [INSERT], MinLatency(us), 7352
    [INSERT], MaxLatency(us), 1443839
    [INSERT], 95thPercentileLatency(us), 250623
    [INSERT], 99thPercentileLatency(us), 447487
    [INSERT], Return=OK, 1000000


    Получается, что если у CS AverageLatency(us) на запись 3114, то у HB AverageLatency(us) = 1162 (помним, что 1 операция = 100 записям и поэтому надо делить).

    В целом получается такой вывод — в заданных условиях имеет место существенное преимущество HBase. Однако нельзя исключать, что SSD и тщательный тюнинг ОС изменит картину радикально. Также нужно понимать, что очень многое зависит от сценариев использования, запросто может оказаться так, что если взять не 4 таблицы, а 400 и работать с терабайтами, баланс сил сложится совсем иным образом. Как говорили классики: практика — критерий истины. Надо пробовать. За одно ScyllaDB теперь уже имеет смысл проверить, так что продолжение следует…
    Сбербанк
    Company

    Comments 134

      +3

      Вы уверены, что эти базы колоночные, а не key-value?

        –8
        Колоночные являются развитием (или подмножеством) key-value.
          –2

          Садись, два.

            +3
            Вы хамите. Минусы не дают на это права, если вы не знали.
            Во вторых, ни один из поставивших минус не аргументировал. Тогда как это факт очевидности уровня википедии:
            «A wide column store can be interpreted as a two-dimensional key-value store.»
            en.wikipedia.org/wiki/Wide_column_store
              –2

              Чем обижаться на правду вы бы лучше разобрались чем эти БД отличаются.


              Ну или хотя бы почитали следующий раздел той ссылки которую привели:


              Wide column stores such as Bigtable and Apache Cassandra are not column stores in the original sense of the term since their two-level structures do not use a columnar data layout. In genuine column stores, a columnar data layout is adopted such that each column is stored separately on disk.
                +1
                Чем давать советы, кому чем заниматься, сами бы сели и написали свое исследование.

                Ну или хотя бы прочитали дальше следующий раздел той же статьи:

                Notable wide column stores include:
                Apache Cassandra
                Apache HBase
                  +2
                  Сдается мне что произошла путаница между Wide Column и Column Oriented.
                  Топик стартер кажется имел ввиду второе
                    0

                    Хуже: он не понимает что это два принципиально разных типа хранения на диске, которые используются для разных целей. И упорствует в своем невежестве :)

                      +2

                      Это не разные типы хранения, это вообще перпендикулярные вещи. Ничто не мешает быть СУБД одновременно и wide column, и column oriented. Правда, непонятно, зачем такое, но можно :-)

                        0

                        Мне, если честно, сложно представить как можно хранить строки с переменным числом колонок в традиционном Columnar-формате где каждая колонка хранится отдельно. Даже NULLы в том же Кликхаусе уже эдакий хак.


                        Понятное дело, что придумать какой-то хак можно и для этого случая, но это будет такой изврат что ужас.


                        Поэтому я и говорю про дисковый формат — принципиальное отличие Columnar DB именно в том что столбцы хранятся и читаются отдельно.

                      0
                      Совершенно верно, это устоявшийся термин для HBase, например:
                      Hbase – колоночная база данных, реализующая парадигму BigTable

                      Просто некоторым людям приятнее и важнее считать, что кругом невежды, чем имеет место банальное несовпадение терминологии)
                        +2

                        Термин-то устоялся, но "устояли" его маркетологи. Ну или "ушатали" — уж не знаю как точнее/корректнее.


                        Все эти термины (Wide Column, Column Oriented) подпорчены и размыты маркетологами, из-за этого и путаница. С точки зрения "как оно устроено" логично говорить "Wide Column Store" (key-value с "широким" JSON-like value) и "Multi-Column Store" (колонки хранятся отдельно, в разных файлах и т.п.).


                        В среднем по-больнице в Multi-Column Store обновления и удаления медленные (на 1-2-3 порядка) или вообще не поддерживаются (хотя есть отрезание данных пачками), зато намного быстрее (на 1-2-3 порядка) обрабатываются сложные запросы (структура хранения позволяет в разы меньше читать с диска).


                        За изобретения термина "Wide Column Store" я бы наказал, ибо "Column" здесь только путает и позволяет втюхивать "Wide Column Store" как "Column Store, плюс еще и Wide". Вместо "Wide Column Store" логичнее было-бы "Wide key-value" или "key-Value2d" — тогда всё встаёт на свое место.

          +4
          Сервера мониторили? Во что упираются сервера кассандры, память, диск, паузы GC? Если не во что не упираются, значит вы ее просто не догрузили. Пишите в Кассандру не в 5 а в 50 потоков через 1 коннект.
          Сравнение не честное, т.к. про HBase Вы все знаете, а Кассандра, для Вас, черный ящик.
          key_cache_size_in_mb — задайте несколько гигов. Он куда более важен для производительности на чтение, чем row_cache, строки и так будут в кеше операционки. И 8 дисков, для данного теста, Кассандре не нужны, она свалит все на один. Много дисков понадобится для множества кейспейсов и таблиц. Писать с CL=ALL, это еще можно понять, но читать смысла нет, достаточно LOCAL_QUORUM.
            +2
            Спасибо за интерес к теме! Во что именно упирается не очевидно. Утилизация приведена на картинке в посте. При этом нужно иметь в виду, что нагрузка на диски бывает разная. Так как тут пишутся WAL (журналы транзакций), то они часто дергают sync, что замедляет запись. Насчет количества потоков, попробовал удвоить. Ниже результаты первых четырех тестов на запись:

            5 потоков (op/sec) -> 10 потоков (op/sec)
            137 194 -> 116 983
            136 250 -> 114 127
            126 346 -> 111 881
            119 544 -> 122 323

            Получается что Кассандра вполне так себе загружена, удвоение потоков прироста скорости не дает.

            >>key_cache_size_in_mb — задайте несколько гигов

            Попробовал 4 Гб, тесты на чтение:
            Без кэша С кэшом
            159 644 153 513
            167 698 164 248
            134 419 131 751
            139 592 141 571

            >>И 8 дисков, для данного теста, Кассандре не нужны, она свалит все на один

            Не вполне понятно, что имеется в виду. Похоже что данные распределились равномерно по всем дискам:
            58M /data1/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16
            58M /data2/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16

            58M /data8/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16

            >>Писать с CL=ALL, это еще можно понять, но читать смысла нет, достаточно LOCAL_QUORUM.

            Совершенно верно, чтение во всех тестах осуществлялось CL=ONE
              0
              вы отключали swap? объём данных записанных у вас очень небольшой, у меня в сек запись была больше, мы за 3 недели записали full storage, при том что половина операций это update, плюс у вас не выставлена оптимизация под hdd, а по дефолту идёт оптимизация под ssd чтения\записи. это указывается в cassandra.yaml. Так же в cassandra-env.sh по дефолту стоит скрипт для оптимизации расходов ресурсов, но при больших нагрузках надо отключать скрипт, и ставить руками значения
              MAX_HEAP_SIZE=«80G»
              HEAP_NEWSIZE="*M" где за основу берётся кол-во физический ядер -2(если говорим о физ железе)
                +1
                Своп не отключали, но у нас 700 Гб памяти и он совсем не работает (кроме теста ничего не крутится на стенде). Остальное ок, поправим, спасибо большое!
                  +1
                  отключите, это 1 команда в терминале, даже если вам кажется что он не используется.
            +6
            В заголовке «Битва двух якодзун», а на фотке один бывший якодзуна (http://www.japan-sumo.ru/?q=kisenosato) а второй вообще не якодзуна (http://www.japan-sumo.ru/?q=shohozan)
              +4
              Вы зануда :)
                +4
                «Это даже не шутка, похоже, что именно эта картинка наиболее точно отражает...» что о Cassandra уже можно забыть, а HBase «не дотягивает»?
                  0
                  Погодите, я думаю рано хоронить CS, в комментах много предложений по оптимизации)
                    –1
                    Да как-то практика показывает, что хоронить надо других, а не касандру. Тут с бенчами и конфигами проблемы.
                  0
                  Ну и конечно «ёкодзун»
                    0
                    Вообще в заголовке не верно только про битву
                  0

                  Не битва, а схватка. Воскресная схватка.

                    0
                    Спасибо что напомнили, точно) Менять уже заголовок не стоит наверное, но схватка определенно звучит лучше))
                    +17
                    Воскресная статья о том, как в сбербанке искали способ не работать c Cassandra, по-другому статью назвать сложно. Ну а теперь по пунктам.

                    1) Вы используете deprecated GC, да в кассандре он по default, но проблема в том, default у кассандры не сделан под нагрузки, не говоря уже о bigdata. Необходимо было поставить G1GC, и 60-80 Gbyte Heap, далее начались бы ошибки в gc, в логах пишется, по факту влияет на сильно, и работает лучше чем если часто сбрасывать на диск. Есть лечение ставим www.azul.com/downloads/zulu-community/?&architecture;=x86-64-bit&package;=jdk ставим вот это и получаем отсутствие ошибок у GC, а так же ещё +50-60% к производительности cassandra(графики увы предоставить не могу, работа была для МО).

                    2) Непонятно как были настроены диски под Cassandra, непонятно как вообще было что настроено, начиная от sysctl.conf заканчивая лимитами. docs.datastax.com/en/dse/5.1/dse-dev/datastax_enterprise/config/configRecommendedSettings.html этой статьи хватает для начала, по мере работы добавится ещё несколько пунктов, а например я ставлю fs.file-max = 1073741824 vm.max_map_count = 1073741824 vm.dirty_bytes = 1073741824 vm.dirty_background_bytes = 10485760 (настройки тестил, ставил меньше, нашёл на github)

                    3) Для нормальной работы кассандра необходимо вынести на отдельный/е ssd saved_caches, key_cache, row_cache, counter_cache, thrift_prepared_statements_cache они не всегда даже будут использоваться, но вынести их на отдельный от /data накопитель обязательно необходимо.
                    Необходимо логи системы и cassandra держать на отдельном от data носителе. У меня был nvme под это дело, система+логи+кеши были на отдельном nvme, а data была на 24 hdd sas 7200 128 cache.

                    4) Cassandra работает существенно лучше на XFS, которую надо специально подготовить, проще всего это сделать через скрипт Scylla_setup, так же этот скрипт сразу настроит нужные для процессора настройки, а их там не мало. При желании можно самому прочесть скрипт и поставить руками настройки.

                    5) Cassandra не любит hyper-threading его отключение сильно снижает latency на больших нагрузках.
                    6) Cassandra не имеет под собой HDFS, поэтому её надо ставить на raid 0, в вашем случае вы работали с 1 диском, естественно у вас результаты были гораздо хуже чем с hbase, где это сделал за вас hdfs(образно, понятное дело, что там механизм иной, но суть в том, что нагрузка шла на все диски а не на 1 как в вашем случае).

                    В заключении, у меня было 3 ноды cassandra, кейс гораздо более сложный, была запись по 300к/с и 160к/с update, тоже rf3, и 3 ноды, запись длилась на показе заказчику 3 недели, и latency был ниже вашего. Да было по 800 мб чтение с data, и запись 500 мб, дисковая подсистема была почти полностью загружена.
                      +3

                      Этот комментарий интереснее и полезнее чем вся статья =)

                        0
                        2 и 6 — из конфига видно, что у них JBOD конфигурация и комитлог на другом диске. В этом плане все правильно вполне. Проблем там другие, ниже описал.
                          +1
                          помимо коммит лога есть ещё логи gc, server и debug, и в дефолте там очень не хилые размеры, не смотря на то что там чисто текст. Судя по 53М на дату, у меня логи эти в день были больше. чем у топикстартера дата на 5 дисках.
                            0
                            Это ерунда все равно. Линейная буферизированная запись. Коммит лог пропускает через себя все записи, он наиболее критичен. И то, т.к. там тоже линейная запись, то один hdd вполне справляется.
                              +1
                              я просто помню что по iops нагрузка на nvme была половина от data, я выше написал что я вынес, подробнее мне было некогда разбирать что и как грузит. А по iops у меня нагрузка почти фулл нагружала дисковый массив.(если брать iops диска и умножать на кол-во дисков), был сделан raid0 средствами mdraid через scylla_setup.
                                +1
                                Вполне уверен, что это был именно коммитлог. В него сохраняются все вставки, чтобы нода могла пережить падение без потери данных. Естественно на него огромная нагрузка. У той же сциллы это вообще доведено до предела — все данные идут в коммитлог и копятся в памяти. В sstable вообще ничего не сохраняется на диск, пока в памяти все помещается. Кэширование очень агрессивное там.
                                  +1
                                  commit log я вынес на nvme, но даже вы выше писали что он пишет потоково, а значит это была бы загрузка просто на запись, а не iops, тем более в ssd. я raid я максимально разгружал от кешей и тп.
                          +3
                          Очень полезный комментарий, спасибо!

                          >>как в сбербанке искали способ не работать c Cassandra
                          Это не так) Никто не просил тестировать CS, это была чисто наша инициатива для удовлетворения собственного любопытства. И статья на хабр, как отличный способ привлечь грамотных специалистов, например таких как вы, для того чтобы обменяться опытом)

                          1. — попробуем G1 для CS, результат отпишу. Я пробовал указывать его для HB, но было хуже, однако вполне возможно, что так как HBase по-другому использует память то, для него G1 не дает такого эффекта как для CS.
                          2. — обязательно прогоним на рекомендованных параметрах. Учитывая, что HB меньше утилизирует диски это может для него не важно, но критично для CS.
                          3. — ну ssd нет, тут ничего не сделать.
                          4. — был бы признателен за ссылку на прирост производительности за счет XFS, чтобы понимать соотношение: усилия/польза.
                          5. — давно была идея проверить как h/t сказывается на производительности всего нашего софта, так что скорее всего так же проверим.
                          6. Насколько я понимаю у нас все разлеглось по многим дискам:
                          58M /data1/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16
                          58M /data2/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16

                          58M /data8/cassandra/ks/t1-3d82bd70385711eab7c4ed6d0a140d16

                          >>В заключении, у меня было 3 ноды cassandra, кейс гораздо более сложный, была запись по 300к/с

                          Спасибо за весьма детальную информацию, очень хорошо, когда есть ориентир. Получается, что аппроксимируя 300 к/с для 3х нод на четыре ноды, то это порядка 400 к/с. Т.е. практически совпадает с HB, однако как вы пишите, что диски при этом полностью нагружены. Таким образом, при прочих равных, другие операции с дисками будут выполняться гораздо медленнее, что для нас очень важно, так как в ПРОМ рядом крутится много другого софта.
                            +1
                            У меня было много update, это заставляло на много больше работать compaction, что в свою очередь и грузило диски. Во вторых я тоже полностью подводные камни не знаю, может ещё какой то кеш выносить надо было.
                            без ssd отдельного под систему и кеши смысла ставить cassandra нет. плюс что hbase что cassandra должны жить на отдельном от другого софта железа(за исключением spark, их лучше на одной ноде, если позволяет конфигурация)
                            SSD стали дешёвые, заказать ssd вполне реально, особенно учитывая сколько потом это будет экономить оборудования. Более того с выходом qlc ssd, можно вообще на них перейти и цена схожа будет с enterprise hdd. Плюс у вас нет update и потому запись у меня могла бы быть сильно больше.
                            На счёт xfs ссылку вряд ли дам, у scylla в было где то в бенчах, но про xfs я узнал на irc cassandra и из google рассылок.
                              0

                              Добавлю, что я не удивлен насчёт рекомендации xfs — та же монга на этой фс работает лучше, чем на ext4

                                0
                                Не знаю как у монги (просто поселил на xfs без разбирательств по рекомендации), а у сциллы основная фишка xfs — многопоточность — как раз задействуется во всю, потому что compaction'ы выполняются не смотря ни на что, в т.ч. на пользовательскую нагрузку.
                                0
                                >>заставляло на много больше работать compaction
                                Понял, поставлю грузиться HB на ночь, чтобы пошла компактификация, посмотрим что получится…
                                  0
                                  Поработало не всю ночь, однако компактицикация имела место и несколько увеличила нагрузку на диски:

                                  Однако я думаю пока еще рано делать выводы, хочу применить ваши и другие рекомендации (часть из них уже привела к кратному росту скорости чтения) и позже дополню пост.
                              • UFO just landed and posted this here
                                  +2
                                  речь все-таки о грамотных специалистах была, вроде без сарказма
                                0

                                По скорости cassandra не вызывает воспросов. Но как-то встретил образную фразу "шлейф записей" который образуется из-за того что вставка происходит с приоритетом по сравнению с обновлением. А поскольку у кассандры нет разницы между вставкой записи и ее обновлением (есть запись с идентификатором — она обновится, нет записи — она добавится) то я лично столкнулся при тестировании небольшого кластера данных с такой аномалией. При массовой вставке записей с одинаковыми (уже существующими) идентификаторами, если запросить селектом количество записей то будет выдана цифра превышающая общее колчиепситво записей. Такое впечатление что кассандра сначала вставляет новую запись и она уже может быть посчитана. В то время когда ее дубликат еще не выявлен и и также существует в базе данных. Потом после окончания массовой вставки это количество приходит в консистентное состояние. Наверное это и называется шлейфом данных и из-за этого какой-то мессенджер (чуть ли не скайп) от нее отказался.
                                Я думаю это не то поведение которое годится для банковских приложений?

                                  +3
                                  Это называется thumbstones. При каждом изменении, удалении старая запись помечается таким thumbstone. При селектах базе приходится их все прочитать, прежде чем дойти до текущей версии строки. Это страшно лишь одним — это сильно замедляет выборки, если много апдейтов. Через определенное время у thumbstone истекает время жизни и компакшен его удаляет, восстанавливая скорость выборок. Таким образом достигается eventual consistency. При проблемах в кластере есть вероятность получить разные версии одной и той же строки. При CL_ONE так вообще запросто. Но это плата за скорость.
                                    +1
                                    На самом деле у томбстоунов есть ещё проблема. По истечению срока жизни, он удаляется. И вот если запись присутствует, то получается воскрешение старых записей. Под эту процедуру надо обслуживание выполнять не реже, чем раз в x дней. Этим страдают, как я понял, все кассандроподобные базы.
                                      +1
                                      Это да, про это везде и всюду пишут к счастью. Вряд ли пропустишь.
                                        +1
                                        Только вот огорчило, что автоматизации repair за столько лет родилось всего ничего. Ну то есть она идёт. А как долго, сколько ориентировочно осталось, возможность остановить, если пошла нагрузка серьёзная… Многих, насколько понял, вопросы такие не заботят, они руками раз в неделю запускают repair на каждой ноде. И как итог — самописный колхоз ansible + jenkins для хоть какой-то автоматизации. Правда логи о процессе — потфактум. Остаётся только смириться (ну или смотреть коммерческие решения).
                                          +1
                                          Есть cassandra reaper. Правда со сциллой не работает пока. У платной сциллы вроде как в комплекте подобное тоже идет.
                                            +1
                                            Ну до 5 нод scylla manager даже вроде и бесплатна. Но пугает ситуация сесть на него, а потом выйти за 5 нод и всё снова на те же круги возвращается.
                                +4

                                Конечно небесполезно знать кто из "динозавров" большие греет атмосферу. Но может всё-таки ScyllaDB вместо Cassandra?

                                  +1
                                  Резонно, судя по тестам что на их сайте, она просто космос. Единственный вопрос, почему она до сих пор на 8 месте того же DB-Engines Ranking (см. вторую картинку в посте) и не видно мощной динамики. Возможно инерция IT-сообщества, возможно тоже есть подводные камни. Видимо как это частенько бывает, пока не попробуешь, не узнаешь…
                                    +2
                                    По моему опыту она работает как drop-in замена. Вообще ничего менять не пришлось за редкими исключениями. Некоторых фич у них когда-то не было (индексы теже и materialized views), но я их и не использовал. Есть свои баги естественно. Есть свои особенности — в каком-то релизе page state имел размер в 50-100КБ, от чего ломались HTTP запросы, у которых он в GET параметре передается. Потом магическим образом исправилось в каком-то релизе, но к этому времени и своими силами обошли проблему. Диагностика хромает в некоторых местах. Недавно проблема с thumbstone кажется была, возможности оценить их количество в сцилле пока нет.

                                    Но это с позиции разработчика так все просто. С devops это абсолютно другая база. Она отдаленно похожа своей концепцией на касандру, но устроена совершенно по-другому. Даже установить ее на сервер это целая наука.
                                      0
                                      Да как по мне, там всё просто. xfs, докер (да, таки можно теперь не заморачиваться и делать посредством докера с небольшой долей настроек и оверхеда на сам докер, к тому же обновления с ним становятся делом пары минут). А что там делать ещё — даже не уверен. Если без докера — чуть больше работы и отсутствие оверхеда (хотя там при правильном подходе это мизер). И с настройками всё проще и сложнее. Проще — их меньше. Сложнее — в файле конфига есть параметры, но они не работают, потому что это файл конфига для кассандры. Т.е. параметр есть, но может выясниться, что не на что не влияет, т.к. у сциллы это автоматический механизм, на который конфигом повлиять и не получится.
                                        +2
                                        Сцилла тюнит под себя машину и что там зачем тоже неплохо понимать. Из докера ее лучше вытащить. Она не случайно в developer mode внутри него запускается. Диски — при старте замеряет характеристики и настраивает все свои внутренности, чтобы держаться у самого предела и не перегружать диски. Это я сам наблюдал — без тюнинга диски перегружены и задержки на IO очень большие. Сеть — очень хочет DPDK, который из официального докер образа не работает. Ну и вот docs.scylladb.com/getting-started/system-configuration Сцилла конечно не содержит тонну настроек сама по себе как касандра, но железо и ОС хочет видеть в очень определенном виде.
                                          +1
                                          который из официального докер образа не работает

                                          Возможно. Там в конфиге в докер-образе есть отличия от обычной установки. Местами я бы даже сказал странные. Когда часть надо загонять как параметры контейнера, а часть — как и прежде, через файлы конфига.

                                          Что же касается определённого вида железа — как по мне, rocket science тут нет. Чуть больше внимания уделяется настройке железа, когда у других баз данных приходится уделять больше внимания просто настройкам. Хотя после того же mssql требования сциллы к настройке железа не выглядят чем-то эдаким необычным.

                                          По DPDK вообще, кстати, материала много не видел. Как-то вскользь упоминается (как и некоторые другие вещи), но без сильных подробностей. При этом по тому же докеру они у себя достаточно обширный пост в блоге накатали в своё время
                                          https://www.scylladb.com/2018/08/09/cost-containerization-scylla/, по которому получается, что сцилла критично вроде бы не просаживается. Здесь не готов сказать. Каких-то негативных эффектов в части производительности при переходе в контейнеры (при сохранении самой версии сциллы) не заметил. По DPDK вообще не уверен в ситуации, когда сцилла и так из ssd выжимает всё, что те могут дать — сеть не самое узкое место. Хотя есть DPDK затрагивает производительность дисковой системы, то тут надо думать, очень хорошо думать. Вдруг чудо действительно произойдёт.
                                            0

                                            теоретически, как я понимаю, docker не мешает работе dpdk…
                                            А вот снижение скорости работы в докере относительно режима без докера я В ПРИНЦИПЕ наблюдал. Есть способы его минимизировать, но your mileage may vary

                                              0
                                              Там скорее идет борьба за латентность. За счет переноса всего сетевого стека в юзерспейс они полностью контролируют очереди, какой шард какие данные обрабатывает. В итоге никаких смен контекста, никакой миграции данных между ядрами. Это все от seastar идет. Все таки когда счет идет уже на миллионы операций на ноду, то каждая микросекунда на счету.
                                                0
                                                Чувствую, надо вернуться к вопросу и ещё раз всё хорошенько просмотреть.
                                        +1
                                        Единственный вопрос, почему она до сих пор на 8 месте того же DB-Engines Ranking.
                                        DB-Engines для рассчёта ранга использует поисковые запросы, вопросы на Stack Overflow, упоминания в вакансиях и т.д..
                                        Однако так как ScyllaDB стремится к полной совместимости, то с точки зрения пользователя они никак не отличаются, и не имеет смысл гуглить синтаксис запросов или лучшие практики создания структуры бд для ScyllaDB, когда такого материала полно для Cassandra.
                                        Специфичные для ScyllaDB вещи гуглят в основном админы и таких запросов на порядки меньше.
                                        Это нормальная практика для drop-in замены.
                                        Например, каждый раз когда мне нужно подсмотреть синтаксис запросов в VictoriaMetrics, я гуглю как это сделать для Prometheus, потому что по нему больше материала, а про VictoriaMetrics я гуглил только один раз, когда её устанавливал.
                                      +2
                                      Ваши запросы по касандре ровненько так укладываются во все антипаттерны:
                                      1. Батчи сами по себе это антипаттерн и очень медленные. Еще хуже, когда, как у вас, они покрывают несколько партишенов, что включает LOGGED режим. Потенциально каждый батч затрагивает все ноды одновременно, т.к. хэширование ключей рабросает их в случайном порядке по всем нодам
                                      2. Выборки с IN тоже захватывают кучу партишенов. Каждая выборка будет ходить за данным на все ноды.

                                      Так что стоит таки по-лучше почитать как датастакс делает подобные измерения или сцилла.
                                        +2
                                        Насчет батчей, тут много зависит от задач и окружения. Например, у нас есть продукты, которые работают с кафкой. Соответственно они вытягивают данные через poll, небольшими батчами (порядка сотни сообщений), это естественным образом приводит к тому, что и обращения к HB выполняются так же батчем, что в разы быстрее, чем поштучно.

                                        На всякий случай пробовал выключить батчи и делать запросы поштучно, но получается в разы медленнее. В частности первый тест на запись вместо 137 тыс. ops показал 54. Аналогично на чтение, вместо 159 стало 56. Но это не значит что CS работает плохо, HB в этой ситуации будет вести себя аналогично.
                                          +2
                                          А запросы вы как, параллельно шлете? Каждый запрос в батче надо посылать параллельно, да еще желательно с token-aware policy у коннектора, чтобы избежать дополнительного хопа из-за координатора.

                                          Тоже самое с IN. Только недавно переписывал его на параллельный запрос всех ключей, которые в IN. Получается заметно быстрее, что не удивительно, т.к. нагрузка размазывается ровно по всем нодам, а не отдается на откуп одном координатору. А параллельность скрывает задержки на round-trip'ы на каждый запрос.

                                          Проблема с батчами из нескольких партишенов в том, что они не скейлятся. Кассандра предназначена для сотен и тысяч нод. Подобный батч означает, что на одного единственного координатора ложится задача этот батч выполнить, что потребует послать запрос, потенциально, на каждую ноду в кластере.

                                          Батчи идеально подходят, когда партишен в запросе один, а строк в него вставить много надо (через clustering key). В этом случае можно делать без всяких опасений UNLOGGED батч и получать серьезный прирост.
                                            0
                                            Круто, благодаря вашим советам удалось повысить скорость чтения в 4 раза! На запись эффекта не оказало. Что касается чтения:
                                            Было: 159 644 ops (4 таблицы, 5 потоков, батч 100).
                                            Добавил:
                                            .withLoadBalancingPolicy(new TokenAwarePolicy(DCAwareRoundRobinPolicy.builder().build()))
                                            И поигрался с количеством потоков. Получилось следующее:
                                            4 таблицы, 100 потоков, батч = 1 (поштучно): 301 969 ops
                                            4 таблицы, 100 потоков, батч = 10: 447 608 ops
                                            4 таблицы, 100 потоков, батч = 100: 625 655 ops

                                            Потом применю другие советы по тюнингу, прогоню полный цикл тестирования и добавлю результаты в конце поста.
                                              +1
                                              Еще несколько советов.
                                              1. Как ниже предлагали, используйте биндинг. Судя по коду, TokenAwarePolicy не вытаскивает из строчных запросов ключ, а значит не может корректно направить запрос на нужную ноду.
                                              2. Вкупе с биндингом используйте prepared statements вместо простого execute.
                                        0

                                        Именно! Батчи в Кассандре созданы для обеспечения атомарности запросов, а не для ускорения загрузки.
                                        Для загрузки должны использоваться АСИНХРОННЫЕ операции. Даже при работе с асинхронными запросами есть нюансы: для ожидания надо использовать не get(), а get uninterruptible(), который является не блокирующим, в отличие от первого. В этом случае можно в одном потоке обеспечить максимальную производительность.
                                        По моему опыту, скорость загрузки в базу в асинхронном режиме была в 5 раз выше, чем в батчевом, видимо из-за того, что было 5 узлов.

                                          0
                                          Подскажите пожалуйста, что имеется в виду под get uninterruptible()? Я использовал select, про геты ничего не нашел с ходу…
                                            0

                                            Речь о Java-драйвере от datastax

                                        0
                                        Было бы интересно сравнить с колоночной СУБД Яндекс ClickHouse — пропаганда утверждает, что, как минимум, в ряде случае ClickHouse уделывает и Cassandra, и HBase, и BigTable… ну, по крайней мере, на не террабайтных таблицах!
                                        Да и попробовать отечественный продукт Яндекс ClickHouse было бы весьма патриотично!
                                          +1
                                          ClickHouse насколько мне известно показывает потрясающую производительность, однако у неё нет апдейтов — это ее принципиальное ограничение, к сожалению…
                                            0

                                            Ну, апдейты можно эмулировать ))) вполне успешно. Но дьявол именно в деталях — какие паттерны нагрузки

                                            +1
                                            А смысл? Это принципиально другая БД для других запросов. По той же скорости вставок она запросто проиграет остальным. С обновлениями там проблемы. Сложные запросы она конечно умеет, но это пока хватает памяти.
                                              +1

                                              По скорости вставок Click не проигрывает, примерно совсем. Другое дело, что у него (и в любой append-oriended базе) эти вставки совсем другие.


                                              Сложные запросы Click умеет быстро не "пока памяти хватает" (это не java), а потому что он более-менее оптимально умеет отображать сложный запрос в конвейер чтения и фильтрации чанков колонок с дисков, и всё это в кластере. У клика гораздо больше шансов существенно меньше читать с дисков, если это в принципе возможно для некого запроса. Соответственно, в сценариях для которых сделан клик, на сопоставимом оборудовании, у обсуждаемых БД кране мало шансов конкурировать.


                                              Тем не менее, это сильно разные БД для принципиально разных сфер применения и сравнивать их — как теплое с мягким.

                                                +1
                                                В моем понимании CH ведет себя как любые другие column-store для аналитики — при вставке данные сильно жмутся и хитро раскладываются так, чтобы эффективно дальше делать сложные запросы. От этого страдает скорость вставок и тот же CH хочет очень большие батчи. На одинарных вставках оно умрет.

                                                Я не про быстро, а вообще. Сложные запросы по определению либо требуют дофига памяти, либо скидывать промежуточные результаты на диск. Чудес тут никаких нет и CH умрет с out of memory запросто как любая другая база, которая умеет сложные агрегации делать. Понятное дело, что на касандре той же подобные запросы просто напросто невозможны, но есть всякие спарки и прочие хадупы, которые конечно медленнее, но скейлятся вполне. Правда и там можно помереть, когда все схлопнется до одной ноды и у нее кончится память. Да и никуда от менее эффективного представления данных на диске не уйдешь.
                                                  0

                                                  В КХ есть распределенные джойны в каком то виде. Ну и вообще данные размазываются по шардам как везде. Поэтому агрегации частично идут локально на всех шардах, а финальная часть уже исполняется там где запрос инициировался. Эдакий мапредьюс.

                                                    0
                                                    В КХ есть распределенные джойны в каком то виде

                                                    весьма ограниченные и все равно можно вылететь по out of memory

                                                    +1

                                                    Не хочу вступать в непродуктивный спор, ибо базы для разных целей. Но в отношении CH у вас всё-таки немного заниженное мнение:


                                                    • CH предназначен на впитывание данных с одновременной обработкой запросов. В этом режиме одиночные вставки не имеют смысла. Рационально вставлять раз в секунду или по ~100К, а как-то сильно иначе — просто нагрев. CH реализует это очень хорошо и без лишних движений (делит данные на по-колоночные чанки и пушит в LSM).


                                                    • "Плохие" сложные агрегации (и прочие кошмары) потребуют памяти в любой БД. "Спарки и хадупы" имеют те же проблемы (если промежуточный результат не влезет в память, то ой). Хотя и для "спарков" и для CH есть рецепты решения таких задач.


                                                    • Что касается эффективности представления данных на диске, то CH хранит данные по-колоночно со сжатием — придумать что-либо эффективнее сложно. Т.е. в отличие от касанды и спарка, в CH значения, которые с большей вероятностью похожи/близки, в среднем хранятся "ближе" друг к другу и поэтому лучше сжимаются.


                                                      0
                                                      >Рационально вставлять раз в секунду или по ~100К, а как-то сильно иначе — просто нагрев.

                                                      Посмотрите что происходит с КХ в режиме вставки около 1,5 млн/сек в реплицированные таблицы. Как раз верхняя граница буфера чуть больше 1 млн.

                                                      >Что касается эффективности представления данных на диске, то CH хранит данные по-колоночно со сжатием — придумать что-либо эффективнее сложно.

                                                      Поколоночно и с сжатием хранят все, для спарка аж 2 формата — паркет и орц так хронят. В кх еще есть сортировка.
                                                        +1
                                                        Посмотрите что происходит с КХ в режиме вставки около 1,5 млн/сек в реплицированные таблицы. Как раз верхняя граница буфера чуть больше 1 млн.

                                                        Не совсем понимаю, какую мысль вы хотите выразить? То что параметры по-умолчанию не оптимальны (или не подходят) для сценариев при вставке 1500К — это очевидно. Как в любом OpenSource для эксплуатации в "не ширпотребных" сценариях требуется донастраивать/докручивать продукт (досконально разобравшись в нём), либо покупать поддержку.


                                                        На всякий, для понимания — в ClickHouse, как во всех LSM есть проблемы с распределением "полосы пропускания" дисков между слиянием внутри LSM, обслуживанием репликации и чтением для обработки запросов. В своём приватном форке мы более-менее решили эту проблему, но только для нужного нам набора сценариев. А вот насколько эта проблема сейчас решена в upstream я не в курсе.

                                                      0
                                                      умрет с out of memory запросто как любая другая база, которая умеет сложные агрегации делать.

                                                      Ну зачем же так обобщать? PostgreSQL довольно сложно уронить по OoM. По крайней мере, одним запросом. Т.к он может сбрасывать промежуточные данные на диск. Конечно, и у него бывают промашки, но вроде бы редко.

                                                        0

                                                        В КХ тоже есть режим группировки на диске. И даже, что интересно, часто он не вызывает фактического протекания на диск т.к. dirty cache страниц ядра не успевает сброситься на носитель.

                                                          0

                                                          Я думаю, что шла речь о том, что запрос отбивается — т.к. то что КХ умирает по ООМ я не видел, а вот запрос — да, сбрасывается

                                                        0
                                                        Для разных целей? И тем не менее, СlickHouse часто упоминают в срании с Cassnadra и HBase, и на сайте Яндекса есть «замеры» но вот реальных, независимых тестов нет.
                                                        Да, с обновлениями и удалениями записей у ClickHouse не всё радужно (хотя и есть решения) — но эти операции вообще узкое место для колоночных СУБД (и не колоночные СУБД их вообще поддерживают; ClickHouse поддерживаются Join — что для колоночных СУБД так же не частая фишка). Вот поэтому интересно сравнить ClickHouse с колоночными якодзунами — в т.ч. на обновление и удаление (ведь всё-таки оно возможно в ClickHouse — хотя в таких СУБД такие операции используются не часто, зачастую просто заменяясь периодическим перестроением таблицы, с удалением лишнего, и видением версий актуализации).
                                                      +2
                                                      Кликхаус он скорее для логов подойдёт. Кассандра и базы иже с ней более общего назначения.
                                                      Патриотичность в таких делах роли не играет (и не должна играть). Сугубо прагматизм.
                                                        +1

                                                        КХ это колоночная аналитическая БД с более или менее полноценным SQL. Кассандра и HBase это обычные KV базы. Нормальные запросы там появляются только если обернуть их в Spark и подобное.


                                                        Цели у этих БД несколько разные и сравнивать ИМХО не особо корректно.

                                                      +1
                                                      Угу, после моего сравнения cassandra и HBASE был выбран… aerospike.
                                                      По факту единственная, у кого на паре серверов и 100к+/сек запросах не скакали максимальные задержки. У Cassandra они до 500мс прыгают(aerospike — 3ms).
                                                        0
                                                        Это надо было в сторону сциллы копать. Там схожие результаты.
                                                          +1

                                                          После того как ераспайкеры кастрировали опенсурсную версию в очередной раз трогать его не хочется больше. А так хорошая БД, да.

                                                          +3

                                                          Честно скажу, опыт только с кассандрой, с hbase нет.
                                                          Сравнение очень странное…
                                                          Вы сравниваете cassandra, базу, целью которой является высокая доступность, которая вообще без каких-либо латенси переживает вылет rf/2-1 ноду (то есть при rf=3 и rw=quorum (классика), вылет одной ноды вообще не влияет на работу кластера от слова совсем), с Hbase, которая, насколько мне известно работает через мастера и соответственно в случае его падения… не работает. То есть для high available бд не подходит…
                                                          Естественно база пишушая через один мастер всегда будет по умолчанию в выигрышной ситуации, хотя бы потому что у неё локализован весь кэш и индексы…
                                                          Но даже при этом вы используете кассандру совсем не по назначению, она по сути key-value база с группировкой колонок по pk. Классическое её использование это read/write (в основном второе) по конкретному ключу, по одной записи (high available риал тайм процессинг), батчи антипаттерн для неё, тем более (и это прям написано в доке) батчи содержащие ключи в разных нодах (что вы и сделали).
                                                          Как тут уже заметили кассандра работает с одним диском и ей нужен raid0, плюс она непосредственно через wal + sync заботится о гарантии записи, в то время как hdfs имеет свой мемори кэш.


                                                          В общем — сравнивать высокодоступную базу с базой имеющей мастера (point of failure) некорректно иначе надо сравнивать одну ноду cs с одной нодой hb, тогда честнее будет.


                                                          А если сравнивать — пишите в большое кол-во потоков (write workers в кассандре) с rf=3, но rw=quorum (классика) при этом по одной записи (один pk) в запросе, либо, чтобы все батчи уходили в одну партицию, иначе вы опять же сравниваете ha базу размазывающую с базой с одним мастером...


                                                          P.s.
                                                          Hb может и быстрее, но она ж для другого...


                                                          P.p.s.
                                                          Кстати, что это за кейс такой где нужна high availability и low latency и при этом батч операции? Зачем вы сравниваете cs и hb...

                                                            +1

                                                            Я не сварщик, но HBase все-таки не такой уж и тупой.


                                                            Мастером для данных является каждый регион сервер (для регионов, за которые он отвечает). Соответственно, при падении регион сервера будет недоступна часть данных, пока эти регионы не назначатся на другие регион сервера.


                                                            Мастер кластера отвечает за изменение метаданных. За хранение отвечает Сторож Зоопарка. Соответственно, если упал мастер кластера, то не получится поменять состав кластера или схему данных. Однако читать и писать данные вы сможете.


                                                            Конечно, если упал мастер кластера и регион сервер одновременно, то данные не будут доступны пока кого-нибудь из них не поднимете, т.к. без мастера кластера регионы не переедут на другие регион-сервера.


                                                            И для мастера кластера и для регион-серверов вроде как в последних версиях можно назначать слейвов, что сильно уменьшает время простоя.

                                                              0

                                                              Как долго после падения регион сервера кластер это понимает и как долго переезжает регион мастер?
                                                              Как об этом узнают клиенты?
                                                              Насколько это автоматически?
                                                              (Как вообще это выглядит для клиентов, если не секрет, интересно узнать)

                                                                0
                                                                Переезд занимает вот столько времени примерно:
                                                                ZooKeeper session timeout + split time + assignment/replay time
                                                                На практике это может занять прилично времени, в частности сильно зависит от количества WAL файлов, которые нужно обработать. Все это занимает примерно минут 10-30.

                                                                >>Насколько это автоматически
                                                                На версии 2.1.0 наблюдали как RS упал, а переезд не начался. Есть информация от человека близкого к разработке HBase что административная часть в первых версиях 2.* не очень написана. Есть вероятность что 2.2.3 уже ок. Однако это исключение, такое было один раз пока что, обычно переезд начинается как надо.

                                                                Клиенты узнают так, что получают NotServingRegionException и должны висеть ждать пока не выяснится какой RS подхватил регион. В теореме CAP HBase жертвует availability…
                                                                  +1
                                                                  > ZooKeeper session timeout + split time + assignment/replay time

                                                                  Split time тут лишнее.

                                                                  Вы сильно раздули MemStore потому у вас при падение RS нужно много данных вычитывать из WAL. У нас после падение RS рекавери за 1-2 минуты проходит.

                                                                  > На версии 2.1.0 наблюдали как RS упал, а переезд не начался
                                                                  Как по мне так намного чаще регионы зависают в transition по разным причинам и их приходится в ручном режиме пропихивать.
                                                                    0
                                                                    >>Вы сильно раздули MemStore
                                                                    Да, так как когда вовсю начинали наваливать то ловили Above memstore limit.

                                                                    >>Как по мне так намного чаще регионы зависают в transition по разным причинам
                                                                    Хе хе, есть такое дело))
                                                              +1
                                                              Спасибо за детальный анализ поста и интерес к теме. Базы безусловно имеют ряд отличий, однако в целом занимают одну нишу — позволяют эффективно оперировать действительно большими объемами. При этом в рамках теоремы CAP они позиционируются по разному, как вы верно заметили. CS считается больше AP, но может быть настроена иначе, тогда как HB это практически полный CP. Однако насчет роли мастера для HB это не верное представление. Как ниже правильно отметили, есть возможность дублировать роль мастера (мы так и делаем) и второй момент в работе с данными мастер не принимает участие. Т.е. выпадение мастера не позволяет выполнять административные функции (создание таблиц и т.д.), но не мешает работе RegionServers (RS).

                                                              Насчет дисков, как я понял, у них тут все идентично. Данные легли на все диски равномерно, в комментариях выше это подтвердили. Также WAL пишется в HB как и CS и тоже делает sync.

                                                              >>А если сравнивать — пишите в большое кол-во потоков
                                                              Поменял схему, вместо записи в 5 потоков батчами по 100 штук писал 100 потоков поштучно. Никакой разницы не было. Однако на чтение вместе с TokenAwarePolicy скорость выросла в 2 раза, с 159 644 до 301 969.

                                                              Попозже проведу более полное и тщательное тестирование, с учетом других предложенных оптимизаций и добавлю в конец поста.
                                                                0

                                                                Если так же поштучно (без батчей) работать с HB во много (100+) потоков насколько она у вас получилась быстрее? И на запись и на чтение интересует… Раз уж тестите, может и мой кейс на hb потестите )

                                                                  0
                                                                  Да, конечно, я хотел все новые тесты CS прогнать и для HB, чтобы уж полная картинка была)
                                                                    0
                                                                    Добавил в пост результаты)
                                                                +1

                                                                "CS может использоваться в режиме допускающем потерю данных. Т.е. это когда только один сервер (нода) отвечает за данные некоего ключа и если он по какой-то причине отвалился, то значение этого ключа будет потеряно."


                                                                Если он отвалится, то данные не будут потеряны, они просто не будут доступны пока вы не поднимите эту ноду, а до тех пор вы получите ошибку чтения/записи, логично, ведь… вы сами задали хранение на одной ноде (rf=1).


                                                                Cs позволяет делать разные настройки для кейспейса (группы таблиц) и из коробки имеет понятие датацентра и настраиваемой политики реплик между дц. Так же можно задавать разную политику консистенции для каждого отдельного запроса. Так что вы сами настраиваете консистенси и авайлабилити считайте чуть ли не на каждый запрос, естественно, если вы хотите выстрелить себе в ногу, то cs даст вам массу возможностей, однако если вы знаете, что вы делаете, всё можно использовать в соответствующих юзкейсах.


                                                                Так же у cs присоединяются (и отсоединяются) ноды без дауниайма и какой-либо латенси.


                                                                Наш юзкейс это большое кол-во key=value записей (в основном) и чтений (~10:1) (рандомных по ключу), но все по одно и латенси критично (так что никаких батчей не получится собрать), но благодаря вашей статье я попробую посмотреть в сторону hbase ещё раз (5ть лет назад уже смотрел и тогда выбрал cs).


                                                                arheops писал про задержки в 500мс, это не cs, это java gc, если правильно под вашу нагрузку настроить и долгих gc, а тем более stw не будет (а 500мс это возможно оно), то вы даже 5мс никогда не увидите.


                                                                (Про scylladb знаю, но с ней были непонятки/проблемы год назад, может тоже посмотрю ещё раз)

                                                                  +1
                                                                  Насчет потери данных, имелось в виду выход из строя например диска. Для кластеров нашего размера это весьма вероятное событие.
                                                                    0

                                                                    Да, я вас понял, просто придрался :) к фразе, что может работать в режиме допускающем потерю данных, она может работать с любым количеством реалик и если копия только одна, то как бы вы ж сами выбрали, то есть это не минус это плюс, есть выбор, возможно вам для определённых таблиц не нужно лишнее дублирование и данные там если что не жалко.


                                                                    Да, у нас тоже прилично данных, а главное куча изменений и ssd диски регулярно сыпятся, потому очень удобно иметь возможность в любой момент просто вытащить ноду из кластера (просто выключить) и что-то с ней поделать без пенальти.

                                                                  0
                                                                  Справедливости ради, все-таки ёкодзуна или йокодзуна, но никак не якодзуна.

                                                                  Сёходзан (тот, что на фото справа — у вас он с подписью HBase) никогда не был ёкодзуной :-)
                                                                    0
                                                                    Много лет назад имел хождение в интернетах истерический смех ведущего комментирующего схватку двух «якодзун», это была отсылка к нему)
                                                                      +1
                                                                      Причём сама та схватка таких эмоций не вызывает)
                                                                    +2

                                                                    Зачем нужна cs когда есть scylladb. Автор попробуй с ней сравнить hbase

                                                                      +2
                                                                      затем что scylla оптимизирована full под ssd, и направление работы с hdd разрабы уже говорили их не очень интересует, и их можно понять, у них мало клиентов на hdd, а большая часть вообще в амазоне.
                                                                        +1
                                                                        У вас есть реальный опыт работы со scylla? А до этого была с cassandra? Если можно — кратко минусы (плюсы у них на сайте разрекламированы) и вообще какова реальность? И что насчёт лицензионной политики?
                                                                          +1
                                                                          Scylla более требовательна к соотношению CPU-RAMM-HDD, т.к. принципиально не использует swap. В Cassandra это настраивается.
                                                                          Для эффективной работы Cassandra надо тонко тюнить Жабомашину. Из коробки она проигрывает в зависимости от типа тестов от 2 до 9 раз (это наши тесты на тестовых контурах 2 реальных систем).
                                                                          Ноды Scylla гораздо быстрее поднимаются и реже «падают». В кавычках, т.к. сталкиваемся в кластере на Cassandra (33 ноды) в том числе с тем, что нода отвечает на все команды, но при этом не пишет и не отдает данные.
                                                                          Лицензионная политика примерно одинакова с Datastax. Есть OpenSourse и Enterprise версии.
                                                                          Для военных Scylla имеет полную совместимость с Astra Linux SE 1.6.
                                                                            0
                                                                            Для военных Scylla имеет полную совместимость с Astra Linux SE 1.6.

                                                                            А вот тут по-подробнее, если можно. Нашел презентацию айтеко, но непонятно, как к этому получить доступ и имеет ли оно сертификат.
                                                                              0
                                                                              Этим я там как раз занимался. Написали часть модулей для сертификации. Получили сертификат совместимости от Русбиттеха. Я ушел, проект закрыли.
                                                                        +1

                                                                        Товарищ подсказывает по Кассандре:


                                                                        • не используйте батчи для записи во многие партиции. (Об этом даже DataStax пишет)
                                                                        • используйте параметризованные запросы вместо склейки строк. Тогда и коннектору и кассандре будет проще разбирать запрос, чтобы понять в какой сервер его посылать.
                                                                        • в коннекторе необходимо указать TokenAwarePolicy (хотя, вроде DataStax коннектор ставит ее по умолчанию)
                                                                          0
                                                                          Да, спасибо, есть существенный прогресс производительности. Попробую еще параметризованные запросы, потом отпишусь что вышло.
                                                                            0

                                                                            Чтение, по идее, тоже лучше параллельными/асинхронными запросами вместо IN, когда много партиций задействовано.

                                                                          +1
                                                                          В тесте для HBase добавьте FLUSH на таблицы в конце записи, что бы чтение было не из MemStore, а с диска. Иначе БД в разных условиях сравниваются на чтение.
                                                                            0
                                                                            Да, это так, я в посте упоминал об этом, скорость после флаша падает примерно в 2 раза. Я пытался привести CS к подобному поведению, увеличивая memtable_heap_space_in_mb, однако это не дало ускорения. Т.е. с одной стороны все верно, а с другой хотелось бы как-то отметить, что HB эффективнее держит данные в памяти. Думаю для полноты картины в финальной версии сравнений выложить два варианта — чтение с дисков и из памяти.
                                                                              0
                                                                              В реальной жизни чтение обычно сильно позже идет после записи, а значит MemStore будет сброшен на диск до чтения. Потому я склоняюсь что тест на чтение должен работать с файлов после принудительного FLUSH что бы зафиксировать скорость чтение в типовом сценарии потребления.
                                                                                0
                                                                                Бывает сильно по разному, например у нас очень часто HB используется для сборки полной версии объекта через комбинацию put-get. Это когда мы получаем вектор изменений (только изменившиеся поля от источника), применяем (put) и тут же делаем get, чтобы получить полный экземпляр объекта для отправки дальше. Однако проверить оба варианта действительно интересно.
                                                                                  +1
                                                                                  В get полного экземпляра у вас будут и «новые» данные из MemStore и «старые» из HFile, так что диски будут задействованы. Причем чтение из MemStore + HDFS возможно будет даже медленее чем если бы вы сразу из HDFS считали объект целиком.
                                                                                    0
                                                                                    Звучит логично, конечно, однако многое зависит от множества сложившихся условий на кластере и иногда бывает контр-интуитивное поведение. Вот к примеру записал данные в 4 таблицы, всего 4 млрд записей. Потом сбросил на диск и прочитал случайные 400 млн (т.е. 10%). Это заняло 41 секунду:
                                                                                    tables=4, threads=100, batch=100, count=100000, dataSize=100, opType=select: 41814.

                                                                                    Затем был сделан рестарт HBase, чтобы почистить кэш, сделан major_compact и залиты те же самые 400 млн ключей по новой, чтобы они лежали и в memstore и в HFile.
                                                                                    И тут же прочитал, и как ни странно, это заняло меньше времени, всего 33 секунды:
                                                                                    tables=4, threads=100, batch=100, count=100000, dataSize=100, opType=select: 33326

                                                                                    Причем если сбросить данные на диск и замажорить, то чтение займет все равно 33 секунды)
                                                                                      0
                                                                                      У HBase небольшой кеш, а вот в кеш файловой системы вполне могло все попасть (у вас там вроде по 700GB памяти).

                                                                                      Зачем major делать до заливки?

                                                                                      Скиньте исходники для HBase. Прогоню на своем нагрузочном кластере. Интересно что у меня получится.
                                                                                        +1
                                                                                        Да, МС был лишний, не подумал про кеш. Версия github.com/cloudera/hbase/tree/cdh5-1.2.0_5.14.2
                                                                                        Тот патч, о котором я писал, играет роль только при кол-во регионов на RS от 800-1000, так что можно не запариваться. Задумал ScyllaDB кстати так же проверить, дам знать что получится)
                                                                                          0
                                                                                          нет смысла, scylla оптимизирована под ssd, у вас же чисто hdd и даже под коммит лог и кеши нет ssd, смысла со scylla нет, плюс scylla требует обязательной оптимизации дисковой подсистемы.
                                                                                            0
                                                                                            Думаю диски потюним, это не быстро, но реально. В любом случае хочется посмотреть что будет)
                                                                                              0
                                                                                              сцилла не умеет JBOD от слова совсем. И похоже они не собираются особо возиться с этим режимом, обосновывая это многочисленными сложностями в реализации и эксплуатации (тут понятно), а так же не особой вообще необходимостью (мол, если raid0 теряет один диск, то ввод ноды с нуля в кластер не займет много времени все равно. Тут уже я и некоторые другие совсем не согласны. Все таки куда лучше было бы потерять один диск и только его, при этом нода жива и возможна горячая замена)

                                                                                              А так, попробовать конечно можно, но с условием raid0. Она хоть под hdd вообще не писалась, но сама по себе внутри чрезвычайно эффективна. Прирост какой-то это даст. Ну и никуда не деваются принципы работы, которые она переняла от касандры, что сильно помогает на hdd само по себе.
                                                                                                0

                                                                                                Печально… А есть возможность высадить к примеру две ноды на один сервер? Или там завязано общение на некий порт и по любому нужно поднимать второй ip адрес?

                                                                                                  0
                                                                                                  сциллу нельзя, она оптимизирует систему под 1 свой процесс, вообще всю систему, иначе производительность будет хуже. вообще идея несколько бд держать на 1 сервере идиотизм.
                                                                                                    0

                                                                                                    Ну, не идиотизм. Например, для эластика это штатный режим работы. Но факт в том, что это требует отдельной настройки, причем иногда весьма нетривиальной, т.к. любая база по умолчанию считает, что сервер принадлежит только ей. Плюс эффекты конкуренции за page cache

                                                                                                      0
                                                                                                      эластик не модифицирует настройки ядра чисто под себя и 1 процесс, в отличии от сциллы. плюс эластик не совсем то с чем надо сравнивать большинство бд, плюс у эластика это проблема в его архитектуре и не умении в 2020 году в heap больше 64 гб, плюс у эластика много проблем с производительностью в целом на мощном железе, он просто не умеет его утилизировать. В отличии от той же сциллы, которая наоборот утилизирует железо по максимуму, нет ограничений по памяти, нет jvm.
                                                                                                        0
                                                                                                        Сцилла тоже это не делает. Все ее твики в конечном итоге сводятся к общим оптимизациям, которые и другим базам будут полезны.
                                                                                                    0
                                                                                                    Да, скорее всего придется на разных IP поднимать. Насчет проблем с производительностью, достаточно будет разных дисков, разного набора ядер (сцилла и так себя пинит к конкретным ядрам) и достаточно памяти и никаких проблем с производительностью не должно быть.
                                                                                                      0
                                                                                                      разрабы сциллы крайне не рекомендуют так делать, они делали её именно с расчётом полной утилизации оборудования, большая часть их клиентов сидит на мощных инстансах aws, и на очень мощном железе. и производительность будет существенно ниже у такой конфигурации по сравнению с 1 экземпляром бд.
                                                                                                        0
                                                                                                        Не будет она существенно ниже. Иначе бы виртуальные машины и докер не работали, на которых эта самая сцилла прекрасно работает. Главное дать каждому экземпляру свою часть ресурсов — процессор, память, диски. Сделать это не сложно. Сложнее банально разрулить конфликты портов.
                                                                                                    0
                                                                                                    Да, у них это принципиальная позиция. Которую изменить не удалось в ходе дискуссий с их инженерами. Нода вводится быстрее Кассандровской, но не прям быстро.
                                                                                0
                                                                                Тот случай, когда статью можно читать сразу с комментов.

                                                                                Only users with full accounts can post comments. Log in, please.