«Традиционно, самым узким местом в архитектуре любой информационной системы является система управления базами данных (СУБД). Можно сколько угодно оптимизировать прикладное программное обеспечение (ПО), но все равно упремся в ограничения в части производительности запросов». В своем материале я рассказываю о том, как построить архитектуру системы без слабых мест, и кого для этого стоит принести в жертву.




Крепкая архитектура начинается с… теории


Если верить исследованиям международной исследовательской и консалтинговой компании IDC, то к 2025 году общий объем цифровых данных, генерируемых во всем мире, вырастет более чем вчетверо — до 175 Зеттабайт. Напомню, что в конце 2020-го года мир перешагнул отметку в 40 Зеттабайт. Естественно, достичь новых рекордов можно только при условии, что все поголовно будут правильно строить свою архитектуру системы. Но как это лучше делать, и какие есть подводные камни — разбираемся вместе в этой статье.


Вообще, чтобы разобрать вопрос в комплексе, следует начать с теории, ведь это основа основ. И в первую очередь, надо понять, что такое архитектура системы.  


Архитектура системы — это принципиальная организация системы, воплощенная в её элементах, их взаимоотношениях друг с другом и со средой, а также принципы, направляющие её проектирование и эволюцию.


Архитектура включает в себя:


  1. выбор элементов, с помощью которых составлена система, а также интерфейсов их взаимодействия;
  2. объединение элементов во всё более крупные блоки (подсистемы);
  3. единый подход и стиль (унификация подходов проектирования).

Если с первыми двумя пунктами все более-менее понятно, то третий, однозначно, требует пояснений. В ходе проектирования, разработки, развития и модернизации информационной системы (ИС), ее архитектура требует постоянного обсуждения со всеми участниками проекта, включая бизнес.


Перейдем к следующему этапу — классификация:


  1. Информационная архитектура — набор методик и инструментов, описывающий информационную модель конкретной предметной области (домена).
    Включает в себя:


    • базы и хранилища данных;
    • информационные потоки.

  2. Архитектура прикладных решений – совокупность прикладных программных продуктов и интерфейсов между ними.


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


    • инфраструктура;
    • базовое ПО (ОС и прочее)
    • системное программное обеспечение (СУБД, системы интеграции);
    • стандарты на программно-аппаратные средства;
    • средства обеспечения безопасности;
    • системы управления инфраструктурой (включая мониторинг).

  4. Бизнес-архитектура — модель бизнес-процессов и сквозных информационных потоков.

    Очевидно, что для эффективного представления архитектурных решений, нужно найти способ, с помощью которого можно доступно, но в тоже время достаточно развернуто донести их суть (концепцию) до максимально широкого круга лиц. Чтобы мне не пришлось долго объяснять, вспомним Джона Захмана, он составил матричную модель, которая позволяет легко презентовать набор архитектурных артефактов путем ответа на простые вопросы:


    • Что?
    • Как?
    • Где?
    • Кто?
    • Когда?
    • Почему?


Сложив этот пазл Захмана, мы однозначно получим два итога: во-первых, откроем глаза всем заинтересованным, во-вторых, сохраним им структуру мозга — вероятно, она могла бы измениться, если бы весь процесс пришлось изучать самостоятельно.


Big Data похожа на «пирог»


Основа архитектуры систем — big data. Традиционно, принято считать, что большие данные имеют три признака – vvv:


  • Volume — объем
  • Velocity — скорость
  • Variety – разнообразие

Ну а дальше появились 4 и 5 признаки (и до бесконечности) – veracity, visualization, value, viability… Видимо, это соревнование ученых мужей в том, сколько умных слов они знают на букву v.  


В отличие от традиционной архитектуры информационных систем (ИС), архитектура современных распределенных систем класса Big Data больше похожа на «пирог» и имеет сложную многоуровневую архитектуру, которая называется LSA — Layered Scalable Architecture. И если, вы думаете, что про «пирог» я шутил, то, ошибаетесь — вот вам все его (LSA) слои:


  • операционный слой первичных данных (Primary Data Layer) (1) — на нем выполняется загрузка исходной информации непосредственно из источника данных;
  • ядро (Core Data Layer) (2) — центральный элемент архитектуры, который осуществляет сбор (консолидацию) данных из разных источников, приводя их (по возможности) к унифицированной структуре. Именно здесь происходит основная работа с данными и общие трансформации (в рамках модели данных и бизнес-процессов). Этот элемент обеспечивает целостность и качество данных;
  • аналитические витрины (Data Mart Layer) (4) — где данные преобразуются к структурам (агрегатам, срезам), удобным для анализа и использования в аналитических системах (BI и прочее). Чаще всего, витрины являются потребителями данных из ядра, но могут быть и вторичные витрины и много всяких других — все зависит от бизнес-требований и постановки;
  • сервисный слой (Service Layer) (5) — обеспечивает управление всеми вышеописанными уровнями. Он не содержит бизнес-данных. Используется для аудита работы ИС, контроля сквозных бизнес-процессов. Помимо этого, тут живут средства мониторинга и диагностики ошибок.

Чтобы было понятнее, объясню, как на практике выглядит архитектура LSA:


  • исходные данные — сырые данные различных форматов (xml, json и т.д.);
  • на операционном уровне сырые данные валидируются, преобразуются (трансформируются) в унифицированный формат с привязкой к сущности в доменной области. Тут обычно реализованы специфичные ETL (аббревиатура от Extract, Transform, Load) и пакетная обработка документов (batch/bulk processing);
  • на уровне ядра проводится валидация данных с точки зрения правил бизнес-процесса, собирается конечная модель сущности, выполняются бизнес-процессы, которые меняют (или не меняют) состояние сущности, и проводится сериализация данных (измененное состояние сущности) в оперативное хранилище;
  • уровень MART — витрины данных различного назначения (произвольный поиск, BI, dashboards).

Если что-то из вышенаписанного осталось неясным, есть два решения: первое — перечитать еще раз, второе – написать мне в сообщения, и мы разберем с вами «на пальцах». 


«Крем» от LinkedIn


Итак, мы и добрались до главного — исходные данные. Тут все достаточно прямолинейно: мы работаем с файлами на входе, соответственно нам нужна файловая система, но так как архитектура у нас распределенная, то и файловая система у нас должна быть распределенной. И вариантов тут не очень много: NFS, HDFS, CephFS, GlusterFS.


NFS – старый, добрый, проверенный и вполне годный. Но если вам нужна более «гибкая» система и возможность масштабирования, то для хранения сырых данных лучше подойдет HDFS.


HDFS (Hadoop Distributed File System) — файловая система, предназначенная для хранения файлов, поблочно-распределённых между узлами вычислительного кластера. Благодаря репликации (механизм синхронизации содержимого нескольких копий объекта) обеспечивается устойчивость распределённой системы к отказам отдельных узлов. Файлы в HDFS могут быть записаны лишь однажды (модификация не поддерживается), а запись в файл в одно время может вести только один процесс. Организация файлов в пространстве имён — традиционная иерархическая: есть корневой каталог, поддерживается вложение каталогов, в одном каталоге могут располагаться и файлы, и другие каталоги.


Но как же склеить коржи в нашем «слоеном пироге», и каков рецепт заварного крема? И хорошие новости – крем будет импортный (Apache Kafka), от известной фабрики LinkedIn, где этот брокер сообщений был создан еще в 2012 году.  


Apache Kafka (3) — распределённый программный брокер сообщений. Спроектирован, как распределённая, горизонтально масштабируемая система, обеспечивающая наращивание пропускной способности как при росте числа и нагрузки со стороны источников, так и количества систем-подписчиков. Подписчики могут быть объединены в группы. Поддерживается возможность временного хранения данных для последующей пакетной обработки. Про Kafka можно рассказывать так много и интересно, что получится отдельная статья, которую я напишу ;)


Вернемся к архитектуре. Традиционно, самым узким местом в архитектуре любой информационной системы является система управления базами данных (СУБД). Можно сколько угодно оптимизировать прикладное программное обеспечение (ПО), но все равно упремся в ограничения в части производительности запросов к СУБД. Что делать? — Использовать NoSQL вместо реляционных СУБД, но придется чем-то жертвовать (об этом позже).


На уровне ядра широко применяются NoSql СУБД:


  • MongoDB
  • Cassandra
  • HBase
  • ScyllaDB

Изначально термин NoSQL буквально читался как: No («Не») и SQL (сокращение от англ. Structured Query Language — «структурированный язык запросов»). Хотя, вероятно, задумка была иной – «не реляционный», но NoSQL звучало лучше и в итоге прижилось. Позднее, NoSQL стали расшифровывать как «Not Only SQL» («не только SQL»).


NoSQL стал общим термином для различных баз данных и хранилищ, но он не обозначает какую-либо одну конкретную технологию или продукт. Традиционные (SQL) СУБД ориентируются на требования ACID к транзакционной системе: атомарность (atomicity), согласованность (consistency), изолированность (isolation), долговечность(durability), тогда как в NoSQL вместо ACID используется усеченный набор признаков BASE:


  1. basic availability — каждый запрос гарантированно завершается (успешно или безуспешно);
  2. soft state — состояние системы может изменяться со временем, даже без ввода новых данных, для достижения согласования данных;
  3. eventual consistency — данные могут быть некоторое время рассогласованы, но приходят к согласованию через некоторое время.

Помните, чуть выше я говорил о «жертвах». Так вот, если вам требуется максимальная производительность, то следует отправить в мир иной консистентность! Как показывает практика,  без этого вполне можно жить, лишь бы система масштабировалась в горизонт линейно с ростом объемов данных.


А как нам быть, если производительности СУБД все равно не хватает, а заказчик требует стремительного отклика на запросы в режиме реального времени?
Тут все просто: часто используемые запросы не надо приземлять сразу на СУБД, иначе она в эту землю и приляжет.
Выход — поднимаем эти данные в оперативную память. Тут проверенным решением является Redis (от англ. remote dictionary server) — резидентная in memory система управления базами данных класса NoSQL с открытым исходным кодом, работающая со структурами данных типа «ключ — значение». Ориентирована она на достижение максимальной производительности на атомарных операциях (приблизительно 100 тыс. SET- и GET-запросов в секунду на сервере начального уровня). Плюс, она хранит базу данных в оперативной памяти.


И пару слов про витрины.
Витрины данных обычно содержат тематические подмножества заранее агрегированных данных, их проще проектировать и настраивать. По сути, витрина — это просто слепок данных для аналитических целей. При этом, данные в витрине уже обогащены всем необходимым. То есть, нет необходимости джойнить данные из НСИ и терять на это уйму времени. Для современных витрин очень часто применяют такие решения как Elasticsearch и, относительно новую, колоночную СУБД Clickhouse от Yandex. Переливать данные можно опять же с помощью нашей любимой Kafka.


Каждая мелочь имеет значение


В завершение статьи я бы хотел остановиться на очень важном аспекте — инфраструктуре в ЦОД (центре обработки данных), где развернута наша прекрасная информационная система.


В погоне за функциональными возможностями и в потоке бесконечно меняющихся бизнес-требований, забывают о самом главном: надежной отказоустойчивой инфраструктуре в ЦОД, с запасом на 3-5 лет, с учетом кратного роста объема данных, количества пользователей и т.д…


Тут огромное количество аспектов, и все они одинаково важны для штатного режима эксплуатации ИС:


  • Сеть с высокой пропускной способностью для снижения latency, а значит времени отклика при протокольном (сетевом) обмене между элементами архитектуры;
  • Высокая доступность базовых сетевых сервисов, таких как DNS. Ведь на них построен весь каркас информационной системы;
  • Производительные серверы. Современные БД и процессинговое прикладное ПО требуют не менее 16 ядер CPU для организации параллельных операций и вычислений;
  • Большой объем оперативной памяти: чаще всего 64Гб + на сервер на загрузку индексов и тяжелые запросы к СУБД и прочее;
  • Высокопроизводительная дисковая подсистема на базе SSD;
  • Правильное размещение серверов кластера. Не надо все серверы ставить в одну стойку. Народная мудрость — «НЕ складывай все яйца в одну корзину!» тут как нельзя кстати;
  • Связность всех компонентов инфраструктуры и ее (связности) мониторинг;
  • Тонкий тюнинг параметров ОС и базового ПО — количество файловых дескрипторов, параметры сетевого стека, transparent huge pages, настройка режима overcommit, swap и многое другое для оптимального режима работы ПО, особенно в разрезе производительности;
  • NTP везде. Время должно быть везде синхронизировано;
  • Использование оптимальной файловой системы для СУБД — чаще всего XFS;
  • Сквозной мониторинг, начиная от аппаратного обеспечения, базового ПО и заканчивая бизнес метриками. Тут не обойтись без dashboards. Часто применяют такие системы как Graphana и Prometheus;
  • Не стоит пренебрегать бэкапами, хотя на таких объемах (речь о терабайтах) — это весьма непросто;
  • Централизованный сбор логов. Не слышали? А зря… Без graylog и подобных ему решений тут никак не обойтись. Пожалуй, анализировать логи на 200+ серверах системы по отдельности — удовольствие ниже среднего и только для особых ценителей;
  • Кубернизация (Kubernetes) сервисов и подсистем. Управлять такой махиной в атомарном режиме — это утопия;
  • Алертинг;
  • Организация служб эксплуатации и мониторинга;
  • Регламенты, инструкции, цепочки эскалации;
  • Широкое применение автоматизированных системы для регистрации и работы с инцидентами. Тут кому как удобно: Jira, Service Desk, Kaiten и др.

Говоря о масштабировании базового и прикладного ПО, стоит отметить, что абсолютно все элементы должны быть развернуты в кластерной конфигурации. Никаких решений — «этот компонент можно развернуть как standalone» тут быть не должно!
Очереди в Kafka должны быть партиционированы, базы данных шардированы.


Резюмируя: при эксплуатации таких огромных информационных систем нет неважных деталей — каждая мелочь имеет вес и может «выстрелить в ногу» в самый неподходящий момент.


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

Комментарии (1)


  1. Phoen
    19.01.2022 14:36
    +4

     инструкция о том, как правильно строить архитектуру системы

    Жаль из статьи мы этого так и не узнали.