2023-07-12: Saint Highload - взгляд на технологии и архитектуру

Материал из MaksWiki
Перейти к: навигация, поиск
О других конференциях

В конце июня прошла конференция Saint Highload-2023 в Питере. Как обычно, на конференции было много интересных докладов про современные технологии. Вообще я пользуюсь конференциями Highload чтобы держать руку на пульсе технологического развития. Правда, на мой взгляд, никаких вау-изменений не происходит, идет поступательное развитие технологий. Но навести фокус всегда полезно.

А еще в этот раз было много докладов про архитектуру приложений и ее реинжиниринг для решения различных задач. Правда, часть из них была в режиме story telling, хотя и со схемами: у нас была задача, мы ее решили. Это несколько огорчает. Потому что такие доклады любопытны, но всегда есть прагматичный вопрос: какой из этой истории можно извлечь позитивный опыт для собственного применения? Высший пилотаж, когда был анализ этого опыта, выделены какие-то классы задач и полезные шаблоны для них. Менее интересно, но тоже содержательно, когда просто выделен некоторый полезный шаблон. Но во многих докладах этого нет. Там идет рассказ о решении распространенных задач, и используются понятные и известные шаблоны. Это не значит, что задача была тривиальной, были исследования и эксперименты, пробовали разное. Но при этом ничего принципиально нового - нет.

Я попробую пояснить аналогией из 10-15 летней давности: клиент-серверная архитектура, приложение медленно работает, потому что база плохо отвечает - задача распространенная, и не тривиальная, если разработчики не сделали очевидных ляпов - нужны поиски и частные решения. Но если задача не первая, то берешь и делаешь. А вот ценный опыт из такого рассказа - не извлечешь, потому как каждый случай - уникален, а приемы - известные. Так вот, доклады на Highload - аналогичны, просто на другом уровне технологий. Теперь в приложении микросервисы, а не база данных, но по-прежнему надо обеспечить производительность или масштабируемость. И тоже берешь - и делаешь, грабли более-менее известны, шаблоны - тоже, и надо подбирать подходящие через эксперименты. Но, может, это я с колокольни своего опыта смотрю, что грабли и шаблоны известны. Может, они не тривиальны, а я их знаю потому, что когда-то очень давно решал аналогичные задачи про консистентность, транзакционность и производиоьтельность - до того, как их взяли на себя реляционные базы данных. Но тогда их надо бы явно выделить в рассказе и подсвечивать на схемах, чтобы люди запомнили, а не просто рассказывать историю.

По-любому, в целом конференция - крутая, доклады - интересные. И участников - много, почти 2000 человек, если я правильно запомнил. И много общения в кулуарах на разные темы. Так что я очень рад, что съездил.

А теперь - заметки с докладов. Я их публиковал в ходе конференции, а теперь собрал вместе. Для себя я отметил доклад Андрея Парамонова из Додо про акторную модель - помимо архитектурных решений там был интересный исторический обзор развития модели.

Андрей Тимофеев Групповые чаты в Одноклассниках

Доклад про архитектуру: в одноклассниках были диалоги между участников, задача была сделать групповые чаты, по-возможности, использовав уже разработанное. Реализация - кассандра для хранения и собственная очередь, когда начинали разработку, Кафка была не очень хорошей. Казалось бы, нет проблем - вместо композитного ключа чата из ключей двух участников делаешь отдельную базу участников чатов, и все начинает работать. Однако, это не так. Дело в том, что есть задача показа главной страницы чатов, где отображаются последние изменения. Ее невозможно посчитать на лету, поэтому для каждого пользователя хранится история его чатов. В случае диалогов посылка одного сообщения меняет историю только для двух участников, а в случае групповых чатов сообщение меняет столько историй, сколько участников у чата. А их можно быть много, десятки тысяч. При этом история у пользователя - длинная. И поэтому было ряд архитектурных решений:

  • Деление истории у пользователя на активные - первые 50 и архивные, которых может быть много, до 10к - мы проигрываем когда чат поднимается из архива или выталкивается, но в 10 раз выигрываем при обновлении среди активных чатов.
  • Двухфазная обработка сообщений: одна очередь пишет сообщения в чат, и обработчик ставит отдельные очереди по обновлению истории для каждого получателя. Если обновлять истории вместе с записью сообщения, то возникают коллизии, так как одна история может обновляться из многих активных групповых чатов, а такая архитектура позволяет обновлять очереди индивидуально в пакетном режиме без коллизий.
  • Отмена readmarks для чатов, где больше 100 участников, так как они распространяются квадратично. Узнать кто прочитал по-прежнему можно, но это - специальный механизм.
  • Утолщение клиента - раньше он каждый раз запрашивал историю с сервера по push-уведомлению об изменении, теперь он сам хранит сообщения и получает все обновления через push без запроса.

В результате они успешно держат нагрузку с групповыми чатами, в презентации были характеристики откликов и железа, и нагрузка на БД даже снизилась.

Максим Павлов. Совмещаем потоковые и пакетные процессы в Camunda BPM

Доклад был про архитектурные шаблоны использования Комунды для оркестрации работы сервисов. Embeded версия, хранение в PostgreSQL, интеграция с внешними системами через Kafka. Две задачи вокруг кредитов: обработка потока заявок на кредиты, которая идет в автоматическом режиме с точечным включением импортных операций; подготовка предодобренных заявок на кредиты по большому количеству данных ежемесячно в пакетном режиме. Задачи разные, но в обоих - сложная схема обработки из полутора десятков шагов, которые выполняются параллельно, но есть зависимости. В докладе были базовые шаблоны: вычислительный элемент, сообщения, конструкции управления процессами, тайминг и ожидание событий и более сложные элементы из них: запуск параллельных процессов, синхронизация потоков для обработки зависимостей, шаблоны для обработки ошибок - экземпляр не прерывается. а приостанавливается и может быть продолжен после решения проблемы, например, если интеграция почему-то приостановилась и ее запустили, шаблоны для включения ручных шагов, исполняемых пользователями. Примеры - со схемками, скриптами.

Ценный опыт использования: уменьшайте контекст процесса, пакуйте его в меньшее число переменных, не забывайте про локальную или глобальную видимость переменных, важно для многопоточного исполнения. Простую логику можно писать в скриптах, сложную - отдельными скриптовыми задачами. А еще Camunda пишет много логов, они это отключили - им хватает логов Kafka.

Анастасия Тушканова из Ozon. Feature store: как мы совместили высокую производительность и безграничные потребности data scientist’ов

Рассказ про доработку архитектуры для обеспечения производительности и обеспечения A/B-тестирования. Feature store - хранилище характеристик, которые используются поиском для сортировки товаров после того, как нижний поиск выдал 2000 товаров, релевантных текстовому запросу. Сортировка учитывает характеристики товаров, включая популярность в заказах и предпочтения конкретного пользователя. Эти характеристики считают аналитики в Hadoop, а дальше их надо переложить в redis для эффективной сортировки.

Проблемы были с производительностью, увеличением числа нод и реплик они не решались. Поэтому пошли на доработку архитектуры, в докладе было несколько решений. Во-первых, сделать шардирование товарных характеристик по категориям товаров, потому что шардирование по товару приводило к тому, что 2000 товаров каждого запроса распределены по всем нодам, а если будет лежать по категориям, то нод будет мало. Но управление надо делать вручную, так как категории содержат разное число товаров, надо разложить равномерно. При этом потребовалось отдельный механизм обновления категорий на Kafka - категории у товара меняются. Во-вторых, сделали отдельное холодное хранилище на реляционке, в которое перенаправили запросы сервисов, которым время ответа не критично, и на котором работают аналитические запросы. Оптимизация запросов позволило уменьшить число реплик с 18 до 3, необходимых для устойчивости работы. И это позволило сделать несколько экземпляров для A/B тестов. И не только для аналитиков, но и для самих моделей приоритизации.

Андрей Парамонов из Додо. Use actors, Luke

На мой взгляд, очень хороший доклад. В нем - интересный обзора концепции и истории Акторной модели. Потому что модель появилась давно, в 1970-х. Андрей говорит про статью 1973 года Carl Hewitt, Peter Bishop и Richard Steiger "A Universal Modular Actor Formalism for AI", и там - теоретическое обоснование, которое дальше было развито в нескольких научных работах.

Замечу, что если смотреть от практики, то может быть другой взгляд - что акторная модель была реализована в Smalltalk, который вышел на год раньше и среди авторов которого был Ален Кей. Его высказывание, что основой замысла ООП были именно акторы как изолированные объtкты, а пошла развивать наследование и полиморфизм, тоже было в докладе. Так или иначе, модель опередила время, акторы стали востребованными в современной архитектуре мультиядерных процессоров, исполняющих множество потоков. А история развития ООП пошла от C к С++ и далее к Java и C#, где многопоточность не была реализована на уровне языка совсем. Хотя в 1986 появился Erlang с легковесными потоками, которые очень удачно реализуют акторную модель. Как сказал Андрей, интересно, авторы не были знакомы с научными работами по подходу, хотя фактически его реализовали. Но все равно, это было вне основного пути.

Актор - примитив параллельного, вернее, конкурентного, вычисления, который обрабатывает сообщения из своей входной очереди и посылает их другим акторам. При этом в статье были важные полагания: одно сообщение обрабатывается полностью, нет гарантий порядка отправки сообщений, сообщения могут теряться и нет никаких синхронных вызовов. У актора есть состояние, которое влияет на обработку сообщений, при обработке он может посылать сообщения другим, менять состояние, создавать других акторов. И, кроме обмена сообщениями, никакого взаимодействия между акторами нет, что как раз обеспечивает возможности масштабирования.

Модель отношений акторов: иерархическая и одноранговая. В иерархической - родитель создает, решает что делать при ошибке, можно восстановить, в том числе с сохранением очереди. В одноранговой акторами управляет run-time, создавая акторы по необходимости для обработки сообщений и удаляя при отсутствии активности.

Usecase: pipeline processing, transaction application, стриминг данных (реактивные системы, event-based, чаты), multi-user concurrency, приложения с распределенным состояниям, для которых не хватает одной машины, IoT - сообщения от датчиков и состояния, Timers - много таймеров по разным условиям.

И дальше был их пример. Dodo работает в 20 странах и в каждой надо интегрироваться с местным эквайрингом для приема платежей, никакого стандарта нет. Они использовали Microsoft Orleans, фреймворк появился в 2015, потом заснул и перспективы были неясны, но сейчас вроде проснулся и будет развиваться. Дальше было ряд рекомендаций: не забыть про observability (логи метрики трейсы); помнить что ресурсы не бесконечны, хотя актор и легковесен, и mailbox не бесконечный. Продумать восстановление состояния и балансировку нагрузки. А еще написание в синхронном стиле async/await приводит к тому, что между потоками могут возникать deadlock.

И выводы: акторы - простая абстракция, сильно упрощает код, хорошо масштабируется. Уместность - решаем конкретно, простые приложения с crud - не нужно. Что есть: Akka, Orleans, Proto.Actor, Darp (распределенные акторы). И был слайд со списком книг.

Из обсуждения в блоге. Phil Delgyado: С акторами две основные беды:

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

Но это, кажется, DoDo рассказывает про свой платежный шлюз, а там вообще все у них грустно, судя по их рассказам. Акторы для платежей были осмысленны лет 8 назад, сейчас есть более удобные инструменты.

mtsepkov: Фишка в том, что акторы - реально другая идеология. Которую надо освоить. То есть это не вопрос высокой квалификации вообще, а именно вопрос понимания этой идеологии. Я помню, как в свое время (середина 90-х) выворачивал мозги, чтобы после чистого C++, включавшего работу с данными через циклы и прочий низкоуровневый доступ освоить написание сложных запросов на SQL. Так и здесь. Нет гарантированной доставки и транзакций, жить надо иначе. А про более удобные инструменты - интересно послушать, безотносительно к акторам.
Phil Delgyado: Ну, про платежи на персистентных авторах я рассказывал лет шесть назад. Сейчас проще взять temporal.io и не переживать. Тем более что нагрузки в DoDo небольшие.


Станислав Богатырев из YADRO. Как мы переживаем сплит-брейн и продолжаем писать данные по S3-протоколу

Доклад был про архитектуру FrontFS. Это объектное хранилище, рассчитанное на установку по всему миру в интернете, вне защитных контуров. При такой установке нет гарантий связности между узлами сети. И им важно, чтобы узлы продолжали работать в этом случае на чтение и запись данных, а после восстановления связи решение конфликтов происходило без участия человека. Следствием этого требования является работа без какого-либо центрального узла хранения метаданных. В самом хранилище объекты являются неизменными и адресуются собственным хешем. И с этим нет особых проблем.

Но для удобной работы необходимо поддержать адресацию по протоколу S3, в котором объекты раскладываются в аналог файловой системы и при этом разрешена их модификация через порождение новых версий. И если при нарушении связности в разных частях системы были созданы новые версии объектов, то надо уметь определить последнюю версию. При этом модификация, в том числе, предполагает перемещение объекта по иерархии - как файлы перекладываются в другую папку. И о том, как обеспечить связь имен с объектами и был доклад. Для этого используют технологию блокчейн, которая заодно дает локальное время в системе, измеряемое номерами блоков. Он обеспечивает распределенное хранение без центрального узла и слияние с разрешением конфликтов с упорядочиванием по локальному времени, а при совпадении - по возрастанию хэша версии объекта. Основой послужила статья про CRDT-дерево Martin Kleppmann, который обосновывает, что дерево может быть описано как последовательность операций добавления и перемещения узлов, при чем они являются коммуникативными, что как раз дает возможность слияние. Реально задача нетривиальная, в докладе было несколько простых вариантов, которые не работают. И было на примерах показано, как работает их алгоритм в сложных случаях решения конфликтов. Тот же алгоритм можно было сделать на распределенной БД, но у нас открытый интернет, распределенная БД не дает защищенности.

FrontFS можно пользоваться, исходный код выложен в git, есть enterprise-версия Tatlin.Object в несколько меньшим масштабированием, но большей управляемостью, она платная.

Павел Велихов из TigerGraph. Распределенные графовые СУБД — будущее для аналитики на Больших Данных?

В докладе был верхнеуровневый обзор - что такое графовые базы данных, чем отличаются от реляционных, и для каких задач применяются. Лично мне в докладе не хватило глубины, получалось, то графовые базы данных - это тоже самое, что реляционные, только эффективно работает большое количество join, и это - чисто техническая разница, она под капотом и от пользователя скрыта. У меня есть подозрение, что это - не так, что есть какая-то более глубокая разница. Во всяком случае, был пример, что свертка аналитики по графамм устроена как-то иначе, чем агрегация с group by в sql, но на уровне принципов эта разница, к сожалению, развернута не было. А может быть, и нет особой разницы, о всяком случае, в моем представлении - потому что я всегда смотрел на написание join в SQL как на путешествие по графу ER-диаграммы. Но это - мое мышление, из общения с людьми я знаю, что так мыслят далеко не все, и в учебниках по SQL учат не так. И, вполне возможно, что такое поверхностное изложение было адекватно аудитории, во всяком случае, реакция была заинтересованная и позитивная.

Был интересный пример антифрода - прослеживание путей перевода денег по транзакциям для отмывания. На чистой реляционке это делается действительно сложно, если пути длинные. Впрочем, для графовой БД, запрос со всеми условиями нам не показали, отослали к книге. И это - один из примеров алгоритмов, которые на графовой базе решаются лучше, чем в реляционной. В TigerGraph, где работал Павел, есть открытая библиотека из 50 алгоритмов, которые можно использовать для прикладных своих задач: кратчайшие пути, community detection, кластеризация. Но на другие БД ее надо портировать, так как, к сожалению, единого стандарта на на язык запросов к графовым БД нет, стандарт ожидается в 23-24 годах, при этом уже понятно, что туда войдет небольшое ядро, а у каждой БД будут свои расширения. Помимо алгоритмов, способ применения - ML на графах, там это получается проще, чем на реляционке, как раз потому что можно легче вытаскивать объекты по связям. Области применения: finantial fraud, risk, monitoring, customer journey, рекомендации, supply chain analysis, energy management (трубопроводы и электросети), network resource optimization...

По имеющимся БД обзора не было, в основном рассказ был про TigerGraph, которая закрытая и работает в американских облаках, но с которой можно бесплатно поиграться. Neo4j - открытая, но есть ограничения по производительности. Впрочем, это - старое сравнение от Tiger, так что надо смотреть конкретные цифры, эти ограничения могут быть несущественны для вашей задачи. Еще есть NebulaDB - китайский open source, она послабее Tiger, но интенсивно развивается. Почему-то не упомянул ArangoDB.

И сейчас есть тренд на гибридные базы данных, встраивание графового движка в реляционки. Павел считает, что это - более перспективно, чем развитие чисто графовых до соразмерных с реляционками объемов и функций. Выходит расширение SQL/PGQ для работы с графами, драйвит это Oracle, у которого, кстати, уже очень давно есть конструкция start with - connect by, позволявшая ходить по деревьям в реляционке, в частности, задача нахождения цепочки транзакций для антифрода через нее решается. Так что. возможно, гибриды действительно будут эффективнее. Посмотрим.

Сергей Прийменко. Продуктовая платформа исполнителей в Яндекс Go

Рассказ был про приложение Яндекс Про, которое родилось из приложения для таксистов, в котором водитель принимал заказ. В ковид интенсивно пошла Яндекс-доставка и Яндекс Еда и было решено использовать для курьеров доработанное приложение. Все делали быстро, и в целом оно работало, но появился ряд проблем

  • Фейковые сущности. Например, ровер на велосипеде, фейковые машины и водительские удостоверения для пеших курьеров.
  • Не все сервисы из коробки понимали расширения: на заказ такси приезжает велокурьер, или в чеки заказа таксиста попадают чеки курьеров.
  • Сильная функциональная связность. Например, от профиля водителя-курьера все зависит. При этом профиль используется в критических точках.
  • Множество интерфейсов сервиса с нюансами. Например, смена водительского удостоверения для водителя такси и для курьера доставки.
  • При увеличении трафика от сторонних сервисов возникает вопрос - а кто платит за масштабирование.
  • Стабильность. Если проводим учения - ломаются все сервисы, и это усложнение процесса.
  • Любая ошибка, случайный скрипт может поломать соседний сервис, потому что не учитывает особенности.

Поэтому была идея сделать реинжиниринг. Они посмотрели на опыт Uber, который проходил аналогичные проблемы в 2018, и их решение - domain oriented microservice architecture: разложить сервисы по доменам, и дальше разлить домены по слоям. Слои Presentation - Product - Business platform - Microservice infrastructure - Low-level infrastructure. Если взглянуть через эту схему, то получается что они развивали слой Product, смешивая в одних сервисах много продуктов, вместо того, чтобы выделить общие части в слое Business platform и над ними - настройки с точками кастомизации. И они пошли этим путем, но постепенно, то что работает, пока оставлено. Первый шаг был с Яндекс-маркетом, были выделены сервисы профилей пользователей и авторизация, при этом профили имеют кастомизацию для разных продуктов. Workflow выполнения задачи пока обобщить не получается, там различается набор статусов и логика, при этом часть статусов может приходить от сервиса. Хотя лично я не очень понимаю, в чем проблема. Может, там бизнес-логика местами сильно повторяется, а местами - наоборот, различается, и хочется больше повторного использования, и требуется сильная реструктуризация кода (но это - чисто моя гипотеза).

Выделили на уровень платформы вознаграждение исполнителю, при этом принципиально поменяли архитектуру: раньше за вознаграждением шло обращение в бизнес-сервисы, а теперь бизнес-сервисы посылают события начисления вознаграждений, а сервис их хранит и показывает. При этом отражение детализации может различаться, это точка кастомизации и там не только текстовое представление, но и могут быть карты.

Андрей Комягин из STM Labs. Квест по синхронизации аналитического и оперативного хранилищ в реальном времени без потерь, когда у тебя сотни терабайт данных

Рассказ о том, как выносили отдельно аналитическое хранилище и налаживали перегрузку в него оперативных данных. Логистика, трекинг движения товаров. Оперативные системы - на MongoDB. И первоначально аналитические запросы и отчеты писали прямо на ней. Смесь OLAP и OLTP нагрузку держала плохо, с заказчиком договорились про отдельное аналитическое хранилище. А в него надо перегружать.

Начали с ETL, помучались с ними, потому что ориентировались на бизнес-дату операции, а не на реальную дату изменения, и не видели удаления, поэтому перегрузка была с ошибками, данные сверялись, расползались и перегружались вручную. Поэтому решили сделать на CDC, у Mongo это oplog, есть API MongoDB Change Stream и есть готовый Mongo Connector, который позволяет читать CDC и писать в Kafka. Они Mongo Connector, потому что он дает много функционала из коробки, в докладе было много подробностей настройки.За Kafka стоит CDC processing, который делает преобразования и пишет в Kafka потребителям, которые забирают online и пишет в аналитическую MongoDB. Сделана дополнительная штука для ручных перегрузок - необходимость не пропала, но их можно сделать технологично, перечитав СDС с заданного места.

[ Хронологический вид ]Комментарии

(нет элементов)

Войдите, чтобы комментировать.