This commit is contained in:
parent
9f78f2962b
commit
9a5643fd64
@ -1,6 +1,7 @@
|
||||
---
|
||||
aliases:
|
||||
- балансировку нагрузки
|
||||
- Балансировщик нагрузки
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-06-13
|
||||
|
@ -24,6 +24,9 @@ linked:
|
||||
2. **Сложность разработки**: Разработка приложений, способных эффективно использовать ресурсы в распределенной среде, может быть более сложной, а значит программисты обходятся дороже.
|
||||
3. **Согласованность данных**: Обеспечение согласованности данных между множеством узлов может представлять собой вызов, особенно в системах, где требуется высокий уровень согласованности.
|
||||
4. **Затраты на сеть**: Горизонтальное масштабирование может повлечь за собой увеличенные затраты на сетевое оборудование и управление сетью, особенно если узлы географически распределены.
|
||||
|
||||
Частные проблемы:
|
||||
- [[../Проблема горизонтального масштабирования Websocket|Проблема горизонтального масштабирования Websocket]]
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
@ -37,4 +40,5 @@ linked:
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
- [[garden/ru/dev/architecture/highload/Репликация.md|Репликация]]
|
||||
- [[Проблема горизонтального масштабирования Websocket]]
|
||||
<!-- SerializedQuery END -->
|
||||
|
@ -0,0 +1,33 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-11-12
|
||||
---
|
||||
При реализации [[../Идемпотентность|идемпотентности]] в системах, где требуется многократная обработка событий или вызовов, [[../../../meta/zero/00 Redis|Redis]] может быть использован как ключевой инструмент для предотвращения повторной обработки сообщений. Данное решение подходит для различных систем обмена сообщениями, таких как [[../../../../../_inbox/00 Kafka|Kafka]], [[../../system-design/gRPC|gRPC]], [[../../network/HTTP|HTTP]], и других видов асинхронных или синхронных вызовов.
|
||||
### Основной подход
|
||||
Каждое сообщение или запрос должен иметь уникальный идентификатор, обычно называемый **requestId**. Этот идентификатор присваивается при создании сообщения или вызова и передаётся вместе с ним в процессе обработки. Потребитель, получая сообщение, сначала проверяет наличие **requestId** в Redis. Этот подход позволяет контролировать, было ли сообщение уже обработано и в каком оно состоянии.
|
||||
|
||||
Алгоритм выглядит следующим образом:
|
||||
1. **Получение сообщения**: Потребитель получает сообщение, извлекает **requestId** и проверяет его наличие в Redis.
|
||||
1. Если **requestId** уже существует в Redis и статус обработки указывает на **COMPLETED**, потребитель ничего не делает и отправляет **ack** (подтверждение) в Kafka (или другой источник).
|
||||
2. **Обработка сообщения**: Если **requestId** отсутствует в Redis или статус обработки указывает на **FAILED**, потребитель, то потребитель обрабатывает сообщение. Перед обработкой статус в Redis обновляется на **IN_PROGRESS** с TTL, например, 40 секунд.
|
||||
3. **Запись результата**:
|
||||
- После успешной обработки статус в Redis обновляется на **COMPLETED**, и устанавливается длительный TTL, например, на 3-24 часа, чтобы сигнализировать, что это сообщение уже было успешно обработано и повторная обработка не требуется.
|
||||
- Если при обработке возникает ошибка, статус обновляется на **FAILED** и потребитель отправляет **nack** в Kafka (или другой источник).
|
||||
### Рекомендации по реализации
|
||||
- **Уникальность requestId**: Генерируйте **requestId** таким образом, чтобы обеспечить его уникальность в пределах всей системы, например, используя UUID или другие подходящие алгоритмы.
|
||||
- **Оптимальный TTL**: Выберите TTL в зависимости от требований к ретеншену данных. Слишком короткий TTL может привести к потере информации об обработке, а слишком длинный — к переполнению Redis.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[../Идемпотентность|Идемпотентность]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-11-12]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
@ -2,19 +2,20 @@
|
||||
aliases:
|
||||
- идемпотентны
|
||||
- идемпотентной
|
||||
- идемпотентности
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-11
|
||||
zero-link:
|
||||
- "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Идемпотентность — это свойство операции, при котором многократное выполнение этой операции с одинаковыми входными данными не изменяет результат после первого выполнения. Иными словами, независимо от того, сколько раз вы выполните операцию, итог будет одним и тем же.
|
||||
|
||||
Примером идемпотентной операции может быть запрос на установку значения, например, «установить цену товара в 100». Если отправить этот запрос несколько раз, цена останется 100, и результат не изменится. В противоположность этому, операция «увеличить цену на 10» не является идемпотентной, так как каждое выполнение увеличивает цену, и результат меняется.
|
||||
|
||||
Идемпотентность позволяет системе быть устойчивой к ошибкам и повторам — если запрос случайно повторится, это не приведет к нежелательным изменениям.
|
||||
|
||||
Примеры реализации:
|
||||
- С использованием уникального идентификатора
|
||||
- Логика приложения устроена таким образом, что выполнение запроса с одними и теми же параметрами всегда приводит к одному и тому же результату.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
|
||||
@ -27,3 +28,6 @@ linked:
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
- [[Идемпотентность на базе уникального идентификатора]]
|
||||
<!-- SerializedQuery END -->
|
||||
|
@ -0,0 +1,33 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-11-13
|
||||
---
|
||||
WebSocket-соединение, в отличие от [[../system-design/RESTful|REST]], имеет состояние, которое представлено объектом класса `Session`. Это создает трудности при горизонтальном масштабировании.
|
||||
|
||||
Представим, что наш сервис чатов развернут в Kubernetes с 3 репликами. Пользователь чата открывает три вкладки браузера с нашим онлайн-чатом. [[highload/Балансировка нагрузки|Балансировщик нагрузки]], использующий алгоритм round robin, распределяет соединения между тремя репликами, и каждое соединение (каждая вкладка) попадает на свою реплику.
|
||||
|
||||
Проблема заключается в том, что ==каждая реплика знает только о своих подключениях и не имеет информации о подключениях других реплик==. Если кто-то отправляет новое сообщение на первую реплику, пользователь увидит это сообщение только в той вкладке, которая подключена именно к этой реплике.
|
||||
|
||||
Есть несколько способов решить проблему масштабирования для сервисов, использующих WebSocket. Основные варианты включают:
|
||||
|
||||
1. **Не предпринимать никаких действий**. В некоторых приложениях строгая синхронизация между WebSocket-соединениями не требуется. Например, ==если ваше приложение только принимает сообщения или отправляет данные для всех пользователей, и вам не важно, из какой реплики они отправляются, возможно, нет необходимости решать эту проблему.==
|
||||
2. **Использовать другой алгоритм балансировки**. Вы можете настроить балансировку так, чтобы все соединения одного и того же чата всегда направлялись на одну и ту же реплику. Это может вызвать менее равномерное распределение нагрузки, но решит проблему синхронизации между репликами.
|
||||
3. [[Тонкий Websocket клиент]]
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[architecture/highload/Горизонтальное масштабирование|Горизонтальное масштабирование]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-11-13]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
- [[Тонкий Websocket клиент]]
|
||||
<!-- SerializedQuery END -->
|
||||
|
24
dev/architecture/Тонкий Websocket клиент.md
Normal file
24
dev/architecture/Тонкий Websocket клиент.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-11-13
|
||||
---
|
||||
При таком подхода вся логика по работе с Websoket соединениями переносится в отдельный сервис. WebSocket-сервис занимается только управлением соединениями и не выполняет бизнес-логику. Вся бизнес-логика обрабатывается отдельным сервисом, который не работает с WebSocket напрямую. Когда WebSocket-сервис получает сообщение, он пересылает его в бизнес-сервис через [[брокер сообщений]], например, [[../../../../_inbox/00 Kafka|Kafka]].
|
||||
|
||||
Бизнес-сервис обрабатывает сообщение и отправляет его обратно во все реплики WebSocket-сервиса, чтобы сообщение было доставлено всем участникам чата. Для того чтобы все реплики WebSocket-сервиса получали сообщение одновременно, можно использовать [[../../../../_inbox/00 Kafka|Kafka]] [[../../../../_inbox/Consumer Group|Consumer Group]].
|
||||
|
||||
![[../../meta/files/images/Pasted image 20241113184935.png]]
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
|
||||
**Родитель**:: [[Проблема горизонтального масштабирования Websocket]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-11-13]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
33
dev/kafka/Dead Letter Queue.md
Normal file
33
dev/kafka/Dead Letter Queue.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
aliases:
|
||||
- DLQ
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-11-12
|
||||
---
|
||||
**DLQ (Dead Letter Queue)** — это специальная очередь, используемая в системах обработки сообщений, таких как [[../../../../_inbox/00 Kafka|Kafka]], для хранения сообщений, которые не могут быть обработаны основным потребителем. Основное назначение DLQ — изолировать проблемные сообщения, чтобы они не блокировали остальную обработку и позволить команде разобраться с ними позже, не нарушая работы системы.
|
||||
|
||||
> [!WARNING] Не лечите симптом
|
||||
> Попадание событий в DLQ говорит о сбоях в работе системы, которые необходимо исправлять. Обработка DLQ делается на всякий случай и не является решением проблемы.
|
||||
|
||||
Подходы по обработке DLQ сообщений:
|
||||
- [[Перенос DLQ сообщений обратно в основной топик]]
|
||||
- **Анализ и исправление ошибок**: Можно настроить процесс, который анализирует причины неудачной обработки и предпринимает меры по их исправлению (например, корректировка данных или обновление логики обработки).
|
||||
- **Уведомления и алерты**: Настроить систему оповещений, которая уведомляет команду о наличии сообщений в DLQ, чтобы они могли вручную принять меры.
|
||||
- **Отложенная повторная обработка**: Использовать механизм отложенной повторной попытки с экспоненциальной задержкой, чтобы избежать постоянного быстрого переотправления сообщений.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[00 Kafka]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-11-12]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
<!-- SerializedQuery: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
- [[Перенос DLQ сообщений обратно в основной топик]]
|
||||
<!-- SerializedQuery END -->
|
||||
|
26
dev/kafka/Перенос DLQ сообщений обратно в основной топик.md
Normal file
26
dev/kafka/Перенос DLQ сообщений обратно в основной топик.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-11-12
|
||||
---
|
||||
Один из распространённых подходов к обработке сообщений из [[Dead Letter Queue|DLQ]] — это перенос их обратно в основной топик с использованием специального счётчика в заголовках сообщений для контроля количества попыток. Однако такой подход может иметь несколько недостатков:
|
||||
|
||||
1. **Порядок сообщений**: Возвращение сообщений в основной топик может нарушить порядок сообщений, что критично для приложений, где последовательность имеет значение.
|
||||
2. **Бесконечные циклы**: Если сообщение постоянно не удаётся обработать, оно может застрять в цикле между основным топиком и DLQ. Даже с ограничением по количеству попыток остаётся риск, что проблемные сообщения будут потреблять ресурсы без достижения результата.
|
||||
3. **Нагрузка на систему**: Повторная обработка сообщений увеличивает нагрузку на систему, что может повлиять на производительность и увеличить затраты на ресурсы.
|
||||
4. **Усложнение отладки**: Труднее отслеживать и отлаживать проблемы, когда сообщения постоянно перемещаются между топиками.
|
||||
5. **Потенциальные дублирования**: Возникает возможность появления дублирующихся сообщений, если не гарантируется [[../architecture/Идемпотентность|идемпотентность]] при обработке.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[00 Kafka]]
|
||||
**Родитель**:: [[Dead Letter Queue|Dead Letter Queue]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-11-12]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
BIN
meta/files/images/Pasted image 20241113184935.png
Normal file
BIN
meta/files/images/Pasted image 20241113184935.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 880 KiB |
BIN
meta/files/images/comp/Pasted image 20241113184935.png
Normal file
BIN
meta/files/images/comp/Pasted image 20241113184935.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 332 KiB |
@ -0,0 +1 @@
|
||||
4caec95bad8e91abd1bda6f41abe0da0
|
BIN
meta/files/images/webp/Pasted image 20241113184935.webp
Normal file
BIN
meta/files/images/webp/Pasted image 20241113184935.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 229 KiB |
@ -0,0 +1 @@
|
||||
4caec95bad8e91abd1bda6f41abe0da0
|
Loading…
Reference in New Issue
Block a user