<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>System Design</title>
<link>https://www.stefaniuk.website/tags/system-design/</link>
<description>Всім привіт! Я — Богдан, фулстек розробник з Києва. Пишу в основному про програмування та штуки які вивчаю. Час від часу публікую підбірки фоток, зроблених на плівку, розказую про подорожі та цікаві речі, що оточують мене.</description>
<author></author>
<language>uk</language>
<generator>Aegea 11.2 (v4116)</generator>

<itunes:subtitle>Всім привіт! Я — Богдан, фулстек розробник з Києва. Пишу в основному про програмування та штуки які вивчаю. Час від часу публікую підбірки фоток, зроблених на плівку, розказую про подорожі та цікаві речі, що оточують мене.</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Интересные статьи</title>
<guid isPermaLink="false">267</guid>
<link>https://www.stefaniuk.website/all/links-24-04-2022/</link>
<pubDate>Sun, 24 Apr 2022 05:39:07 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/links-24-04-2022/</comments>
<description>
&lt;p&gt;Решил вернуться к своему блогу после столь долгой паузы. Начну с небольшой подборки статей, которые я недавно прочитал и которые мне очень понравились.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://boringtechnology.club"&gt;Choose Boring Technology&lt;/a&gt; — статья-презентация от одного из первых разработчиков Etsy. Рассказывает про выбор технологий для проекта. Основная идея в том чтобы выбирать «скучные», а если быть точнее, то хорошо изученные и устоявшиеся технологии. Горячо советую почитать.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lethain.com/introduction-to-architecting-systems-for-scale/"&gt;Introduction to architecting systems for scale&lt;/a&gt; — кратко о том из чего состоят приложения, которые рассчитаны для масштабирование.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jvns.ca/blog/2022/03/13/celebrate-tiny-learning-milestones/"&gt;Celebrate tiny learning milestones&lt;/a&gt; — не совсем техническая статья. Вместо того чтобы придумывать себе большие цели на год, лучше придумать набор небольших целей «майлстоунов» и идти по ним.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://jvns.ca/blog/brag-documents"&gt;Get your work recognized: write a brag document&lt;/a&gt; — очень частая проблема это распознавание того что ты сделал на проекте. Когда приходит перформанс ревью, то бывает сложно вспомнить все что ты сделал за год. Автор советует завести документ в который нужно записывать результаты своей работы, а именно то, что было сделано и к чему это привело.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://henrikwarne.com/2020/07/23/good-logging/"&gt;Good Logging&lt;/a&gt; — коротко о том какими должны быть логи чтобы ими было удобно пользоваться. Ну и сразу еще две статьи от этого же автора: &lt;a href="https://henrikwarne.com/2013/05/05/great-programmers-write-debuggable-code/"&gt;Great Programmers Write Debuggable Code&lt;/a&gt; и &lt;a href="https://henrikwarne.com/2014/01/01/finding-bugs-debugger-versus-logging/"&gt;Finding Bugs: Debugger versus Logging&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Паттерн «Репозиторий»</title>
<guid isPermaLink="false">256</guid>
<link>https://www.stefaniuk.website/all/repository-pattern/</link>
<pubDate>Thu, 08 Jul 2021 08:50:13 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/repository-pattern/</comments>
<description>
&lt;p&gt;Репозиторий один из самых популярных паттернов для доступа к данным. Он используется для абстрагирования от конкретной реализации и нюансов работы с источником данных, внешних сервисов, файловой системой и т. д.&lt;/p&gt;
&lt;p&gt;С одной стороны, это очень простой паттерн, который позволяет скрыть сложность работы с БД. Но с другой стороны, спросите 10 программистов описать этот шаблон и вы получите 10 разных реализаций.&lt;/p&gt;
&lt;p&gt;Самая большая проблема этого шаблона — множество вопросов, которые возникают при его реализации и дальнейшей поддержки.&lt;/p&gt;
&lt;p&gt;Изначально хотел сам расписать проблемы, но за меня это уже сделали, поэтому настоятельно советую прочитать статью: &lt;a href="https://blog.byndyu.ru/2011/01/domain-driven-design-repository.html"&gt;«Проблемы паттерна Репозиторий».&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Если кратно, то:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Что делать если репозиториям нужно использовать закрытые методы друг друга?&lt;/li&gt;
&lt;li&gt;Можно ли использовать один репозиторий на весь проект или делать репозиторий на каждую сущность?&lt;/li&gt;
&lt;li&gt;Нужно ли дублировать методы репозитория в сервис или мы можем напрямую использовать репозиторий в контроллерах?&lt;/li&gt;
&lt;li&gt;Нужно ли возвращать IQueryable и как это повлияет на дизайн системы в случае с .NET кодом? Если нет, то как правильно изменять сущности без использования Change Tracking?&lt;/li&gt;
&lt;li&gt;Как правильно объединить репозиторий и UoW?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Отдельно также хочу отметить доклад: &lt;a href="https://www.youtube.com/watch?v=3yPpL1rEK9o&amp;t=1208s"&gt;Денис Цветцих «Repository и UnitOfWork в 2020 году, must have или антипаттерн?»&lt;/a&gt;. В нем также поднимаются проблемы репозитория, способы их решения и варианты замены этот шаблона на другой.&lt;/p&gt;
&lt;p&gt;Репозиторий — хороший паттерн, который должен быть в арсенале любого программиста, но стоит использовать его с умом и учитывать проблемы, которые он может вызвать.&lt;/p&gt;
&lt;p&gt;Для себя я решил что репозиторий хорошо подходит, когда вся логика приложения вписывается в CRUD модель. Но если логика более сложная или приложение подразумевает Task Base UI, тогда лучше прибегнуть к подходу CQRS. Он позволяет разбить сложную бизнес логику включая репозитории на независимые объекты, каждый из которых выполняет только одну бизнес задачу или use case.&lt;/p&gt;
&lt;div style="max-width: 750px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/repository-pattern-orm-db.png" width="1200" height="579" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Я кроме все прочего не люблю репозитории за:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ограничение функциональности ORM, большенство специфических операций недоступны. В зависимости от реализации можем потерять Change Tracking.&lt;/li&gt;
&lt;li&gt;Дополнительный мапинг из доменных объектов в DTO.&lt;/li&gt;
&lt;li&gt;Дополнительный слой абстракции, который зачастую просто не нужен. Особенно если речь идет о небольших сервисах где логику нужно делать максимально простой и незамысловатой.&lt;/li&gt;
&lt;li&gt;Работает только в простых CRUD сценариях.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Очереди сообщений</title>
<guid isPermaLink="false">253</guid>
<link>https://www.stefaniuk.website/all/message-queues/</link>
<pubDate>Tue, 18 May 2021 02:17:40 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/message-queues/</comments>
<description>
&lt;p&gt;При работе с большими системами, которые состоят из множества компонентов, возникает вопрос: «Как интегрировать несколько приложений для работы друг с другом?». Для этого нужен надёжный, асинхронный и быстрый способ передачи данных, который также позволит передавать информацию в разных форматах.&lt;/p&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-general.png" width="1936" height="789" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Все эти свойства есть в системе обмена сообщениями. Они полезны когда:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Нужно отправить данные из точки А в точку Б.&lt;/li&gt;
&lt;li&gt;Нужно интегрировать несколько систем.&lt;/li&gt;
&lt;li&gt;Нужно масштабирование.&lt;/li&gt;
&lt;li&gt;Нужна возможность мониторить потоки данных.&lt;/li&gt;
&lt;li&gt;Нужна асинхронная обработка.&lt;/li&gt;
&lt;li&gt;Нужна буферизация.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Концепт обмена сообщениями&lt;/h2&gt;
&lt;p&gt;Обмен сообщениями неновое изобретение. Он активно используется внутри операционной системы для обмена информацией между несколькими процессами (inter-process communication) и для обмена между несколькими потоками внутри процесса (inter-thread communication).&lt;/p&gt;
&lt;p&gt;Самый простой способ представить очередь сообщений как длинную трубу в которую можно помещать шарики. Мы можем написать сообщение на шаре и закинуть его в трубу и кто-то получит его на другой стороне. Из такой концепции можно понять несколько вещей.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Отправитель не имеет представления о том кто именно примет сообщение.&lt;/li&gt;
&lt;li&gt;Отправитель не переживает о том когда его сообщение будет получено.&lt;/li&gt;
&lt;li&gt;Отправитель может засовывать сколько угодно сообщений с удобной ему скорость.&lt;/li&gt;
&lt;li&gt;Это не повлияет на получателя, ведь он сам решает сколько сообщений ему удобно доставать.&lt;/li&gt;
&lt;li&gt;Ни отправитель, ни получатель не знают об устройстве друг друга.&lt;/li&gt;
&lt;li&gt;Ни отправитель, ни получатель не переживают про нагрузку и вместительность друг друга.&lt;/li&gt;
&lt;li&gt;Также они не знаю о том где каждый из них находиться. Они могут быть в одной комнате, в разных комнатах или зданиях.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Все эти свойства позволяют разделить две системы с точки зрения ответственности, времени, пропускной способности, внутреннего устройства, нагрузки и географии. Само по себе разделение является очень важной частью большой распределенной системы. Чем больше независимых компонентов, тем проще их разрабатывать, тестировать и запускать независимо от других.&lt;/p&gt;
&lt;p&gt;Также очереди работают по модели «издатель-подписчик». В ней издатель оправляет сообщение в очередь, а подписчик смотрит в очередь и извлекает интересные ему сообщения, после чего занимается их обработкой. Благодаря этой концепции, осуществляется асинхронная коммуникация.&lt;/p&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-pub-sub.png" width="1617" height="597" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2&gt;Причины использовать очереди сообщений&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;Избыточность и поддержка транзакций&lt;/b&gt;&lt;br /&gt;
Перед тем как сообщение будет удалено может потребоваться подтверждение, что приложение, которое прочитало сообщение, успешно его обработало. В случае возникновения проблем, сообщение не потеряется, что позволит повторно его обработать.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Масштабирование&lt;/b&gt;&lt;br /&gt;
Очереди распределяют процессы обработки информации. Это дает возможность гибко реагировать на нагрузку и добавлять или убирать дополнительные обработчики.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эластичность&lt;/b&gt;&lt;br /&gt;
Очереди сообщений позволяют выровнять нагрузку на приложение за счет буферизации данных. В случае большой нагрузки на систему очередь будет накапливать сообщения, а сами обработчики будут работать в нормальном режиме самым облегчая обработку данных и не допуская отказа системы.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Отказоустойчивость&lt;/b&gt;&lt;br /&gt;
В случае отказа обработчиков, очередь продолжит сохранять все сообщения, что позволит обработать их когда система поднимется, тем самым не потеряв никаких данных.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Decoupling and coupling&lt;/b&gt;&lt;br /&gt;
С помощью очередей можно достичь двух противоположных целей.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decoupling. Если у нас большой монолит, то будет сложно интегрировать новые фичи. В таком случае очередь сообщений позволяет разъединить одно приложения на несколько независимых компонентов и настроить коммуникацию между ними.&lt;/li&gt;
&lt;li&gt;Coupling. Иногда нужно, чтобы несколько систем работали как одно целое, очередь позволяют создать промежуточный слой для коммуникации между разными элементами системы.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Понимание потоков данных&lt;/b&gt;&lt;br /&gt;
По сути, очереди накладывают ограничения на передачу данных между компонентами, что позволяет очень легко мониторить как обрабатываются данные. Благодаря этой информации можно понять как работает система и ее компоненты. Например, некоторые очереди могут простаивать, а некоторые всегда забиты, тем самым показывая где у нас есть проблемы с обработкой.&lt;/p&gt;
&lt;h2&gt;Гарантированная доставка&lt;/h2&gt;
&lt;p&gt;Гарантированная доставка является одной из ключевых характеристик системы обмена сообщений. Всего есть три типа доставки:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;at least once&lt;/li&gt;
&lt;li&gt;at most once&lt;/li&gt;
&lt;li&gt;exactly once&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;At least once&lt;/b&gt;&lt;br /&gt;
Самый простой способ доставки при котором обработчик получает одно и то же сообщение до тех пор, пока не удалит его из очереди или не подтвердит получение. Это значит что возможны ситуации, когда приложение обрабатывает одно сообщение несколько раз.&lt;/p&gt;
&lt;p&gt;Такая особенность подразумевает, что обработчик будет корректно работать в случае дублирования сообщений. А такое может случаться часто. Например, упала сеть в момент, когда приложение подтверждало получение — оно получит его ещё раз.&lt;/p&gt;
&lt;p&gt;Если в сообщениях хранятся результаты каких-то измерений, у которых есть временная метка, то ничего страшного не произойдёт, если мы получим хоть миллион дубликатов. Но если в сообщениях храниться информация о финансовых транзакциях то будет совсем не круто обработать его дважды. Но такую ситуацию можно решить используя уникальные идентификаторы для сообщений и хранить список сообщений, которые мы уже обработали.&lt;/p&gt;
&lt;p&gt;С другой стороны, такой подход гарантирует 100% получение сообщения. Даже если получатель сообщения упадёт, до того как подтвердит обработку, то он просто ещё раз его обработает после перезапуска.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;At most once&lt;/b&gt;&lt;br /&gt;
Очень редкий сценарий, к нему прибегают когда двойная обработка сообщения может привести к серьезным проблемам. В таких очередях мы предпочтем потерять сообщение чем обработать его дважды.&lt;/p&gt;
&lt;p&gt;Если приложение упадет во время обработки сообщения, то мы его повторно не получим и оно будет считаться утерянным.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Exactly Once&lt;/b&gt;&lt;br /&gt;
Идеальный сценарий работы очереди, но проблема в том что его нереально воплотить в жизнь из-за множества проблема, которые сами по себе решить сложно, не говоря уже об их совокупности.&lt;/p&gt;
&lt;p&gt;Все они происходят из двух утверждений:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Отправители и получатели не идеальны&lt;/li&gt;
&lt;li&gt;Сеть не идеальна.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Что порождает такие проблемы как:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Отправитель может забыть отправить сообщение&lt;/li&gt;
&lt;li&gt;Сеть между отправителем и очередью может упасть&lt;/li&gt;
&lt;li&gt;Сеть между очередью и получателем может упасть&lt;/li&gt;
&lt;li&gt;База данных самой очереди может не сохранить сообщение&lt;/li&gt;
&lt;li&gt;Подтверждение что сообщение обработано может не дойти до очереди и отправителя&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Именно поэтому очень сложно гарантировать одноразовую доставку сообщения. Намного проще сделать систему устойчивой к дубликатам сообщений и использовать подход at-least-once.&lt;/p&gt;
&lt;h2&gt;Компоненты очереди сообщений&lt;/h2&gt;
&lt;p&gt;Система обмена сообщениями состоит из нескольких компонентов, которые позволяют ей нормально функционировать и выполнять свои задачи.&lt;/p&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-components.png" width="1456" height="543" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;b&gt;Сообщения&lt;/b&gt; — любые данные, которые нужно передать через очередь конвертируются в сообщение, которые состоят из двух частей:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Заголовки (headers) — в них расположена служебная информация, которая используется самой очередью для правильной обработки сообщения.&lt;/li&gt;
&lt;li&gt;Тело (body) — информация, которую мы передаем с помощью очереди.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Каналы (channels)&lt;/b&gt; — логические соединения между приложениями и системой очередей, которые предоставляют изолированную коммуникацию. Каналы позволяют передавать сообщение в одном из двух режимов:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;point-to-point — протокол, который обеспечивает прямую коммуникацию между двумя приложениями.&lt;/li&gt;
&lt;li&gt;publish-subscribe — протокол, в котором отправитель сообщения не знает конкретного получателя, а просто отправляет сообщение в очередь, на которую могут быть подписаны потребители.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Маршрутизатор (router)&lt;/b&gt; — помещает сообщения из каналов по разным очередям используя ключ маршрутизации из заголовков сообщения.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Очередь (queue)&lt;/b&gt; — хранилище для наших сообщений, которое может находиться как в оперативной памяти так и на диске.&lt;/p&gt;
&lt;h2&gt;Виды очередей&lt;/h2&gt;
&lt;p&gt;Очереди сообщений можно разделить на несколько видов. Обычно несколько видом могут быть реализованы в одном продукте.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;broadcast (fanout) exchange&lt;/b&gt;&lt;br /&gt;
В таком случае отправляется копия сообщения во все доступные очереди, ключ маршрутизации игнорируется.&lt;/p&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-fanout-exchange.png" width="1414" height="617" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;b&gt;direct exchange&lt;/b&gt;&lt;br /&gt;
Все сообщения имеют свой ключ маршрутизации, который определяет в какую очередь нужно положить сообщение. В дальнейшем сообщения будут переданы по принципу Round Robin подписанным обработчикам. Это значит что только один обработчик получит сообщение.&lt;/p&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-direct-exchange.png" width="1356" height="574" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;b&gt;topic exchange (multicast)&lt;/b&gt;&lt;br /&gt;
Такие очереди подписаны на получение сообщений чей ключ подпадает под определенный паттерн. Если ключ маршрутизации подходит для нескольких очередей, то каждая получит по своей копии.&lt;/p&gt;
&lt;p&gt;Обычно ключи маршрутизации стараются делать в иерархическом виде. Это достигается за счет разделения логических частей (слов) точками. Например вот так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;[region].[availability-zone].[service].[instance]

eu-east.az1.computer.homepc&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Сами же паттерны создаются с использованием специальных символов:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;* — заменитель только для одного слова.&lt;/li&gt;
&lt;li&gt;# — заменитель для нескольких слов&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Что позволяет сделать такие шаблоны:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;*.*.computer.* — очередь, которая может обработать сообщения только от компьютеров без разницы где они находятся.&lt;/li&gt;
&lt;li&gt;eu-east.# — очередь, которая может обрабатывать сообщения только из зоны eu-east&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="max-width: 650px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/queue-topic-exchange.png" width="1307" height="576" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2&gt;Протоколы&lt;/h2&gt;
&lt;p&gt;Исторически сложилось так, что почти все существующие протоколы для работы с очередями были проприетарными. Это накладывало массу ограничений, потому что не все языки поддерживали тот или иной протокол.&lt;/p&gt;
&lt;p&gt;Спустя какое-то время появились три открытых стандарта, которые сейчас повсеместно используются:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Advanced Message Queuing Protocol (AMQP)&lt;/b&gt; — бинарный протокол, который проектировался для  взаимодействия между различными вендорами и стал заменой существующих проприетарных протоколов. Основными особенностями AMQP является надежности и совместимость.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Streaming Text Oriented Messaging Protocol (STOMP)&lt;/b&gt; — простой текстовый протокол обмена сообщениями, который очень похож на HTTP и работает поверх TCP.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MQTT (formerly MQ Telemetry Transport)&lt;/b&gt; — очень простой и легковесный протокол, который разрабатывался для минимального использования трафика и работы в нестабильной сети. Все эти качества идеально подошли для использования протокола для общения между устройствами.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Материалы&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://fulmanski.pl/tutorials/computer-science/big-data/message-queues/"&gt;Message queues&lt;/a&gt; — отличная статья, которая описывает основные концепты работы очередей.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sudhir.io/the-big-little-guide-to-message-queues/"&gt;The Big Little Guide to Message Queues&lt;/a&gt; — большой гайд в котором описано про причины создания очередей их свойства и особенности работы, а также кратный разбор самых популярных реализаций.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Балансировка нагрузки</title>
<guid isPermaLink="false">250</guid>
<link>https://www.stefaniuk.website/all/load-balancing/</link>
<pubDate>Sat, 03 Apr 2021 16:48:50 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/load-balancing/</comments>
<description>
&lt;p&gt;Рано или поздно наступает момент, когда приложение начинает не справляться с нагрузкой и мы решаем горизонтально масштабировать нашу систему. Тогда возникает вопрос: как распределить запросы между несколькими машинами?&lt;/p&gt;
&lt;p&gt;Для решения этой проблемы используют балансировщики нагрузки. С помощью набора алгоритмов они позволяют равномерно распределить нагрузку на сервера. Зачастую представлены в виде софтверного решения, реже как отдельные устройства.&lt;/p&gt;
&lt;div style="max-width:620px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-intro.jpg" width="1000" height="599" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Помимо распределения нагрузки, балансировщики также выполняют дополнительные задачи, такие как обнаружение служб и проверка работоспособности. Иногда они работают в качестве API Gateway для маршрутизации трафика или его троттлинга. Например, отправлять запросы по специфичному URL на какой-то конкретный сервис и не давать пользователям делать больше указанного порога запросов в секунду.&lt;/p&gt;
&lt;h2&gt;Обнаружение служб&lt;/h2&gt;
&lt;p&gt;Это процесс, который позволяет определить набор сервером, на которые можно отправлять запросы. Для реализации этого подхода можно использовать несколько способов:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Файлы конфигурации.&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;Zookeper, Consul и т. д.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Проверка работоспособности&lt;/h2&gt;
&lt;div style="max-width:620px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-health.jpg" width="1000" height="608" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Проверки работоспособности позволяют понять, какие сервера сейчас работают и могут обрабатывать запросы. Сами проверки деляться на два типа: активные и пассивные.&lt;/p&gt;
&lt;p&gt;В пассивном режиме балансировщик наблюдает за основным потоком запросов и за тем как бэкенд на них отвечает. Например, он может решить что  сервер нерабочий, если он несколько раз подряд отвечает 503 статус кодом.&lt;/p&gt;
&lt;p&gt;В активном режиме балансировщик периодически делает запросы на специальный эндпоинт, который проверяет состояние приложения. Их также можно разделить на несколько типов: liveness и readiness&lt;/p&gt;
&lt;h2&gt;Алгоритмы балансировки нагрузки&lt;/h2&gt;
&lt;p&gt;Все современные балансировщики имеют поддержку множества алгоритмов, которые позволяют оптимально распределить запросы. Самих алгоритмов есть огромное множество, но основных всего несколько:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;Sticky Session&lt;/li&gt;
&lt;li&gt;Round Robin&lt;/li&gt;
&lt;li&gt;Weighted Round Robin&lt;/li&gt;
&lt;li&gt;Least Connection&lt;/li&gt;
&lt;li&gt;IP Hash&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;DNS&lt;/b&gt;&lt;br /&gt;
Самый простой способ распределить запросы это использовать DNS, он позволяет работать клиентам с несколькими серверами и повысить их доступность.  Для этого достаточно зарегистрировать несколько серверов на одно доменное имя. Когда клиент запрашивает IP адрес, DNS возвращает список адресов серверов, который каждый раз начинается с другого адреса. Такой подход похож на работу алгоритма Round Robin.&lt;/p&gt;
&lt;div style="max-width:420px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-dns.jpg" width="620" height="501" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Проблема заключается в том, что DNS запросы обычно кэшируются в браузере пользователя или на уровне операционной системы. Из-за такого поведения пользователь может обращяться к неработающему серверу. Даже если оперативно удалить адрес упавшего сервера из списка, может пройти время пока DNS записи реплицируются на другие сервера и пока кэш пользователя инвалидируется.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Round Robin&lt;/b&gt;&lt;br /&gt;
Самый простой алгоритм. Балансировщик держит обычную очередь из серверов. Первый сервер в очереди обрабатывает запрос и помещается в конец очереди и так по кругу. Таким образом сервера равномерно нагружены.&lt;/p&gt;
&lt;p&gt;Алгоритм отлично походит когда сервера в пуле имеют одинаковую мощность и время обработки запросов.&lt;/p&gt;
&lt;div style="max-width:420px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-robin.jpg" width="679" height="616" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;b&gt;Weighted Round Robin&lt;/b&gt;&lt;br /&gt;
Тот же round robin, но имеет дополнительное свойство — вес сервера. С его помощью мы можем указать балансировщику сколько трафика отправлять на тот или иной сервер. Так сервера помощнее будут иметь больший вес и соответственно обрабатывать больше запросов чем другие сервера.&lt;/p&gt;
&lt;div style="max-width:450px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-weighted.jpg" width="783" height="423" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;b&gt;Least Connections&lt;/b&gt;&lt;br /&gt;
В основе алгоритма лежит очередь с приоритетом, которая отсортирована по количеству активных пользователей, где первый сервер имеет наименьшее количество соединений. Такой способ отлично подходит для систем где много активных соединений, например стриминг сервис или онлайн чат.&lt;/p&gt;
&lt;div style="max-width:480px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-least.jpg" width="820" height="652" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Алгоритм можно улучшить и учитывать не только количество соединений, но и среднее время. Тогда первым в списке будет сервер с наименьшим количеством подключений и наименьшим временем ответа. Такой алгоритм называется Least Response Time. Такой способ позволяет выровнять нагрузку если сервера отвечают с разной скоростью.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Hash&lt;/b&gt;&lt;br /&gt;
Такой способ использует в своей основе механизм хеширования. Он позволяет распределить запросы на основе хеша, для которого обычно используется IP адрес или URL. В таком случае запросы от одного и того же IP будут отправлены на один и тот же сервер. Тоже самое касается URL. Такой алгоритм обычно используют, когда сервер хранит какие-то локальные данные, которые нужны для ответа.&lt;/p&gt;
&lt;div style="max-width:420px"&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/load-balancing-hash.jpg" width="566" height="417" alt="" /&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2&gt;Примеры софтверных балансировщиков&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;HAProxy&lt;/li&gt;
&lt;li&gt;nginx&lt;/li&gt;
&lt;li&gt;AWS Route 53&lt;/li&gt;
&lt;li&gt;AWS Elastic Load Balancer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Дополнительная информация&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://brooker.co.za/blog/2012/01/17/two-random.html"&gt;The power of two random choices&lt;/a&gt;. Автор предлагает отказаться от централизованной балансировки нагрузки и использовать балансировку на стороне клиента. Для этого информации и загруженности серверов сохраняется в каком-то кэше, который время от времени обновляется. Сами же клиенты будут случайным образом выбирать два сервера и отправлять запрос на менее загруженных из двух. Такой подход позволяет оптимально распределять нагрузку и избавиться от центрального балансировщика.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.envoyproxy.io/introduction-to-modern-network-load-balancing-and-proxying-a57f6ff80236"&gt;Introduction to modern network load balancing and proxying&lt;/a&gt;. Хорошая статья в которой описаны способы использования балансировщиков нагрузки и в чем разница между L4 и L7 балансировкой. &lt;a href="https://medium.com/southbridge/introduction-to-modern-network-load-balancing-and-proxying-52e8ca36adde"&gt;Перевод на русский&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>stateless и stateful сервисы</title>
<guid isPermaLink="false">169</guid>
<link>https://www.stefaniuk.website/all/stateless-i-stateful-services/</link>
<pubDate>Wed, 18 Dec 2019 13:03:03 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/stateless-i-stateful-services/</comments>
<description>
&lt;p&gt;&lt;b&gt;Stateful системы&lt;/b&gt;&lt;br /&gt;
Такие системы хранят внутри себя состояние, которое влияет на запросы от пользователя. Примером могут быть сессии пользователей, которые хранятся на сервера. Ответ на запрос пользователя зависит от состояния сессии.&lt;/p&gt;
&lt;p&gt;Одна из основных проблем таких систем — горизонтальное масштабирование. Чтобы развернуть несколько экземпляров сервиса нужно как переносить состояния но новые машины и синхронизировать их. Но проблема относительно легко решается за счет внешнего хранилища в котором можно хранить сессии. Система все равно является stateful, но сами веб сервисы стали stateless и теперь можно спокойно их масштабировать.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Stateless системы&lt;/b&gt;&lt;br /&gt;
Как альтернативу сессиям можно использовать cookie файлы или JWT токены. В таком случае вместе с запросом мы всегда отправляем всю необходимую информацию для его выполнения и аутентификации. В таком случае серверу не нужно хранить информацию о пользователе, достаточно проверить на валидность куки или токен в запросе. Так что stateless система зависит только от данных которые ей были переданы, а не от внутреннего состояния.&lt;/p&gt;
&lt;p&gt;Еще один пример системы, которая хранит состояние: у нас есть интернет магазин. Пока корзина пользователя храниться в памяти сервера — это stateful. В таком случае мы опять упираемся в проблему с масштабированием. Но мы можем вынести состояние корзины в базу данных, тогда сервис станет stateless и можно легко его раскатывать на несколько машин.&lt;/p&gt;
&lt;p&gt;Более детально расписано тут: &lt;a href="http://rsdn.org/forum/design/2951941.1"&gt;stateless/full web service&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Документация</title>
<guid isPermaLink="false">56</guid>
<link>https://www.stefaniuk.website/all/tech-documentation/</link>
<pubDate>Thu, 09 May 2019 05:22:39 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/tech-documentation/</comments>
<description>
&lt;p&gt;Ох сколько проблем вызывает документация. И зачастую эти проблемы связаны с ее отсутствием. Почти всегда разработчики считаю что написание документации это: лишнее, бюрократия, скучно. Также часто разработчики приводят в пример цитату из скрам гайда: работающий продукт важнее исчерпывающей&lt;br /&gt;
документации.&lt;/p&gt;
&lt;p&gt;Я считаю что документация в том или ином виде должна присутствовать. Зачастую ее ценность понимается не сразу, а по прошествию времени. Например так случилось и в нашей команде, когда старые разработчики ушли и новеньким было очень сложно делать экскурс по системе, а она очень большая!&lt;/p&gt;
&lt;p&gt;Но я против детально и огромной документации. Для себя и своих личных проектов я придерживаюсь следующего шаблона. Он достаточно компактный и простой в написании. Да это не ГОСТ, не ISO и не IEEE. Но она понятная и ее написание не занимает много времени.&lt;/p&gt;
&lt;p&gt;Какие проблемы я пробую решить своим шаблоном:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Для чего нужен данный модуль или архитектура?&lt;/li&gt;
&lt;li&gt;Как ее использовать?&lt;/li&gt;
&lt;li&gt;Как вносить изменения?&lt;/li&gt;
&lt;li&gt;Как осуществлять диагностику или проверку состояния?&lt;/li&gt;
&lt;li&gt;Какие были связаны с ней проблемы?&lt;/li&gt;
&lt;li&gt;Какими тестами покрыто? (Проблема очень важная, так как часто при планировании изменений приходилось вспоминать/идти проверять какими тестами покрыт функционал, что отнимало иногда много времени).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Шаблон документации&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;Назначение:&lt;/b&gt; для чего нужен этот модуль, какую задачу решает?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Основная задача:&lt;/b&gt; ссылка на задачу в трекере в рамках которой разрабатывалась данный модуль.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Диаграмма:&lt;/b&gt; графическое отображение архитектуры. Позволит понять что от кого зависит и как взаимодействует с другими частями системы.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Зоны ответственности:&lt;/b&gt; кратко описать элементы модуля и за что они отвечают. Смысл приёма в том, чтобы явно выделить назначение класса. Идеальный результат — получить класс, который можно описать одной фразой или даже одним словом.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример использования:&lt;/b&gt; небольшой пример того как использовать данный функционал.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Обработка ошибок:&lt;/b&gt; как обрабатываются ошибки.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Логирование:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;В какой файл пишутся логи.&lt;/li&gt;
&lt;li&gt;Уровни логирования и какую они могут дать информацию.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Тесты:&lt;/b&gt; каким типом тестов покрыта данная функциональность.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;FAQ: &lt;/b&gt; вопросы и ответы по данной функциональности. Например: как объединить 2 объекта в сущности?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Инциденты и баги:&lt;/b&gt; ссылки на баги, которые были найдены в данной функциональности и исправленные.&lt;/p&gt;
&lt;h2&gt;Статьи по теме&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/143920/"&gt;Еще раз о документации&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/303760/"&gt;7 правил написания технической документации мирового класса&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Логирование</title>
<guid isPermaLink="false">54</guid>
<link>https://www.stefaniuk.website/all/logging/</link>
<pubDate>Mon, 29 Apr 2019 13:58:18 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/logging/</comments>
<description>
&lt;p&gt;Для чего вообще нужно логирование в приложении:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Сказать, что делать система, не прибегая к отладчику.&lt;/li&gt;
&lt;li&gt;Найти причины возникновения той или иной ситуации внутри приложения.&lt;/li&gt;
&lt;li&gt;Анализ того на что тратится больше всего ресурсов.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Какие есть требования к логерам?&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Уровни логирования и фильтрация сообщений.&lt;/li&gt;
&lt;li&gt;Ротация лог файлов.&lt;/li&gt;
&lt;li&gt;Возможность писать сообщения не только в файл.&lt;/li&gt;
&lt;li&gt;Thread safety.&lt;/li&gt;
&lt;li&gt;Асинхронное логирование.&lt;/li&gt;
&lt;li&gt;Формат и конфигурация логов.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Уровни логирования&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;TRACE&lt;/b&gt; — вывод всего подряд. На тот случай, если Debug не позволяет локализовать ошибку. В нем полезно отмечать вызовы разнообразных блокирующих и асинхронных операций.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DEBUG&lt;/b&gt; — журналирование моментов вызова «крупных» операций. Старт/остановка потока, запрос пользователя и т. п.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;INFO&lt;/b&gt; — обычные сообщения, информирующие о действиях системы. Реагировать на такие сообщения вообще не надо, но они могут помочь, например, при поиске багов, расследовании интересных ситуаций итд.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WARNING&lt;/b&gt; — нештатные ситуации. Например непредвиденные параметры, странные форматы запроса. Любая информация, которая должна привлечь внимание. Некритичные ошибки.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ERROR&lt;/b&gt; — ошибка в работе системы, требующая вмешательства. Что-то не сохранилось, что-то отвалилось.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FATAL&lt;/b&gt; — критическая ситуация, которая требует немедленной реакции. Обычно значит что система в неработоспособном состоянии. Пишем в лог все до чего можем дотянутся.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Замечание! Никогда не отправляйте пустое исключение в лог. Так как обычно не понятно к чему принадлежит этот стэк-трейс, как программа отреагировала на ошибку. Чтобы избежать этого, в дополнение к трейсам  прикладывайте и сообщение, которое обьясняет что именно произошло.&lt;/p&gt;
&lt;h2&gt;Интересные статьи на тему&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/135242/"&gt;Архитектура логирования&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thekua.com/atwork/2008/11/application-logging-principles/"&gt;Application logging principles&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Шардинг</title>
<guid isPermaLink="false">47</guid>
<link>https://www.stefaniuk.website/all/sharding/</link>
<pubDate>Thu, 04 Apr 2019 17:26:34 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/sharding/</comments>
<description>
&lt;p&gt;Шардинг (иногда шардирование) — это другая техника масштабирования работы с данными. Суть его в разделении (партиционирование) базы данных на отдельные части так, чтобы каждую из них можно было вынести на отдельный сервер. Этот процесс зависит от структуры базы данных и выполняется прямо в приложении в отличие от репликации&lt;/p&gt;
&lt;h2&gt;Вертикальный шардинг&lt;/h2&gt;
&lt;p&gt;Вертикальный шардинг — это выделение таблицы или группы таблиц на отдельный сервер. Например, в приложении есть такие таблицы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;users&lt;/i&gt; — данные пользователей&lt;/li&gt;
&lt;li&gt;&lt;i&gt;photos&lt;/i&gt; — фотографии пользователей&lt;/li&gt;
&lt;li&gt;&lt;i&gt;albums&lt;/i&gt; — альбомы пользователей&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Таблицу users Вы оставляете на одном сервере, а таблицы &lt;i&gt;photos&lt;/i&gt; и &lt;i&gt;albums&lt;/i&gt; переносите на другой. В таком случае в приложении Вам необходимо будет использовать соответствующее соединение для работы с каждой таблицей&lt;/p&gt;
&lt;h2&gt;Горизонтальный шардинг&lt;/h2&gt;
&lt;p&gt;Горизонтальный шардинг — это разделение одной таблицы на разные сервера. Это необходимо использовать для огромных таблиц, которые не умещаются на одном сервере. Разделение таблицы на куски делается по такому принципу:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;На нескольких серверах создается одна и та же таблица (только структура, без данных).&lt;/li&gt;
&lt;li&gt;В приложении выбирается условие, по которому будет определяться нужное соединение (например, четные на один сервер, а нечетные — на другой).&lt;/li&gt;
&lt;li&gt;Перед каждым обращением к таблице происходит выбор нужного соединения.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Совместное использование&lt;/h2&gt;
&lt;p&gt;Шардинг и репликация часто используются совместно. В нашем примере, мы могли бы использовать по два сервера на каждый шард таблицы&lt;/p&gt;
&lt;h2&gt;Key-value базы данных&lt;/h2&gt;
&lt;p&gt;Следует отметить, что большинство Key-value баз данных поддерживает шардинг на уровне платформы. Например, Memcache. В таком случае, Вы просто указываете набор серверов для соединения, а платформа сделает все остальное&lt;/p&gt;
&lt;h2&gt;Итог&lt;/h2&gt;
&lt;p&gt;Не следует применять технику шардинга ко всем таблицам. Правильный подход — это поэтапный процесс разделения растущих таблиц. Следует задумываться о горизонтальном шардинге, когда количество записей в одной таблице переходит за пределы от нескольких десятков миллионов до сотен миллионов.&lt;/p&gt;
&lt;h2&gt;P.S.&lt;/h2&gt;
&lt;p&gt;Помните, процесс масштабирования данных — это архитектурное решение, оно не связано с конкретной технологией. Не делайте ошибок наших отцов — не переезжайте с известной Вам технологии на новую из-за поддержки или не поддержки шардинга. Проблемы обычно связаны с архитектурой, а не конкретной базой данных&lt;/p&gt;
&lt;h2&gt;Ссылки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%92%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9+%D1%88%D0%B0%D1%80%D0%B4%D0%B8%D0%BD%D0%B3"&gt;Вертикальный шардинг&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%A8%D0%B0%D1%80%D0%B4%D0%B8%D0%BD%D0%B3+%D0%B8+%D1%80%D0%B5%D0%BF%D0%BB%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F"&gt;Шардинг и репликация&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Репликация данных</title>
<guid isPermaLink="false">46</guid>
<link>https://www.stefaniuk.website/all/db-replication/</link>
<pubDate>Thu, 04 Apr 2019 17:23:42 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/db-replication/</comments>
<description>
&lt;p&gt;Репликация — одна из техник масштабирования баз данных. Состоит эта техника в том, что данные с одного сервера базы данных постоянно копируются (реплицируются) на один или несколько других. Для приложения появляется возможность использовать не один сервер для обработки всех запросов, а несколько. Таким образом появляется возможность распределить нагрузку с одного сервера на несколько.&lt;/p&gt;
&lt;p&gt;Существует два основных подхода при работе с репликацией данных:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Репликация Master-Slave;&lt;/li&gt;
&lt;li&gt;Репликация Master-Master.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Master-Slave репликация&lt;/h2&gt;
&lt;p&gt;В этом подходе выделяется один основной сервер базы данных, который называется Мастером. На нем происходят все изменения в данных (любые запросы INSERT/UPDATE/DELETE). Слейв сервер постоянно копирует все изменения с Мастера. С приложения на Слейв сервер отправляются запросы чтения данных. Таким образом Мастер сервер отвечает за изменения данных, а Слейв за чтение.&lt;/p&gt;
&lt;h2&gt;Несколько Слейвов&lt;/h2&gt;
&lt;p&gt;Преимущество этого типа репликации в том, что Вы можете использовать более одного Слейва. Обычно следует использовать не более 20 Слейв серверов при работе с одним Мастером.&lt;br /&gt;
Тогда из приложения выбирает случайным образом один из Слейвов для обработки запросов, тем самым распределяя нагрузку на БД.&lt;/p&gt;
&lt;h2&gt;Выход из строя&lt;/h2&gt;
&lt;p&gt;При выходе из строя Слейва, достаточно просто переключить все приложение на работу с Мастером. После этого восстановить репликацию на Слейве и снова его запустить.&lt;br /&gt;
Если выходит из строя Мастер, нужно переключить все операции (и чтения и записи) на Слейв. Таким образом он станет новым Мастером. После восстановления старого Мастера, настроить на нем реплику, и он станет новым Слейвом.&lt;/p&gt;
&lt;h2&gt;Master-Master репликация&lt;/h2&gt;
&lt;p&gt;В этой схеме, любой из серверов может использоваться как для чтения так и для записи.&lt;/p&gt;
&lt;h2&gt;«Ручная» репликация&lt;/h2&gt;
&lt;p&gt;Некоторые технологии вообще не имеют встроенной репликации. В таких случаях, следует использовать самостоятельную реализацию репликации. В самом простом случае, приложение будет дублировать все запросы сразу на несколько серверов базы данных.&lt;/p&gt;
&lt;h2&gt;Итог&lt;/h2&gt;
&lt;p&gt;Репликация используется в большей мере для резервирования баз данных и в меньшей для масштабирования. Master-Slave репликация удобна для распределения запросов чтения по нескольким серверам. Подход ручной репликации позволит использовать преимущества репликации для технологий, которые ее не поддерживают. Зачастую репликация используется вместе с шардингом при решении вопросов масштабирования.&lt;/p&gt;
&lt;p&gt;Следует отметить, что репликация сама по себе не очень удобный механизм масштабирования. Причиной тому — рассинхронизация данных и задержки в копировании с мастера на слейв. Зато это отличное средство для обеспечения отказоустойчивости. Вы всегда можете переключиться на слейв, если мастер ломается и наоборот. Чаще всего репликация используется совместно с шардингом именно из соображений надежности.&lt;/p&gt;
</description>
</item>

<item>
<title>Кэширование</title>
<guid isPermaLink="false">25</guid>
<link>https://www.stefaniuk.website/all/cache/</link>
<pubDate>Sat, 02 Mar 2019 12:42:18 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/cache/</comments>
<description>
&lt;p&gt;Кеширование — механизм, с помощью которого можно повысить скорость работы приложения за счёт переноса часто используемых данных в очень быстрое хранилище.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/cache-main.jpg" width="500" height="254" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Кэширование очень активно используют во множестве систем. Например:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Внутренний кэш баз данных.&lt;/li&gt;
&lt;li&gt;DNS кэш внутри нашего компьютера или браузера.&lt;/li&gt;
&lt;li&gt;Кэш статического контента в браузере.&lt;/li&gt;
&lt;li&gt;CDN также является своего рода кэшем.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В любом приложении есть операции, которые долго выполнялись, но результат которых можно сохранить на какое-то время. Это позволит меньше выполнять таких операций и отдавать заранее сохранённые данные.&lt;/p&gt;
&lt;p&gt;Что можно кэшировать?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Запросы в базу данных.&lt;/li&gt;
&lt;li&gt;Пользовательские сессии.&lt;/li&gt;
&lt;li&gt;Медленные операции внутри приложения (расчеты, какие-то итоговые данные и т. д.)&lt;/li&gt;
&lt;li&gt;Запросы к внешним системам.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Алгоритм работы&lt;/h2&gt;
&lt;p&gt;Приложение в первую очередь идёт за данными в кэш, если они там есть, то запроса в базу данных не происходит, что позволяет сэкономить время и ресурсы, такой случай называется &lt;i&gt;попаданием кэша&lt;/i&gt;. Если данных нету, то приложение читает данные из базы данных после чего кладёт их в кэш для дальнейшего использования, такая ситуация называется &lt;i&gt;промахом кэша&lt;/i&gt;. На основании этих двух показателей можно вычислить эффективность системы кэширования.&lt;/p&gt;
&lt;h2&gt;Стратегии кэширования&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;Cache Aside&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/cache-aside.png" width="750" height="343" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Самый простой способ кэширования, зачастую множество фреймворков уже имеют встроенную реализацию.&lt;/p&gt;
&lt;p&gt;В такой системе данные лениво загружаются в кэш. Пользователь делает запрос к нашей системе, после этого приложение сначала идет в кэш, если данные в нем есть, то возвращает их клиенту иначе идет в базу данных, обновляет кэш и отдает пользователю.&lt;/p&gt;
&lt;p&gt;Плюсы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Отлично подходит для тяжелых операций чтения.&lt;/li&gt;
&lt;li&gt;Обычно система устойчива к отказу кэша. Если он упадет всегда можно пойти напрямую в базу данных.&lt;/li&gt;
&lt;li&gt;Возможно использовать разные структуры данных для кэша и базы данных. Особенно полезно когда нам нужно закешировать результат какой-то сложной выборки&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Минусы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Из-за того что запись идет напрямую в базу данных, данные в кэше могут стать не консистентными. Для этого нужно использовать TTL (время жизни данных в кэше) или инвалидировать кэш, когда нужно гарантированно отдавать актуальные данные.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br&gt;&lt;br /&gt;
&lt;b&gt;Read Through&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/read-through.png" width="750" height="204" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Очень похожий на ленивый кэш, но в таком случае данные всегда остаются консистентными. Это достигается за счет того что приложение читает данные только из кэша, а уже он сам идет в базу данных в случае промаха.&lt;/p&gt;
&lt;p&gt;Плюсы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Отлично работает с тяжелыми операциями чтения.&lt;/li&gt;
&lt;li&gt;Данные всегда в консистентном виде.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Минусы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Модель данных в кэше и в базе данных не могут отличатся.&lt;/li&gt;
&lt;li&gt;Первый запрос в кэш всегда будет приводить к промаху и последующему запросу в БД. Эту проблему можно — решить с помощью “прогревания” кэша.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br&gt;&lt;br /&gt;
&lt;b&gt;Write Through&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/write-through.png" width="750" height="184" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Эта стратегия подразумевает приложение сначала запишет данные в кэш, после чего сохранит их в базу данных.&lt;/p&gt;
&lt;p&gt;Лучше всего использовать эту стратегию вместе с read-through подходом. В таком случае мы получаем плюсы двух стратегий.&lt;/p&gt;
&lt;p&gt;Плюсы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Гарантирует полною консистентность данных.&lt;/li&gt;
&lt;li&gt;Отлично работает с тяжелыми операциями записи.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Минусы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Добавляет дополнительную задержку для операций записи.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br&gt;&lt;br /&gt;
&lt;b&gt;Write Back&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/write-back.png" width="750" height="184" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Самый сложный способ кэширования, в нем все операции записи происходят только в кэше, откуда они с некоторой задержкой попадают в основное хранилище.&lt;/p&gt;
&lt;p&gt;Плюсы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Позволяет сильно оптимизировать сложные операции записи.&lt;/li&gt;
&lt;li&gt;Данные всегда в консистентном виде.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Минусы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Сложность реализации.&lt;/li&gt;
&lt;li&gt;Есть шанс потерять данные если произойдет сбой кэша до того как данные запишутся в основное хранилище.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Алгоритмы вытеснения&lt;/h2&gt;
&lt;p&gt;Если в кэше нет свободного места для новых данных, то в работу вступают разнообразные механизмы вытеснения (очистки) кэша.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LRU (Least recently used) — алгоритм, который находит и вытесняет данные, которые не использовались дольше всех.&lt;/li&gt;
&lt;li&gt;MRU (Most Recently Used) — вытесняются последние используемые данные.&lt;/li&gt;
&lt;li&gt;LFU (Least Frequently Used) — вытесняются редко запрашиваемые данные.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Выбор правильного алгоритма зависит от того как данные используются в системе. LRU подходит в тех случая когда данные гарантированно будут повторно используемые. MRU подходит для данных, которые запрашивались совсем недавно, но данные не будут повторно использованы в ближайшее время.&lt;/p&gt;
&lt;h2&gt;Проблемы с кэшированием&lt;/h2&gt;
&lt;p&gt;В процессе создания и работы кэширующей системы может возникнуть набор разные проблем и вопросы, такие как:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Деление данных между кэширующими серверами.&lt;/li&gt;
&lt;li&gt;Параллельные запросы на обновление данных.&lt;/li&gt;
&lt;li&gt;“Холодный” старт приложения.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Деление данных между кэширующими серверами&lt;/b&gt;&lt;br /&gt;
Для повышения надежности и производительности системы кеширования приходится разделять ее на несколько серверов. Поэтому возникает вопрос как делить данные между серверами.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Вариант 1.&lt;/b&gt; Использовать хеширование ключей. В таком случае данные разделяются по серверам в зависимости от ключа кэширования. Для этого используется хеш функция, которая на вход принимает ключ и возвращает номер сервера.&lt;/p&gt;
&lt;p&gt;Проблема такого подхода заключается в том, что в случае падения сервера мы теряем почти 80% данных из-за изменения месторасположения ключей.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Вариант 2.&lt;/b&gt; Логическое разделение данных на основе какого-то признака. Например мы можем разделять данные на основании пользователя. Так данные одного пользователя будут лежать рядом на одном сервере.&lt;br /&gt;
Примеры проблем и их решения отлично описаны в статье “Проблемы при работе с кэшем и способы их решения”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Параллельные запросы на обновление данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Время от времени данные в кеше протухают и удаляются. В таком случае их необходимо обновить. Обычно это происходит, когда запрос обращается в кэш, видит, что данных нет, идет за ними в БД после чего обновляет кэш. Может возникнуть ситуация, когда таких запросов нескольколько, тогда все они пойдут в базу данных и нагрузят систему.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Решение 1.&lt;/b&gt; Блокировка перед обновлением кеша. Первый запрос получает уникальную блокировку на загрузку данных в кэш, все остальные ожидают блокировку. Это решает проблему с обновлением, но порождает новые: как обрабатывать таймауты, как правильно подобрать время блокировки и т. д.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Решение 2.&lt;/b&gt; Фоновое обновление кэша. Приложение всегда читает данные из кеша и никогда не ходит в базу данных. Данные в кеше обновляет специальный скрипт или программа, которая работает в фоне. В таком случае никогда не наступит параллельного обновления кеша. Но возникает проблема с временем реакции на изменение данных в БД.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Решение 3.&lt;/b&gt; Вероятностное обновление данных. Обновляем не только данные, которых нет в кэше, но и с какой-то вероятностью те что уже есть. Это позволит обновить данные, до того как они протухнут и будут удалены.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Решение 4.&lt;/b&gt; Дублирование ключей. В системе есть два ключа, где второй имеет время жизни немного больше чем первый. В таком случае после того как исчезнет первый ключ мы обновляем его данные, но остальные запросы на чтение могут взять данные из второго ключа.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;«Холодный» старт приложения&lt;/b&gt;&lt;br /&gt;
В момент запуска приложения данных в кэше может не быть. Как только пойдут запросы от пользователей все они пойдут массово в базу данных и начнуть одновременно обновлять кэш. Такая ситуация может привести к резкому падению производительности всей системы.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Решение.&lt;/i&gt; Можно прибегнуть к технике «прогревания» кеша. В таком случае при старте приложения мы также наполняем кэш данными, которые активно используются.&lt;/p&gt;
&lt;h2&gt;Итого&lt;/h2&gt;
&lt;p&gt;Кэширование это очень мощный и простой в использовании механизм, который позволяет значительно увеличить производительность системы. Если вы планируете использовать кэш, то стоит внимательно посмотреть на то какие данные вы хотите кэшировать и как они используются. От этого зависит эффективность решения и какую стратегию выбрать.&lt;/p&gt;
&lt;h2&gt;Ссылки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%9A%D1%8D%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85"&gt;Кэширование данных&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ru/caching/"&gt;Обзор кэширования от amazon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/company/ruvds/blog/350310/"&gt;Кэширование и производительность веб-приложений&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/company/zerotech/blog/316316/"&gt;11 видов кэширования для современного сайта&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ruhighload.com/%D0%A2%D1%8F%D0%B6%D0%B5%D0%BB%D0%BE%D0%B5+%D0%BA%D1%8D%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5"&gt;Тяжелое кэширование&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/company/badoo/blog/352186/"&gt;Проблемы при работе с кэшем и способы их решения&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://habr.com/ru/post/43540/"&gt;Проблема одновременного перестроения кэшей&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Кластеризация</title>
<guid isPermaLink="false">23</guid>
<link>https://www.stefaniuk.website/all/clusters/</link>
<pubDate>Sat, 02 Mar 2019 05:08:04 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/clusters/</comments>
<description>
&lt;p&gt;Кластер — слабо связанная совокупность нескольких вычислительных систем, работающих совместно для выполнения общих приложений, и представляющихся пользователю единой системой.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/cluster-overvoew.png" width="600" height="639" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Виды кластеров&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Отказоустойчивые кластеры (High-availability clusters, HA)&lt;/li&gt;
&lt;li&gt;Кластеры с балансировкой нагрузки (Load balancing clusters)&lt;/li&gt;
&lt;li&gt;Вычислительные кластеры (High performance computing clusters, HPC)&lt;/li&gt;
&lt;li&gt;Системы распределенных вычислений&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Отказоустойчивые кластеры&lt;/h2&gt;
&lt;p&gt;Создаются для обеспечения высокой доступности сервиса, предоставляемого кластером. Избыточное число узлов, входящих в кластер, гарантирует предоставление сервиса в случае отказа одного или нескольких серверов. Типичное число узлов — два, это минимальное количество, приводящее к повышению доступности.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/high-avialible-cluster.png" width="600" height="423" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Подтипы отказоустойчивых кластеров&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;С холодным резервом&lt;/li&gt;
&lt;li&gt;С горячим резервом&lt;/li&gt;
&lt;li&gt;С модульной избыточностью&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;i&gt;Холодный резерв&lt;/i&gt;&lt;br /&gt;
Один сервер находится в пассивном режиме и ждет падения основного сервера&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/cold-cluster.gif" width="400" height="178" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;Горячий резерв&lt;/i&gt;&lt;br /&gt;
Два сервера обрабатывают запросы, в случае падения одного, вся нагрузка направляется на живой.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/hot-cluster.gif" width="400" height="226" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;Модульная избыточность&lt;/i&gt;&lt;br /&gt;
Два сервера обрабатывают один и тот же запрос. Необходимо, когда нам нужно гарантированно обработать запрос и получить результат (результат берется любой).&lt;/p&gt;
&lt;h2&gt;Кластеры распределения нагрузки&lt;/h2&gt;
&lt;p&gt;Принцип действия базируется на распределении нагрузки через один или несколько входных узлов. Также такой кластер часто называют веб фермой.&lt;/p&gt;
&lt;h2&gt;Вычислительные кластеры&lt;/h2&gt;
&lt;p&gt;Кластеры используются в вычислительных целях, в частности в научных исследованиях. Для вычислительных кластеров существенными показателями являются высокая производительность процессора в операциях над числами с плавающей точкой (flops) и низкая латентность объединяющей сети, и менее существенными — скорость операций ввода-вывода, которая в большей степени важна для баз данных и web-сервисов. Вычислительные кластеры позволяют уменьшить время расчетов, по сравнению с одиночным компьютером, разбивая задание на параллельно выполняющиеся ветки, которые обмениваются данными по связывающей сети.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/calc-clusters.png" width="600" height="522" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Типовые задачи для расчетных кластеров&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;решение задач механики жидкости и газа, теплопередачи и теплообмена, электродинамики, акустики;&lt;/li&gt;
&lt;li&gt;моделирование аэрогазодинамических процессов;&lt;/li&gt;
&lt;li&gt;моделирование физико-химических процессов и реакций;&lt;/li&gt;
&lt;li&gt;моделирование сложного динамического поведения различных механических систем;&lt;/li&gt;
&lt;li&gt;решение задач цифровой обработки сигналов, финансового анализа, разнообразных математических задач, визуализации и представления данных&lt;/li&gt;
&lt;li&gt;анализ и расчет статической и динамической прочности;&lt;/li&gt;
&lt;li&gt;газодинамика, термодинамика, теплопроводность и радиочастотный анализ;&lt;/li&gt;
&lt;li&gt;моделирование задач любой степени геометрической сложности;&lt;/li&gt;
&lt;li&gt;рендеринг анимации и фотореалистичных VFX эффектов&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Системы распределенных вычислений&lt;/h2&gt;
&lt;p&gt;Такие системы не принято считать кластерами, но их принципы в значительной степени сходны с кластерной технологией. Их также называют grid-системами. Главное отличие — низкая доступность каждого узла, то есть невозможность гарантировать его работу в заданный момент времени, поэтому задача должна быть разбита на ряд независимых друг от друга процессов. Такая система, в отличие от кластеров, не похожа на единый компьютер, а служит упрощенным средством распределения вычислений. Состоит из множества ресурсов разных типов.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример&lt;/b&gt;&lt;br /&gt;
Кластер в CERN представляет из себя иерархический грид, который имеет 3 слоя:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Нулевой — собирает информацию с датчиков и осуществляет первичное хранение информации&lt;/li&gt;
&lt;li&gt;Tier 1 — хранит копии данных в разных точках мира&lt;/li&gt;
&lt;li&gt;Tier 2 — преимущественно обладают высокой вычислительной мощностью — обрабатывают информацию.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Достоинства&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Эффективная утилизация ресурсов.&lt;/li&gt;
&lt;li&gt;Обновления без остановки&lt;/li&gt;
&lt;li&gt;Увеличение производительности&lt;/li&gt;
&lt;li&gt;Отказоустойчивость (круглосуточная работа)&lt;/li&gt;
&lt;li&gt;Абсолютная масштабируемость&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Недостатки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Синхронизация между приложениями — необходимо обеспечить синхронизацию данных между серверами в кластере.&lt;/li&gt;
&lt;li&gt;Цена&lt;/li&gt;
&lt;li&gt;Сложность в управлении&lt;/li&gt;
&lt;li&gt;Необходимость адаптации приложения для работы в кластере (веб-ферме).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Ссылки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80_(%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D0%B0_%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BE%D0%B2)"&gt;Википедия: Кластер (группа компьютеров&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.soft4retail.ru/clustering"&gt;Кластеризация&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://studref.com/328799/informatika/klasternye_vychislitelnye_sistemy"&gt;Кластерные вычислительные системы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://citforum.ck.ua/hardware/app_kis/glava_5.shtml"&gt;Кластерные архитектуры&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D1%84%D0%B5%D1%80%D0%BC%D0%B0"&gt;Википедия: Серверная ферма&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.inventa.ru/service/catalog/cluster/hacluster.php"&gt;Отказоустойчивые кластеры (кластеры высокой доступности) &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Pipeline архитектура</title>
<guid isPermaLink="false">24</guid>
<link>https://www.stefaniuk.website/all/pipeline-architecture/</link>
<pubDate>Fri, 01 Mar 2019 15:27:04 -0400</pubDate>
<author></author>
<comments>https://www.stefaniuk.website/all/pipeline-architecture/</comments>
<description>
&lt;p&gt;Очень простая, надежная и достаточно мощная архитектура. Она состоит из множества фильтров, который фильтруют или обрабатывают информацию, прежде чем передать другим компонентам. Все фильтры работают одновременно. Архитектура часто используется как простая последовательность, но она также может использоваться для очень сложных структур.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/pipe.png" width="529" height="90" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Составляющие&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Фильтр — преобразует или фильтрует данные, которые он получает через каналы, с которыми он связан. Фильтр может иметь любое количество входных каналов и любое количество выходных каналов.&lt;/li&gt;
&lt;li&gt;Канал — это соединитель, который передает данные от одного фильтра к другому. Это направленный поток данных, который обычно реализуется буфером данных для хранения всех данных до тех пор, пока следующий фильтр не успеет их обработать.&lt;/li&gt;
&lt;li&gt;Продюсер — является источником данных. Это может быть статический текстовый файл или устройство ввода с клавиатуры, постоянно создающее новые данные.&lt;/li&gt;
&lt;li&gt;Приемник или потребитель является целью данных. Это может быть другой файл, база данных или экран компьютера.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Примеры&lt;/h2&gt;
&lt;p&gt;UNIX приложения, выход одной программы можно передать на вход в другую программу.&lt;/p&gt;
&lt;pre&gt;$ ps aux | grep [k]de | gawk ’{ print $2}’&lt;/pre&gt;
&lt;p&gt;&lt;small&gt;выводит на экран список процессов, которые содержат в имени kde&lt;/small&gt;&lt;br /&gt;
&lt;br&gt;&lt;br /&gt;
Компиляторы&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://www.stefaniuk.website/pictures/compillers.png" width="500" height="190" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Когда следует использовать этот шаблон&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Процесс обработки, требуемый приложением, можно легко разделить на ряд независимых этапов.&lt;/li&gt;
&lt;li&gt;У этапов обработки, которые выполняются приложением, разные требования к масштабируемости.&lt;/li&gt;
&lt;li&gt;Требуется определенная гибкость, чтобы изменять порядок шагов обработки, выполняемых приложением, или добавлять и удалять шаги.&lt;/li&gt;
&lt;li&gt;Система будет работать эффективнее, если распределить шаги обработки между несколькими серверами.&lt;/li&gt;
&lt;li&gt;Чтобы свести к минимуму последствия сбоя на шаге при обработке данных, требуется надежное решение&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Проблемы и рекомендации&lt;/h2&gt;
&lt;p&gt;При выборе схемы реализации этого шаблона следует учитывать следующие моменты.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Сложность — повышенная гибкость, которую обеспечивает этот шаблон, может также вызвать сложности, особенно если фильтры в конвейере распределяются между разными серверами.&lt;/li&gt;
&lt;li&gt;Надежность — используйте инфраструктуру, которая гарантирует сохранность данных, передаваемых между фильтрами в конвейере.&lt;/li&gt;
&lt;li&gt;Идемпотентность — свойство объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом. Если после получения сообщения происходит сбой фильтра в конвейере и операция переносится на другой экземпляр фильтра, часть операции может быть уже выполнена. Тем самым продолжение выполнения должно вернуть нам такой же результат.&lt;/li&gt;
&lt;li&gt;Повторяющиеся сообщения — если сбой фильтра в конвейере происходит после публикации сообщения для следующего этапа конвейера, может запуститься другой экземпляр фильтра и опубликовать копию этого сообщения в конвейере. Это может привести к передаче следующему фильтру двух экземпляров одного сообщения.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Достоинства&lt;/h2&gt;
&lt;p&gt;Ключевое преимущество конвейерной структуры заключается в том, что в ней можно параллельно выполнять экземпляры медленных фильтров, позволяя распределить нагрузку и повысить пропускную способность в системе.&lt;/p&gt;
&lt;h2&gt;Недостатки&lt;/h2&gt;
&lt;p&gt;Есть множество проблем, описанных выше, которые необходимо учесть при разработке.&lt;/p&gt;
&lt;h2&gt;Ссылки&lt;/h2&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;a href="http://www.cs.sjsu.edu/~pearce/modules/patterns/distArch/pipeline.htm"&gt;Pipeline Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=jMZviSKf3QU"&gt;YouTube: 101 способ приготовления RabbitMQ и о pipeline-архитектуре&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.highload.ru/2015/abstracts/1879.html"&gt;Текст: 101 способ приготовления RabbitMQ и о pipeline-архитектуре&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://highload.guide/blog/principles-and-methods-of-queuing.html"&gt;Принципы и приёмы обработки очередей&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/pipes-and-filters"&gt;Pipes and Filters pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dossier-andreas.net/software_architecture/pipe_and_filter.html"&gt;Pipe-And-Filter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/PipesAndFilters.html"&gt;Pipes and Filters&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>


</channel>
</rss>