Прямоугольники и стрелочки – Telegram
Прямоугольники и стрелочки
803 subscribers
37 photos
44 files
60 links
Заметки по Архитектуре программного обеспечения и около того.
Ведущий Максим Юнусов.
Download Telegram
Механизация архитектуры. Матрица противоречий

В тему предыдущего поста - несколько разъяснений.

- Матрица противоречий (ТРИЗ) используется при решении типовых задач, "механизируя" поиск решений.
- Если нам удалось свести задачу к простому противоречию, то в матрице мы найдём список приемов, решающих проблему.
- Строки матрицы представляют позитивные типовые параметры (что хотим улучшить)
- Столбцы матрицы представляют негативные типовые параметры (что при этом ухудшается)
- Номера приемов в ячейках на пересечениях противоречащих параметров.

Классическая матрица ТРИЗ была построена Альтшуллером для технических систем на основе анализа более 40000 идей и решений.

Существуют попытки построить подобную матрицу для решения архитектурных задач.
Здесь авторы в качестве типовых параметров выбирают качества проектируемой системы.

На прикреплённом рисунке фрагмент такой матрицы для основных качеств производительности.

Здесь каждое качество определено, количественно измеряемо и положительно, с т.з стейкхолдера.

Эффективность показывает насколько оптимально используется железо. Чем больше ресурсов при прочих равных метриках, тем ниже эффективность

Мощность - предельная пропускная способность.

Отзывчивость определяется временем отклика.

В теории, построив такую матрицу, мы механизируем активность архитектора по поиску решения процентов на 90.
Если, конечно, архитектор не использует принцип Technology First )

#ТРИЗ
👍3
The Essential Guide To Queueing Theory.pdf
1.5 MB
Книга по теории массового обслуживания

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

Когда-то распространялась бесплатно. Сейчас сайт перепрофилировался.

Выложу тут.



#Книга #Производительность
🔥8
Как правильно масштабировать микросервисы?

Существует два подхода:
1. Исключительно горизонтально. По одному потоку (ядру) на сервис. (Прям как в Redis)
2. По возможности вертикально. То есть добавлять побольше ядер и настраивать параллелизм в самом сервисе.
При этом потоки (threads) всё чаще уступают место сопрограммам (корутинам)

За первый подход
1. 8й фактор (из тех 12-ти): VIII. Параллелизм. Где сказано: "Масштабируйте приложение с помощью процессов".
2. Предсказуемость масштабирования. Контролируемая балансировка между ядрами на уровне сервисов.
3. Низкая когнитивная нагрузка. Разработчику сервиса не нужно заботиться о гонках и тупиках (deadlock).
4. Простая модель конкурентного доступа к ресурсам (чаще всего Actor Model).

За второй подход
1. Экономия памяти. (например, одна общая jdk)
2. Синергия, возможность переиспользования данных других потоков (например, общий кэш)
3. "Размазано" влияние служебных процессов. (GC - на одном потоке из одного или из 16-ти ?)

Каждому из этих аргументов легко можно противопоставить контраргумент и с удовольствием похоливарить.

Chat GPT ответит: "it depends" )

Я же зайду от производительности и закину свой кейс.

Предположим, вам нужна высокая пропускная способность при низкой задержке.
Существует точка Кляйнрока (Kleinrock), в которой пропускная способность максимальна, и время отклика минимально (см. рисунок)
- левее – зона недозагрузки
- правее - зона высокой латентности

Мы должны удерживать сервис в точке Кляйнрока, нагружая его M задачами.
Где М = Dmax/D. D - потребность в ресурсе (время).

Забавное следствие
Если сервис использует только один ресурс (например CPU), то Dmax=D, и самым эффективным будет однопоточный вариант.

#Производительность #Микросервисы #Масштабирование
👍4
Книга по "быстрым данным"

Fast Data Architectures for Streaming Applications (2nd Edition)
Dean Wampler, Ph.D., VP of Fast Data Engineering, Lightbend, Inc.

В свободном доступе тут
https://go.lightbend.com/fast-data-architectures-for-streaming-applications-oreilly-2nd-edition

Отдают после заполнения анкеты.

#Book #Книга
👍1
image_2023-04-29_22-42-48.png
210.9 KB
Как я теперь рассчитываю масштабируемость

Открыл для себя язык R и с успехом заменяю Excel в задачах по моделированию производительности.
(см. картинку)

По шагам:
1. Установил R
choco install r
2. Установил R-Studio
choco install r.studio
3. Взял данные с нагрузочного теста
( Вадим Ткаченко провел на сервере Cisco, описано в "Practical Scalability Analysis With The Universal Scalability Law", VividCortex) закинул в файл
4. Открыл R-Studio
5. Загрузил файл
benchmark <- read.csv("D:/benchmark.txt", sep=" ")
6. Использовал non-linear least squares над формулой USL (универсальный закон масштабирования)
usl <- nls(tput ~ lambda * size/(1 + sigma * (size - 1) + kappa * size * (size - 1)), benchmark, start = c(sigma=0.1, kappa=0.1, lambda=1000))
7. Нашёл коэффициенты
summary(usl)
8. Инициализировал переменные
sigma <- coef(usl)['sigma']
kappa <- coef(usl)['kappa']
lambda <- coef(usl)['lambda']
9. Вывел график
u=function(x){y=x*lambda/(1+sigma*(x-1)+kappa*x*(x-1))}
plot(u,0, max(benchmark$size)*2, xlab="Size", ylab="Thtoughput",lty="dashed")
points(benchmark$size, benchmark$tput)

Профит!

15 минут времени и я знаю, что сервер Cisco масштабирутся до 30 инстансов
🔥3
Измеряем мощность системы

В очередной раз встала задача померить мощность системы.
Напомню, что под мощностью (capacity) подразумевают максимальную пропускную способность (throughput).

Покажу варианты, с которыми сталкивался

1. Банальная ошибка. Запускаем JMeter. Даем нагрузку в один поток. Смотрим пропускную способность (X). Называем это мощностью.
Понятно, что, в этом случае, при наличии в системе более одного ресурса (например нескольких ядер CPU), мы явно недогрузили систему (левая часть графика). При задержке ответа Z=0, эта область аппроксимируется выражением X=M/D, где M - число клиентов (потоков jMeter), а D - общая потребность в ресурсах.

Кстати, этот замер полезен, так как позволяет определить D (D=1/X).

2. Кладем систему на полку. Начинаем накидывать потоки пока не выйдем на плато справа (аппроксимируется формулой X=1/Dmax, где Dmax - потребность в ресурсе, являющемся узким местом)
Фиксируем точку на плато называем её мощностью Xmax.

Однако это плато - плато только в теории , в жизни это скат. Цифры экспериментов пляшут. Точность так себе.

3. Добавим математики. Замерили несколько точек (минимум 6) с разным количеством потоков. Аппроксимировали через USL (см. предыдущий пост) получили красивую точку Xmax (в предыдущем посте 12 krps)

Всё вроде хорошо, но на практике вы не захотите работать в системе нагруженной на Xmax. Время отклика будет запредельным.

4. Практически полезное значение. Всё таки мощностью лучше называть приемлемую максимальную пропускную способность. То есть ту, что до колена на графике R от X.
Но как ее найти ?

Для системы на одном ресурсе всё просто X=0.5*Xmax.
Для сложных систем существует множество вариантов решения.

Математики всё еще спорят.
Практики давно решили этот вопрос:
Считаем мощностью 0.7 * Xmax (то есть 70 процентов от предельной)
Для примера из предыдущего поста получается 0.7*12000 ~ 8500 rps

Вот собственно и всё.

Можно показывать этот пост тестировщикам перед очередным замером )

#Производительность
🔥3👍2
Колено

Закрывая тему предыдущего поста 👆

1. Почему мощность это значение пропускной способности в точке Knee (колено) ?
Потому что за коленом "жизни нет" )
Незначительные изменения нагрузки на этом участке приводят к большим скачкам времени отклика.
Здесь огромный джиттер и полная непредсказуемость. Держать SLA на этом участке нереально.
2. Математически колено это утилизация, при которой время отклика деленное на утилизацию минимально т.е. d(R/U)/dU = 0
3. И покаюсь 😏.
Искать колено, умножая максимальную пропускную способность на 0.7 (см. предыдущий пост) - подход распространённый, но не верный.

При умножении лучше воспользоваться вот этой таблицей:

Число ресурсов Значение
1 0.5
2 0.57
4 0.66
8 0.74
16 0.81
32 0.86
64 0.89
128 0.92

Где число ресурсов это число ресурсов используемых параллельно, например, ядра CPU.

#Производительность
👍3🔥1
Оценка трудозатрат

Оценка трудозатрат - одна из сложнейших задач планирования.

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

Популярные формальные техники:
- PERT
E = (O+4M+P)/6 (O - Optimistic, P- Pessimistic, M - Most Likely)
- FP
Ключевыми компонентами, которые рассматриваются здесь, являются внешний ввод, внешний вывод, внешние запросы, внутренние логические файлы и файлы внешнего интерфейса/
- UCP
UCP = TCF * ECF * UUCP * PF (Коэффициент технической сложности (TCF), Коэффициент сложности среды (ECF), нескорректированные точки варианта использования (UUCP), коэффициент производительности (PF))

Эти техники хорошо проработаны и описаны. Если вы решили формализовать процесс, вряд ли стоит изобретать велосипед. Любые "кубики" будут хуже.

Другой вопрос: а стоит ли вообще формализовать процесс?

Зайдем с другой стороны.
От чего зависит время разработки?

1. Анализ, т.е. условно понимание куда воткнуть код (зависит от чистоты/ясности системы)
2. Неизбежный рефакторинг, подгонка системы под новый функционал (зависит от накопленного тех. долга)
3. Собственно кодирование функционала (зависит от технической сложности, может быть оценено формально)
4. Подстройка под существующие решения/библиотеки (зависит от вязкости)
5. Исправление зависимостей (зависит от связанности/коннасценции)
6. Опциональный рефакторинг (можем оставить как долг на следующую итерацию)
7. Тестирование (зависит от тестируемости)

Таким образом, методы оценки сложности дадут оценку трудозатрат только для чистого кодинга.
Большую часть времени занимают другие активности, никоем образом не связанные с требованиями и сложностью.

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

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

И как вывод - единственный надежный способ оценки выглядит так:
1. разбиваем задачу на части (WBS), до атомов, умещающихся в скоупе отдельного разработчика
2. получаем экспертную оценку (можно три точки)
3. умножаем на Pi ) (ну или PERT для солидности)

Всё остальное, увы, профанация

#оценка
👍4
Прямоугольники и стрелочки
The Essential Guide To Queueing Theory.pdf
scalability.pdf
2.3 MB
Еще одна книга от Baron Schwartz.

Practical Scalability Analysis With The
Universal Scalability Law (Масштабируемость)

Короткая и очень полезная)

#Книги #Производительность #Масштабируемость
🔥4
Архитектурный_стиль_Дерево_принятия_решения.png
840.8 KB
Выбор архитектурного стиля

В пятницу описывал коллегам метод выбора архитектурного стиля на основе атрибутов качества.

Этот подход проповедуют многие. В частности:
- SEI со своим ABAS (Attribute-Based Architectural Styles, https://resources.sei.cmu.edu/library/asset-view.cfm?assetid=13505)
- Нил Фор в новой модной книжке "Фундаментальный подход к программной архитектуре".

Поймал себя на мысли, что сам я этим методом не пользуюсь. Да и результат может получиться несколько странным.

Решил накидать "дерево принятия решений по стилю". Получился граф )

Очень драфтово, поэтому
буду рад любым комментариям.

#АрхитектурныйСтиль
👍4🔥4
Подходы к принятию архитектурного решения:
1. Technology first

Этот подход предполагает выбор технологического стека без определения основных архитектурных стилей и паттернов, а зачастую и без постановки задачи.
Стили и паттерны в этом случае диктуются выбранными технологиями (т. н. референсная архитектура)

Основные паттерны:
1. Выбираем технологию, так как она хорошо знакома и неплохо зарекомендовала себя на предыдущих проектах.
2. Подыскиваем альтернативную технологию в замен хорошо известной, не оправдавшей ожидания на предыдущих проектах.
3. Пробуем альтернативную технологию распиаренную вендором/комьюнити.

Преимущества:
1. Быстрое решение. Экономит время архитектора.
2. Используем известные нам/команде/службе эксплуатации технологии.

Применимость:
Задача хорошо известная архитектору.

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

Смягчать риски можно, применяя прототипирование.


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

#ПринятиеРешения
👍4
Подходы к принятию архитектурного решения:
2. Очевидное решение

Ставим архитектурную задачу и сразу же определяем очевидное, интуитивно понятное решение.
Зачастую и сама задача в этом случае выглядит как решение.
Например:
1. Кешируем операции чтения из БД.
2. Все микросервисы должны масштабироваться.

Паттерн:
Вопрос-решение

Преимущества:
1. Быстрое решение. Экономит время архитектора.
2. Интуитивно понятное решение не требует обоснования и объяснения.

Проблемы:
"Очевидно" не значит "верно".
Кластер PostgreSQL не всегда увеличивает доступность.
Кэш может увеличивать задержку.
Многопоточность может существенно снизить пропускную способность.
И. т. д.

Любая, даже самая сложная, проблема обязательно имеет простое, легкое для понимания, неправильное решение (Закон Мерфи)

Особенности:
Так как очевидное решение часто проходит как задача, в последствии это решение трудно переиграть.

#ПринятиеРешения
👍5
Подходы к принятию архитектурного решения:
3. Формальный подход

В этом случае фиксируем архитектурно значимые требования (драйвера) и используем определённый алгоритм для выбора решения.

Примеры:
1. ABAS (Attribute-Based Architectural Styles от SEI) - алгоритм выбора архитектурного стиля на базе атрибутов качества.
2. ADD (Attribute-Driven Design от SEI) - алгоритм выбора решения на базе атрибутов качества.
3. Деревья принятия решений различных авторов (Нил Форд, Мартин Фаулер и др.).
4. LAAM (Lean Architecture Analysis Method) и аналогичные - алгоритмы с применением матрицы принятия решений
5. Матрица противоречий ТРИЗ (переработанная под архитектуру).

Преимущества:
1. Быстрое решение.
2. Может быть применено архитектором не имеющим опыта по теме.

Применимость:
Хорошо работает при формировании короткого списка решений. Легко определить неподходящие варианты.

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

Особенности:
Результат применения формального подхода сильно зависит от применяющего подход архитектора. За архитектором выбор вводных и трактовка результата.

Работая над решением задачи, всегда полезно знать ответ заранее (Закон точности)

#ПринятиеРешения
Подходы к принятию архитектурного решения:
4. Метод
перебора

Этот подход известен также под именем морфологический метод.

Шаги:
1. Формируем список всех возможных/известных вариантов решения (фантограммы).
2. Определяем критерии пригодности (фитнес-функции).
3. Верифицируем варианты и отбрасываем нежизнеспособные.

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

Применимость:
Работает при возможности быстрой верификации. Например при верификации моделированием, без вывода решения в код.

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

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

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

#ПринятиеРешения
О терминологии в IT

Забавно вновь и вновь наблюдать споры вокруг слов. Что такое архитектор, что такое микросервисы, что такое ddd и так далее до бесконца.

Как будто много веков назад для разрешения подобных споров люди не придумали научную методологию и механизм определений.

Можно что угодно понимать под словом "архитектор" и отстаивать свое мнение с пеной у рта.

А можно прочитать, что в этот термин вкладывал автор концепции, и как эта концепция развивалась во времени.

Отсутствие явных и точных определений известных каждому серьезно сдерживает развитие сферы IT.
👍5
Потребность в архитекторе

Перефразируя Черчилля:

Необходимость в архитекторе обусловлена тем, что предпочитает менеджер: платить или расплачиваться.
👍6🔥3🤔2😁1
ADR и "перспективы"

ADR как способ фиксации архитектурных решений на пике популярности.

Однако, есть запросы не покрываемые данным подходом.
Например, требуется определить какие решения предприняты для обеспечения отказоустойчивости.

"Старые" методологии (например Розански и Вудс) предлагали "перспективы" (см. https://www.amazon.com/Software-Systems-Architecture-Stakeholders-Perspectives/dp/0321112296).
Перспектива это раздел описания посвященный одному качеству (например производительности).

Я хотел бы объединить эти два подхода.
Для этого нужно иметь возможность группировать архитектурные решения (ADR) по качествам (а возможно и по бизнес функциям).

Задача выглядит простой пока не попытаешься реализовать это практически:
1. Гит не дает тегать общим тегом несколько коммитов
2. Конфлюенс плохо демонстрирует динамику и плохо связан с этапами работы в гите.
3. Хочется использовать obsidian с тегами обратными ссылками и привязкой к git. Но тут проблема - инструмент новый и уговаривать на переезд придется долго )

Коллеги, а у вас есть опыт фасетной группировки арх. решений?

#Документация
Закономерности развития ИТ систем

В очередной раз убеждаюсь в правоте герметики - "То, что находится внизу, соответствует тому, что пребывает вверху; и то, что пребывает вверху, соответствует тому, что находится внизу".

Сервисные архитектуры почти идеально повторяют решения выработанные адептами ООП.

Единая цель "снижение когнитивной нагрузки на разработчика" приводит к одним и тем же структурам.

Приведу несколько примеров:

1. Независимая разработка потребовала введение объектов на уровне монолита и сервисов в распределенной системе.
2. Устраняя связанность по данным получили инкапсуляцию в ООП и автономность с собственными БД в сервисах.
3. Усиливая автономность ввели понятие строгих контрактов в ООП и аналогично на сервисах (API и т. п.)
4. Модули закрыли фасадами. Сервисы закрыли шлюзами.
5. Разделяя бизнес логику и сценарии использования в ООП ввели слой приложения и сервисы приложения. В сервисных архитектурах появились оркестраторы.
6. Минимизация связанностей привела к понятию "домен" в который объединяется множество объектов. Тот же самый механизм использован при объединении сервисов (см. например DOMA от Uber)

и так далее и тому подобное.

ИМХО, глядя на эти соответствия можно не только находить общие закономерности в развитии архитектурных стилей, но и предсказывать новые решения.
👍1
Структура архитектурной документации

В любом арх. процессе присутствуют следующие группы арх. артифактов:
1. Сырье - необработанное нечто на входе.
2. Требования, гипотезы или как назовете - нечто после анализа и структурирования.
3. Решения с обоснованиями
4. Модель (точнее их множество)
5. Представления, rfc, презентации - выжимки для коммуникаций.

- документирование всего этого хозяйства целиком/частями опция и выбор зависит от массы факторов

Сырье кидаю в обсидиан в папку raw и мечу тегами под поиск.

Требования беру у аналитиков и докидываю свои драйвера - текст с трассировкой на jira

Решения - madr

Модель веду в конфлюенсе (в текущем проекте), но предпочел бы archi

Представления размазаны по конфлюенсу (rfc) и разным документам (в основном powerpoint)

А хочется единого пространства и удобной трассировки (

#Документирование
👍5
http://microservices.io/i/SuccessTriangleWithBooks.png

Красивая картинка у К. Ричардсона.

"Ignoring those two elements is a common anti-pattern of microservice adoption."
👍3
Нефункциональные требования и ограничения (Constraints)

Для того чтобы принять оптимальное архитектурное решение необходимо обработать большой массив входящих данных (т.н. архитектурных драйверов или мотивов).

Часть этих данных структурирована, часть нет (т.н. контекст проектирования).

В одном из арх. каналов возник спор по поводу структурированных данных.
Было предложено всех их обобщить термином "требования".

В этом вопросе я придерживаюсь классического подхода - разделяю требования и ограничения.

Зачем? Казалось бы, и то и другое приходит от стейкхолдеров и формирует архитектуру. В чём разница?

Мои резоны:
1. Среди всех стейкхолдеров я выделяю потребителя. Того для кого готовится продукт.
Требования прочих заинтересованных лиц ограничивают развитие продукта, а зачастую и ухудшают его потребительские качества.

Пользователю нужна функциональность, производительность, надежность и безопасность . Это требования.

Служба эксплуатации ограничивает список технологий. Смежники диктуют интерфейсы и протоколы. Бизнес ограничивает время/деньги. Команда предоставляет ограниченный набор скиллов. Это ограничения.

2. Мне нравится подход, при котором я сперва проектирую идеальную архитектуру, которая бы на все сто удовлетворила пользователя, а потом начинаю "портить" ее имеющимися ограничениями.

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

#АрхитектурныеДрайвера
👍5🔥2