Pull to refresh
16
0
Игорь Стрыхарь @sublimity

Tex.Дир.

Send message

Ошибка явно указывает на ограничения пользователя, в настройках вашей db.


Access denied to database linear for user
Для запроса: SHOW TABLES FORMAT JSON
https://clickhouse.tech/docs/ru/operations/access-rights/amp/

Как разработчик Tabix ( может слышали ), смотрите в сторону React, но только не angular))

Взял за основу pgsql + mssql "шаблоны" в AceJs и собрал под CH
Последняя Dev версия если интересно тут

Сообщество выпустило интеграцию с grafana: https://github.com/Vertamedia/clickhouse-grafana


О GraphiteRollupSorted лучше спросить в Telegram группе — там есть люди которые активно используют этот сторедж, мы не стали использовать его.

CH позиционируется для очень больших хранилищ данных, для работы на HDD. Пока мы храним несколько десятков ТБ. В этом его сверх "крутость CH" что на блинах такая скорость работы )

Кто то добрый взялся и перевел -> спасибо!

Да есть такое в issue и roadmap — появятся силы добавим мультиязычность https://github.com/smi2/clickhouse-frontend/issues/21

Если по каким-то причинах реляционная СУБД не подходит (например, очень много данных) и требуется выполнять обновления записей, то при выполнении ряда условий:


  1. Статус продаж в конечном итоге финализируется (т.е. переходит в состояние, когда информация о продаже более не меняется, например, продажа состоялась).
  2. Количество продаж, у которых потенциально может измениться состояние, в сравнении с общим количеством продаж значительно меньше и эта информация может сохраняться во внешнее хранилище с быстрым доступом по ключу (по идентификатору продажи).

рекомендуется использовать движок https://clickhouse.yandex/reference_ru.html#CollapsingMergeTree, работа которого основана на двух состояниях записи { old_state, new_state }, и иметь возможность быстрого получения состояний продаж, которые потенциально могут быть изменены, например, во внешнем key-value хранилище, где ключом будет идентификатор продажи, а значением — информация о продаже, включая статус.


Например, будет следующая структура таблицы: ( sign, ( sale_uuid ), manager_id, price, status ). Тогда работа с данными будет выглядеть следующим образом.


  1. Добавление продажи (запись в key-value хранилище отсутствует по заданному ключу: sale_uuid):

Key-value:


put( 'sale_uuid_0', { 867, 120.34, 'pending' } )

CH:


( 1, 'sale_uuid_0', 867, 120.34, 'pending' )

  1. Обновление продажи (запись в key-value хранилище присутствует по заданному ключу: sale_uuid):
    old_state = get( 'sale_uuid_0' )
    new_state = { 867, 120.34, 'approved' }

Key-value:


put( 'sale_uuid_0', { old_state.manager_id, old_state.price, 'approved' } )

CH:


(-1, 'sale_uuid_0', 867, 120.34, 'pending' )
( 1, 'sale_uuid_0', 867, 120.34, 'approved' )

На текущем этапе CH будет хранить 3 записи:


( 1, 'sale_uuid_0', 867, 120.34, 'pending' )
(-1, 'sale_uuid_0', 867, 120.34, 'pending' )
( 1, 'sale_uuid_0', 867, 120.34, 'approved' )

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


( 1, 'sale_uuid_0', 867, 120.34, 'approved' )

Аналогичным образом могут 'изменяться' любые поля для заданного ключа.


  1. Удаление продажи (запись в key-value хранилище присутствует по заданному ключу: sale_uuid):

old_state = get( 'sale_uuid_0' )
new_state — не задан


Key-value:


remove( 'sale_uuid_0' )


CH:


(-1, 'sale_uuid_0', old_state.manager_id, old_state.price, old_state.status )

На текущем этапе CH будет хранить 4 записи (если схлопывание движком еще не произошло):


( 1, 'sale_uuid_0', 867, 120.34, 'pending' )
(-1, 'sale_uuid_0', 867, 120.34, 'pending' )

( 1, 'sale_uuid_0', 867, 120.34, 'approved' )
(-1, 'sale_uuid_0', 867, 120.34, 'approved' )

Либо CH будет хранить 2 записи:


( 1, 'sale_uuid_0', 867, 120.34, 'approved' )
(-1, 'sale_uuid_0', 867, 120.34, 'approved' )

Во всех случаях (рано или поздно) записи будут схлопнуты и запись о продаже будет 'удалена'.

Готовых продуктов/дашбордов мы не знаем, частично поэтому мы реализовали свой GUI для редактора SQL. В котором планируется реализовать отрисовку графиков ( визуализацию данных) после создания запроса.


Думаю использовать Grafana для отрисовки графика на обычных движках CH, не очень правильный кейс.


Для Graphite, в CH предусмотрен отдельный сторедж, который хранит и “сворачивает” данные в виде Graphite схемы данных. GraphiteRollupSorted не документирован, и опыта у нас работы с ним пока нет.

Есть много способов решения задачи. Основная идея в том, что лучше хранить события в одной большой таблице и не использовать JOIN по большим данным. Или дублировать данные при вставке в несколько таблиц, в терминологии статьи это значит "писать в несколько TSV-файлов".


Также есть вариант, когда вы пишете RAW событий в одну большую таблицу (назовем ее "поток"), к которой прикреплены MaterializedView. Эти MaterializedView будут раскладывать RAW-поток на нужные составляющие.


Возможно, лучше изменить понятие uuid, и ввести понятие session_id. Сессия меняется, а uuid нет, если это возможно.


Если без uuid, то тогда можно сделать еще такие варианты:


  • Использовать две колонки uuid: например first_uuid и main_uuid. При изменении uuid вы пишете в разные поля, как изменилась сессия.
  • Использовать отдельное поле, массив сессий.
  • Использовать движок CollapsingMergeTree.
  • Ввести единый uuid и добавить признак типа enum|int — is_login.

Я бы посоветовал написать прототип по одному из вариантов или сразу несколько вариантов и начать делать запросы SELECT. Придумать несколько штук, которые самые популярные у вас. И исходя из запросов на чтение понять оптимальную структуру.


В статье мы привели самый простой пример, для упрощения. На самом деле мы используем практически все из перечисленных выше методов. И меняли структуру данных под CH.

Вопрос хороший, на самом деле в этом отличие СМИ2 от рекламных сетей, у нас высокое требование по доставки свежего контента пользователю – и вообще, и особенно если происходит что-то что чрезвычайно важное (как выборы в Америке сегодня).
Тогда об этом начинают писать все СМИ, и чем быстрее наша система заметит свежую и важную новость по теме, тем лучше. А новости могут устаревать даже спустя полчаса (если появился апдейт, сообщающий о новых подробностях или изменении суть происходящего)


Поэтому сейчас мы ранжируем за 5 секунд весь набор активных новостей, плюс-минус 30 тысяч, и пользователь получает каждую минуту свежий набор новостей. Безусловно, это не значит, что обновляются вообще ВСЕ новости – речь о том, что мы стремимся показывать актуальный набор на конкретный момент времени.

Я надеялся избежать этого вопроса )


  • Желание изучить максимально предметную область — все “фичи” CH на самом низком уровне, чтобы реализовать нужный нам ф-ционал, асинхронная отправка с сжатием потока.
  • В нашем приложении под HHVM, использую только максимально легковесный код, в котором можно быть уверенным что все работает так как нужно.
  • Драйвер мы не используем под большой нагрузкой, т/к не представляю у нас такой кейс.

Есть альтернативный драйвер на Guzzle, но в нем не реализован функционал которые хотелось и выглядит он заброшенным.
HTTPlug показался неподходящим, т/к не нашел в нем реализации curl_multi_exec, (возможно плохо искал).
Реализация показалась тяжелой в Guzzle, хотя в нем отлично реализован GuzzleHttp\Handler\CurlMultiHandler


Примеры странного специфичного кода


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


У каждого из подходов есть плюсы и минусы:


Перешардирование даёт лучшее распределение данных в кластере и при выполнении запросов узлы кластера будут нагружены примерно одинаково. Минус перешардирования — кроме того, что это очень тяжелая операция, возможно, потребует остановки кластера. Если СУБД, к примеру, является подсистемой, то остановка кластера может быть недопустима.


Использование весов даёт неравномерное распределение, зато позволяет быстро добавлять узлы без создания дополнительной нагрузки на кластер.


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


Рекомендую:
Перешардирование
bug on groups

Самим средствами CH — проверить при вставке валидность uuid думаю не правильно, это просто строка, без типизации.


Можно отдельно отправить запрос и узнать сколько «плохих» строк, которые не соответствуют длине, не содержат ‘-’ и т/д.


Лучший кейс — это проверка при сохранении «события» в файл, т/е на стороне «писателя» данных.


Если «писатель» получил пустой uuid или не валидный — то можно проставить новый рандомный uuid, пометив что он искусственный, через отдельную колонку в таблице типа is_true_uuis = [ 0 | 1 ].


Теоретически, можно сделать еще так, через новое поле check_uuis DEFAULT (length(uuid)=61 ? 1 : 0 ), но думаю это тоже плохой кейс.

Спасибо за позитивный комментарий.
Внутри драйвера мы чуда не сотворили.
Используется curl_multi.
Функция execLoopWait ждет в цикле — через проверку состояния curl_multi_exec.
См. https://github.com/smi2/phpClickHouse/blob/master/src/Transport/CurlerRolling.php#L159

Под realtime мы подразумевали, что данные достаточно быстро доступны для чтения, по сравнению со стеком Hadoop.

В видеороликах продемонстрировано, насколько быстро ClickHouse анализирует исторические данные. Демонстировать запросы данных за последние 5-10 минут тяжело, т. к. их выполнение занимает сотые доли секунды.

Как пример, для чего мы используем запросы, близкие к realtime, могу привести ранжирование статей. Допустим, 1 минутут назад статью просмотрело 100 человек, в промежутке между 2-й и 3-й минутами от текущего времени — 120 человек. Эти данные используются нами для ранжирования статей. У нас порядка 25 тысяч статей. По каждой из них нужно получать состояние по каждой минуте и на основе этой информации ранжировать статьи.
Как только мы приготовились запускать Druid в продакшн, мы успели накопить в нём данные всего лишь за месяц. Druid показал хорошую производительность на данных с глубиной в несколько дней. При запросах большей глубины были заметные тормоза.

Как только мы увидели ClickHouse в открытом доступе, мы удалили с серверов Druid и поставили ClickHouse. В ClickHouse данные у нас храняться больше 3,5 месяцев.

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

Druid много чего не поддерживает по сравнению с ClickHouse. Мы хотели/мечтали о базе с «SQL-подобными запросами». Когда мы анализировали Druid, он не понравился нам запросами в «своем формате». Писать SQL-запросы приятнее и проще, чем огромные «массивы» в postAggregation, hyperUniqueCardinality и т. д.
Для своей работы делал сервис skype|telegram <=> mail|restapi

используем его в проде, для
алертов из приложений и nagios и получить состояние и
Решил сам проверить 3.0 в действии, тест простой но близкий к моей задаче, пишем случайный ключ и читаем по случайному ключу.

Тесты делал на php-fpm + nginx, три отдельных сервера — на одном сразу три монги запущенно.
Возможно где то ошибся и тест сильно " синтетический ", результаты: в два раза быстрее и компактнее…
Подробности: gist.github.com/isublimity/4974919e38c66367804d



1

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity