This commit is contained in:
@@ -17,7 +17,7 @@ steps:
|
||||
- name: build site
|
||||
# https://hub.docker.com/r/library/docker
|
||||
pull: always
|
||||
image: docker.struchkov.dev/quartz:develop
|
||||
image: docker.struchkov.dev/quartz:v.4.4.7
|
||||
environment:
|
||||
GITHUB_SSH:
|
||||
from_secret: GITHUB_SSH
|
||||
@@ -66,6 +66,6 @@ steps:
|
||||
# drone sign --save upagge/digital-garden
|
||||
---
|
||||
kind: signature
|
||||
hmac: 136d4effa27f318fb6ff0cf16bc1bf7b20b428610832f7bdd8224c164a804e69
|
||||
hmac: fd5326b43706588aa4b35e24e551954df3dba6fc88e94c462ab91b9384ba0d6d
|
||||
|
||||
...
|
||||
|
||||
39
dev/Mapped Diagnostic Context.md
Normal file
39
dev/Mapped Diagnostic Context.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
aliases:
|
||||
- MDC
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-24
|
||||
---
|
||||
MDC — это структура данных, основанная на концепции ThreadLocal, которая позволяет привязать набор ключ-значение к текущему [[fundamental/Поток процесса ОС|потоку]] выполнения. Это значит, что для каждого потока можно задать свой уникальный контекст, который автоматически будет включаться в записи лога.
|
||||
|
||||
Например, с помощью MDC можно добавить в лог идентификатор запроса, информацию о пользователе или данные сессии. Эти данные впоследствии помогают отследить цепочку событий, относящихся к одному запросу или сессии, что значительно упрощает диагностику и анализ работы приложения.
|
||||
|
||||
**Зачем нужен MDC**
|
||||
- **Улучшение отладки и мониторинга:** Благодаря MDC в каждом сообщении лога оказывается дополнительная информация (например, request ID, user ID). Это помогает быстро сопоставить связанные события и понять, как обрабатывается конкретный запрос.
|
||||
- **Анализ в распределённых системах:** В [[../../../wiki/zero/00 Микросервисная архитектура|микросервисных архитектурах]] запрос может проходить через несколько сервисов. Использование MDC позволяет передавать и сохранять идентификаторы на протяжении всей цепочки вызовов, что существенно упрощает трассировку.
|
||||
- **Фильтрация и поиск логов:** С дополнительными метаданными логи становятся более структурированными. Это позволяет фильтровать и искать конкретные записи по значимым атрибутам, ускоряя процесс анализа инцидентов.
|
||||
|
||||
**Основные возможности MDC**
|
||||
- **Добавление контекста:** С помощью методов вроде `MDC.put(key, value)` можно установить необходимые данные, которые автоматически добавляются в каждую запись лога, если логгер настроен на их отображение.
|
||||
- **Получение и удаление контекста:** Методы `MDC.get(key)` и `MDC.remove(key)` позволяют получить или удалить конкретное значение, что важно для избежания утечек данных при повторном использовании потоков.
|
||||
- **Автоматическая интеграция с логгерами:** Многие современные логирующие библиотеки, такие как Logback, Log4j или SLF4J, имеют встроенную поддержку MDC. Это позволяет легко настраивать формат логов так, чтобы он автоматически включал информацию из MDC.
|
||||
|
||||
**Ограничения и нюансы использования**
|
||||
- **Привязка к потоку:** Поскольку MDC реализован через ThreadLocal, его данные по умолчанию привязаны к конкретному потоку. В асинхронных и реактивных системах, где управление потоками осуществляется динамически, может возникать необходимость вручную переносить данные MDC между потоками.
|
||||
- [[java/quarkus/Обеспечение корректного асинхронного выполнения в Quarkus|Обеспечение корректного асинхронного выполнения в Quarkus]]
|
||||
- **Ручное управление:** Чтобы избежать ошибок и утечек информации, рекомендуется всегда очищать MDC после завершения обработки запроса, например, с помощью конструкции `try-finally`.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-24]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
32
dev/NanoId.md
Normal file
32
dev/NanoId.md
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-10-30
|
||||
---
|
||||
NanoID — это генератор уникальных [[Идентификатор сущности|идентификаторов]], разработанный как альтернатива [[Universal Unique IDentifier|UUID]]. Он отличается компактностью, высокой скоростью генерации и повышенной криптографической стойкостью. Идентификаторы, созданные с помощью NanoID, используют алфавит из безопасных символов и могут быть настроены по длине.
|
||||
|
||||
**Основные характеристики NanoID**
|
||||
- Компактность. По умолчанию NanoID генерирует идентификаторы длиной 21 символ, что делает их короче UUID (36 символов) при схожем уровне уникальности.
|
||||
- Высокая скорость. Генерация NanoID происходит быстрее, чем UUID, поскольку использует оптимизированные алгоритмы и не требует сложных вычислений.
|
||||
- Криптографическая стойкость. В отличие от некоторых других генераторов идентификаторов, NanoID использует криптографически безопасный генератор случайных чисел, что делает его подходящим для задач, где важна защита от предсказуемости.
|
||||
- Настраиваемость. Можно изменить алфавит и длину идентификаторов в зависимости от требований системы.
|
||||
|
||||
NanoID идеально подходит для:
|
||||
- Генерации идентификаторов в веб-приложениях и API.
|
||||
- Создания ссылок с короткими, но уникальными значениями.
|
||||
- Использования в системах, где важна производительность и компактность.
|
||||
- Обеспечения защиты от предсказуемости идентификаторов.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-10-30]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
- Порт для Java [GitHub - aventrix/jnanoid: A unique string ID generator for Java.](https://github.com/aventrix/jnanoid)
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
31
dev/Time-Sorted Identifier.md
Normal file
31
dev/Time-Sorted Identifier.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
aliases:
|
||||
- TSID
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-10-30
|
||||
---
|
||||
TSID (Time-Sorted Identifier) — это тип уникального [[Идентификатор сущности|идентификатора]], который генерируется так, чтобы его можно было сортировать по времени создания. Он сочетает временную метку с дополнительными компонентами, обеспечивающими уникальность, что делает его особенно полезным для распределённых систем и [[../meta/zero/00 HighLoad|высоконагруженных приложений]].
|
||||
|
||||
**Основные характеристики TSID:**
|
||||
- Уникальность. Гарантирует отсутствие коллизий, даже при высокой скорости генерации и в распределённых средах.
|
||||
- Сортируемость по времени. Временная компонента в структуре TSID позволяет автоматически упорядочивать идентификаторы в хронологическом порядке, упрощая работу с базами данных и логами.
|
||||
- Компактность. В отличие от [[Universal Unique IDentifier|UUID]], TSID занимает меньше места, что снижает нагрузку на хранилище и каналы передачи данных.
|
||||
- Высокая производительность. Генерация TSID происходит быстро и не требует централизованного сервера, что делает этот тип идентификаторов эффективным для масштабируемых систем.
|
||||
|
||||
**Альтернативы TSID:**
|
||||
- [[Universal Unique IDentifier|Universal Unique IDentifier]] — широко используемый уникальный идентификатор, но не гарантирует временную сортируемость.
|
||||
- [[NanoId]] — компактный идентификатор, генерируемый случайным образом, но без встроенной поддержки сортировки по времени.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[Идентификатор сущности]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-10-30]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
- [The best UUID type for a database Primary Key - Vlad Mihalcea](https://vladmihalcea.com/uuid-database-primary-key/)
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -4,9 +4,6 @@ aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2023-11-12
|
||||
zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
**UUID (Universal Unique IDentifier)** — это 128-битный идентификатор, представленный в виде строки. Однако для пользовательских данных доступно только 122 бита, так как 6 бит зарезервировано:
|
||||
- 4 бита используются для указания версии UUID;
|
||||
@@ -135,13 +132,13 @@ UUID V7 может иметь несколько типов генерации,
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Родитель**:: [[Идентификатор сущности|Идентификатор сущности]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2023-11-12]]
|
||||
### Дополнительные материалы
|
||||
- [ID-баттл: UUID vs автоинкремент / Валентин Удальцов - YouTube](https://www.youtube.com/watch?v=Xr_SNd9LIng&t=1762s)
|
||||
- [Библиотека для генерации UUID в Java. Все версии](https://github.com/f4b6a3/uuid-creator)
|
||||
- [[../../../_inbox/Автоинкремент|Автоинкремент]]
|
||||
- [[database/other/Автоинкремент в БД|Автоинкремент в БД]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
51
dev/database/other/Автоинкремент в БД.md
Normal file
51
dev/database/other/Автоинкремент в БД.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
aliases:
|
||||
- автоинкремент
|
||||
- sequence
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-18
|
||||
---
|
||||
Автоинкремент — это механизм [[../../../meta/zero/00 Реляционная база данных|баз данных]], который автоматически увеличивает значение числового идентификатора при добавлении новой записи. Обычно он используется для генерации уникальных первичных ключей.
|
||||
|
||||
Для работы автоинкремента ==требуется место, где хранится последнее сгенерированное значение.== В разных СУБД это может быть реализовано через:
|
||||
- **Sequences** (например, `CREATE SEQUENCE` в PostgreSQL, Oracle);
|
||||
- **Auto-increment fields** (например, `AUTO_INCREMENT` в MySQL, `IDENTITY` в SQL Server);
|
||||
- **Таблицы-счетчики** (редко используемый способ, если СУБД не поддерживает автоинкремент напрямую).
|
||||
|
||||
При добавлении новой строки в таблицу БД получает следующее доступное значение из последовательности или автоинкрементного счетчика и использует его как идентификатор.
|
||||
|
||||
**Плюсы автоинкремента**
|
||||
- **Сортируемость**. Поскольку значения увеличиваются последовательно, записи автоматически упорядочиваются по времени вставки.
|
||||
- **Легко читаемый и запоминаемый**. Числовые идентификаторы проще воспринимать, чем длинные [[../../Universal Unique IDentifier|UUID]].
|
||||
- **Оптимизация индексов**. Последовательные ключи могут работать быстрее в [[../Индекс базы данных|индексах]], поскольку новые данные добавляются в конец индекса, а не в случайные позиции (актуально для [[../../fundamental/structure/B-tree|B-деревьев]]).
|
||||
- **Проще отлаживать**. В логах легче сопоставлять записи с их идентификаторами.
|
||||
|
||||
**Минусы автоинкремента**
|
||||
- **Можно предсказать количество записей**. Последовательные идентификаторы позволяют злоумышленникам оценить активность системы, например, количество заказов в интернет-магазине.
|
||||
- **Легкость перебора записей**. Зная один идентификатор, можно предполагать другие и пытаться получать не авторизованные данные.
|
||||
- **Конечный диапазон значений**. У каждого типа данных есть границы (например, `BIGINT` в PostgreSQL поддерживает максимум `9,223,372,036,854,775,807` записей).
|
||||
- **Не хранит дополнительную информацию**. В отличие от UUID, автоинкрементные идентификаторы не содержат метаданных, например, о времени создания или сервере, который их сгенерировал.
|
||||
|
||||
Если необходимо скрыть количество записей или усложнить перебор ID, можно использовать:
|
||||
- [[../../Universal Unique IDentifier|UUID]]. Позволяет избежать предсказуемости, но увеличивает размер индексов.
|
||||
- **Случайные ID**. Вместо автоинкремента можно генерировать случайные числа.
|
||||
- **Маскирование ID**. Например, через хеширование (`SHA-256`) или кодирование (`Base62`).
|
||||
- **Salted-ключи**. Добавление уникального префикса к числам (например, `ORD-1001`).
|
||||
### Преобразование автоинкремента в UUID
|
||||

|
||||
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[../../Идентификатор сущности|Идентификатор сущности]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-18]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
108
dev/database/other/Миграция с UUID на автоинкремент.md
Normal file
108
dev/database/other/Миграция с UUID на автоинкремент.md
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-18
|
||||
---
|
||||
В этой заметке описывается процесс миграции с [[../../Universal Unique IDentifier|UUID]] на [[Автоинкремент в БД]]
|
||||
|
||||
Подготовка и анализ зависимостей
|
||||
- Нет ли в других таблицах внешних ключей (FK), ссылающихся на старую колонку UUID.
|
||||
- Проверьте код приложения, API, скрипты: не используют ли они явным образом старый тип ключа или его формат.
|
||||
|
||||
Создание нового столбца
|
||||
- Создайте новую колонку с типом `BIGINT` (или `BIGSERIAL`, если используете PostgreSQL).
|
||||
- Если требуется, создайте последовательность:
|
||||
|
||||
```sql
|
||||
CREATE SEQUENCE your_table_id_seq;
|
||||
```
|
||||
|
||||
Назначьте этой колонке `DEFAULT`, чтобы при вставке новых данных значение генерировалось автоматически:
|
||||
|
||||
```sql
|
||||
ALTER TABLE your_table
|
||||
ALTER COLUMN temp_id SET DEFAULT nextval('your_table_id_seq');
|
||||
```
|
||||
|
||||
Сделайте колонку `NOT NULL` (если уверены, что в ней не должно быть пропусков):
|
||||
|
||||
```sql
|
||||
ALTER TABLE your_table
|
||||
ALTER COLUMN temp_id SET NOT NULL;
|
||||
```
|
||||
|
||||
Заполнение новой колонки (бэкфил). Обновите существующие записи, чтобы у каждой строки появилось уникальное значение:
|
||||
```sql
|
||||
UPDATE your_table
|
||||
SET temp_id = nextval('your_table_id_seq');
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Если важен порядок (например, по дате создания), можно использовать более сложный запрос с сортировкой.
|
||||
|
||||
Переключение на новый ключ
|
||||
- Удалите внешние ключи, если они указывали на старую колонку-ключ.
|
||||
- Удалите или переименуйте старую колонку:
|
||||
|
||||
```sql
|
||||
ALTER TABLE your_table DROP COLUMN old_uuid_column;
|
||||
```
|
||||
или:
|
||||
```sql
|
||||
ALTER TABLE your_table RENAME COLUMN old_uuid_column TO uuid_backup;
|
||||
```
|
||||
|
||||
Переименуйте `temp_id` в `id`:
|
||||
```sql
|
||||
ALTER TABLE your_table
|
||||
RENAME COLUMN temp_id TO id;
|
||||
```
|
||||
|
||||
Добавьте первичный ключ:
|
||||
```sql
|
||||
ALTER TABLE your_table
|
||||
ADD CONSTRAINT your_table_pkey PRIMARY KEY (id);
|
||||
```
|
||||
|
||||
- Если были внешние ключи, которые ссылаются на старый UUID, обновите их или добавьте новые, ссылающиеся на новую колонку.
|
||||
- Проверьте код приложения: там, где раньше ожидался UUID, теперь будет число. При необходимости скорректируйте схемы, DTO, сервисы и т. п.
|
||||
### Пример миграции с Liquibase
|
||||
Добавление нового столбца с автоинкрементом
|
||||
```xml
|
||||
<changeSet id="1" author="dev">
|
||||
<addColumn tableName="your_table">
|
||||
<column name="temp_id" type="BIGINT" autoIncrement="true"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
```
|
||||
|
||||
Заполнение нового столбца значениями
|
||||
```xml
|
||||
<changeSet id="2" author="dev">
|
||||
<sql>UPDATE your_table SET temp_id = nextval('your_table_id_seq');</sql>
|
||||
</changeSet>
|
||||
```
|
||||
|
||||
Удаление старого UUID и установка нового первичного ключа
|
||||
```xml
|
||||
<changeSet id="3" author="dev">
|
||||
<dropPrimaryKey tableName="your_table" constraintName="your_table_pkey"/>
|
||||
<dropColumn tableName="your_table" columnName="old_uuid_column"/>
|
||||
<renameColumn tableName="your_table" oldColumnName="temp_id" newColumnName="id"/>
|
||||
<addPrimaryKey tableName="your_table" columnNames="id" constraintName="your_table_pkey"/>
|
||||
</changeSet>
|
||||
```
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-18]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -5,6 +5,7 @@ aliases:
|
||||
- индексы
|
||||
- индексирования
|
||||
- индекса
|
||||
- индексах
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-10-11
|
||||
|
||||
27
dev/devops/other/Автоматическая диагностика в Gitea.md
Normal file
27
dev/devops/other/Автоматическая диагностика в Gitea.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
aliases:
|
||||
- самодиагностику Gitea
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-05
|
||||
---
|
||||
```shell
|
||||
gitea doctor check
|
||||
```
|
||||
|
||||
```shell
|
||||
docker exec -it gitea su git -c "gitea doctor check"
|
||||
```
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Gitea|00 Gitea]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-05]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
- content/problem
|
||||
date: 2025-02-04
|
||||
---
|
||||
В какой-то момент я обнаружил, что мой сервер (Процессор: 2 core Память: 4 Gb Хранилище: 60 Gb) на котором запущена Gitea стал потреблять много ресурсов.
|
||||
|
||||
```
|
||||
top -o %CPU -b -n 1 | head -20
|
||||
```
|
||||
|
||||
Cудя по top, основным потребителем CPU является Gitea, которая занимает 22,7% CPU и использует 61,6% оперативной памяти. Также увидел несколько активных процессов git, которые могут быть вызваны Gitea для обработки репозиториев, и они тоже нагружают CPU.
|
||||
|
||||
Следующим шагом я проверил логи контейнера
|
||||
|
||||
```
|
||||
docker logs --tail 50 gitea
|
||||
```
|
||||
|
||||
По логам увидел, что у меня много **медленных запросов (slow GET)**, связанных с:
|
||||
1. Обработкой коммитов и blame (история изменений файлов)
|
||||
2. Доступом к файлам в репозиториях
|
||||
3. Работой с RSS и raw-файлами
|
||||
4. Запросами на поиск и скачивание контента
|
||||
|
||||
Кроме того, встречались 404-ошибки, которые могут указывать на частые обращения к несуществующим ресурсам.
|
||||
|
||||
Далее я проверил активные процессы Gitea
|
||||
|
||||
```
|
||||
docker exec -it gitea top -b -n 1
|
||||
```
|
||||
|
||||
Gitea активно выполняла много процессов Git, связанных с read-tree, rev-list, cat-file, check-attr и batch-check. Это говорило о том, что Gitea либо индексирует файлы, либо выполняет операции, связанные с доступом к репозиториям:
|
||||
- read-tree → Чтение структуры репозитория.
|
||||
- log -1 → Получение последнего коммита для файла.
|
||||
- cat-file --batch → Доступ к содержимому файлов.
|
||||
|
||||
Это может быть вызвано:
|
||||
1. [[Фоновые задачи Gitea|Фоновыми задачи Gitea]].
|
||||
2. **Запросами от пользователей** — если кто-то активно использует Gitea через UI. Но у меня персональный Git хостинг, никто кроме меня им не пользуется.
|
||||
3. **Запросы от ботов** - какие-нибудь парсеры, особенно если пользователей в Gitea не много.
|
||||
4. **Webhooks или интеграциями** — если какие-то сервисы взаимодействуют с Gitea. Интеграция у меня была только с Drone CI, которая вряд ли может создавать такую нагрузку.
|
||||
|
||||
|
||||
|
||||
Перед дальнейшими действиям, я решил провести [[Автоматическая диагностика в Gitea|самодиагностику Gitea]]. Но все проверки были успешно пройдены.
|
||||
## Отключение переодических задач
|
||||
Я решил, что проблема в [[Фоновые задачи Gitea|фоновых задачах Gitea]]. Тем более, что у меня было много репозиториев зеркал, которые стягивались с GitHub. Так что мой следующий шаг: Проверить фоновые задачи в Gitea. Это можно сделать или запросом, или через панель управления в UI.
|
||||
|
||||
```
|
||||
curl -X GET "http://localhost:3000/api/v1/admin/cron" -H "Authorization: token YOUR_ACCESS_TOKEN"
|
||||
```
|
||||
|
||||
Далее я отключил сначала все фоновые задачи и оставил только важные. И на первый взгляд показалось, что это помогло.
|
||||
|
||||
Однако спустя час Gitea снова потребляла CPU (41,2%) и память (13,7%). Кроме того, снова был запущен процесс git (17,6% CPU), что говорило о том, что Gitea выполняет какие-то операции с репозиториями. Хотя пользователей в это время не было.
|
||||
## Запросы от ботов
|
||||
Как я уже говорил это мой персональный публичный Git хостинг, так что им пользуюсь только я. Но он публичный, и я предположил, что возможно какие-то парсеры могут постоянно сканировать репозитории, например в надежде получить какие-нибудь случайно опубликованные ключи доступа.
|
||||
|
||||
Я решил проверить эту гипотезу.
|
||||
|
||||
|
||||
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Gitea|00 Gitea]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-04]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
68
dev/devops/other/Проверка get запросов к Gitea.md
Normal file
68
dev/devops/other/Проверка get запросов к Gitea.md
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-05
|
||||
---
|
||||
Это команда покажет, какие операции в Gitea происходят чаще всего за последние 8 часов.
|
||||
|
||||
```shell
|
||||
docker logs gitea --since "8h" | grep "router: completed GET" | awk '{print $NF}' | sort | uniq -c | sort -nr | head -20
|
||||
```
|
||||
|
||||
Пример вывода:
|
||||
```
|
||||
grep: (стандартный ввод): двоичный файл совпадает
|
||||
6933 repo/view_home.go:314(repo.Home)
|
||||
1332 repo/commit.go:44(repo.RefCommits)
|
||||
860 <autogenerated>:1(WebNotFound)
|
||||
824 repo/download.go:111(repo.SingleDownload)
|
||||
805 repo/blame.go:42(repo.RefBlame)
|
||||
531 context/repo.go:401(context.RepoAssignment)
|
||||
88 repo/issue_list.go:750(repo.Issues)
|
||||
56 repo/commit.go:279(repo.Diff)
|
||||
23 repo/commit.go:410(repo.RawDiff)
|
||||
21 auth/auth.go:179(auth.SignIn)
|
||||
9 repo/download.go:123(repo.SingleDownloadOrLFS)
|
||||
9 feed/render.go:11(feed.RenderBranchFeed)
|
||||
7 repo/milestone.go:244(repo.MilestoneIssuesAndPulls)
|
||||
6 misc/misc.go:36(misc.RobotsTxt)
|
||||
5 repo/find.go:19(repo.FindFiles)
|
||||
4 repo/compare.go:708(repo.CompareDiff)
|
||||
3 repo/milestone.go:34(repo.Milestones)
|
||||
1 web/goget.go:20(web.goGet)
|
||||
1 repo/treelist.go:17(repo.TreeList)
|
||||
1 repo/repo.go:469(repo.Download)
|
||||
```
|
||||
|
||||
- **repo/view_home.go:314(repo.Home) → 6933 запросов**
|
||||
- Главная страница репозитория (обзор файлов, README).
|
||||
- Может быть вызвано частым обновлением страниц пользователями или ботами.
|
||||
- **repo/commit.go:44(repo.RefCommits) → 1332 запросов**
|
||||
- Просмотр списка коммитов в репозитории.
|
||||
- Может быть вызвано активной работой разработчиков или парсерами.
|
||||
- **\<autogenerated\>:1(WebNotFound) → 860 ошибок 404**
|
||||
- Кто-то (или что-то) запрашивает несуществующие страницы.
|
||||
- Возможные причины:
|
||||
- Боты, сканирующие сайт (поиск уязвимостей).
|
||||
- Пользователи, переходящие по несуществующим ссылкам.
|
||||
- Неправильные ссылки в коде (например, старые или сломанные URL).
|
||||
- **repo/download.go:111(repo.SingleDownload) → 824 запросов**
|
||||
- Загрузка файлов из репозитория.
|
||||
- Если это **LFS-файлы**, то они могут быть **очень большими**, что увеличивает нагрузку на CPU и сеть.
|
||||
- **repo/blame.go:42(repo.RefBlame) → 805 запросов**
|
||||
- Просмотр истории изменений в файле (git blame).
|
||||
- Очень тяжёлая операция, особенно для больших файлов.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**::
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-05]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
90
dev/devops/other/Фоновые задачи Gitea.md
Normal file
90
dev/devops/other/Фоновые задачи Gitea.md
Normal file
@@ -0,0 +1,90 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-04
|
||||
---
|
||||
Вот список основных задач (cron-задач), которые Gitea выполняет по расписанию:
|
||||
### Задача `start_schedule_tasks`
|
||||
Задача `start_schedule_tasks` в Gitea отвечает за **запуск всех запланированных фоновых задач**, которые должны выполняться через определенные интервалы времени. Она запускается **каждую минуту**.
|
||||
|
||||
### Задача `update_mirrors`
|
||||
- Проверяет обновления в зеркалах (mirror repositories) и синхронизирует их.
|
||||
- Если у тебя есть зеркала репозиториев, теперь они не будут автоматически обновляться.
|
||||
### Задача `repo_health_check`
|
||||
- Проверяет репозитории на повреждения (например, отсутствующие файлы или некорректные коммиты).
|
||||
- Если репозитории работают стабильно, проблем не будет, но в долгосрочной перспективе могут появиться “битые” репозитории, если что-то сломается.
|
||||
### Задача `check_repo_stats`
|
||||
- Пересчитывает количество коммитов, изменений, контрибьюторов.
|
||||
### Задача `archive_cleanup`
|
||||
- Удаляет временные архивы (.zip, .tar.gz), созданные при скачивании репозиториев.
|
||||
- Без этой задачи дисковое пространство может постепенно заполняться ненужными файлами.
|
||||
### Задача `deleted_branches_cleanup`
|
||||
- Удаляет метаданные о ветках, которые были удалены.
|
||||
- Без этой задачи дисковое пространство может постепенно заполняться ненужными файлами.
|
||||
### Задача `cleanup_packages`
|
||||
- Очищает устаревшие пакеты из Gitea Package Registry.
|
||||
- Если ты используешь Gitea для хранения артефактов (например, Docker-образов, Maven-пакетов), они могут оставаться в системе навсегда.
|
||||
|
||||
### Задачи `stop_zombie_tasks` и `stop_endless_tasks`
|
||||
- Останавливает фоновые задачи, которые зависли или выполняются бесконечно.
|
||||
- Если в Gitea зависнет процесс (например, Git-команда или индексация), он может остаться активным навсегда и жрать ресурсы.
|
||||
### Задача `cleanup_hook_task_table`
|
||||
- Удаляет старые уведомления о системных событиях.
|
||||
- Если у тебя много пользователей, база данных может расти из-за ненужных логов.
|
||||
### Задача `git_gc_repos`
|
||||
- Запускает git gc (сборщик мусора) для репозиториев, чтобы оптимизировать их размер.
|
||||
- Если ты часто пушишь большие файлы, размер репозиториев может расти быстрее, чем обычно.
|
||||
### Задача `gc_lfs`
|
||||
- Удаляет устаревшие файлы из Git LFS (если используется).
|
||||
- Если у тебя включен Git LFS, репозитории могут занимать больше места, чем нужно.
|
||||
|
||||
## Включаем только важные задачи
|
||||
Для экономии ресурсов процессора можно включить только важные задачи
|
||||
|
||||
```shell
|
||||
nano /data/gitea/conf/app.ini
|
||||
```
|
||||
|
||||
```toml
|
||||
[cron]
|
||||
ENABLED = false
|
||||
|
||||
[cron.cleanup_packages]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
|
||||
[cron.archive_cleanup]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
|
||||
[cron.deleted_branches_cleanup]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
|
||||
[cron.cleanup_hook_task_table]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
|
||||
[cron.git_gc_repos]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
```
|
||||
|
||||
```
|
||||
docker restart gitea
|
||||
```
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Gitea|00 Gitea]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-04]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
---
|
||||
aliases:
|
||||
aliases:
|
||||
- сениор
|
||||
- мидл
|
||||
- джун
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-10-22
|
||||
@@ -29,7 +32,7 @@ date: 2024-10-22
|
||||
Самостоятельность на уровне синьора максимальна. Он может работать как над конкретной задачей, так и принимать участие в стратегическом планировании проекта. В отличие от мидла, синьор способен не только реализовывать технические решения, но и формировать их на уровне концепций, выбирая наилучшие пути реализации. Для него важен результат, и он умеет находить пути его достижения с минимальными затратами времени и ресурсов.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-10-22]]
|
||||
58
dev/efficiency/Ответственность за сервисы.md
Normal file
58
dev/efficiency/Ответственность за сервисы.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-13
|
||||
---
|
||||
В каждом сервисе есть два ответственных: это обеспечивает баланс нагрузки, взаимный контроль, а также непрерывность работы в случае отсутствия одного из них. ==У каждого сервиса должны быть ответственные разработчики. В противном случае сервис превращается в "ничей" и становится легаси.==
|
||||
|
||||
- **Старший ответственный** — обладает правами maintainer-а, но при этом также проходит код-ревью. Обычно это [[Грейды разработчиков|сениор]] или крепкий [[Грейды разработчиков|мидл]].
|
||||
- **Младший ответственный** — поддерживает основного ответственного и заменяет его в случае отсутствия. Обычно это [[Грейды разработчиков|джун]] или [[Грейды разработчиков|мидл]], который забирает на себя рутинные задачи и учится у своего старшего коллеги.
|
||||
|
||||
**Общие обязанности ответственных:**
|
||||
- Заполнять [[Сhangelog изменений сервисов|changelog]] для всех изменений в сервисе.
|
||||
- Проводить и участвовать в технических встречах для обсуждения текущего состояния, проблем и планов по развитию сервиса.
|
||||
- Разрабатывать и поддерживать документацию сервиса.
|
||||
|
||||
**Обязанности старшего ответственного:**
|
||||
- Обеспечивать техническую реализацию сервиса, включая разработку и исправление ошибок.
|
||||
- Осуществлять основной технический контроль качества и проводить код-ревью.
|
||||
- Консультировать другие команды по вопросам работы сервиса.
|
||||
|
||||
**Полномочия старшего ответственного:**
|
||||
- В случае необходимости передавать код-ревью младшему ответственному.
|
||||
- Мержить доработки в сервис после прохождения ревью
|
||||
|
||||
**Обязанности младшего ответственного:**
|
||||
- Выполнять обязанности основного ответственного в его отсутствие.
|
||||
- Помогать в проведении код-ревью.
|
||||
- Участвовать в разработке и исправлении ошибок.
|
||||
- Консультировать другие команды по вопросам работы сервиса.
|
||||
|
||||
**Контроль изменений в сервисе**
|
||||
- Младший ответственный назначает на ревью старшего, старший — младшего.
|
||||
- Если разработку выполняет не ответственный за сервис, то ревью проводит старший ответственный. Он может передать ревью младшему ответственному.
|
||||
- Все изменения должны проходить код-ревью ответственных за сервис, чтобы избежать хаотичных доработок.
|
||||
- В случае разногласий между старшим и младшим ответственными изменения обсуждаются с архитектором и/или техлидом.
|
||||
|
||||
**Процесс передачи ответственности**
|
||||
- Если старший ответственный уходит из компании или переводится на другой проект, архитектор модуля определяет нового старшего ответственного. Это может быть назначение младшего на эту роль или поиск нового кандидата.
|
||||
- До официального назначения нового старшего младший временно выполняет его обязанности.
|
||||
- В системе должен быть актуальный список сервисов с указанием ответственных разработчиков.
|
||||
|
||||
**Принятие значительных изменений в архитектуре сервиса**
|
||||
- Решения о значительных изменениях принимаются на технических обсуждениях с архитектором модуля.
|
||||
- В качестве утверждающего органа выступает техлид и/или архитектор.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-13]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
113
dev/efficiency/Сhangelog изменений сервисов.md
Normal file
113
dev/efficiency/Сhangelog изменений сервисов.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
aliases:
|
||||
- changelog
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-13
|
||||
---
|
||||
Changelog (журнал изменений) — это больше, чем просто список исправлений и новых фич. Это коммуникационный мост между разными участниками продуктовой команды и будущими версиями системы. Это способ зафиксировать эволюцию продукта, сделать его предсказуемым и понятным, а также избежать хаоса, который неизбежно наступает, когда изменения теряются в глубинах репозиториев или устных обсуждений.
|
||||
|
||||
Changelog — это структурированный журнал изменений в сервисе или продукте. Хороший сhangelog отвечает на три ключевых вопроса:
|
||||
1. **Что изменилось?** (новые возможности, исправления, улучшения, депрекейшены)
|
||||
2. **Почему это изменилось?** (какие проблемы решены, какие задачи стояли)
|
||||
3. **Как это влияет на систему и пользователей?** (что нужно учесть при обновлении, есть ли [[../other/Backward compatibility|backward compatibility]])
|
||||
|
||||
**Зачем это нужно?**
|
||||
- **Прозрачность**. Разработчики, DevOps-инженеры и даже пользователи должны понимать, что происходит с системой и как это влияет на их работу.
|
||||
- **История развития**. Changelog фиксирует техническую эволюцию проекта и помогает анализировать причины изменений.
|
||||
- Обратная совместимость. Понимание изменений помогает избежать неожиданных проблем при обновлении версий.
|
||||
- **Взаимодействие с пользователями и заказчиками**. Хорошо написанный changelog упрощает адаптацию пользователей к новым версиям, а также служит маркетинговым инструментом, демонстрируя активное развитие продукта.
|
||||
|
||||
**Ограничения и возможные проблемы**
|
||||
- **Слабая структура и хаос**. Если changelog ведется нерегулярно или его формат непоследователен, он теряет свою пользу.
|
||||
- **Избыточность**. Если changelog превращается в поток технических подробностей, понятных только разработчикам, он перестает быть полезным.
|
||||
- **Недостаточная детализация**. Формулировка «Исправлены баги» или «Улучшена производительность» не дает читателям никакой полезной информации.
|
||||
|
||||
**Типовая структура**
|
||||
- **Изменения API**. Включает все изменения, влияющие на взаимодействие с внешними системами и пользователями API:
|
||||
- Добавлено: новые эндпоинты, новые параметры запросов/ответов.
|
||||
- Изменено: изменения контрактов API, изменения кодов ответов, обновление документации API.
|
||||
- Удалено: устаревшие эндпоинты или версии API, удаленные параметры запросов/ответов.
|
||||
- Введение новых ограничений (rate-limiting, авторизация и т. д.).
|
||||
- **Изменения межсервисных взаимодействий**. Фиксируются изменения в том, какие сервисы вызывают друг друга и зачем. Сюда не включаются изменения API.
|
||||
- Начали вызывать новый сервис.
|
||||
- Перестали вызывать сервис
|
||||
- Изменена схема вызова между сервисами
|
||||
- billing теперь вызывается асинхронно через очередь вместо синхронного REST-запроса.
|
||||
- **Изменения конфигураций**. Фиксирует изменения, влияющие на настройки системы:
|
||||
- Новые переменные окружения.
|
||||
- Изменение значений конфигурационных параметров.
|
||||
- Введение новых фич-флагов.
|
||||
- Изменения в форматах конфигурационных файлов.
|
||||
- **Исправления багов**. Список устраненных проблем, влияющих на работу системы:
|
||||
- Критические фиксы, вызывавшие падения или утечки памяти.
|
||||
- Исправления в логике расчетов, валидации данных, обработке ошибок.
|
||||
- Баги, связанные с интеграциями и совместимостью.
|
||||
- Обновления зависимостей, исправляющие известные уязвимости.
|
||||
- **Новый функционал**. В этом разделе фиксируются все новые возможности, которые появляются в системе:
|
||||
- **Добавленные фичи**. Новые возможности, модули, крупные изменения в логике работы сервиса.
|
||||
- **Новые сценарии использования**, появившиеся после обновления.
|
||||
- **Поддержка новых технологий и интеграций**.
|
||||
- **Технические изменения**. Изменения, которые не влияют напрямую на API, но важны для работы системы:
|
||||
- Оптимизация алгоритмов и производительности.
|
||||
- Рефакторинг кода и переработка архитектуры.
|
||||
- Улучшение логирования (новые уровни логов, новые метрики).
|
||||
- Обновления зависимостей.
|
||||
- Изменения в CI/CD, механизме деплоя, мониторинге.
|
||||
- **Устаревшие функции**. Функциональность, которая будет удалена в будущем, с указанием сроков и альтернатив:
|
||||
- Устаревшие API и их замены.
|
||||
- Удаляемые конфигурационные параметры.
|
||||
- Фичи, которые больше не поддерживаются.
|
||||
- **Действия при обновлении**. Что необходимо сделать перед или после обновления:
|
||||
- Запуск миграций базы данных.
|
||||
- Очистка кэша или пересборка индексов.
|
||||
- Обновление конфигурации окружения.
|
||||
- Ручной запуск скриптов или дополнительных процессов.
|
||||
|
||||
**Как писать полезный changelog?**
|
||||
1. **Соблюдайте структуру**
|
||||
2. **Changelog не должен быть черновиком разработки**
|
||||
1. Если что-то добавили и потом убрали до релиза, этого никогда не существовало для пользователя.
|
||||
2. Не нужно записывать историю разработки — changelog фиксирует только итоговые изменения.
|
||||
3. **Пишите понятно**. Ваша целевая аудитория это люди, которые не погружены в ваш сервис.
|
||||
1. Избегайте технического жаргона, если это не критично.
|
||||
2. Описывайте изменения так, чтобы их мог понять человек, не знакомый с внутренним устройством системы.
|
||||
3. Указывайте контекст: что исправлено и почему.
|
||||
4. Фиксируйте причину изменений
|
||||
4. Не просто «обновлен API», а «обновлен API для поддержки новых параметров, влияющих на X».
|
||||
5. Добавляйте ссылки на тикеты, если это возможно.
|
||||
5. **Обновляйте changelog перед релизом, а не после.** Changelog должен быть частью процесса разработки, а не постфактум-документом.
|
||||
6. **Синхронизируйте с версиями.**
|
||||
1. Используйте версионирование (например, [[../other/Семантическое версионирование|Semantic Versioning]]).
|
||||
2. Если выпускается патч, changelog должен отражать только исправления ошибок, а не все изменения за последние месяцы.
|
||||
|
||||
**Процесс ведения changelog**
|
||||
Чтобы changelog был полезным и актуальным, он должен вестись в рамках строгого процесса:
|
||||
5. **Changelog фиксирует только выпущенные изменения**
|
||||
1. В changelog должны попадать только те изменения, которые вошли в релиз
|
||||
2. Если во время разработки что-то добавили, а затем удалили до выпуска версии, то это **не должно оставлять следов в changelog**. Например, если в SNAPSHOT-версии добавили API, а потом удалили его до релиза, то запись о нем просто удаляется, а не заменяется на «удалили API».
|
||||
6. **Разработчик, выполняющий доработку, отвечает за корректное добавление записей в changelog**. Изменения не должны теряться — каждая доработка должна быть зафиксирована в changelog, а не оставаться только в коде или коммитах.
|
||||
7. **Ревьювер обязан проверить наличие и корректность записей в changelog**.
|
||||
- Проверка changelog становится такой же важной частью code review, как и сам код.
|
||||
- Запись должна быть понятной, отражать суть изменений и быть написана простым языком.
|
||||
- Ревьювер должен убедиться, что не попали временные изменения, не вошедшие в релиз.
|
||||
|
||||
**Дополнительные советы**
|
||||
- Можно настроить сбор changelog на основе PR-описаний, но важно, чтобы в итоговый changelog попадали только финальные изменения. Генерация changelog из commit history (например, Conventional Commits) может помочь, но требует жесткой дисциплины.
|
||||
- Если пользователи или команда часто задают вопросы по changelog, это сигнал, что его стоит делать понятнее.
|
||||
- Можно тестировать понятность changelog, давая его прочитать коллегам, не участвовавшим в разработке изменения.
|
||||
- Changelog старых версий не должен меняться после их выпуска.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-13]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
aliases:
|
||||
aliases:
|
||||
- B-деревьев
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-01-29
|
||||
|
||||
64
dev/java/quarkus/Контексты в Quarkus и Vert.x.md
Normal file
64
dev/java/quarkus/Контексты в Quarkus и Vert.x.md
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-24
|
||||
---
|
||||
Допустим, мы разрабатываем веб-сервис, который обрабатывает входящие HTTP-запросы. Каждому запросу назначается уникальный идентификатор, который должен сохраняться на протяжении всей обработки запроса, включая асинхронные операции, такие как:
|
||||
- обращение к базе данных,
|
||||
- вызовы внешних API,
|
||||
- запись логов,
|
||||
- отправка событий в Kafka или RabbitMQ.
|
||||
|
||||
В синхронных приложениях все просто: данные привязываются к [[../../fundamental/Поток процесса ОС|потоку]], который обслуживает запрос, и остаются неизменными на протяжении всего выполнения.
|
||||
|
||||
Но в асинхронных системах задача усложняется. В отличие от синхронных программ, где каждый запрос выполняется в одном потоке от начала до конца, в асинхронных системах выполнение может передаваться между разными потоками, а один поток может обслуживать множество операций. В итоге:
|
||||
- **Потоки могут переключаться** — одна часть кода выполняется в одном потоке, а затем продолжение запроса передается другому. Данные, связанные с первым потоком, могут потеряться.
|
||||
- **Логирование может работать некорректно** — если идентификатор запроса не передается автоматически, логи окажутся несвязанными, и отладка системы станет сложной.
|
||||
- **Настройки или переменные запроса могут сбрасываться** — например, если определенные переменные нужны для аутентификации, они могут «потеряться» между вызовами.
|
||||
|
||||
В таких условиях возникает важный вопрос: ==как сохранить состояние данных при переключении между потоками?== Например, если у нас есть уникальный идентификатор запроса для логирования, как убедиться, что он не потеряется при передаче управления между разными частями кода?
|
||||
|
||||
Для решения этой проблемы в [[../../../meta/zero/00 Quarkus|Quarkus]] и Vert.x используются контексты. Они позволяют хранить локальные данные и передавать их между асинхронными вызовами. Однако существует несколько видов контекстов, каждый из которых решает свои задачи. Разберем их подробнее.
|
||||
|
||||
==В большинстве случаев Quarkus и Vert.x автоматически управляют контекстами==, но если ваш код выполняется в разных потоках, стоит использовать дублированный контекст. Это поможет избежать [[Обеспечение корректного асинхронного выполнения в Quarkus|неожиданных ошибок]] и сделать вашу систему более стабильной и предсказуемой.
|
||||
|
||||
В Quarkus и Vert.x есть несколько видов контекстов, каждый из которых выполняет свою роль.
|
||||
## Корневой контекст
|
||||
Корневой контекст — это самый базовый контекст, который используется для работы с глобальными процессами, выходящими за пределы одного запроса.
|
||||
|
||||
Особенности корневого контекста:
|
||||
- Он общий для всех процессов, что делает его небезопасным для хранения локальных данных.
|
||||
- Если попытаться сохранить в нем данные, они могут быть случайно переданы в другие запросы.
|
||||
- Любая попытка модифицировать его может привести к исключению `UnsupportedOperationException`.
|
||||
|
||||
|
||||
> [!DANGER] Не используйте
|
||||
> Не используйте корневой контекст для хранения уникальных данных запроса. Вместо этого лучше работать с **обычным или дублированным контекстом**.
|
||||
## Обычный (основной) контекст
|
||||
Это контекст, который автоматически создается системой при обработке запроса. Он содержит:
|
||||
- информацию о текущем [[../../architecture/Event Loop|event loop]],
|
||||
- локальные данные, такие как настройки, переменные и данные для логирования (например, MDC),
|
||||
- механизм автоматической передачи данных между асинхронными вызовами в пределах одного event loop.
|
||||
|
||||
Когда вы обрабатываете HTTP-запрос или сообщение из Kafka, Quarkus автоматически создает основной контекст и использует его для выполнения всей операции.
|
||||
|
||||
Однако проблема в том, что если выполнение запроса переключается между потоками, этот контекст может потеряться.
|
||||
## Дублированный контекст
|
||||
Обычный контекст автоматически передается между асинхронными вызовами, но только в пределах одного event loop. Если выполнение задачи выходит за его пределы (например, передается другому потоку), контекст может не сохраниться.
|
||||
|
||||
Решение — создать дублированный контекст. Это копия текущего контекста, которая остается доступной даже при переключении потоков.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Quarkus|00 Quarkus]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-24]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
- content/problem
|
||||
date: 2025-02-24
|
||||
---
|
||||
В процессе разработки одного из сервисов я обнаружил, что при асинхронной обработке данных с почтового сервера терялась диагностическая информация, передаваемая через [[../../Mapped Diagnostic Context|MDC]].
|
||||
|
||||
Первоначально код выглядел как-то так:
|
||||
|
||||
```java
|
||||
Unis.voidItem()
|
||||
.chain(() -> mailService.process(msg));
|
||||
```
|
||||
|
||||
**Возникающие проблемы:**
|
||||
- **Потеря MDC:** MDC хранится в ThreadLocal, а асинхронные операции могут переключаться между потоками. Из-за этого данные, установленные в MDC, терялись или оказывались перепутанными, что усложняло диагностику.
|
||||
- **Отсутствие изоляции:** Поскольку вызов выполнялся в общем контексте, отсутствовало явное управление окружением выполнения. Это могло привести к состояниям гонки или другим непредсказуемым ошибкам.
|
||||
- Блокировка [[../../architecture/Event Loop|event loop]]: Если метод `mailService.process` выполнял блокирующий код, это могло негативно сказаться на производительности.
|
||||
|
||||
Стоит подчеркнуть, что если бы запрос поступал через стандартные механизмы [[../../../meta/zero/00 Quarkus|Quarkus]] (gRPC, GraphQL, Kafka), то управление контекстом осуществлялось бы системой, и подобных проблем бы не возникало. Однако в нашем случае вызов инициировался через `org.apache.camel.Processor`, что требовало дополнительных усилий по сохранению контекстной информации.
|
||||
|
||||
Анализ показал, что основная проблема кроется в потере MDC при переключении между потоками. В условиях асинхронного выполнения вызовы, инициированные через Camel, не гарантируют автоматическую передачу контекста, что приводит к потере данных, необходимых для корректного логирования и диагностики.
|
||||
|
||||
==Чтобы решить эту проблему, было решено явно создать дублированный контекст и переключить выполнение на него.== Код был изменён следующим образом:
|
||||
|
||||
```java
|
||||
final Context duplicateContext = Context.newInstance(
|
||||
VertxContext.getOrCreateDuplicatedContext(vertx.getDelegate())
|
||||
);
|
||||
Unis.voidItem()
|
||||
.emitOn(duplicateContext::runOnContext)
|
||||
.chain(() -> mailService.process(msg));
|
||||
```
|
||||
|
||||
**Преимущества данного подхода:**
|
||||
- **Сохранение MDC:** Дублированный контекст позволяет перенести все данные, связанные с текущим окружением (включая MDC), что обеспечивает корректное логирование даже при асинхронном выполнении.
|
||||
- **Изоляция выполнения:** Переключение на новый контекст гарантирует, что все последующие операции выполняются в заданном окружении, исключая неожиданные переключения потоков.
|
||||
- Устранение блокировки [[../../architecture/Event Loop|event loop]]: Если метод `mailService.process` содержит блокирующие или ресурсоёмкие операции, их выполнение в изолированном контексте помогает снизить негативное влияние на основной event loop.
|
||||
|
||||
Таким образом, если ваши асинхронные операции инициируются через нестандартные компоненты, такие как Apache Camel, и Quarkus не управляет контекстом напрямую, создание дублированного контекста становится необходимым для корректной работы.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Quarkus|00 Quarkus]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-24]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
44
dev/other/Синхронизация папок в MacOS.md
Normal file
44
dev/other/Синхронизация папок в MacOS.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
- content/problem
|
||||
date: 2025-02-11
|
||||
---
|
||||
У меня есть жесткий диск, который я переодически бэкапирую на MacOS. Под бэкапом я понимаю копирование точной структуры и файлов. Нужно удалить те файлы, что были удалены и добавить те, которые появились.
|
||||
|
||||
Для этого я использую команду `rsync` :
|
||||
|
||||
```shell
|
||||
rsync -av --delete /путь/к/первой_папке/ /путь/ко/второй_папке/
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> В конце пути первой папки (/путь/к/первой_папке/) есть **слэш /**. Это важно: rsync в этом случае копирует **содержимое** папки, а не саму папку.
|
||||
|
||||
**Разбор флагов:**
|
||||
- -a — архивный режим (сохраняет права, даты, символические ссылки и пр.)
|
||||
- -v — режим вывода информации (можно убрать, если не нужен список файлов)
|
||||
- --delete — удаляет файлы во второй папке, если их больше нет в первой
|
||||
|
||||
Если хочешь проверить, какие файлы будут удалены или добавлены, перед выполнением можешь сделать сухой прогон:
|
||||
|
||||
```shell
|
||||
rsync -av --delete --dry-run ~/Documents/source/ ~/Documents/backup/
|
||||
```
|
||||
|
||||
Он покажет, что будет сделано, но не изменит файлы.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-11]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
||||
39
dev/Идентификатор сущности.md
Normal file
39
dev/Идентификатор сущности.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
aliases:
|
||||
- идентификатор
|
||||
- идентификатора
|
||||
- идентификаторов
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2025-02-18
|
||||
---
|
||||
Идентификатор (ID) — это уникальное значение, используемое для однозначного определения объектов в системе. Он играет ключевую роль в [[architecture/Бизнес-логика|бизнес-логике]], связывая сущности и обеспечивая их однозначное различение.
|
||||
|
||||
**Типы идентификаторов**
|
||||
- [[database/other/Автоинкремент в БД|Автоинкремент в БД]]
|
||||
- [[Universal Unique IDentifier|UUID]]
|
||||
- [[Time-Sorted Identifier]]
|
||||
- [[NanoId|NanoId]]
|
||||
- Хешированные идентификаторы
|
||||
- Комбинированные идентификаторы. Иногда идентификаторы комбинируются для удобства и повышения уникальности:
|
||||
- UUID + порядковый номер (для удобства пользователей).
|
||||
- Осмысленные ID (например, ORD-20240218-1234 для заказов).
|
||||
- Хеш-идентификаторы ([[cryptography/SHA-256|SHA-256]], Base62), чтобы скрыть предсказуемые ID.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**::
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2025-02-18]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Universal Unique IDentifier]]
|
||||
- [[Автоинкремент в БД]]
|
||||
- [[Time-Sorted Identifier]]
|
||||
<!-- SerializedQuery END -->
|
||||
|
||||
17
meta/zero/00 Gitea.md
Normal file
17
meta/zero/00 Gitea.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
aliases:
|
||||
- Gitea
|
||||
tags:
|
||||
- type/zero-link
|
||||
date: 2025-02-04
|
||||
title: Gitea
|
||||
---
|
||||
- [[../../dev/devops/other/Фоновые задачи Gitea|Фоновые задачи Gitea]]
|
||||
|
||||
|
||||
Диагностика:
|
||||
- [[../../dev/devops/other/Автоматическая диагностика в Gitea|Автоматическая диагностика в Gitea]]
|
||||
- [[../../dev/devops/other/Проверка get запросов к Gitea|Проверка get запросов к Gitea]]
|
||||
|
||||
Решение проблем:
|
||||
- [[../../dev/devops/other/Высокое потребление ресурсов контейнером Gitea|Высокое потребление ресурсов контейнером Gitea]]
|
||||
@@ -11,6 +11,7 @@ aliases:
|
||||
- высоконагруженных систем
|
||||
- систем с высокой нагрузкой
|
||||
- высокой нагрузкой
|
||||
- высоконагруженных приложений
|
||||
---
|
||||
## Что такое HighLoad?
|
||||
Например, один запрос в секунду – это нагрузка явно не highload, любой сервер, вроде бы, справится. Но, например, если он перекодирует видеоролики, то тут может наступить highload.
|
||||
|
||||
@@ -10,6 +10,7 @@ aliases:
|
||||
- Реляционная база данных
|
||||
- базами данных
|
||||
- базы данных
|
||||
- баз данных
|
||||
linked:
|
||||
- "[[../../../../_inbox/00 In-memory СуБД|00 In-memory СуБД]]"
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user