Сделать невозможное
Я … не думаю, что это то, как это должно выглядеть
Так что это Это Время года опять таки , нам нужно обновить нашу кластер MemsQL и расширить наш контракт, чтобы соответствовать новой топологии кластера.
На этот раз мы действительно преуменьшаемся на этот раз, расширение к кластеру 1TB впечатляет, особенно когда он совсем не оправдан.
Фон
Ждать. Кластер 1TB?
Да, да, позвоните нам испорченным, но запрос в PostgreSQL (PG отныне) просто не то же самое.
Конечно, вы можете получить Хорошо Скорость Если вы используете правильные индексы и оптимизируете свои запросы, но это даже не сравнимо с производительностью, которую вы получаете от Rowstore на основе памяти, или безумно быстрых скоплений колонны.
Короткое (короткое) Краткое изложение различных типов хранения MEM
Таким образом, мы в основном имеем 2 типа хранения в MEM, ROWSTORE и COOLLSTORE.
Rowstore хранится в значительной степени похоже на любую другую базу данных, но в памяти вместо диска (Crazy Fast). Это означает, что каждая строка хранится вместе со всеми его колоннами
ColumnStore является вроде транспонированного строки, вместо того, чтобы хранить строки, мы храним столбцы ( Спасибо, капитан очевидно ), что позволяет нам делать агрегации глупыми быстро (думать об этом, а не собираться в каждую строку и суммируя «стоимость» «Столбец, мы можем просто перейти к столбцу« Стоимость »и суммируйте его). Конкульская поверхность хранится на диске.
Проблема является лицензией MEMSQL стоит больше, чем у нас больше памяти в нашем кластере, не говоря уже о стоимости самих машин (1 ТБ памяти не совсем дешево)
«Так почему бы не хранить все в колонной? Это дешевле, как лицензия, так и инфраструктура мудрые, а это глупо быстро! » Вы можете спросить (если вы говорите с самим собой, читая технические статьи)
Итак, вот улово — способ хранения данных в колонном месте, делает его невероятно быстрыми в агрегированных запросах и позволяет удивительно сжатие, но обновление ряд — медленно Отказ
Как медленно? Если нам нужно обновить несколько столбцов для строк в определенный день, для нас быстрее удалить данные с этого дня и повторно вставить обновленный вместо обновления существующих строк.
Так как мы храним наши данные?
Ну, в моей команде мы используем 7 ароматов баз данных (могут быть больше, не могут следить за этим днями) Но Главными являются PostgressQL, размещенные и управляемые RDS (для транзакционной обработки) и MEMSQL, размещенные на EC2 и управляемым по-настоящему (для аналитической обработки * )
Инстинктивно, большинство наших данных хранятся в PG (за исключением некоторых больших столов для колонны, содержащие север 8b Records)
Проблема в том, что, как только вы пойдете MEM, вы никогда не вернетесь, поэтому мы создали службу репликации, которая может воспроизводить строку из PG в Rowstore Mem’s в режиме реального времени. Это позволяет нам обогащать наши столбцы только таблицы, создавать ETL и, что самое главное, ускоряют запросы.
Если вы здесь, вы либо используете MEM и, таким образом, знаете его производительность, либо просто хотели бы обойти dev.to, чтение случайных статей о нишевых dbs. Если вы последнее, позвольте мне ударить вас некоторыми номерами.
Полностью разумный запрос, состоящий из 6 присоединений, занял 30 минут на PG. После оптимизации его в течение 2-3 часов добавляя индексы, стучая головой к стене и молясь за быстройкансию, я смог сократить его до 3 минут.
Принимая именно оригинальный запрос (30 минут) и работает на мем, это заняло 1,87 секунды Отказ
Реальная сделка
Определение проблем, ака, что заставляет меня потерять сон
Итак, МЕМ дорого, мы почти у нас Новый Лимит лицензии (после более чем удвоения) и нет возможности вернуться к запросу исключительно на PG.
Решение кажется простым, переместите большие таблицы в колонну, освободите некоторую память, чтобы вам не нужно увеличивать лицензию и обновить свои машины.
Для этой статьи я буду использовать наш стол touch_points
В качестве примера, это наша самая большая (как в память, так и в COUNT COUNT), хранятся в ROWSTORE — он имеет более 180 м соров, а весит более 190 ГБ.
Почему это в нашем Роусторе? Во-первых, потому что мы повторили его из PG, и до сих пор наша услуга поддерживает только репликацию в таблицы Rowstore, но, что более важно, его необходимо обновить. Из 30 столбцов, 2 может быть обновлен — Visitor_id
и Стоимость
Отказ
Растворы
Первое решение
Так что это был «правильный» дизайн-мудрый раствор.
Короче говоря, используя Accisterecord обратных вызовов я сохранял 2 таблицы в актуальном состоянии, один из них touch_points
Таблица в колонне, содержащий все столбцы, которые существуют в настоящее время на touch_points
кроме 2, которые обновляются. Кроме touch_points
Я создал таблицу под названием touch_points_extra_data
В ROWSTORE, содержащий 2 отсутствующих столбцов и 1 столбца ID, который позволяет мне подключить 2 таблицы.
Как я уже сказал, это был правильный дизайн решения, проблема в том, что так много может пойти не так. С таким количеством движущихся частей все зависит от рельсов крючков, мы обязались выйти из синхронизации когда-то . Не говоря уже о том, что нам придется редактировать все наши вопросы от touch_points
Чтобы добавить эту дополнительную Присоединяйтесь к
Отказ
Второе решение, ака «BruteForce»
Поэтому мы поняли, что наш главный приоритет состоит в том, чтобы сохранить данные правильными, и мы готовы сделать некоторые компромиссы (предвещать)
Я решил реплицировать весь стол, как есть, из PG время от времени. Таким образом, мы можем убедиться, что (до момента репликации) наших данных будут идентичны как в дб.
Компромисс состоит в том, что мы используем для обновления этих данных в режиме реального времени, и теперь она будет устарела до следующей репликации. Это компромисс, который я готов взять.
Техническая часть
Проще сказать, чем сделать
Так что, по-видимому, реплицируя целую таблицу от одной БД к другому, не так просто, как вы думаете. Особенно, когда два DBS полностью бегают на разных двигателях.
Первое, что я пытался использовать pg_dump
, с равнина
Формат файла (который по существу создает файл с нагрузками inslue
утверждения), а затем преобразовать его в синтаксис MySQL и загрузить в MEM.
Звучит очень хорошо? Я начал pg_dump
и 5 часов спустя это даже не было близко к отдельности, пока файл дампа был уже на 60 ГБ. pg_dump
с равнина
Опция — самый неэффективный способ хранения данных. Задержка 5 часов репликации неприемлема.
Если сначала вы не добитесь успеха. Потерпеть неудачу
Следующая вещь, которую я пытался, использовал Скопировать
Команда PG, эта команда может копировать (DUH) таблицу или запрос в Файл
, а Программа
или Stdout
Отказ
Сначала я попробовал использовать опцию stdout (простейший, и это не создает след огромного файла дампа)
psql -U read_user -h very-cool-hostname.rds.amazonaws.com -p 5432 -d very_cool_db -c\ "\COPY (SELECT * FROM touch_points) TO STDOUT\ WITH(DELIMITER ',', FORMAT CSV, NULL 'NULL', QUOTE '\"');" > touch_points.csv
И это сработало! У меня есть файл «дамп» из PG, содержащий весь этот touch_points
Таблица, всего за 20 минут.
Теперь нам просто нужно импортировать его в MEM, но почему сделать Мне нужен файл? Я могу просто получить результат прямо из PG прямо в MEM!
Поэтому мне нужно было создать часть, где MEM получает эту таблицу CSV, и загружает его в БД. К счастью, MEM MySQL совместим и предоставляет нам Загрузить данные
пункт!
LOAD DATA LOCAL INFILE '/dev/stdin' SKIP DUPLICATE KEY ERRORS INTO TABLE touch_points_columnstore FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '' LINES TERMINATED BY '\n' MAX_ERRORS 1000000;
Теперь, как я уже сказал, мы хотим трусить это данные прямо в MEM, поэтому нам нужно создать соединение с нашей БД:
mysql -h memsql.very-cool-hostname.com -u write_user -P 3306 -D very_cool_db\ -p'4m4z1nglyS3cur3P455w0rd' -A --local-infile --default-auth=mysql_native_password -e\ "LOAD DATA LOCAL INFILE '/dev/stdin' SKIP DUPLICATE KEY ERRORS\ INTO TABLE touch_points_columnstore FIELDS TERMINATED BY ','\ ENCLOSED BY '\\\"' ESCAPED BY '' LINES TERMINATED BY '\\n' MAX_ERRORS 1000000;"
А потом просто проложите данные из PG к этому соединению!
psql -U read_user -h very-cool-hostname.rds.amazonaws.com -p 5432 -d very_cool_db -c\ "\COPY (SELECT * FROM touch_points) TO STDOUT\ WITH(DELIMITER ',', FORMAT CSV, NULL 'NULL', QUOTE '\"');" |\ mysql -h memsql.very-cool-hostname.com -u write_user -P 3306 -D very_cool_db\ -p'4m4z1nglyS3cur3P455w0rd' -A --local-infile --default-auth=mysql_native_password -e\ "LOAD DATA LOCAL INFILE '/dev/stdin' SKIP DUPLICATE KEY ERRORS\ INTO TABLE touch_points_columnstore FIELDS TERMINATED BY ','\ ENCLOSED BY '\\\"' ESCAPED BY '' LINES TERMINATED BY '\\n' MAX_ERRORS 1000000;"
И … это сработало! Но это заняло 2 часа. Я Конечно Мы можем сделать лучше, чем это.
Сжатие — твой друг
Так что два классных веща, важно понимать о загрузке данных в MEM:
- При вставке файла данных в MEM он копирует файл локально к агрегатору и разделяет файл между узлами кластера, значительно ускоряет нагрузку данных.
- MEM поддерживает получение GZIP-сжатых файлов данных.
Сочетание этих двух частей информации заставило меня понять, что создание файла в середине, возможно, не так плохо, как я думал.
Я могу сжать этот файл, делая хранилище неисправности, он также ускорит передачу файла в агрегатор (до расщепления), вырезая большую часть задержки, связанной с сетью, и она позволит MEM разделить данные между узлами.
Давай сделаем это!
Прежде всего, мне нужно изменить часть PG, поэтому вместо трубопроводов содержание в Stdin.
, это трубы это к Программа
и в нашем случае гzip.
psql -U read_user -h very-cool-hostname.rds.amazonaws.com -p 5432 -d very_cool_db -c\ "\COPY (SELECT * FROM touch_points) TO PROGRAM 'gzip > /data/tmp/replication/touch_points_columnstore.gz'\ WITH(DELIMITER ',', FORMAT CSV, NULL 'NULL', QUOTE '\"');"
После того, как мы создали этот файл TMP, нам нужно его загрузить. К счастью, единственное, что нам нужно сделать, это изменить источник входного файла! Наш готовый скрипт выглядит так:
psql -U read_user -h very-cool-hostname.rds.amazonaws.com -p 5432 -d very_cool_db -c\ "\COPY (SELECT * FROM touch_points) TO PROGRAM 'gzip > /data/tmp/replication/touch_points_columnstore.gz'\ WITH(DELIMITER ',', FORMAT CSV, NULL 'NULL', QUOTE '\"');" &&\ mysql -h memsql.very-cool-hostname.com -u write_user -P 3306 -D very_cool_db\ -p'4m4z1nglyS3cur3P455w0rd' -A --local-infile --default-auth=mysql_native_password -e\ "LOAD DATA LOCAL INFILE '/data/tmp/replication/touch_points_columnstore.gz' SKIP DUPLICATE KEY ERRORS\ INTO TABLE touch_points_columnstore FIELDS TERMINATED BY ','\ ENCLOSED BY '\\\"' ESCAPED BY '' LINES TERMINATED BY '\\n' MAX_ERRORS 1000000;"
Вот и все!
Созданный файл весит 7 ГБ, и весь процесс занимает менее 20 минут, поэтому мы можем запустить его один раз в час и иметь данные полуреагирования!
Очевидно, что это не конец, я завернул его в модуль приятных рельсов, который позволяет легко воспроизводить любые запросы от PG в MEM легко, включая усечение старых данных и использование 2 таблиц для минимизации простоя во время репликации.
Не стесняйтесь обращаться ко мне с любыми вопросами! * в том числе не ограничивается аналитикой и транзакциями.
Оригинал: «https://dev.to/oryanmoshe/replicating-postgressql-into-memsql-s-columnstore-322h»