Создание надежного кода для распределенных систем

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

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

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

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

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

1. Сеть надежна
2. Задержка нулевая
3. Полоса пропускания бесконечна
4. Сеть безопасна
5. Топология не меняется
6 .Администратор один
7. Транспортные расходы нулевые
8. Сеть однородная

Укрепление вашего кода

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

Мы можем использовать шаблоны стабильности в нашем коде, чтобы сделать его более надежным. В этой статье обсуждается один из таких шаблонов: шаблон повторных попыток. Язык программирования, выбранный в этой статье, — язык программирования Go. Однако вы можете применить шаблон на своем любимом языке программирования.

Повторить шаблон

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

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

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

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

В шаблоне есть два основных компонента. Тип Effector определяет сигнатуру функции, и эта функция взаимодействует со сторонней службой. Эффектор может принимать любую форму, которую вы хотите. Для демонстрационного кода мы сохраняем простоту.

Вторая часть — это функция Retry. Эта функция принимает эффектор и возвращает анонимную функцию с той же сигнатурой, что и эффектор. По сути, он оборачивает полученную функцию логикой повтора.

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

Анонимные функции

В последнем разделе упоминается термин анонимная функция. Давайте на секунду отвлечемся и обсудим, что это такое и как мы можем его использовать. Мы можем объявить именованные функции на уровне пакета в Go, и примером этого является функция Retry.

Другим вариантом объявления функции является использование функционального литерала . Литерал функции записывается как объявление функции без имени, следующего за ключевым словом func. Значение этого выражения называется анонимной функцией.

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

Например, в функции Retry внутренняя анонимная функция имеет доступ к параметрам объемлющей функции. Более простым примером является функция квадратов:

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

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

Применение шаблона

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

Запуск этого кода выводит следующее:

2022/03/06 13:14:40 Function call failed, retrying in 2s
2022/03/06 13:14:42 Function call failed, retrying in 2s
2022/03/06 13:14:44 Function call failed, retrying in 2s
https://linktopdf.com <nil>

Заключение

В этой статье показано, как реализовать шаблон Retry в Go. Шаблон учитывает возможные временные сбои в распределенной системе. Если вам понравилась статья, пожалуйста, подпишитесь на меня на Medium.