Сижу я вчера спокойно, как водится никого особо не трогаю. Тут с двух разных контактов, почти одновременно присылают ссылку на небезызвестный твит про JSON из SQL. Одно из сообщений выглядело так:  Это был уже прямой вызов. Игнорировать его я не мог. Поэтому решил рассказать историю, которая до сих пор вызывает во мне двойственные чувства. Спустя три года. В то благословенное время все грезили криптой, занимались ICO и ваяли криптобиржи. Это было действительно что-то новое. У меня был опыт создания систем для классического управления активами (акции, облигации и т.п.). Проблема была в том, что он сформировался вокруг учетных систем. Мне хотелось реализоваться в создании биржи. Не удивительно, что я с удовольствием нырнул в этот кипящий котел. Это предыстория. Было много чего интересного, но сегодня я хочу рассказать о конкретном случае — как мы создавали свой матчер.  Матчер, это ядро биржи. Именно в нем происходят сделки. В классическом стереотипе это высокопроизводительная подсистема. Но это справедливо для крупных бирж. Там открытые заявки на куплю и продажу исчисляются сотнями тысяч. Создаваемая “на коленке” биржа не может нагнать себе такой трафик. Она вынуждена искать нишу. Один из методов — создание специфичных инструментов, которые оттягивают на себя часть пользователей крупных бирж. Самый тупой метод — демпинг комиссии на ввод и вывод крипты. В нашем случае разговор шел о сотнях сделок в сутки.  Матчер у нас был на Java от стороннего вендора. Эта штука регулярно валилась, требовала ресурсов, и стоила денег по подписке. Плюс имела свою экосистему, которую без разрешения вендора развивать было нельзя. Отсюда мы попросту не могли предоставить те самые “уникальные” инструменты трейдеру. Именно это стало причиной писать свой матчер. В своей практике я всегда стараюсь придерживаться пути селекции решений. Под селекцией я понимаю выбор перспективных решений, затем их сравнение, прототипирование и возможное “скрещивание” для получения лучших результатов. В этот раз все пошло по той же схеме. В результате появился прототип матчера на С, который был способен выдавать около 270К сделок в секунду на моем компе. Принимал заявки и отдавал сделки он в RabbitMQ. Но…. Но матчер требовал доработок. Пока это был прототип. Оценка была около 2х месяцев. И, к сожалению, допилить мог его только я. Конечно, если бы он взлетел, то речь бы шла о включении С в стек и наем персонала. Состоялся разговор с фаундером. Он скептически отнесся к идее. Т.е. да, это здорово… но требует времени, людей и т.п. И это не весело. Честно сказать я расстроился и брякнул что-то типа:  Кто бы мог подумать, но фаундер зацепился за эту идею. И предложил ее прототипировать. Ну как предложил… сказал сделать. Нет слов описать мои чувства на тот момент. Одно дело брякнуть, другое сделать. Суть задачи в том, что есть входящие заявки на покупку и продажу. Одни хотят продать подороже, другие купить подешевле. Эти заявки нужно сопоставлять и выполнять — генерировать сделку.  Фишка в том, что заявка может матчиться с несколькими заявками. Например, есть несколько заявок на продажу по 100р, каждая с объемом 5. В этом случае заявка на покупку по 100р с объемом 7 должна полностью погасить первую по хронологии заявку и частично погасить вторую по хронологии заявку. Если же заявка на покупку превосходит цену продажи, то сматчиться она должна по цене продажи. Из этого рисуется не сильно простой и быстрый SQL код. Я искренне надеялся, что результат окажется плачевным. Но дело было с MySQL и обнаружилась интересная фича. Дело в том, что внутри запросов MySQL можно менять значение переменной. Т.е. есть возможность считать накопительный итог построчно выполняя запрос. Выглядит это примерно так: и отдельно В голове быстро родился план как филить (исполнять) заявку по стакану.  Второй прекрасной фичей оказались IN MEMORY таблицы. Т.е. данные этих таблиц хранятся в ОЗУ сервера. Что делает операции с ними ощутимо быстрыми. Все внезапно срослось и родился прототип. Имя мы ему дали — Скулятчер. Во многом это название отражало мое отношение к нему. В гит я класть его не стал, спрятал тут, в подкате.  Дам буквально несколько пояснений к коду, т.к. в целом он лаконичен. Имеются три таблицы: Вызывая процедуру make_order_v2 ей передаются параметры заявки: При вызове процедуры, она проверяет тип заявки и матчит ее с противоположными по типу. Ищет в стакане подходящие заявки и филит их — указывает исполненный объем по каждой заявке. Затем, пробегает по полученной таблице и выбирает исполненные заявки генерируя сделки. Последним шагом удаляет исполненные заявки из стакана. Если заявка не была выполнена или оказалась выполнена частично, она помещается в соответствующий стакан и ждет встречной заявки. Производительность, зависит от глубины стаканов. В подкате можно найти процедуру нагрузки. Она генерирует 100К заявок. В результате получается около 95К сделок. На моей машине процедура выполняется за 1.46 минуты. Это около 570 сделок в секунду. Более чем достаточно для задач биржи на тот момент. Еще раз обращу внимание, что это прототип. Ему требуется обвязка. Например, по контролю баланса. И много что еще. Т.ч. свою биржу за вечер наваять не удасться. Почему до сих пор во мне бушуют чувства, когда я вспоминаю этот опыт? С одной стороны: С другой стороны: Конечно, я не разделяю оптимизма автора оригинального поста о том, что можно все сделать через СУБД, но опыт показывает, что через СУБД можно сделать все. Если захотеть. Поэтому, нужно аккуратно относиться к своим желаниям. В противном случае придется испытывать душевную боль годами. Всем добра! Оригинальный твит Archi Product Owner