Low Latency в High-Load: шлях від Redis Pub/Sub до In-Memory Runtime | Dmytro Hnatiuk

Low Latency в High-Load: шлях від Redis Pub/Sub до In-Memory Runtime | Dmytro Hnatiuk

Everlabs· · 3 хв читання · Дивитися на YouTube →

Практичні поради з розробки високонавантаженої системи реального часу для арбітражу на криптобіржах

Тема: Досвід розробки та оптимізації системи моніторингу та виконання арбітражних операцій на криптобіржах.

Суть: Доповідь описує еволюцію архітектури системи — від простих скриптів до високопродуктивної distributed системи, що обробляє сотні тисяч оновлень за секунду з цільовою затримкою ~200 мс. Ключові аспекти: обробка великих обсягів даних у реальному часі, низьколатентна комунікація, стабільність 24/7 та точність фінансових розрахунків.


Ключові виклики та рішення

1. Обробка великих обсягів даних у реальному часі

  • Виклик: До 500 000 оновлень ордербуків (стаканів) на секунду з 12-16 бірж. Кожен стакан — це 2-5 Кб даних.
  • Порада:
    • Мінімізуйте серіалізацію/десеріалізацію. Кожна така операція — це мережевий стрибок (network jump) і витрати часу.
    • Використовуйте біндарні (binary) протоколи та форматами даних (наприклад, raw bytes) замість JSON для внутрішньої комунікації між компонентами.
    • Застосовуйте batch processing (пакетну обробку): Накопичуйте повідомлення протягом короткого тайм-ауту (наприклад, 0.5-0.7 с) або до досягнення певного розміру, і відправляйте їх пачками, щоб знизити навантаження на мережу та систему.

2. Низьколатентна комунікація

  • Виклик: Цільова затримка від отримання даних до виконання всіх ордерів — ~200 мс.
  • Порада:
    • Уникайте зайвих мережевих стрибків. Кожен проміжний компонент (наприклад, окремий message broker) додає затримку.
    • Використовуйте direct connection (пряме підключення) між компонентами, де це можливо. У третьому підході використання gRPC замість черги (RabbitMQ) значно прискорило систему.
    • Застосовуйте error-driven flow control: використовуйте статус-коди помилок gRPC для швидкого контролю потоку даних без десеріалізації повноцінних повідомлень.
    • Розміщуйте вузли (ноди) ближче до бірж з урахуванням географії для мінімізації мережевої затримки (network latency), особливо при міжбіржовому арбітражі.

3. Стабільність та управління пам'яттю

  • Виклик: Система має працювати 24/7 без втрат даних. Проблеми з витоком пам'яті (memory leak) призводять до падінь.
  • Порада:
    • Регулюйте логування (logging). Необмежене консольне логування, особливо в Docker, може швидко заповнити оперативну пам'ять. Обов'язково налаштовуйте ротацію та обмеження для лог-файлів (наприклад, через logrotate або налаштування journald в Docker).
    • Ведіть активне профілювання (profiling) пам'яті. Не покладайтеся на здогадки. Інструменти профілювання допоможуть точно визначити джерело витоку.
    • Ізолюйте проблемні компоненти. Якщо певний модуль (наприклад, конектор до біржі) нестабільний, запускайте його в окремих процесах, щоб його падіння не впливало на всю систему.

4. Точність фінансових розрахунків

  • Виклик: Неправильний розрахунок комісій, обсягів або проскальзування (slippage) призводить до прямих фінансових втрат.
  • Порада:
    • Враховуйте всі обмеження бірж: точність чисел (кількість знаків після коми), мінімальні суми ордерів, правила округлення.
    • Розраховуйте комісії на кожному етапі: торгівля, виведення коштів (withdrawal) між біржами.
    • Імітуйте (paper trade) та ретельно тестуйте алгоритми на історичних даних перед реальним запуском.

5. Вибір технологій та архітектури

  • Виклик: Багатомовна система (Node.js, .NET) зі складною взаємодією.
  • Порада:
    • Мікросервіси — не срібна куля. Для систем, де критична низька затримка і швидкий доступ до пам'яті, монолітна архітектура або дуже тісно пов'язані модулі можуть бути ефективнішими.
    • Концентрація на одній технології (наприклад, повний перехід на .NET) може спростити розробку, покращити продуктивність за рахунок усунення вартості "міжмовної" конвертації даних.
    • Використовуйте перевірені технології під конкретне навантаження. Для чистих обчислень .NET показує добру продуктивність. Node.js може не впоратися з дуже високою інтенсивністю сокет-з'єднань через event loop.
    • Пишіть власні низькорівневі конектори до API бірж. Готові бібліотеки часто не оптимізовані під high-load, можуть містити баги або не мати механізмів стабілізації з'єднань (наприклад, ping-pong для веб-сокетів).

Висновки

  1. Профілювання важливіше за здогадки (Profiling > Guesswork). Завжди вимірюйте, де витрачається час і пам'ять, перед оптимізацією.
  2. Мережеві стрибки — ваш головний ворог. Мінімізуйте кількість компонентів у пайплайні обробки даних.
  3. Стабільність досягається через ізоляцію та контроль ресурсів. Уважно стежте за логами, пам'яттю та станом мережевих з'єднань.
  4. Архітектура повинна відповідати домену. Для high-frequency trading-like систем пріоритет — швидкість і детермінованість, а не гнучкість мікросервісів.
  5. Тестуйте на реальних навантаженнях. Проблеми з масштабуванням (наприклад, накопичення подій в чергах) часто виявляються лише під час тривалої роботи.

Цей досвід демонструє, що успішне створення фінансової системи реального часу — це поєднання глибокого розуміння предметної області, ретельної інженерії та постійної ітерації на основі вимірів.

Сподобався цей підсумок? Кинь будь-яке YouTube-відео нашому боту — отримай свій підсумок за 30 секунд.
Спробувати YTSummarAI

Не маєш 2 години на подкаст?

Кинь YouTube-лінк боту в Telegram — отримай ключові ідеї за 30 секунд. 9 зірок безкоштовно при старті.

Спробувати YTSummarAI