Рефакторинг архитектуры

This commit is contained in:
Struchkov Mark 2024-11-17 19:37:00 +03:00
parent 9a5643fd64
commit 53849bae6b
No known key found for this signature in database
GPG Key ID: A3F0AC3F0FA52F3C
19 changed files with 160 additions and 34 deletions

View File

@ -40,7 +40,7 @@ linked:
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**:: [[../../../../knowledge/dev/Реактивное программирование|Реактивное программирование]]
**Родитель**:: [[Реактивное программирование|Реактивное программирование]]
**Источник**::
**Автор**::
**Создана**::

View File

@ -0,0 +1,55 @@
---
aliases:
- transactional outbox
- транзакционный аутбокс
tags:
- maturity/🌱
date: 2024-11-15
---
Transactional Outbox — это [[Паттерн проектирования|шаблон проектирования]], используемый в распределённых системах для обеспечения гарантированной отправки сообщений, особенно при интеграции с [[Брокер сообщений|брокерами сообщений]]. Этот шаблон помогает решить [[Отправка сообщений в Kafka из транзакции БД| проблему атомарности между изменениями в базе данных и отправкой событий]], гарантируя, что сообщение будет отправлено только после успешного выполнения транзакции в базе данных.
**Схема работы:**
1. При выполнении бизнес-операции, например, при изменении данных в базе данных, создаётся запись в таблице `outbox`. Эта запись содержит сообщение, которое нужно отправить другим сервисам.
2. Операция создания записи в таблице `outbox` происходит в одной транзакции с основной бизнес-операцией. Это гарантирует, что и изменение данных, и запись сообщения будут выполнены атомарно.
3. После успешной фиксации транзакции фоновый процесс или отдельный компонент читает сообщения из таблицы `outbox` и отправляет их в [[брокер сообщений]].
4. После успешной отправки сообщения запись в таблице outbox помечается как обработанная и спустя какое-то время удаляется.
**Преимущества:**
- **Гарантированная доставка сообщений**: сообщения фиксируются вместе с бизнес-операциями, что предотвращает ситуацию, когда данные в базе данных обновлены, а сообщение не отправлено.
- **Упрощение архитектуры**: использование таблицы `outbox` вместо распределённых транзакций (2PC) значительно упрощает архитектуру и позволяет избежать сложных механизмов блокировки.
**Недостатки:**
- **Дополнительная задержка**: отправка сообщений через фоновый процесс может вызвать небольшую задержку в доставке сообщений, по сравнению с немедленной отправкой.
- **Увеличение нагрузки на базу данных**: таблица `outbox` требует дополнительного хранения и управления, что увеличивает нагрузку на базу данных, особенно при большом объёме сообщений.
Сначала необходимо создать таблицу `outbox` в вашей базе данных для хранения сообщений, ожидающих отправки в Kafka.
Возможная структура `outbox` таблицы
```sql
CREATE TABLE outbox (
id BIGSERIAL PRIMARY KEY,
topic VARCHAR(255) NOT NULL,
payload TEXT NOT NULL,
status VARCHAR(20) DEFAULT 'PENDING',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
- `id`: Уникальный идентификатор записи.
- `topic`: Название топика/очереди, в который должно быть отправлено событие.
- `payload`: данные события.
- `status`: Статус обработки (`PENDING`, `SENT`, `FAILED`).
- `created_at` и `updated_at`: Временные метки для отслеживания создания и обновления записи.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**:: [[Паттерн проектирования]]
**Источник**::
**Создана**:: [[2024-11-15]]
**Автор**::
### Дополнительные материалы
- [[../../../../_inbox/Transactional Inbox|Transactional Inbox]]
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -3,11 +3,21 @@ aliases:
tags:
- maturity/🌱
date: 2024-10-01
zero-link:
- "[[../garden/ru/meta/zero/00 Архитектура ПО|00 Архитектура ПО]]"
parents:
linked:
---
Архитектурная концепция это общая идея или принцип построения архитектуры системы или отдельного компонента системы.
**Цель**:
- Определить базовые принципы, которые будут направлять разработку всей системы.
- Решать проблемы на уровне системы, а не отдельных компонентов.
## Классификация
На уровне системы:
- [[../../../../wiki/zero/Микросервисная архитектура|Микросервисная архитектура]]
- [[../../../../_inbox/Событийно-ориентированное программирование|Событийно-ориентированное программирование]]
- [[Асинхронное программирование]]
- [[Реактивное программирование|Реактивное программирование]]
На уровне компонентов системы:
- [[Inversion of Control]]
- [[Один клиент — один поток]]
- [[Много клиентов — один поток]]
@ -24,8 +34,11 @@ 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) -->
- [[Событийно-ориентированное программирование]]
- [[Микросервисная архитектура]]
- [[Inversion of Control]]
- [[Много клиентов — один поток]]
- [[Один клиент — один поток]]
- [[Паттерн проектирования]]
- [[Асинхронное программирование]]
<!-- SerializedQuery END -->

View File

@ -3,17 +3,14 @@ aliases:
tags:
- maturity/🌱
date: 2024-10-08
zero-link:
parents:
linked:
---
Асинхронность позволяет задачам выполняться в фоновом режиме, не блокируя основной поток программы. В синхронных операциях задача должна завершиться, прежде чем начнётся следующая, тогда как асинхронные задачи могут выполняться независимо, что особенно полезно для [[../architecture/Блокирующий вызов|блокирующих операций]].
Асинхронность позволяет задачам выполняться в фоновом режиме, не блокируя основной поток программы, тем самым реализуя [[Concurrency]]. В синхронных операциях задача должна завершиться, прежде чем начнётся следующая, тогда как асинхронные задачи могут выполняться независимо, что особенно полезно для [[../architecture/Блокирующий вызов|блокирующих операций]].
Асинхронное программирование делает программы более отзывчивыми, позволяя основному потоку продолжать выполнение других задач, пока асинхронная операция выполняется. После завершения такой операции программа может вернуться к её результатам. В Java для этого используется класс `CompletableFuture`.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
**Родитель**:: [[Concurrency]]
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**:: [[../architecture/Архитектурная концепция|Архитектурная концепция]]
**Источник**::
**Создана**:: [[2024-10-08]]
**Автор**::

View File

@ -1,5 +1,6 @@
---
aliases:
- брокерами сообщений
tags:
- maturity/🌱
date: 2024-07-02

View File

@ -13,8 +13,8 @@ date: 2024-09-11
Идемпотентность позволяет системе быть устойчивой к ошибкам и повторам — если запрос случайно повторится, это не приведет к нежелательным изменениям.
Примеры реализации:
- С использованием уникального идентификатора
**Примеры реализации:**
- [[highload/Идемпотентность на базе уникального идентификатора|Идемпотентность на базе уникального идентификатора]]
- Логика приложения устроена таким образом, что выполнение запроса с одними и теми же параметрами всегда приводит к одному и тому же результату.
***
## Мета информация

View File

@ -36,7 +36,7 @@ linked:
С ростом масштабов приложений, особенно в веб-разработке, стали популярны асинхронные и реактивные подходы, где один поток может обслуживать множество клиентов, не создавая новый поток для каждого запроса. Такие подходы позволяют лучше использовать ресурсы системы:
- **Асинхронные модели.** Серверы, такие как [[../../meta/zero/00 Nginx|Nginx]], используют [[../../../../_inbox/Событийно-ориентированное программирование|событийно-ориентированную архитектуру]], где запросы обрабатываются без необходимости создавать новый поток на каждый запрос. Это снижает потребление памяти и улучшает масштабируемость.
- [[../../../../knowledge/dev/Реактивное программирование|Реактивное программирование]]. В таких фреймворках, как [[../../meta/zero/00 Quarkus|Quarkus]], Vert.x или [[../../meta/zero/00 SpringBoot|Spring]] WebFlux, запросы обрабатываются асинхронно с использованием реактивных потоков, что позволяет эффективно распределять ресурсы даже при высокой нагрузке.
- [[Реактивное программирование|Реактивное программирование]]. В таких фреймворках, как [[../../meta/zero/00 Quarkus|Quarkus]], Vert.x или [[../../meta/zero/00 SpringBoot|Spring]] WebFlux, запросы обрабатываются асинхронно с использованием реактивных потоков, что позволяет эффективно распределять ресурсы даже при высокой нагрузке.
***
## Мета информация

View File

@ -0,0 +1,29 @@
---
aliases:
tags:
- maturity/🌱
date: 2024-11-15
---
Отправка сообщений в [[00 Kafka|Kafka]] из [[Транзакция БД|транзакций базы данных]] приводит к проблемам с согласованностью данных между системами, особенно в условиях распределённых систем. Если сначала происходит отправка сообщения в Kafka, а затем транзакция в БД откатывается, то сообщение останется в Kafka, но база данных не зафиксирует изменений, что приведёт к рассинхронизации данных.
Для обеспечения согласованности данных между базой данных и Kafka необходимо использовать следующие подходы:
- [[Transactional Outbox|Transactional Outbox]]. Этот подход позволяет отделить запись в базу данных от отправки сообщения в брокер. Изменения сначала фиксируются в основной таблице базы данных, а затем записываются в специальную таблицу "Outbox". Отдельный процесс или сервис асинхронно считывает из таблицы "Outbox" и отправляет сообщения в Kafka, что гарантирует согласованность данных.
- Change Data Capture (CDC). Использование CDC с инструментами вроде Debezium позволяет отслеживать изменения в базе данных и публиковать их в Kafka. Это решение подходит для случаев, когда необходимо обеспечить автоматическую синхронизацию изменений, но может потребовать дополнительных настроек и ресурсов.
- Распределённые транзакции (двухфазный коммит). Этот метод позволяет гарантировать согласованность между базой данных и Kafka за счёт координации транзакций между ними. Однако этот подход часто считается сложным и менее масштабируемым, особенно в распределённых системах.
Другая серьёзная проблема связана с возможностью двойной обработки. В случае сбоя приложения или инфраструктуры транзакции могут повторяться, приводя к дублированию событий в Kafka. Дублирование событий может вызвать некорректное состояние системы, повторное выполнение операций. Чтобы предотвратить дублирование, можно использовать следующие подходы:
- [[highload/Идемпотентность на базе уникального идентификатора|Идемпотентность на базе уникального идентификатора]]
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-11-15]]
**Автор**::
### Дополнительные материалы
-
### Дочерние заметки
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->

View File

@ -1,20 +1,17 @@
---
aliases:
- паттерн
- шаблон проектирования
tags:
- maturity/🌱
date: 2023-11-05
zero-link:
- "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]"
parents:
- "[[Архитектурная концепция]]"
linked:
---
- [[Dependency Injection]]
- [[Порождающий паттерн проектирования]]
- [[Builder Pattern|Builder Pattern]]: строит объекты поэтапно, разделяя процесс создания и внешний вид.
- Abstract Factory: создаёт группы связанных элементов.
- [[Builder Pattern|Builder Pattern]]: строит объекты поэтапно, разделяя процесс создания и внешний вид.
- Prototype: создаёт копии полностью подготовленных экземпляров.
- Singleton: One and Only — особый класс, имеющий только один экземпляр.
- Adapter: Universal Plug — соединяет объекты с разными интерфейсами.
@ -32,6 +29,9 @@ linked:
- Observer: News Broadcaster — уведомляет классы об изменениях в других объектах.
- Visitor: Skillful Guest — добавляет новые операции классу, не изменяя его.
- [[../../../../_inbox/Transactional Inbox|Transactional Inbox]]
- [[Transactional Outbox]]
***
## Мета информация
**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]
@ -44,6 +44,8 @@ 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) -->
- [[MVC]]
- [[Dependency Injection]]
- [[Порождающий паттерн проектирования]]
- [[Transactional Outbox]]
<!-- SerializedQuery END -->

View File

@ -0,0 +1,30 @@
---
aliases:
- реактивном программировании
tags:
- maturity/🌱
date: "[[2023-10-26]]"
zero-link:
- "[[../../meta/zero/00 Разработка|00 Разработка]]"
parents:
- "[[Парадигмы разработки]]"
linked:
---
**Реактивное программирование** — это парадигма, ориентированная на потоки данных и распространение изменений. Она использует асинхронные потоки данных (например, Observables в RxJava), которые позволяют обрабатывать события по мере их поступления с автоматическим управлением параллелизмом и асинхронностью.
**Реактивное программирование** используется для создания отзывчивых, устойчивых и масштабируемых систем, где важно быстро реагировать на поступающие данные, управляя backpressure (ситуация, когда данные поступают быстрее, чем могут быть обработаны) и обеспечивая неблокирующее взаимодействие.
***
## Мета информация
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
**Родитель**:: [[Архитектурная концепция]]
**Источник**::
**Автор**::
**Создана**:: [[2023-10-26]]
### Дополнительные материалы
- [Реактивное программирование на Java. Будущее, настоящее и прошлое](https://struchkov.dev/blog/ru/overview-of-reactive-programming/)
### Дочерние заметки
```dataview
LIST
FROM [[]]
WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link)
```

View File

@ -12,13 +12,13 @@ linked:
---
Конкурентность — это общий термин, описывающий способность программы обрабатывать несколько задач. ==Это не обязательно означает одновременное выполнение.==
- [[Parallelism]]. Физическое одновременное выполнение нескольких задач на разных ядрах или процессорах. Параллелизм является формой конкурентности, но требует аппаратной поддержки для одновременного выполнения.
[[Parallelism]]. Физическое одновременное выполнение нескольких задач на разных ядрах или процессорах. Параллелизм является формой конкурентности, но требует аппаратной поддержки для одновременного выполнения.
**Механизмы реализации конкурентности**
- [[Многозадачность|Multitasking]].
- [[Multithreading]]. Использование нескольких потоков внутри одного процесса. Потоки могут выполняться конкурентно, разделяя память и ресурсы процесса. Также требует механизма переключения контекстов, но на уровне потоков.
- [[Асинхронное программирование]]
- [[../../../../knowledge/dev/Реактивное программирование|Реактивное программирование]]
- [[../architecture/Асинхронное программирование]]
- [[../architecture/Реактивное программирование|Реактивное программирование]]
![[../../meta/files/images/telegram-cloud-photo-size-2-5271536941378167546-y.jpg]]
***
@ -33,6 +33,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) -->
- [[Асинхронное программирование]]
- [[Многозадачность]]
<!-- SerializedQuery END -->

View File

@ -89,7 +89,7 @@ private Tuple<String, Integer> fetchUserData() {
- Если потребуется передавать данные в другие классы в будущем.
- Если работа с данными требует дополнительной логики, такой как валидация или преобразование.
## Tuple в реактивном программировании
В [[../../../../knowledge/dev/Реактивное программирование|реактивном программировании]], особенно с использованием [[../../meta/zero/00 Quarkus|Quarkus]] и Mutiny, часто возникает необходимость передачи нескольких значений между стадиями реактивного потока данных. `Tuple` может быть удобным решением для объединения значений, особенно когда результат остаётся внутри потока и не становится частью публичного API.
В [[../architecture/Реактивное программирование|реактивном программировании]], особенно с использованием [[../../meta/zero/00 Quarkus|Quarkus]] и Mutiny, часто возникает необходимость передачи нескольких значений между стадиями реактивного потока данных. `Tuple` может быть удобным решением для объединения значений, особенно когда результат остаётся внутри потока и не становится частью публичного API.
Например, в реактивных пайпах могут использоваться такие структуры, как `Tuple2`, `Tuple3` и далее:

View File

@ -16,7 +16,7 @@ date: 2024-11-03
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**:: [[Протоколы коммуникаций|Протоколы коммуникаций]]
**Источник**::
**Создана**:: [[2024-11-03]]

View File

@ -15,7 +15,7 @@ date: 2024-11-03
- Удержание открытого соединения может быть менее эффективным для серверов с ограниченными ресурсами, особенно при большом количестве клиентов.
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-11-03]]

View File

@ -16,7 +16,7 @@ date: 2024-11-03
![[../../meta/files/images/Pasted image 20241103020635.png]]
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**:: [[Протоколы коммуникаций|Протоколы коммуникаций]]
**Источник**::
**Создана**:: [[2024-11-03]]

View File

@ -11,7 +11,7 @@ RPC (удалённый вызов процедур) — это **общая к
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-11-03]]

View File

@ -17,7 +17,7 @@ date: 2024-11-03
- Сложнее тестировать и отлаживать, так как вебхуки зависят от событий, происходящих на сервере.
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**:: [[Протоколы коммуникаций]]
**Источник**::
**Создана**:: [[2024-11-03]]

View File

@ -19,7 +19,7 @@ date: 2024-04-12
**Балансировка нагрузки L7 vs L4**: Kubernetes обычно использует балансировку нагрузки на уровне 4 (L4), которая перенаправляет трафик на основе информации IP и порта. Однако gRPC полагается на HTTP/2, что требует балансировки на уровне 7 (L7) для эффективного распределения запросов. Это может потребовать дополнительных настроек или использования специализированных ингресс-контроллеров, поддерживающих HTTP/2.
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**:: [[Remote Procedure Call|RPC]], [[Протоколы коммуникаций]]
**Источник**::
**Автор**::

View File

@ -23,7 +23,7 @@ date: 2024-11-03
- Уведомляет системы при наступлении событий
***
## Мета информация
**Область**:: [[../../meta/zero/00 System Design|00 System Design]]
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
**Родитель**::
**Источник**::
**Создана**:: [[2024-11-03]]
@ -34,9 +34,9 @@ date: 2024-11-03
### Дочерние заметки
<!-- 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) -->
- [[RESTful]]
- [[GraphQL]]
- [[gRPC]]
- [[RESTful]]
- [[Webhook]]
- [[gRPC]]
<!-- SerializedQuery END -->