Кто-то сказал ужасное слово архитектуры, а вы не архитектор?

Боитесь, когда кто-то ставит под сомнение ваше понимание вычислительной сложности, когда все, что вы пытаетесь сделать, - это разместить виджет на веб-странице? Не бойтесь - это, вероятно, далеко не так сложно, как вы думаете.

Архитектура имеет репутацию недоступной, закрытой и «сложной информатики». Большая часть архитектуры программного обеспечения, с которой вы сталкиваетесь, для веб-приложений среднего размера и веб-масштаба удивительно похожа. Мы собираемся охватить основы, некоторый жаргон и некоторые архитектурные паттерны, которые вы, вероятно, встретите повсюду в этом кратком архитектурном учебнике для не архитекторов и веб-программистов.

Что вообще такое веб-сервер?

Хорошо, давайте начнем с основ. «Интернет» или «всемирная паутина» - если использовать его уморительно устаревшее полное почтение - это просто группа компьютеров, подключенных к Интернету. Интернет - это серия соглашений, описывающих, как «ресурсы» (читай: веб-страницы) могут быть получены с этих подключенных компьютеров.

Короче говоря, «веб-серверы» реализуют «протокол HTTP» - серию команд, которые вы можете отправлять на удаленные компьютеры, - которые позволяют вам сказать «эй, компьютер, отправь мне этот документ». Если это звучит знакомо, то потому, что так работают ваши веб-браузеры.

Когда вы вводите www.my-awesome-website.com в браузере, код, запущенный на вашем компьютере, создает «HTTP-запрос» и отправляет его на веб-сервер, связанный с URL-адресом (читай: адрес веб-сайта), который вы ввели в адресную строку.

Итак, веб-сервер - программа, работающая на удаленном компьютере, подключенная к Интернету, которая прослушивает запросы и возвращает данные при их получении. Тот факт, что это вообще работает, является маленьким чудом и построен на основе DNS (то, что превращает my-awesome-website.com в IP-адрес), а также множества сетевых функций, маршрутизации и коммутации. Вам, вероятно, не нужно слишком много знать об этом в реальном выражении, если вы не углубляетесь.

Существует тонна веб-серверов общего назначения, но на самом деле вы, вероятно, просто увидите смесь Apache, NGINX и Microsoft IIS, а также некоторые веб-серверы, специфичные для стека разработки (Node.js обслуживает сам себя, как и такие вещи, как ASP .NET CORE для C # и HTTP4K для Kotlin).

Как работает HTTP? И это архитектура?

Если вы когда-либо занимались веб-программированием, вы, вероятно, хотя бы немного знакомы с HTTP. Это расшифровывается как «Протокол передачи гипертекста», и это то, о чем ваш браузер говорит, когда обращается к веб-серверам. Давайте посмотрим на простое необработанное HTTP-сообщение с запросом:

GET http://www.davidwhitney.co.uk/ HTTP/1.1
Host: www.davidwhitney.co.uk
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64…
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

Основы HTTP легко понять - есть обязательная «строка запроса» - это первый бит с глаголом (чаще всего GET, POST, PUT и HEAD), URL-адрес (веб-адрес) и версия протокола ( HTTP / 1.1). Затем есть несколько необязательных полей заголовка запроса - и все остальное - подумайте об этом как о дополнительной информации, которую вы передаете веб-серверу о себе. После заголовков следует пустая строка и необязательный текст. Это HTTP / 1.1. Мы здесь закончили. Сервер ответит в аналогичной форме

HTTP/1.1 200 OK
Cache-Control: public,max-age=1
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Server: Kestrel
X-Powered-By: ASP.NET
Date: Wed, 11 Dec 2019 21:52:23 GMT
Content-Length: 8479

<!DOCTYPE html>
<html lang="en">...

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

Интернет - это реализация шаблона проектирования REST, что означает «передача репрезентативного состояния». Вы услышите, как люди много говорят о REST - он был первоначально определен Роем Филдингом в его докторской диссертации, но, что более важно, это было описание того, как HTTP / 1.0 работал в то время, и было задокументировано в то же время, когда Филдинг работал. по HTTP / 1.1.

Таким образом, Интернет по умолчанию является RESTful. REST описывает способ работы HTTP.

Краткая версия? Уникально адресуемые URI (веб-адреса), которые возвращают представление некоторого состояния, хранящегося где-то на машине (веб-страницы, документы, изображения и т. Д.). В зависимости от того, что просит клиент, представление этого состояния может варьироваться.

Это и HTTP, и REST, и архитектурный стиль в одном лице.

Как выглядит архитектура веб-приложения?

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

«Приложение MVC»

MVC - контроллер представления модели - это простой шаблон проектирования, который разделяет логику обработки приложения и его представление. MVC действительно оказался в центре внимания благодаря успеху Ruby on Rails (хотя шаблон был на пару десятилетий старше), и когда большинство людей говорят «MVC», они на самом деле описывают приложения MVC «в стиле Rails», в которых организован ваш код. в несколько разных каталогов

/controllers
/models
/views

Rails популяризировал использование «соглашения по конфигурации», чтобы связать все это вместе, наряду с идеей «маршрутизации» и разумных значений по умолчанию. Это было клонировано ASP.NET MVC почти оптом, а с тех пор и практически любой другой инфраструктурой MVC.

В целом, по умолчанию, если у вас есть URL-адрес, который выглядит примерно так

http://www.mycoolsite.com/Home/Index

Фреймворк MVC, используя свои «маршруты» - правила, определяющие, где что искать, - будет пытаться найти файл или модуль «HomeController» (в зависимости от вашего языка программирования) внутри каталога контроллеров. Вероятно, существует функция под названием «Индекс». Эта функция вернет модель - некоторые данные - которая визуализируется «представлением» - шаблоном HTML из папки представлений.

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

«Одностраничное приложение с API

SPA невероятно распространены, популяризируются клиентскими веб-фреймворками, такими как Angular, React и Vue.js. Единственная реальная разница в том, что мы берем наше приложение MVC и перекладываем большую часть работы на клиентскую сторону.

Здесь есть несколько разновидностей: есть MVC на стороне клиента, есть MVVM (модель-представление-представление-модель) и есть функциональное реактивное программирование (FRP). Поначалу различия могут показаться довольно незначительными.

Angular - это клиентская платформа MVC, работающая по шаблону «модели, представления и контроллеры», за исключением того, что теперь она работает внутри пользовательского веб-браузера.

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

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

Под всеми этими тяжелыми клиентскими платформами JavaScript обычно находится API, который выглядит почти неотличимым от «приложения MVC», но вместо того, чтобы возвращать предварительно обработанные страницы, возвращает данные, к которым клиент «привязывает» свой пользовательский интерфейс.

«Статические сайты, размещенные на CDN или другом« глупом »сервере»

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

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

В качестве реакции перевод рендеринга контента на «время разработки» имеет явные преимущества с точки зрения затрат и масштабируемости. Если код не запущен, сбой не произойдет!

Таким образом, генераторы статических сайтов становились все более популярными - обычно позволяя вам использовать обычный стек фронтенд веб-разработчиков, но затем генерируя все файлы с помощью инструмента сборки для объединения и распространения на немые веб-серверы или CDN. См. Такие инструменты, как - Gatsby, Hugo, Jekyll, Wyam.

"Что-то другое"

Существуют и другие архетипы, которым следуют веб-приложения - в транспилируемых фреймворках наблюдается медленно растущая тенденция (Blazor для C # в WebAssembly и цели компиляции javascript Kotlin), но с огромной популярностью доминирующих в то время фреймворков javascript все они пытаются играть хорошо.

Почему я должен предпочесть одно другому?

Вопрос на засыпку. Честно говоря, по большей части это дело вкуса, и все они идеально подходят для создания веб-приложений.

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

Все, что требует высокого качества UX, сейчас почти по умолчанию, вероятно, является приложением React, Angular или Vue. Модели программирования хорошо работают для создания отзывчивого пользовательского опыта, и если вы не будете их использовать, вам придется изобретать их заново.

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

HTTP API, Rest, GraphQL, Backend-for-Frontends

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

Вы будете отправлять такие же «HTTP-запросы», что и ваши браузеры, в основном возвращая ответы JSON (хотя иногда и XML). Можно безопасно описать большинство этих API как JSON-RPC или XML-RPC.

На рубеже тысячелетий был толчок к стандартизации API-интерфейсов «SOAP» (простой протокол доступа к объектам), и, хотя это сопровождалось множеством хороших вещей, люди сочли XML громоздким для чтения, и их популярность уменьшилась.

По иронии судьбы, многие вещи, которые были решены в SOAP (согласованные форматы конвертов сообщений, соображения безопасности, проверка схемы), впоследствии пришлось «заново решить» поверх JSON с использованием новых открытых стандартов, таких как Swagger (теперь OpenAPI) и JSON: API.

Мы умеем заново изобретать то, что уже было в сети.

Итак, что делает REST API REST API, а не JSON-RPC?

Я рада, что вы не спросили.

В основе REST лежит моделирование операций, которые могут происходить с ресурсами через HTTP. Есть отличная книга Джима Уэббера под названием Отдых на практике, если вы хотите глубоко погрузиться в то, почему REST является хорошим архитектурным стилем (и это так, многие современные отрицания REST относительно неинформированы и не слишком отличаются от обращения с SOAP. перед этим).

Людей действительно волнует, что такое REST, а что нет, и вы, возможно, расстроите людей, которые действительно заботятся о REST, описав JSON-RPC как REST. JSON-RPC - это «уровень 0» модели зрелости Ричардсона - модели, которая описывает качества дизайна REST. Не беспокойтесь об этом слишком сильно, потому что вы можете создать RESTish, нормальный, достойный JSON-RPC, выполнив несколько действий.

Во-первых, вам нужно правильно использовать HTTP-глаголы, GET для выборки (и никогда с побочными эффектами), POST для «выполнения операций», PUT для «создания материала, состояние которого контролируется клиентом». После этого убедитесь, что вы организовали свои API в логические «ресурсы» - концепции вашей основной предметной области «клиент», «продукт», «каталог» и т. Д.

Наконец, используйте правильные коды ответов HTTP для взаимодействия с вашим API.

Возможно, вы не используете «гипермедиа как двигатель состояния приложения», но, вероятно, у вас все получится, и никто не придет за вашей кровью.

Вы также получите множество преимуществ полностью RESTful API, если сделаете достаточно - ресурсы будут доступны через HTTP, ваши документы будут кэшируемыми, ваш API будет работать с большинством распространенных инструментов. Используйте swagger или библиотеку OpenAPI для создания схемы, и вы в значительной степени делаете то, что делают большинство людей.

Но я читал в хакерских новостях, что REST sux и GraphQL - это то, что нужно?

Да, мы все тоже читаем этот пост.

Как ни странно, GraphQL - это язык запросов, стандарт для HTTP API и инструмент схемы одновременно. С распространением тяжелых веб-приложений на стороне клиента GraphQL приобрел популярность благодаря эффективному внедрению определения того, какие данные должны быть возвращены клиенту, в сам клиентский код.

Подобные подходы в стиле «запрос из внешнего интерфейса» предлагаются не впервые и, вероятно, не будут последними. Что немного отличает GraphQL от предыдущих подходов (в частности, OData Microsoft), так это идея о том, что типы и запросы реализуются с кодом Resolver на стороне сервера, а не просто отображаются напрямую в какое-то хранилище SQL.

Это полезно по нескольким причинам - это означает, что GraphQL может быть единым API для множества разнородных API в вашем домене, он решает проблему «избыточной выборки», которая довольно часто встречается в API REST, позволяя клиенту указать подмножество. данных, которые они пытаются вернуть, а также действует как своего рода антикоррупционный слой, предотвращая неограниченный доступ к базовому хранилищу.

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

GraphQL на самом деле просто умный и эффективный способ схематизировать ваши API-интерфейсы и предоставить BFF - бэкэнд для внешнего интерфейса, а не лучший друг навсегда, - который быстро меняется.

BFF? Что такое лучшая подруга?

Представьте себе эту проблему - вы работаете в MEGACORP, где есть сотня команд или отрядов (вы не помните, они меняют номенклатуру каждые две недели), каждая из которых отвечает за набор микросервисов.

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

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

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

Извините, бэкэнд для интерфейса.

BFF - это API, который обслуживает одно, а точнее только одно приложение. Он переводит внутренний домен (MEGACORPS BUSINESS) на внутренний язык приложения, которое он обслуживает. Он заботится о таких вещах, как аутентификация, ограничение скорости, о том, что вы не хотите делать больше одного раза. Это сокращает количество ненужных обращений к серверу и преобразует данные, чтобы они больше подходили для целевого приложения.

Думайте об этом как об API, предназначенном только для вашего приложения, которое вы контролируете.

А такие инструменты, как GraphQL и OData, отлично подходят для BFF. GraphQL особенно хорошо сочетается с современными интерфейсами, управляемыми JavaScript, с превосходными инструментами, такими как Apollo и Apollo-Server, которые помогают оптимизировать эти вызовы путем пакетной обработки запросов.

Кроме того, он довольно удобен для интерфейсных разработчиков - запросы и схемы сильно напоминают json, и он сохраняет ваш стек «javascript до самого конца», не привязываясь к какой-то удаленной бэкэнд-команде.

Другие вещи, которые вы можете увидеть и почему

Итак, теперь мы понимаем наши веб-серверы, веб-приложения и наши API. Разве в современном веб-программировании есть нечто большее, чем это? Вот с чем вы, вероятно, будете сталкиваться чаще всего.

Балансировки нагрузки

Если вам посчастливилось иметь трафик на свой сайт, но достаточно не повезло, что вы не пользуетесь платформой как услуга (подробнее об этом позже), в какой-то момент вы столкнетесь с балансировщиком нагрузки. Без паники. Балансировщики нагрузки говорят на архаичном языке, часто управляются сварливыми сисопами или просто работают с копиями NGINX.

Все, что делает балансировщик нагрузки, это принимает HTTP-запросы для вашего приложения (или от него), выбирает сервер, который не очень занят, и пересылает запрос.

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

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

Распределенное кеширование

Если один компьютер может хранить некоторые данные в памяти, то многие компьютеры могут хранить… ну, намного больше данных!

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

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

Распределенное кэширование также действительно полезно для предотвращения «паники кеша» - когда нераспределенный кеш выходит из строя, и кэшированные данные будут пересчитываться всеми клиентами, но при совместном использовании их памяти вероятность полного отказа кеша значительно снижается, и даже когда это произойдет, только некоторые данные будут пересчитаны.

Распределенные кеши есть повсюду, и все основные хостинг-провайдеры, как правило, поддерживают memcached или redis-совместимые (читайте: для доступа к ним вы можете использовать клиентские библиотеки memcached) управляемые кеши.

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

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

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

Сети доставки контента (CDN)

CDN - это веб-серверы, которыми управляют другие люди по всему миру. Вы загружаете им свои данные, и они реплицируют ваши данные по всем своим «краям» (глупый термин, означающий просто «на все серверы по всему миру, которые они запускают»), так что, когда кто-то запрашивает ваш контент, Ответ DNS вернет сервер, который находится рядом с ними, и время, необходимое им для получения этого контента, будет намного быстрее.

Механика работы с CDN намного сложнее, чем ее использование, но это отличный выбор, если у вас много статических ресурсов (изображений!) Или особенно больших файлов (видео! Большие двоичные файлы!). Они также очень полезны для снижения общей нагрузки на ваши серверы.

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

Поговорим о шаблонах проектирования! Это настоящая архитектура

“Design patterns are just bug fixes for your programming languages”

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

Давайте быстро рассмотрим некоторые из наиболее распространенных:

  • MVC - «Разделите модель данных, код пользовательского интерфейса и бизнес-логику, чтобы их не перепутали»
  • ORM - «Объектно-реляционное сопоставление» - используйте библиотеку сопоставления и настроенные правила для управления хранением ваших объектов в памяти в реляционном хранилище. Не путайте предметы и куда вы их вместе сохраняете ».
  • Active Record - «Все ваши объекты должны иметь возможность сохранять себя, потому что это всего лишь веб-формы, кого волнует, привязаны ли они к базе данных!»
  • Репозиторий - «Весь ваш доступ к данным находится в этом классе - взаимодействуйте с ним, чтобы загружать вещи».
  • Декоратор - «Добавьте или оберните« декораторы »вокруг объекта, класса или функции, чтобы добавить общее поведение, такое как кеширование или ведение журнала, без изменения исходной реализации».
  • Внедрение зависимостей - "Если ваш класс или функция от чего-то зависит, ответственность за обеспечение этой зависимости лежит на вызывающем (часто используемом вами фреймворке)"
  • Завод - «Поместите весь код, необходимый для создания одного из них, в одном месте и только в одном месте»
  • Адаптер - «Используйте адаптер, чтобы преодолеть разрыв между вещами, которые иначе не работали бы вместе, - переводя внутренние представления данных во внешние. Как преобразование ответа Twitter в YourSocialMediaDataStructure »
  • Команда - «Каждое отдельное действие или запрос выполняется в одном месте»
  • Стратегия - «Определите несколько способов сделать что-то, что можно менять местами»
  • Синглтон - «Во всем моем приложении есть только один из них».

Это неполный список некоторых шаблонных жаргонов, которые вы услышите. В шаблонах проектирования нет ничего особенного, это всего лишь версия общепринятого и популярного решения stackoverflow 1990-х годов.

Микросервисные архитектуры

Микросервисные архитектуры - это всего лишь «третья волна» сервис-ориентированного проектирования.

Откуда они пришли?

В середине 90-х «COM +» (службы компонентов) и SOAP были популярны, потому что они снижали риск развертывания вещей, разделяя их на небольшие компоненты - и предоставляя стандартный и относительно простой способ общения через границы процессов. Это привело к популяризации «трехуровневой», а затем и «многоуровневой» архитектуры для распределенных систем.

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

Затем вмешались поставщики продуктов, и SOAP стал сложным и немодным, что подтолкнуло людей ко «второй волне» - партизанской SOA. Подобный дизайн, только без высоких церемоний, более вертикальные срезы и меньшее количество промежуточного программного обеспечения от поставщиков.

Это привело к распространению более мелких и более гибких сервисов примерно в то же время, когда Netflix продвигал hystrix - свою платформу для систем с задержкой и отказоустойчивостью.

Третья волна SOA, именуемая микросервисными архитектурами (Джеймсом Льюисом и Мартином Фаулером), очень популярна, но, возможно, не очень хорошо изучена.

Какими должны быть микросервисы: небольшие, независимо полезные, независимо поддерживаемые версии, независимо доставляемые сервисы, которые выполняют определенную функцию или операцию домена.

Микросервисы часто бывают: хрупкими, взаимозависимыми, близорукими сервисами, которые действуют как объекты доступа к данным через HTTP, которые часто терпят неудачу, как домино.

Хороший дизайн микросервисов следует нескольким простым правилам

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

Микросервисы, не обладающие этими качествами, скорее всего, представляют собой секретные распределенные монолиты. Это нормально, множество людей управляют распределенными монолитами в большом масштабе, но в какой-то момент вы почувствуете боль.

Шестиугольные архитектуры

Теперь это звучит как какая-то «Настоящая архитектура TM»!

Гексагональные архитектуры, также известные как шаблон «порты и адаптеры», по определению Алистера Кокберна, являются одним из лучших советов по «реальной архитектуре приложения».

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

Все эти «внешние вещи» «адаптируются» к вашей внутренней модели и вводятся при необходимости.

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

Почему? Что ж, это означает, что вы можете тестировать все изолированно, без вмешательства вашего веб-фреймворка или какого-либо сломанного API. Избегать всех этих внешних проблем в своей логике - безопасный способ разработки приложений.

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

Масштабирование

Масштабирование сложно, если вы попытаетесь сделать это самостоятельно, поэтому ни в коем случае не пытайтесь сделать это самостоятельно.

Используйте предоставленные поставщиком облачные абстракции, такие как Google App Engine, Azure Web Apps или AWS Lambda с включенной поддержкой автомасштабирования, если вы можете этого избежать.

Рассмотрите возможность размещения ваших API в бессерверном стеке. Чем дальше вы продвигаетесь к абстракции, тем проще будет масштабирование.

Принято считать, что «горизонтальное масштабирование - единственная рентабельная вещь», но многим успешным компаниям удалось масштабироваться с помощью нескольких больших машин или виртуальных машин. Горизонтальное масштабирование дает вам другие преимущества (часто связанные с географическим распределением или отказоустойчивостью между зонами доступности), но не расстраивайтесь, если у вас есть единственный выход, помеченный как «больше возможностей».

Архитектурные шаблоны для распределенных систем

Построение распределенных систем сложнее, чем создание всего одного приложения. Никто на самом деле не говорит об этом много, но это так. Гораздо легче что-то потерпеть неудачу, если разбить все на мелкие части, но у вас меньше шансов полностью развалиться, если вы все сделаете правильно.

Есть пара вещей, которые всегда могут пригодиться.

Автоматические выключатели повсюду

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

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

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

Вы будете еще более благодарны своим автоматическим выключателям, когда поймете, что API, который вызываете, принадлежат вам.

Идемпотентность и повторные попытки

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

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

Переборки

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

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

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

Управляемые событиями архитектуры с журналами воспроизведения / сообщений

Архитектуры, основанные на событиях / сообщениях, часто бывают устойчивыми, потому что по замыслу входящие вызовы, поступающие к ним, не являются синхронными. Используя события, которые помещаются в буфер в очередях, ваша система может поддерживать отключение, увеличение и уменьшение масштаба, а также постепенные обновления без каких-либо особых соображений. Это нормальный режим работы - «чтение из очереди», и это не меняется в исключительных обстоятельствах.

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

Нужен ли мне для этого Kubernetes?

Нет. Вероятно, у вас нет таких проблем с масштабированием, как у Google.

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

Если вы можете каким-либо образом управлять этим, используйте как можно более близкую к чисто управляемой платформе. Службы приложений Azure, Google App Engine и AWS Lambda будут на несколько порядков более продуктивными для вас как программиста. С ними будет проще работать в производственной среде, они станут более понятными и поддерживаются.

Kubernetes (часто раздражающе сокращенно k8s, вместе с его замечательной экосистемой дополнений с эзотерическими названиями, такими как helm и flux) требует для работы постоянной оперативной команды, и даже в «режиме управляемого поставщика» на EKS / AKS / GKS кривая обучения - это намного круче альтернатив.

Heroku? Службы приложений? App Engine? Это то, что вы сможете самостоятельно настроить для производства за считанные минуты или всего за несколько часов.

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

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

Разумные рекомендации

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

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