Продолжаю своё знакомство (первый опыт контакта был описан в посте про функциональные и интеграционные тесты) с детищем mail.ru - in-memory NoSQL базой данных Tarantool.
In-memory значит, что все данные она держит в оперативной памяти, то есть работает как кэш. Изначально это и был кэш над mysql. Постепенно тарантул мутировал и превратился в настоящего Арагога: под капотом интерпретатор языка Lua для написания хранимок, но можно запросы делать и на sql (к NoSQL базе, да).
Основные отличия от главного конкурента - кэша Redis - состоят в том, что Redis умеет работать как кэш для MongoDB, но при этом тарантул позволяет делать намного более сложные выборки: Redis работает как ключ - значение, то есть, выражаясь языком SQL, у него есть только индексированный primary key.
Тарантул же умеет строить сложносочинённые индексы из многих частей (до 256). Так что если нужны сложные но очень быстрые выборки - тарантул ваш выбор. Для пользователя тарантул не слишком дружелюбен. Впрочем, возможно дело в том, что официальной библиотеки для работы с тарантулом на c# от mail нету. Есть некая опенсорсная поделка, которая работает, и работает нормально, но в использовании она какая-то неудалая.
Данные в тарантуле лежат в space-ах - аналоге sql таблиц в виде кортежей: как строка в таблице. Но, в отличие от sql, жёстко фиксированы типы только столбцов, по которым строятся индексы. В остальных может быть суп из данных. Впрочем, если хочется, можно жёстко задать схему данных при создании space-а.
Индексы в тарантуле могут строиться как по одной "колонке", так и по многим. Составные индексы позволяют делать запросы как по части индекса, так и по значениям для всей строки целиком.
Предположим, хранятся у нас данные вида:
Id, Дата рождения, Фамилия, Имя, Отчество, Должность, Статус (работает/не работает), произвольная информация в следующих колонках. Индекс типа TREE (бинарное дерево под капотом) строится по всем полям, кроме Id. Он сможет отвечать на следующие запросы:
Первое знакомство с тарантулом скорее положительное, работает шустро. Главная претензия к шарповой обертке, там при написании кода получается дикая лапша, а еще без плясок с бубнами мне не удалось отправить в тарантул Guid (uuid, уникальный 128 байтовый идентификатор): превратил в строку, отправил в таком виде на сервер, там распарсил Guid обратно, что конечно дикость, но пока сойдет.
#tarantool
#кодинг
In-memory значит, что все данные она держит в оперативной памяти, то есть работает как кэш. Изначально это и был кэш над mysql. Постепенно тарантул мутировал и превратился в настоящего Арагога: под капотом интерпретатор языка Lua для написания хранимок, но можно запросы делать и на sql (к NoSQL базе, да).
Основные отличия от главного конкурента - кэша Redis - состоят в том, что Redis умеет работать как кэш для MongoDB, но при этом тарантул позволяет делать намного более сложные выборки: Redis работает как ключ - значение, то есть, выражаясь языком SQL, у него есть только индексированный primary key.
Тарантул же умеет строить сложносочинённые индексы из многих частей (до 256). Так что если нужны сложные но очень быстрые выборки - тарантул ваш выбор. Для пользователя тарантул не слишком дружелюбен. Впрочем, возможно дело в том, что официальной библиотеки для работы с тарантулом на c# от mail нету. Есть некая опенсорсная поделка, которая работает, и работает нормально, но в использовании она какая-то неудалая.
Данные в тарантуле лежат в space-ах - аналоге sql таблиц в виде кортежей: как строка в таблице. Но, в отличие от sql, жёстко фиксированы типы только столбцов, по которым строятся индексы. В остальных может быть суп из данных. Впрочем, если хочется, можно жёстко задать схему данных при создании space-а.
Индексы в тарантуле могут строиться как по одной "колонке", так и по многим. Составные индексы позволяют делать запросы как по части индекса, так и по значениям для всей строки целиком.
Предположим, хранятся у нас данные вида:
Id, Дата рождения, Фамилия, Имя, Отчество, Должность, Статус (работает/не работает), произвольная информация в следующих колонках. Индекс типа TREE (бинарное дерево под капотом) строится по всем полям, кроме Id. Он сможет отвечать на следующие запросы:
ФамилияВ вот
Фамилия + Имя
Фамилия + Имя + Отчество
Фамилия + Имя + Отчество + Должность
Фамилия + Имя + Отчество + Должность + Статус
Фамилия + Должность
- уже нет, для такого нужно создавать отдельный индекс или отправляться писать sql-запрос, который отрабатывает медленнее чем lua.Первое знакомство с тарантулом скорее положительное, работает шустро. Главная претензия к шарповой обертке, там при написании кода получается дикая лапша, а еще без плясок с бубнами мне не удалось отправить в тарантул Guid (uuid, уникальный 128 байтовый идентификатор): превратил в строку, отправил в таком виде на сервер, там распарсил Guid обратно, что конечно дикость, но пока сойдет.
#tarantool
#кодинг
Telegram
Эшу быдлокодит
Продолжу затронутую уважаемым @ssleg тему тестов. Я наконец повзрослел и осознал логику организации функциональных и интеграционных тестов.
Если коротко - используем CD/CI (в моем случае Github Actions) для прогона обычных unit-тестов, завязанных на внешние…
Если коротко - используем CD/CI (в моем случае Github Actions) для прогона обычных unit-тестов, завязанных на внешние…
👍5
Не прошло и двух месяцев, как я начал работать с Тарантулом, и только сейчас я наткнулся на красивое: https://try.tarantool.io/
Песочница для экспериментов с тарантулом для всех желающих. При том - экспериментов в т.ч. взрослых - с настройкой имитации распределенной системы из нескольких тарантулов.
#tarantool
Песочница для экспериментов с тарантулом для всех желающих. При том - экспериментов в т.ч. взрослых - с настройкой имитации распределенной системы из нескольких тарантулов.
#tarantool
👍6
Прошли два месяца работы с тарантулом, и я наконец осознал (и отладил) адекватный способ хранить там слабо структурированную информацию: отправлять туда массив байтов byte[] из c#, а внутри тарантула соответствующее поле - string.
Принимать - тоже byte[]. string в тарантуле лежит просто как произвольная последовательность байт. Соответственно, никто не мешает хранить в этой куче байтов guid, который иначе без лишних преобразований из c# в тарантул не прокинуть.
Или - сериализовать в байты структуру (struct в c#, что-то типа класса, но хранится в стеке), или, вообще, использовать protobuf.
#tarantool
#кодинг
Принимать - тоже byte[]. string в тарантуле лежит просто как произвольная последовательность байт. Соответственно, никто не мешает хранить в этой куче байтов guid, который иначе без лишних преобразований из c# в тарантул не прокинуть.
Или - сериализовать в байты структуру (struct в c#, что-то типа класса, но хранится в стеке), или, вообще, использовать protobuf.
#tarantool
#кодинг
👍3
Выложил на гитхаб небольшой проектик - переделку бота-модератора телеграммных чатов. При написании его использовал несколько новых для себя подходов: TDD - test driven development, отказ от хранения состояния в приложении, использование тарантула в качестве персистентной очереди команд.
Бот не хранит никакой информации о собственном состоянии, зная лишь свой id, строку подключения к тарантулу и токен бота. Из телеграма прилетают оповещения об обновлениях, анализируются, после чего ставятся в очередь задач, хранящуюся в Тарантуле. За своим текущим состоянием, ответами на команды и т.д. бот тоже каждый раз ходит в тарантул. Отдельный поток слушает очередь задач в тарантуле, при появлении новых - исполняет.
Тарантул полностью живет в оперативной памяти, для связи по дефолту использует достаточно компактный и шустрый протокол - MessagePack. Это располагает к оптимизациям и работе с отдельными байтиками. Так, задача в очереди - это просто массив байт. Первый байт указывает на тип задачи, в соответствии с которым она и парсится и исполняется. Обычно задачи содержат, кроме первого байта, еще 2-3 int64 айдишника, то есть объем задачи получается во основном 17 или 25 байт. Такие объемы информации летают очень шустро.
К построению хранилища из нескольких инстансов на тарантуле есть два подхода: олдскульный, со сложными манипуляциями с конфигами и более современный, с использованием внешней утилиты - tarantool cartridge и модуля crud, предоставляющего синтаксический сахар над обычными операциями с данными и функционал для шардирования тарантула.
В репозитории по сути выложен шарповый стартер для экспериментов с конфигурацией кластера не выходя из Visual Studio: при запуске из докерфайла билдится контейнер, содержащих заданную конфигурацию кластера (по дефолту - мастер + реплика + балансировщик) и уже готовый к работе.
#tarantool
Бот не хранит никакой информации о собственном состоянии, зная лишь свой id, строку подключения к тарантулу и токен бота. Из телеграма прилетают оповещения об обновлениях, анализируются, после чего ставятся в очередь задач, хранящуюся в Тарантуле. За своим текущим состоянием, ответами на команды и т.д. бот тоже каждый раз ходит в тарантул. Отдельный поток слушает очередь задач в тарантуле, при появлении новых - исполняет.
Тарантул полностью живет в оперативной памяти, для связи по дефолту использует достаточно компактный и шустрый протокол - MessagePack. Это располагает к оптимизациям и работе с отдельными байтиками. Так, задача в очереди - это просто массив байт. Первый байт указывает на тип задачи, в соответствии с которым она и парсится и исполняется. Обычно задачи содержат, кроме первого байта, еще 2-3 int64 айдишника, то есть объем задачи получается во основном 17 или 25 байт. Такие объемы информации летают очень шустро.
К построению хранилища из нескольких инстансов на тарантуле есть два подхода: олдскульный, со сложными манипуляциями с конфигами и более современный, с использованием внешней утилиты - tarantool cartridge и модуля crud, предоставляющего синтаксический сахар над обычными операциями с данными и функционал для шардирования тарантула.
В репозитории по сути выложен шарповый стартер для экспериментов с конфигурацией кластера не выходя из Visual Studio: при запуске из докерфайла билдится контейнер, содержащих заданную конфигурацию кластера (по дефолту - мастер + реплика + балансировщик) и уже готовый к работе.
#tarantool
👍6🔥1
Получил лвлап и кучу экспириенса по работе с тарантулом, что характерно - на ровном месте.
Рассмотрим кейс: есть некая запись, относящаяся к человеку (user_id, unsigned(UInt64)). У нее есть время создания (creation_time, integer (Int64)) и время закрытия (cancelled_at, integer (Int64)).
Нужно дёрнуть все записи, относящиеся к человеку, актуальные на определенный момент времени. То есть запрос вида:
И все было прекрасно, пока я не столкнулся с реальностью: на "жирном" пользователе, с 20к+ записей, запрос выполняется неадекватные 20+ секунд.
В тарантуле есть составные индексы, туда можно передавать запросы из нескольких частей. Но вот беда: запрос, объединяющий сравнения == <= и >= он выполнить не может.
Решил зайти с необычной стороны: сделать условием >= и построить следующий индекс:
Сравнение происходит не по частям индекса. В сравнении участвует весь массив целиком как единая сущность. Говорят, что логика сравнения где-то была описана, но с ходу страница документации не ищется и где она лежит никто не помнит.
В тарантуле есть специальный инструментарий для работы с пространственными данными. Казалось бы, при чём тут они?
Поднимемся по лестнице абстракций на пару ступеней. Представим себе запись о пользователе прямоугольником в системе координат (id пользователя/время). Одна точка прямоугольника - создание записи, имеет координаты (user_id, creation_time). Вторая - (user_id, cancelled_at).
Соответственно, проверка "существовала ли запись о пользователе в определенный момент времени"? Сводится к задаче о принадлежности точки прямоугольнику. Готовое решение для запроса по индексу - в наличии. При желании, можно добавить ещё измерений (до 20), но что-то пока не хочется.
Проблема решена? Фииигушки. Индекс не ест мои значения в Int64 и UInt64, ему подавай Float64. При ковертации "в лоб" хвостики id теряются, из-за ограничений точности Float64. Добавляем очередной велосипед.
Барабанная дробь... Стандартный инструмент для запросов к кластеру не поддерживает (и скорее всего не будет) запросы по этому типу индексов. Опускаемся на пару уровней абстракций ниже, берем апи маршрутизации и делаем небольшую велосипедную хранимку, позволяющую вызвать хранимку на инстансах с данными через инстанс-маршрутизатор.
А вот теперь - всё. Ну или мне так кажется:)
P.S. В монге решил эту же задачу за 25 (!) минут, запрос + индексы, всё работает с первого раза.
#tarantool
Рассмотрим кейс: есть некая запись, относящаяся к человеку (user_id, unsigned(UInt64)). У нее есть время создания (creation_time, integer (Int64)) и время закрытия (cancelled_at, integer (Int64)).
Нужно дёрнуть все записи, относящиеся к человеку, актуальные на определенный момент времени. То есть запрос вида:
Входящие параметры: id, time.
user_id == id && creation_time <= time && (cancelled_at == nil || cancelled_at >= time)
Во всех мануалах предлагается простое решение, сделать select по самому лучшему условию, а дальше с помощью специального синтаксиса перебрать результат и отфильтровать нужное. Использовал этот подход, решил задачу и пошел дальше.И все было прекрасно, пока я не столкнулся с реальностью: на "жирном" пользователе, с 20к+ записей, запрос выполняется неадекватные 20+ секунд.
В тарантуле есть составные индексы, туда можно передавать запросы из нескольких частей. Но вот беда: запрос, объединяющий сравнения == <= и >= он выполнить не может.
Решил зайти с необычной стороны: сделать условием >= и построить следующий индекс:
creation_time, user_id, - user_id, - cancellation_time
То есть добавить в индекс инвертированный id пользователя и инвертировать время закрытия. Тогда в теории все должно выцепляться одним условием ">=". Что могло пойти не так? Всё. Как оказалось, для составных условий используется логика обработки частей запроса, отличающаяся от той, что заложена в схожей ситуации в MongoDB или PostgreSQL.Сравнение происходит не по частям индекса. В сравнении участвует весь массив целиком как единая сущность. Говорят, что логика сравнения где-то была описана, но с ходу страница документации не ищется и где она лежит никто не помнит.
В тарантуле есть специальный инструментарий для работы с пространственными данными. Казалось бы, при чём тут они?
Поднимемся по лестнице абстракций на пару ступеней. Представим себе запись о пользователе прямоугольником в системе координат (id пользователя/время). Одна точка прямоугольника - создание записи, имеет координаты (user_id, creation_time). Вторая - (user_id, cancelled_at).
Соответственно, проверка "существовала ли запись о пользователе в определенный момент времени"? Сводится к задаче о принадлежности точки прямоугольнику. Готовое решение для запроса по индексу - в наличии. При желании, можно добавить ещё измерений (до 20), но что-то пока не хочется.
Барабанная дробь... Стандартный инструмент для запросов к кластеру не поддерживает (и скорее всего не будет) запросы по этому типу индексов. Опускаемся на пару уровней абстракций ниже, берем апи маршрутизации и делаем небольшую велосипедную хранимку, позволяющую вызвать хранимку на инстансах с данными через инстанс-маршрутизатор.
А вот теперь - всё. Ну или мне так кажется:)
#tarantool
🔥4🤡2
Sphagnum. Часть 6. Техобзор. Репликация и отказоустойчивость в Tarantool
#sphagnum@eshu_coding
Тарантул изначально проектировался как решение, которое можно без боли (ха-ха) раскатать в бесконечное по размеру облако. Вообще, про взаимодействие между инстансами можно почитать вполне себе неплохую статью на Хабре. Если кратко, инстансы обмениваются друг с другом "слухами" о происходящих событиях по UDP (с помощью механизма SWIM) и формируюткартину мира текущее состояние кластера. В случае падения мастера, выборами занимаются специальные инстансы тарантула, имеющие роль failover coordinator. Текущее состояние кластера сохраняется или в etcd (распределенное хранилище ключ-значенин) или в специфическом инстансе тарантула.
И также неплохая статья про механизм репликации. Если коротко - между мастером и репликами распространяется журнал WAL мастера. При том, распространяется отдельными процессами, живущими рядом с основным тарантулом, по процессу на реплику. Репликация может осуществляться как асинхронно (транзакция считается выполненной до того, как все реплики подтвердят получение данных), так и синхронно. Для синхронной репликации используется алгоритм Raft.
Что мне очень понравилось в тарантуле - удобный ui для создания и управления кластером (входит в Tarantool Cartridge). В нем можно проставить репликам как дефолтные роли (failover coordinator, master, replica, router), так и пользовательские, включающие определенный набор "таблиц" и хранимок. При желании, этот же ui можно использовать для написания или правки хранимых процедур и распространения обновлений по кластеру. Все команды ui также могут быть продублированы в виде скриптов в командной строке (что я и делал).
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. UI + дублирующие консольные команды, позволяющие создать кластер без боли. И выбор ролей инстансов через UI - тоже огонь.
2. Идея обмена слухами о происходящем в кластере хороша.
#sphagnum_theory@eshu_coding
#tarantool
#sphagnum@eshu_coding
Тарантул изначально проектировался как решение, которое можно без боли (ха-ха) раскатать в бесконечное по размеру облако. Вообще, про взаимодействие между инстансами можно почитать вполне себе неплохую статью на Хабре. Если кратко, инстансы обмениваются друг с другом "слухами" о происходящих событиях по UDP (с помощью механизма SWIM) и формируют
И также неплохая статья про механизм репликации. Если коротко - между мастером и репликами распространяется журнал WAL мастера. При том, распространяется отдельными процессами, живущими рядом с основным тарантулом, по процессу на реплику. Репликация может осуществляться как асинхронно (транзакция считается выполненной до того, как все реплики подтвердят получение данных), так и синхронно. Для синхронной репликации используется алгоритм Raft.
Что мне очень понравилось в тарантуле - удобный ui для создания и управления кластером (входит в Tarantool Cartridge). В нем можно проставить репликам как дефолтные роли (failover coordinator, master, replica, router), так и пользовательские, включающие определенный набор "таблиц" и хранимок. При желании, этот же ui можно использовать для написания или правки хранимых процедур и распространения обновлений по кластеру. Все команды ui также могут быть продублированы в виде скриптов в командной строке (что я и делал).
Итого, из того, что мне пока хотелось бы взять для своего проекта:
1. UI + дублирующие консольные команды, позволяющие создать кластер без боли. И выбор ролей инстансов через UI - тоже огонь.
2. Идея обмена слухами о происходящем в кластере хороша.
#sphagnum_theory@eshu_coding
#tarantool
Хабр
Отказоустойчивая архитектура: почему Tarantool не падает?
Основная проблема в высоконагруженных приложениях — отказоустойчивость. Нагрузка с упавших узлов в кластере должна переключаться на живые. Это кажется несложной задачей, но на практике появляется...
👍1
Пожалуй пришло время обновить закреплённый пост. Каналу уже 5 лет, с прошлого закрепа изменилось многое.
Датасаенс, питон и наука были заброшены. В настоящий момент я работаю сеньор C# разработчиком в одном из российских банков.
За прошедшие 5 лет я сменил 4 места работы:
1. Фирма, занимающая АСУ ТП в области учёта ресурсов.
2. Медтех стартап в Сколково, делали системы поддержки принятия врачебных решений.
3. Сеть общепита, делал бэкенд службы доставки.
4. Банк, текущее место работы. Работаю в домене клиентских карточек.
Мой технологический стек:
C#, PostgreSQL. Плотно работал с MongoDB, RabbitMQ, Tarantool, умею строить базовую инфраструктуру: логи (Loki), метрики (Prometheus), девопсятина (gitlab, gitea, github actions, docker).
Поверхностно знаком с Apache Kafka, MS SQL и фронтовыми фреймворками - React.js и AvaloniaUI.
По образованию я инженер-оптик, потому часть базы приходится добирать на ходу. В планах закрыть гештальт по алгоритмам и двигаться в сторону архитектуры.
Далее будет навигация по каналу.
Общие теги:
#csharp@eshu_coding - общий тег для постов про разные аспекты разработки на языке программирования c#
#postgresql@eshu_coding - разные интересные моменты про PostgreSQL.
#devops@eshu_coding - мои эксперименты в девопсятине и инфраструктуре.
#mongodb@eshu_coding - записки про MongoDB.
#tarantool@eshu_coding - заметки про Tarantool.
Pet - проекты:
#палантир@eshu_coding - завершенный проект, которым я занимался весь 2021 год - поисковик по телеграму.
#sphagnum@eshu_coding - попытка написать свой брокер сообщений, пока застопорилась на стадии изучения теории и прототипирования по причине нехватки времени.
Книги:
#рихтер@eshu_coding - заметки и конспекты по основополагающей книге про C# - CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#, Джеффри Рихтер. Хоть .NET 4.5 вышел до моего появления в IT, внутренности платформы во основном остались прежними.
Конспекты прослушанных выступлений на конференциях:
#dotnext@eshu_coding - Dotnext 2023
#highload@eshu_coding - Highload++ 2024
Шпаргалки и мои заметки для подготовки к собеседованиям #собес@eshu_coding
Природа и путешествия #природа@eshu_coding #путешествие@eshu_coding
Датасаенс, питон и наука были заброшены. В настоящий момент я работаю сеньор C# разработчиком в одном из российских банков.
За прошедшие 5 лет я сменил 4 места работы:
1. Фирма, занимающая АСУ ТП в области учёта ресурсов.
2. Медтех стартап в Сколково, делали системы поддержки принятия врачебных решений.
3. Сеть общепита, делал бэкенд службы доставки.
4. Банк, текущее место работы. Работаю в домене клиентских карточек.
Мой технологический стек:
C#, PostgreSQL. Плотно работал с MongoDB, RabbitMQ, Tarantool, умею строить базовую инфраструктуру: логи (Loki), метрики (Prometheus), девопсятина (gitlab, gitea, github actions, docker).
Поверхностно знаком с Apache Kafka, MS SQL и фронтовыми фреймворками - React.js и AvaloniaUI.
По образованию я инженер-оптик, потому часть базы приходится добирать на ходу. В планах закрыть гештальт по алгоритмам и двигаться в сторону архитектуры.
Далее будет навигация по каналу.
Общие теги:
#csharp@eshu_coding - общий тег для постов про разные аспекты разработки на языке программирования c#
#postgresql@eshu_coding - разные интересные моменты про PostgreSQL.
#devops@eshu_coding - мои эксперименты в девопсятине и инфраструктуре.
#mongodb@eshu_coding - записки про MongoDB.
#tarantool@eshu_coding - заметки про Tarantool.
Pet - проекты:
#палантир@eshu_coding - завершенный проект, которым я занимался весь 2021 год - поисковик по телеграму.
#sphagnum@eshu_coding - попытка написать свой брокер сообщений, пока застопорилась на стадии изучения теории и прототипирования по причине нехватки времени.
Книги:
#рихтер@eshu_coding - заметки и конспекты по основополагающей книге про C# - CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#, Джеффри Рихтер. Хоть .NET 4.5 вышел до моего появления в IT, внутренности платформы во основном остались прежними.
Конспекты прослушанных выступлений на конференциях:
#dotnext@eshu_coding - Dotnext 2023
#highload@eshu_coding - Highload++ 2024
Шпаргалки и мои заметки для подготовки к собеседованиям #собес@eshu_coding
Природа и путешествия #природа@eshu_coding #путешествие@eshu_coding
❤7👍6🔥2👎1