Compare commits
2 Commits
6273fd512d
...
d0de9bc884
Author | SHA1 | Date | |
---|---|---|---|
d0de9bc884 | |||
b4b8f83b1f |
@ -9,13 +9,13 @@ parents:
|
||||
- "[[Реактивное программирование]]"
|
||||
linked:
|
||||
---
|
||||
По сути, Event Loop - это реализация [шаблона Reactor](http://design-pattern.ru/patterns/reactor.html). Является неблокирующим потоком ввода-вывода, который работает непрерывно. Его основная задача — проверка новых событий. И как только событие пришло перенаправлять его тому, кто в данный момент может его обработать. Иногда их может быть несколько для увеличения производительности.
|
||||
По сути, Event Loop - это реализация [шаблона Reactor](http://design-pattern.ru/patterns/reactor.html). Является неблокирующим потоком ввода-вывода, который работает непрерывно. Его основная задача — проверка новых событий. И как только событие пришло перенаправлять его тому, кто в данный момент может его обработать. Иногда их может быть несколько для увеличения производительности.
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020231026115508.png)
|
||||
|
||||
Выше приведён абстрактный дизайн цикла событий, который представляет идеи реактивного асинхронного программирования:
|
||||
|
||||
- Цикл событий выполняется непрерывно в одном потоке, хотя у нас может быть столько циклов событий, сколько доступно [[../fundamental/Ядро процессора|ядер]].
|
||||
- Цикл событий выполняется непрерывно в одном потоке, хотя у нас может быть столько циклов событий, сколько доступно [[../fundamental/Ядро процессора|ядер]].
|
||||
- Цикл событий последовательно обрабатывает события из очереди событий и возвращается сразу после регистрации [[../../../../_inbox/Callback|обратного вызова]] в платформе.
|
||||
- Платформа может инициировать завершение операции, такой как вызов базы данных или вызов внешней службы.
|
||||
- Цикл событий может запускать обратный вызов при уведомлении о завершении операции и отправлять результат обратно исходному вызывающему.
|
||||
|
@ -13,7 +13,7 @@ linked: []
|
||||
|
||||
Самый простой способ побороть эту проблему, это использовать fingerprint файла. То есть, когда файл меняется, вы меняете его название. Делается это обычно добавлением какого-нибудь префикса/суфикса к названию файла.
|
||||
|
||||
Например у нас есть файл стилей `style.css`, мы можем посчитать для него [[../cryptography/MD5|MD5]] хеш и добавить его в название. Тогда у нас получится следующее название: `style.e626dd36e0085927f334adbe3eb38e7a.css`.
|
||||
Например у нас есть файл стилей `style.css`, мы можем посчитать для него [[../cryptography/MD5|MD5]] хеш и добавить его в название. Тогда у нас получится следующее название: `style.e626dd36e0085927f334adbe3eb38e7a.css`.
|
||||
|
||||
При любом изменении файла [[../cryptography/MD5|MD5]] хеш должен пересчитываться. Таким образом при изменении файла у него будет другое название, и браузер будет вынужден скачать его в любом случае.
|
||||
***
|
||||
|
53
dev/architecture/highload/Асинхронная репликация.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-07
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
- "[[Синхронная репликация]]"
|
||||
- "[[Полу-синхронная репликация]]"
|
||||
---
|
||||
Изменения записываются на master и пересылаются на slaves с некоторой задержкой. Этот метод отличается от синхронной репликации тем, что подтверждение транзакции возвращается клиенту до того, как изменения применены на всех репликах, что позволяет улучшить производительность, но может привести к несогласованности данных.
|
||||
|
||||
Быстро, но не надежно. Возможно используется по умолчанию. Реализовано в [MySQL](../../../meta/zero/00%20MySQL.md), [PostgreSQL](../../../meta/zero/00%20PostgreSQL.md)
|
||||
|
||||
Схема выполнения на MySQL.
|
||||
![](../../../meta/files/images/Pasted%20image%2020240206195611.png)
|
||||
|
||||
**Как работает**
|
||||
- Подготовка транзакции в движке БД: Транзакция начинается на главном сервере, где собираются все изменения данных.
|
||||
- Запись транзакции в лог: Все изменения записываются в журнал транзакций (например, Write-Ahead Log в PostgreSQL).
|
||||
- Завершение транзакции в движке БД: Транзакция завершается на master.
|
||||
- Возврат результата клиенту: Клиент получает подтверждение о завершении транзакции
|
||||
- Пересылка лога репликам: Журнал транзакций отправляется на реплики для асинхронного применения изменений.
|
||||
- Воспроизведение транзакции на репликах: Реплики получают журнал и применяют изменения к своим копиям данных, но это может произойти с задержкой.
|
||||
|
||||
**Преимущества**
|
||||
- Высокая производительность: Поскольку подтверждение транзакции возвращается клиенту до её применения на репликах, время отклика уменьшается, что улучшает производительность системы.
|
||||
- Уменьшенная нагрузка на сеть: Пересылка изменений на реплики происходит асинхронно, что снижает нагрузку на сеть и позволяет более эффективно использовать сетевые ресурсы.
|
||||
- Гибкость в использовании: Асинхронная репликация позволяет использовать реплики для различных задач, таких как отчеты или резервное копирование, без влияния на производительность главного сервера.
|
||||
|
||||
**Минусы**
|
||||
- Потеря данных при сбое: Если master выходит из строя до пересылки изменений на реплики, данные могут быть потеряны. Это может привести к несогласованности данных и необходимости восстановления системы.
|
||||
- [Отставание реплики БД](Отставание%20реплики%20БД.md): Задержка в применении изменений на репликах может привести к отставанию реплик от master, что может затруднить выполнение некоторых операций, требующих актуальных данных.
|
||||
- Проблемы с консистентностью данных: Каждая реплика может отставать по разному, из-за этого данные могут быть несогласованными между репликами. Например, пользователь может получить разные результаты для одного и того же запроса.
|
||||
|
||||
## Примеры использования
|
||||
Асинхронная репликация широко используется в системах, где высокая производительность и низкое время отклика имеют приоритет над полной консистентностью данных. Например, в системах аналитики и отчетности, где задержки в обновлении данных не критичны, асинхронная репликация позволяет эффективно распределять нагрузку и использовать реплики для выполнения сложных запросов, не влияя на производительность основного сервера.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-07]]
|
||||
### Дополнительные материалы
|
||||
- [[Синхронная репликация]]
|
||||
- [[Полу-синхронная репликация|Полу-синхронная репликация]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
67
dev/architecture/highload/Безмастерная репликация.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
aliases:
|
||||
- безмастерной репликацией
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-04
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Базы Данных|00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Репликация БД|Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
Безмастерная репликация — это метод репликации в котором отсутствует главный master. Все узлы системы являются равноправными.
|
||||
|
||||
Клиентские приложения могут записывать данные на любой узел системы. Более того ==запросы отправляются сразу на все реплики, но применяются только на тех, которые доступны в данный момент.==
|
||||
|
||||
Для успешного завершения операции записи требуется подтверждение от определенного количества реплик (W). Если количество успешных записей превышает значение W, операция считается успешной. ==Если их меньше, но не 0, отката транзакции не будет.==
|
||||
|
||||
Клиентские приложения читают данные со всех доступных в данный момент реплик. Для успешного чтения требуется подтверждение от определенного количества реплик (R). Если количество ответивших реплик превышает значение R, операция считается успешной.
|
||||
|
||||
![800](../../../meta/files/images/Pasted%20image%2020240226135429.png)
|
||||
|
||||
Формула расчета кворума: W + R > number of replics
|
||||
- W - в каком количестве реплик должна примениться запись, чтобы мы считали ее успешной
|
||||
- R - со скольки реплик мы должны прочитать значение ключа, чтобы считать, что чтение прошло успешным
|
||||
|
||||
**Преимущества:**
|
||||
- **Высокая доступность:** Поскольку все узлы являются равноправными, система не имеет единой точки отказа. Даже если несколько узлов выйдут из строя, остальные узлы продолжают обслуживать запросы.
|
||||
- **Горизонтальное масштабирование:** Безмастерная репликация позволяет легко добавлять новые узлы для повышения производительности и масштабируемости системы.
|
||||
- **Гибкость конфигурации:** Система может быть настроена для достижения различных уровней консистентности и доступности, в зависимости от требований приложений.
|
||||
|
||||
**Проблемы:**
|
||||
- [Нестрогий кворум](Нестрогий%20кворум.md). Возможно чтение старых данных при W+R < N
|
||||
- Проблемы с откатом транзакций: В безмастерной репликации отсутствует механизм отката транзакций, что может усложнить управление ошибками и восстановление данных.
|
||||
- Как в таком случае работает обновление при чтении или противодействие энтропии, ведь эти данные становятся новыми.
|
||||
- Проблемы с консистентностью данных: Поскольку запись данных может происходить на нескольких узлах одновременно, возникает риск конфликтов и несогласованности данных. Для разрешения конфликтов используются различные методы, такие как Last Write Wins или версионирование данных.
|
||||
- Конфликт записей и [Потерянное обновление](Потерянное%20обновление.md).
|
||||
- Проблемы с линеаризуемостью.
|
||||
|
||||
**Поддержание консистентности:**
|
||||
- Анти-энтропия. Реплики могут периодически синхронизоваться друг с другом, чтобы обеспечить консистентность данных.
|
||||
- Противодействие энтропии. Внешний клиент опрашивает все ноды, находит устаревшие данные и обновляет их.
|
||||
- Обновление при чтении (Set on read). Берем последнюю версию после чтения и отправляем в реплики с устаревшими данными.
|
||||
- Last write wins. Кто последний записал, те данные и верные.
|
||||
- [Happens before](Happens%20before.md).
|
||||
- Векторы версий.
|
||||
- [Tombstone](Tombstone.md)
|
||||
|
||||
Такая репликация есть в:
|
||||
- DynamoDB
|
||||
- [[Cassandra]]
|
||||
- Scylla (Переписанная на C++ Cassandra)
|
||||
- Riak
|
||||
- Voldemort
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД|Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-04]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
40
dev/architecture/highload/Групповая репликация.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-05
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
Работает как [Репликация master-master](Репликация%20master-master.md), но при количестве узлов больше 2
|
||||
|
||||
- Все транзакции чтения и записи фиксируются только после того, как они были одобрены группой.
|
||||
- Read-only транзакции не требуют координации внутри группы и фиксируются немедленно
|
||||
- Групповая репликация - eventual consistency система
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240605091036.png)
|
||||
|
||||
## Консенсус
|
||||
- Когда транзакция read-write готова к фиксации на исходном сервере, сервер атомарно передает значения записи (строки, которые были изменены) и соответствующий набор записи (уникальные идентификаторы строк, которые были обновлены).
|
||||
- Транзакция отправляется через атомарную broadcast рассылку, транзакцию получают либо все серверы в группе, либо ни один.
|
||||
- Если они его получат, то все они получат его в том же порядке относительно других транзакций, которые были отправлены ранее.
|
||||
|
||||
Таким образом, все серверы получают один и тот же набор транзакций в одном и том же порядке, и для транзакций устанавливается глобальный общий порядок.
|
||||
|
||||
## Дополнительные материалы
|
||||
- [MySQL 20.1.1.2 Group Replication](https://dev.mysql.com/doc/refman/8.0/en/group-replication-summary.html)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-05]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
@ -27,18 +27,18 @@ public List<User> getUsersByType(String userType, Set<Long> userIds)
|
||||
|
||||
Значения аргументов метода также должны попасть в ключ. Возьмем наш первый аргумент `String userType`. Для аргумента также можно использовать префиксы, но это не обязательно. В данном случае пусть будет `USER_TYPE`. А вот для самого значения параметра есть несколько вариантов:
|
||||
- Оставить строкой и просто выполнить конкатенацию.
|
||||
- Использовать [[../../cryptography/Криптографическая хеш-функция|хеш-функцию]] с фиксированной длиной выхода, например [[../../cryptography/MD5|MD5]]. Фиксированная длина выхода нужна, чтобы иметь предсказуемую и ограниченную длину ключа.
|
||||
- Использовать [[../../cryptography/Хеш-функция|хеш-функцию]] с фиксированной длиной выхода, например [[../../cryptography/MD5|MD5]]. Фиксированная длина выхода нужна, чтобы иметь предсказуемую и ограниченную длину ключа.
|
||||
|
||||
Оставим просто строкой, так как тип пользователя вряд ли может быть длинным. В итоге пока наш ключ выглядит как-то так: `USER_SERVICE:USERS:USER_TYPE:VIP:`.
|
||||
|
||||
Переходим ко второму аргументу `Set<Long> userIds`. С коллекцией все будет сложнее. Мы точно должны использовать какую-нибудь [[../../cryptography/Криптографическая хеш-функция|хеш-функцию]], но как?
|
||||
Переходим ко второму аргументу `Set<Long> userIds`. С коллекцией все будет сложнее. Мы точно должны использовать какую-нибудь [[../../cryptography/Хеш-функция|хеш-функцию]], но как?
|
||||
|
||||
> [!WARNING] Disclamer
|
||||
> Этот способ я придумал сам, возможно он не самый удачный, но он работает. Если вы придумаете лучше, напишите в комментариях ниже 👇
|
||||
|
||||
Во-первых, коллекцию необходимо предварительно отсортировать. Иначе на одинаковые параметры коллекций мы будем получать разные результаты [[../../cryptography/Криптографическая хеш-функция|хеш-функции]].
|
||||
Во-первых, коллекцию необходимо предварительно отсортировать. Иначе на одинаковые параметры коллекций мы будем получать разные результаты [[../../cryptography/Хеш-функция|хеш-функции]].
|
||||
|
||||
Во-вторых, нужно представить коллекцию как что-то понятное для [[../../cryptography/Криптографическая хеш-функция|хеш-функции]]. Для этого я преобразую коллекцию в JSON. JSON используется, потому что ваша коллекция может быть из сложных объектов.
|
||||
Во-вторых, нужно представить коллекцию как что-то понятное для [[../../cryptography/Хеш-функция|хеш-функции]]. Для этого я преобразую коллекцию в JSON. JSON используется, потому что ваша коллекция может быть из сложных объектов.
|
||||
|
||||
Теперь используем [[../../cryptography/SHA-256|SHA-256]], чтобы из нашей строки получить какой-то хеш. И уже этот хеш мы добавляем к нашему ключу, получается примерно такое:
|
||||
|
||||
|
@ -18,7 +18,7 @@ linked:
|
||||
sudo mkdir -p /var/nginx/cache
|
||||
```
|
||||
|
||||
Чтобы включить кэширование, нужно прописать несколько директив в основной конфигурации `nginx.conf`.
|
||||
Чтобы включить кэширование, нужно прописать несколько директив в основной конфигурации `nginx.conf`.
|
||||
|
||||
```nginx
|
||||
http {
|
||||
@ -29,16 +29,16 @@ http {
|
||||
}
|
||||
```
|
||||
|
||||
`proxy_cache_path` указывает путь в файловой системе.
|
||||
`proxy_cache_path` указывает путь в файловой системе.
|
||||
|
||||
Не кэшируйте HTTP-ответы при первом обращении. Используйте `proxy_cache_min_uses 2`, чтобы кэшировать только те элементы, к которым обращались более одного раза. Таким образом, вы уменьшите нагрузку прокси-кэша на запись и предотвратите заполнение кэша содержимым, к которому редко обращаются.
|
||||
Не кэшируйте HTTP-ответы при первом обращении. Используйте `proxy_cache_min_uses 2`, чтобы кэшировать только те элементы, к которым обращались более одного раза. Таким образом, вы уменьшите нагрузку прокси-кэша на запись и предотвратите заполнение кэша содержимым, к которому редко обращаются.
|
||||
|
||||
Ключ кэширования Nginx по умолчанию не очень хорошо работает с сайтами с несколькими поддоменами. Вы можете настроить ключ кэширования, задав proxy_cache_key. В своей конфигурации я использую вот такой ключ: `proxy_cache_key $scheme$host$uri$is_args$args;`
|
||||
|
||||
## Переносим кэш Nginx в RAM
|
||||
Можно значительно ускорить кэш, если смонтировать его не в файловую систему а в RAM.
|
||||
|
||||
Для этого также создаем папку для кэша, можно использовать ту же, но ее нужно очистить от папок. Далее монтируем созданный каталог в RAM с помощью команды [tmpfs](https://wiki.archlinux.org/index.php/Tmpfs), выделяя 256 мегабайт под кэш:
|
||||
Для этого также создаем папку для кэша, можно использовать ту же, но ее нужно очистить от папок. Далее монтируем созданный каталог в RAM с помощью команды [tmpfs](https://wiki.archlinux.org/index.php/Tmpfs), выделяя 256 мегабайт под кэш:
|
||||
|
||||
```shell
|
||||
sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cache
|
||||
@ -50,7 +50,7 @@ sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cache
|
||||
sudo umount /var/nginx/cache
|
||||
```
|
||||
|
||||
Чтобы автоматически пересоздать каталог к'ша в RAM после перезагрузки сервера, нам нужно обновить файл `/etc/fstab`. Добавьте в него следующую строку:
|
||||
Чтобы автоматически пересоздать каталог к'ша в RAM после перезагрузки сервера, нам нужно обновить файл `/etc/fstab`. Добавьте в него следующую строку:
|
||||
|
||||
```txt
|
||||
tmpfs /var/nginx/cache tmpfs defaults,size=256M 0 0
|
||||
|
26
dev/architecture/highload/Монотонное чтение.md
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-07
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
Монотонное чтение — это проблема, возникающая при репликации данных, когда пользователи могут получить несогласованные результаты при выполнении последовательных запросов. Это происходит, когда изменения на мастере не успевают синхронизироваться с репликами, и разные запросы пользователя могут попадать на реплики с различными состояниями данных.
|
||||
## Пример проблемы монотонного чтения
|
||||
Рассмотрим ситуацию, когда пользователь запрашивает список комментариев к статье. Если новый комментарий был добавлен и записан на мастер, но ещё не успел синхронизироваться со всеми репликами, пользователь может столкнуться с несогласованными результатами:
|
||||
|
||||
1. Пользователь делает первый запрос и получает список комментариев без нового комментария.
|
||||
2. Пользователь делает второй запрос и получает список комментариев, включающий новый комментарий.
|
||||
3. При следующем запросе пользователь снова может не увидеть новый комментарий, если его запрос попадает на другую реплику.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240607211612.png)
|
||||
|
||||
## Методы решения проблемы монотонного чтения
|
||||
- Привязка пользователя к конкретной реплике (stickiness): Один из способов решения проблемы монотонного чтения — это привязка пользователя к конкретной реплике для всех последовательных запросов. Это можно реализовать с помощью сессий или токенов, обеспечивая пользователю доступ к одной и той же реплике, пока она доступна.
|
||||
- Настройка задержек при чтении: Можно настроить задержки при чтении данных с реплик, чтобы обеспечить их синхронизацию с мастером. Например, задержка может быть настроена таким образом, чтобы реплики всегда отставали от мастера на фиксированное время, достаточное для синхронизации данных.
|
||||
- Использование кворумных чтений: В системах с [[Безмастерная репликация|безмастерной репликацией]] можно использовать кворумные чтения, когда запросы выполняются на нескольких репликах одновременно, и результат считается успешным только если он подтвержден большинством реплик. Это повышает вероятность получения актуальных данных.
|
37
dev/architecture/highload/Отставание реплики БД.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
aliases:
|
||||
- лаг репликации
|
||||
- задержки репликации
|
||||
- задержка репликации
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-04
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
Отставание реплики (или лаг репликации) — это проблема, возникающая, когда изменения, выполненные на мастере, не успевают применяться на репликах вовремя. Это может привести к несогласованности данных между мастером и репликами и затруднить выполнение операций, требующих актуальных данных.
|
||||
|
||||
В нормальной ситуации отставание может достигать 1 секунды.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240219184314.png)
|
||||
|
||||
Так как в [[../../../meta/zero/00 PostgreSQL|PostgreSQL]] мы передаем не сам запрос, а блоки данных, то отставание по идее должно быть меньше, чем в [[../../../meta/zero/00 MySQL|MySQL]].
|
||||
|
||||
Что может приводить к лагу:
|
||||
- Медленные и сложные запросы: Если реплики выполняют сложные или ресурсоемкие запросы, это может замедлить процесс применения изменений.
|
||||
- Сетевые проблемы: Задержки в сети могут замедлить передачу журнала транзакций (WAL) от мастера к репликам.
|
||||
- Размер журнала транзакций: Большие объемы изменений могут создать нагрузку на систему репликации, увеличивая время обработки.
|
||||
- Проблемы с дисковой подсистемой: Медленные дисковые операции на репликах могут замедлить процесс применения изменений.
|
||||
|
||||
Рекомендации:
|
||||
- Оптимизация запросов: Оптимизация сложных запросов может снизить нагрузку на реплики и ускорить процесс применения изменений. Это включает в себя индексацию, переработку запросов и использование эффективных алгоритмов.
|
||||
- Убивайте медленные запросы. Если запрос висит уже 10 секунд, то лучше его прибить.
|
||||
- Использование выделенных реплик: Для выполнения сложных запросов или резервного копирования можно использовать выделенные реплики, что позволит снизить нагрузку на основные реплики, обеспечивающие актуальность данных.
|
||||
- Подумайте о кросс-СУБД репликации Репликация из реляционной бд в NoSQL
|
||||
- Избегайте [[../../database/Write-read pattern|Write-read pattern]]
|
||||
- Выделить отдельный жесткий диск под [Журнал БД](../../database/Журнал%20БД.md), чтобы обеспечить эксклюзивный доступ к ресурсам диска, тем самым улучшая производительность. Менее актуально для SSD.
|
||||
- Настройка параметров репликации: Оптимизация параметров репликации, таких как размер WAL и частота его отправки, может помочь уменьшить лаг репликации. В PostgreSQL, например, можно настроить параметры wal_level и max_wal_senders для оптимизации процесса репликации.
|
53
dev/architecture/highload/Полу-синхронная репликация.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
aliases:
|
||||
- semi-sync
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-07
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
- "[[Асинхронная репликация]]"
|
||||
- "[[Синхронная репликация]]"
|
||||
---
|
||||
Полу-синхронная репликация — это компромиссный метод между [[Синхронная репликация|синхронной]] и [[Асинхронная репликация|асинхронной]] репликацией. Он обеспечивает более высокую надежность данных по сравнению с асинхронной репликацией, но при этом снижает время отклика по сравнению с синхронной.
|
||||
|
||||
Комит прошел на одной реплике, но данные по транзакции были скопированы во все остальные реплики, но еще не были применены.
|
||||
|
||||
Реализовано в [MySQL](../../../meta/zero/00%20MySQL.md)
|
||||
|
||||
Схема выполнения на MySQL ![](../../../meta/files/images/Pasted%20image%2020240206195639.png)
|
||||
|
||||
**Как работает**
|
||||
- Подготовка транзакции в движке БД: Транзакция начинается на master, где собираются все изменения данных.
|
||||
- Запись транзакции в лог: Все изменения записываются в журнал транзакций.
|
||||
- Пересылка лога репликам: Журнал транзакций отправляется на реплики. Master ждет подтверждения от как минимум одной реплики о получении журнала, но не обязательно его применении.
|
||||
- Завершение транзакции в движке БД: После получения подтверждения от одной или нескольких реплик транзакция завершается на master, и клиент получает подтверждение.
|
||||
- Воспроизведение транзакции на репликах: Реплики применяют полученные изменения к своим копиям данных, но это может произойти с задержкой.
|
||||
|
||||
**Преимущества**
|
||||
- Баланс между надежностью и производительностью: Полу-синхронная репликация обеспечивает более высокую надежность данных по сравнению с асинхронной репликацией, так как master ждет подтверждения от реплик перед завершением транзакции. Это снижает риск потери данных при сбое.
|
||||
- Сниженное время отклика: В отличие от синхронной репликации, master не ждет подтверждения от всех реплик, что снижает время отклика и повышает производительность системы.
|
||||
- Меньшая вероятность отставания данных: Благодаря ожиданию подтверждения от реплик перед завершением транзакции, вероятность отставания данных на репликах уменьшается.
|
||||
|
||||
**Минусы**
|
||||
- Проблемы с консистентностью данных: Хотя master ждет подтверждения от одной или нескольких реплик, данные на других репликах могут оставаться несогласованными до применения изменений, что может привести к проблемам с консистентностью. [Фантомное чтение](Фантомное%20чтение.md).
|
||||
- Сложность управления: Полу-синхронная репликация требует более сложной настройки и управления по сравнению с асинхронной репликацией, так как необходимо следить за подтверждениями от реплик и управлять задержками.
|
||||
- Увеличенное время отклика по сравнению с асинхронной репликацией: Несмотря на снижение времени отклика по сравнению с синхронной репликацией, полу-синхронная репликация все же медленнее асинхронной, так как требует ожидания подтверждений от реплик.
|
||||
## Примеры использования
|
||||
Полу-синхронная репликация часто используется в системах, где требуется баланс между надежностью данных и производительностью. Например, в финансовых системах, где важна высокая доступность и консистентность данных, но при этом необходимо обеспечить приемлемое время отклика для клиентов. Полу-синхронная репликация позволяет снизить риск потери данных при сбоях и поддерживать консистентность данных на более высоком уровне, чем асинхронная репликация.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-07]]
|
||||
### Дополнительные материалы
|
||||
- [[Асинхронная репликация]]
|
||||
- [[Синхронная репликация]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
55
dev/architecture/highload/Репликация master-master.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-03-10
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
- "[[Репликация master-slave]]"
|
||||
---
|
||||
Все реплики являются ведущими (master). Во все реплики можно писать изменения, а они каким-то образом синхронизируются между собой. Ведущие реплики могут также иметь дополнительные реплики в режиме [[Репликация master-slave|репликации master-slave]].
|
||||
|
||||
![](Pasted%20image%2020240206194251.png)
|
||||
|
||||
**Плюсы**:
|
||||
- Нет единой точки отказа
|
||||
- Дает максимальный [High Availability](High%20Availability.md).
|
||||
- Легкий failover
|
||||
|
||||
**Минусы:**
|
||||
- Нет консистентности. Могут возникать конфликты при одновременной работе с одним и тем же набором данных на разных репликах.
|
||||
- Усложнение логики. Встречается редко.
|
||||
- Все равно не масштабирует запись. Для масштабирования нужно использовать [шардирование](Шардирование%20БД.md).
|
||||
|
||||
**Варианты применения:**
|
||||
- Географическая распределенность. Репликация между ЦОД-ами в разных странах. Улучшается производительность, так как пользователь из страны работает с ближайшим ЦОД. Вы устойчивы к потере ЦОД и к сетевым проблемам, так как данные есть в других ЦОД-ах.
|
||||
- Hot-standby реплика (VIP). Второй мастер всегда на готове, на случай если упадет основной. Во время штатной работы второй мастер не используется.
|
||||
- Offline клиенты. При плохом или вовсе временно отсутвующем интерент соединении для ассинхронного объединения данных. CouchDB является примером такой БД.
|
||||
|
||||
Варианты реализаций:
|
||||
- Amazon Aurora
|
||||
- Google Spanner
|
||||
## Решение конфликтов
|
||||
- Избегайте конфликтов. Организуйте взаимодействие так, чтобы конфликты не возникали.
|
||||
- Last write wins. Выигрывает последняя запись. Но обычно сложно определить кто был первым.
|
||||
- Ранг реплик. Выигрывает запись от старейшей реплки.
|
||||
- Слияние. Автоматическое объединение конфликтных данных.
|
||||
- Решение конфликтов на клиенте.
|
||||
- Conflict-free replicated data types (CRDT).
|
||||
- Mergeable persistent data structures.
|
||||
- В этом режиме работает [00 Git](../../../meta/zero/00%20Git.md)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-03-10]]
|
||||
### Дополнительные материалы
|
||||
- [[Репликация master-slave]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
38
dev/architecture/highload/Репликация master-slave.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
aliases:
|
||||
- репликации master-slave
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-03-10
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД|Репликация БД]]"
|
||||
linked:
|
||||
- "[[Репликация master-master]]"
|
||||
---
|
||||
В такой схеме у нас есть одна ведущая реплика (master) в которую пишутся изменения и несколько ведомых реплик (slave), на которые эти изменения копируются, из них можно только читать. Это наиболее распространенный подход репликации, так как он относительно прост и понятен.
|
||||
|
||||
![](Pasted%20image%2020240206194227.png)
|
||||
|
||||
**Проблемы и недостатки:**
|
||||
- Мастер обязательно когда-нибудь упадет. И нужно будет как-то выбрать из slaves нового master.
|
||||
- Как и другие способы репликации не ускоряет операции вставки данных.
|
||||
- Этот способ никогда не даст 99,9999 [High Availability](High%20Availability.md).
|
||||
|
||||
Управление master-slave:
|
||||
- MHA (MySQL Master HA)
|
||||
- MySQL Failover (Oracle)
|
||||
- Orchestrator
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД|Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-03-10]]
|
||||
### Дополнительные материалы
|
||||
- [[Репликация master-master|Репликация master-master]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
100
dev/architecture/highload/Репликация БД.md
Normal file
@ -0,0 +1,100 @@
|
||||
---
|
||||
aliases:
|
||||
- репликация базы данных
|
||||
- репликацию бд
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-03-10
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
- "[[../../../meta/zero/00 DevOps|00 DevOps]]"
|
||||
- "[[../../../meta/zero/00 Базы Данных|00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Репликация|Репликация]]"
|
||||
linked:
|
||||
---
|
||||
## Тезисы
|
||||
- Репликация это копирование измененных данных с одного сервера БД на другой.
|
||||
- Не отменяет первоначального копирования БД. Сначала нужно первый раз скопировать данные, а потом уже запустить репликацию.
|
||||
- Репликация не является [резервной копией БД](Резервные%20копии%20БД.md).
|
||||
- Обычно реализуются на базе [[../../database/Журнал БД|журнала БД]].
|
||||
- Плюсы:
|
||||
- Помогает улучшить [High Availability](High%20Availability.md). Помогает при падении.
|
||||
- Ускоряет чтение данных
|
||||
- Проблемы:
|
||||
- Не ускоряет запись в БД
|
||||
- [Отставание реплики БД](Отставание%20реплики%20БД.md)
|
||||
- [[Монотонное чтение|Монотонное чтение]]
|
||||
- Репликация это ресурсозатратно.
|
||||
- Репликации БД:
|
||||
- [Репликация в MySQL](../../database/mysql/Репликация%20в%20MySQL.md)
|
||||
- [Репликация в PostgreSQL](../../database/postgresql/Репликация%20в%20PostgreSQL.md)
|
||||
***
|
||||
Репликация позволяет сделать N копий одной БД. Обычно есть одна ведущая копия, которую называют master, и есть N ведомых реплик, которые называют slaves.
|
||||
|
||||
Репликация не отменяет первоначального копирования БД. Сначала нужно первый раз скопировать данные, а потом уже запустить репликацию.
|
||||
|
||||
**Для чего делают репликацию?**
|
||||
- [[../../../../../_inbox/High Availability|High Availability]]. Если один сервер выходит из строя, другие реплики продолжают обслуживать запросы, обеспечивая непрерывный доступ к данным.
|
||||
- **Масштабирование чтения**. Нагрузка на чтение может быть распределена между несколькими репликами, что улучшает производительность системы.
|
||||
- **Распределение нагрузки**. Сложные аналитические запросы для построения отчетов и асинхронное [резервное копирование БД](Резервные%20копии%20БД.md) могут выполняться на отдельных репликах, не нагружая основной сервер.
|
||||
- **Географическое распределение**. Реплики могут быть размещены ближе к пользователям в разных регионах, уменьшая задержки доступа к данным.
|
||||
|
||||
**Недостатки репликации:**
|
||||
- Не позволяет получить увеличение производительности запросов на вставку данных. Для этого нужно использовать [[../../../../../_inbox/Шардирование БД|шардирование]].
|
||||
- **Сложность управления**. Управление несколькими репликами требует дополнительных ресурсов и сложной конфигурации. Это включает настройку синхронизации данных, мониторинг состояния реплик и управление конфликтами.
|
||||
- **Ресурсозатратность**. Поддержание нескольких копий данных требует дополнительных ресурсов, что может значительно увеличить расходы на инфраструктуру.
|
||||
- **Проблемы консистентности:** В асинхронной репликации данные на разных репликах могут быть несогласованными, что может привести к проблемам с консистентностью. Например, пользователь может получить разные результаты для одного и того же запроса, если реплики не успели синхронизироваться.
|
||||
## Роль журнала БД в репликации
|
||||
Прямой способ сделать репликацию - это скопировать [[../../database/Журнал БД|журнал БД]] с master на slave и применить его. PostgreSQL работает именно так используя журнал [WAL](../../database/postgresql/Write-Ahead%20Log.md). Однако, не все так просто. Формат и возможности журнала напрямую зависят от СУБД.
|
||||
|
||||
![](Pasted%20image%2020240531083508.png)
|
||||
## Классификация репликаций
|
||||
- **По синхронизации.** Гарантия наличия и доступности.
|
||||
- [Синхронная репликация](Синхронная%20репликация.md)
|
||||
- [Асинхронная репликация](Асинхронная%20репликация.md)
|
||||
- [Полу-синхронная репликация](Полу-синхронная%20репликация.md)
|
||||
- **По уровню работы**
|
||||
- Физическая репликация. Работа на уровне хранилища, мы работаем напрямую со страницами памяти
|
||||
- [Write-Ahead Log](../../database/postgresql/Write-Ahead%20Log.md) в PostgreSQL
|
||||
- [InnoDB Undo/Redo Log](../../database/mysql/Журналы%20в%20MySQL.md#InnoDB%20Undo/Redo%20Log) в MySQL
|
||||
- Логическая репликация. Работает с кортежами. Мы храним набор кортежей до и после.
|
||||
- [Row-based Binary Log](../../database/mysql/Журналы%20в%20MySQL.md#Row-based%20Binary%20Log) в MySQL
|
||||
- [Statement-based Binary Log](../../database/mysql/Журналы%20в%20MySQL.md#Statement-based%20Binary%20Log) недоразумение, которое работает на уровне запросов. Для такой репликации нужно выполнять запрос на слейве, и если запрос выполнялся 30 минут, то и на слейве он будет выполняться 30 минут. Также присутсвует зависимость в функциях, например функция времени вернет одно значение на мастере и совершенно другое на слейве.
|
||||
- **По расспространению изменений**
|
||||
- push. мастер сует, слейву пофиг. Реализуется редко. (Postgres)
|
||||
- pull. слейв качает, мастеру пофиг. (MySQL)
|
||||
- **По количеству точек записи**
|
||||
- [Репликация master-slave](Репликация%20master-slave.md)
|
||||
- [Репликация master-master](Репликация%20master-master.md)
|
||||
- [Безмастерная репликация](Безмастерная%20репликация.md)
|
||||
- [Групповая репликация](Групповая%20репликация.md). Реализовано в MySQL.
|
||||
## Проблемы
|
||||
- [Отставание реплики БД](Отставание%20реплики%20БД.md)
|
||||
- [Монотонное чтение](Монотонное%20чтение.md)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]], [[../../../meta/zero/00 DevOps|00 DevOps]], [[../../../meta/zero/00 Базы Данных|00 Базы Данных]]
|
||||
**Родитель**:: [[../../../../../source/курсы/otus/Архитектор высоких нагрузок 2019/Репликация|Репликация]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-03-10]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Согласованное префиксное чтение]]
|
||||
- [[Репликация в MySQL]]
|
||||
- [[Репликация в PostgreSQL]]
|
||||
- [[Репликация master-slave]]
|
||||
- [[Репликация master-master]]
|
||||
- [[Безмастерная репликация]]
|
||||
- [[Синхронная репликация]]
|
||||
- [[Асинхронная репликация]]
|
||||
- [[Полу-синхронная репликация]]
|
||||
- [[Отставание реплики БД]]
|
||||
- [[Монотонное чтение]]
|
||||
- [[Групповая репликация]]
|
||||
<!-- SerializedQuery END -->
|
37
dev/architecture/highload/Репликация.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
aliases:
|
||||
- зеркалирование
|
||||
- репликацию
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-05
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
linked:
|
||||
---
|
||||
Один из видов [горизонтального масштабирования](Горизонтальное%20масштабирование.md), который позволяет создать несколько копий одного узла системы.
|
||||
|
||||
**Плюсы:**
|
||||
- Помогает при падениях
|
||||
- Можно размазать нагрузку по узлам
|
||||
|
||||
**Минусы:**
|
||||
- Всегда ресурсозатратно.
|
||||
|
||||
**Виды репликации:**
|
||||
- [Репликация БД](Репликация%20БД.md)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Горизонтальное масштабирование]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-05]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- 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 -->
|
45
dev/architecture/highload/Синхронная репликация.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-07
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Базы Данных|00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
- "[[Асинхронная репликация]]"
|
||||
- "[[Полу-синхронная репликация]]"
|
||||
---
|
||||
При получении запроса от клиента master ожидает, пока все реплики получат новые данные и подтвердят их применение у себя, и только после этого сообщает клиенту, что запрос успешно выполнен. Работает надежно, но медленно.
|
||||
|
||||
Реализовано в [PostgreSQL](../../../meta/zero/00%20PostgreSQL.md).
|
||||
|
||||
**Механизм работы**:
|
||||
- Подготовка транзакции в движке БД: Транзакция начинается на главном сервере (мастере), где собираются все изменения данных.
|
||||
- Запись транзакции в лог: Все изменения записываются в журнал транзакций, что обеспечивает возможность восстановления данных в случае сбоя.
|
||||
- Пересылка лога репликам: Журнал транзакций отправляется на все реплики для синхронного применения изменений.
|
||||
- Выполнение транзакций на репликах: Реплики применяют полученные изменения к своим копиям данных.
|
||||
- Завершение транзакции в движке БД: После успешного применения изменений на всех репликах транзакция завершается.
|
||||
- Возврат результата клиенту: Клиент получает подтверждение о завершении транзакции только после того, как изменения применены на всех репликах.
|
||||
|
||||
**Плюсы:**
|
||||
- Высокая надежность данных: Данные не теряются даже в случае сбоя одного из серверов, так как изменения применяются на всех репликах одновременно.
|
||||
- Консистентность данных: Обеспечивается консистентность данных на всех репликах, что исключает возможность получения различных результатов для одного и того же запроса.
|
||||
|
||||
**Минусы:**
|
||||
- Увеличенное время отклика: Поскольку подтверждение транзакции возвращается клиенту только после её завершения на всех репликах, время отклика увеличивается. Это может негативно сказаться на производительности системы, особенно при большом количестве реплик.
|
||||
- Высокая вероятность сбоев: С увеличением числа реплик общая вероятность сбоя возрастает, так как транзакция завершается только при успешном выполнении на всех репликах. Если хотя бы одна реплика не отвечает, транзакция не может быть завершена.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-07]]
|
||||
### Дополнительные материалы
|
||||
- [[Асинхронная репликация|Асинхронная репликация]]
|
||||
- [[Полу-синхронная репликация|Полу-синхронная репликация]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
32
dev/architecture/highload/Согласованное префиксное чтение.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-07
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 HighLoad|00 HighLoad]]"
|
||||
parents:
|
||||
- "[[Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
Ситуация, которая возникает при наличии нескольких master-ов ([[Репликация master-master]] или [[Групповая репликация]]) или при [Шардирование БД](Шардирование%20БД.md).
|
||||
|
||||
У нас есть 2 участника чата и один сторонний наблюдатель. Сначала один пользователь пишет в чат, а следом другой пользователь пишет в чат. Далее наблюдатель читает сообщения из реплики, в которую сначала пришло второе сообщение, а потом только первое.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240607212223.png)
|
||||
|
||||
**Возможные решения:**
|
||||
- Сортировка по какому-то монотонному полю.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]]
|
||||
**Родитель**:: [[Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-07]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
@ -22,7 +22,7 @@ linked:
|
||||
![](../../meta/files/images/Pasted%20image%2020240319200211.png)
|
||||
|
||||
## Почему простаивание потока — это проблема?
|
||||
Каждый поток нуждается в памяти для хранения своего стека вызовов и других связанных с ним структур данных. ==Когда поток простаивает, он продолжает потреблять ресурсы для поддержания своего состояния.==
|
||||
Каждый поток нуждается в памяти для хранения своего стека вызовов и других связанных с ним структур данных. ==Когда поток простаивает, он продолжает потреблять ресурсы для поддержания своего состояния.==
|
||||
|
||||
Кроме того, процессорное время, которое выделяется неработающим потокам, могло бы быть использовано для других задач. Если большое количество потоков простаивает, это может привести к увеличению загрузки процессора и снижению производительности, так как операционная система будет тратить больше времени на переключение между потоками.
|
||||
## Заметки
|
||||
|
@ -38,7 +38,7 @@ linked:
|
||||
- Кэширование на стороне сервиса. [Схема](../../meta/files/images/Pasted%20image%2020240617194759.png).
|
||||
- Опережающее. Кладем данные в кэш заранее. [Схема](../../meta/files/images/Pasted%20image%2020240617194938.png).
|
||||
|
||||
Чаще всего кэш реализуется на основе хеш-таблиц и использует [принцип локальности](../fundamental/Принцип%20локальности.md). Для работы с хеш-таблицей вам необходим [[highload/Ключ кэширования|ключ кэширования]] и сами данные. По ключу данные кладутся и забираются из таблицы.
|
||||
Чаще всего кэш реализуется на основе [[../fundamental/structure/Хеш-таблица|хеш-таблиц]] и использует [принцип локальности](../fundamental/Принцип%20локальности.md). Для работы с хеш-таблицей вам необходим [[highload/Ключ кэширования|ключ кэширования]] и сами данные. По ключу данные кладутся и забираются из таблицы.
|
||||
|
||||
Для хранения результатов кэширования я обычно использую JSON. Использую для этого библиотеку [[../../../../knowledge/dev/java/other/Jackson|Jackson]], но есть один [[../../../../_inbox/Преобразование Json из коллекции в Java объект при помощи Jackson|нюанс при работе с коллекциям]], который стоит учитывать.
|
||||
|
||||
|
@ -16,7 +16,7 @@ linked:
|
||||
|
||||
- [Фронтенд](Фронтенд.md). предназначен для быстрой обработки легких данных, как правило, статики. Эти запросы обрабатываются тут и не проходят на массивный, тяжелый бэкенд. Для фронтенда используются такие легковесные сервера, как [nginx](00%20Nginx.md). В разработке подобных серверов огромное внимание уделяется тому, какое количество ресурсов тратится на обработку одного запроса.
|
||||
- [Бэкенд](Бэкенд.md), как правило, это тяжелые приложения, в которых происходят вычисления, зашита бизнес-логика, и обрабатывать статические запросы бэкендом попросту неэффективно.
|
||||
- Следующий слой – это хранение данных, в простейшем варианте – [база данных](00%20Базы%20Данных.md).
|
||||
- Следующий слой – это хранение данных, в простейшем варианте – [база данных](../../meta/zero/00%20Базы%20Данных.md).
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]
|
||||
|
@ -9,10 +9,10 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае [SpringBoot](../../meta/zero/00%20SpringBoot.md) и [Quarkus](../../meta/zero/00%20Quarkus.md) не знают, как создать такие бины и внедрить их друг в друга.
|
||||
Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае [SpringBoot](../../meta/zero/00%20SpringBoot.md) и [Quarkus](../../meta/zero/00%20Quarkus.md) не знают, как создать такие бины и внедрить их друг в друга.
|
||||
|
||||
> [!WARNING]
|
||||
> Обычно такая ситуация сигнализирует о плохо продуманной архитектуре приложения.
|
||||
> Обычно такая ситуация сигнализирует о плохо продуманной архитектуре приложения.
|
||||
|
||||
Пример циклической зависимости в Spring:
|
||||
|
||||
@ -44,7 +44,7 @@ public class ServiceTwo {
|
||||
|
||||
Вот что вы можете с этим сделать:
|
||||
## Пересмотреть архитектуру приложения
|
||||
==Это предпочтительный вариант.== Возможно вам стоит создать сервис В, который внедрит в себя сервисы А и Б. В таком случае вы распутаете циклическую зависимость.
|
||||
==Это предпочтительный вариант.== Возможно вам стоит создать сервис В, который внедрит в себя сервисы А и Б. В таком случае вы распутаете циклическую зависимость.
|
||||
|
||||
```java
|
||||
@Service
|
||||
@ -75,7 +75,7 @@ public class ServiceTwo {
|
||||
}
|
||||
```
|
||||
## Ленивое внедрение
|
||||
В Spring вы можете указать аннотацию `@Lazy` у аргумента конструктора одного их сервисов. Таким образом сначала будет создан один сервис, для второго сервиса спринг создаст прокси класс, создаст из него бин и внедрит его в ваш сервис. После чего создаст второй сервис и внедрит туда уже созданный первый. А далее заменит ссылку с прокси объекта на второй сервис.
|
||||
В Spring вы можете указать аннотацию `@Lazy` у аргумента конструктора одного их сервисов. Таким образом сначала будет создан один сервис, для второго сервиса спринг создаст прокси класс, создаст из него бин и внедрит его в ваш сервис. После чего создаст второй сервис и внедрит туда уже созданный первый. А далее заменит ссылку с прокси объекта на второй сервис.
|
||||
|
||||
```java
|
||||
@Service
|
||||
|
@ -8,10 +8,10 @@ zero-link:
|
||||
- "[[../../meta/zero/00 Криптография|00 Криптография]]"
|
||||
- "[[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]"
|
||||
parents:
|
||||
- "[[Криптографическая хеш-функция]]"
|
||||
linked:
|
||||
- "[[Хеш-функция]]"
|
||||
linked:
|
||||
---
|
||||
MD5 (Message Digest Algorithm 5) — это [[криптографическая хеш-функция]], которая преобразует входные данные в 128-битное (16-байтное) значение, называемое хешем или дайджестом сообщения.
|
||||
MD5 (Message Digest Algorithm 5) — это [[Хеш-функция]], которая преобразует входные данные в 128-битное (16-байтное) значение, называемое хешем или дайджестом сообщения.
|
||||
|
||||
|
||||
> [!DANGER]
|
||||
@ -37,7 +37,7 @@ MD5 (Message Digest Algorithm 5) — это [[криптографическая
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]]
|
||||
**Родитель**:: [[Криптографическая хеш-функция]]
|
||||
**Родитель**:: [[Хеш-функция]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-14]]
|
||||
**Автор**::
|
||||
|
@ -9,10 +9,10 @@ zero-link:
|
||||
- "[[../../meta/zero/00 Криптография|00 Криптография]]"
|
||||
- "[[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]"
|
||||
parents:
|
||||
- "[[Криптографическая хеш-функция]]"
|
||||
linked:
|
||||
- "[[Хеш-функция]]"
|
||||
linked:
|
||||
---
|
||||
SHA-256 (Secure Hash Algorithm 256-bit) — это [[криптографическая хеш-функция]], которая преобразует входные данные в 256-битное (32-байтное) значение, называемое хешем. SHA-256 является частью семейства алгоритмов SHA-2.
|
||||
SHA-256 (Secure Hash Algorithm 256-bit) — это [[Хеш-функция]], которая преобразует входные данные в 256-битное (32-байтное) значение, называемое хешем. SHA-256 является частью семейства алгоритмов SHA-2.
|
||||
|
||||
**Основные характеристики SHA-256:**
|
||||
- **Фиксированная длина выхода**: Независимо от размера входных данных (например, файл, текст, строка), выход всегда имеет длину 256 бит (32 байта).
|
||||
@ -31,7 +31,7 @@ SHA-256 (Secure Hash Algorithm 256-bit) — это [[криптографиче
|
||||
- [[../snippet/Реализация SHA-256 на Java|Реализация SHA-256 на Java]]
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]], [[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]
|
||||
**Родитель**:: [[Криптографическая хеш-функция]]
|
||||
**Родитель**:: [[Хеш-функция]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-14]]
|
||||
**Автор**::
|
||||
|
@ -19,13 +19,13 @@ linked:
|
||||
ssh-keygen -t ed25519-sk -O resident -O application=ssh:key_name -f ~/.ssh/key_name
|
||||
```
|
||||
|
||||
Все как с обычными SSH ключами, появится 2 файла в папке ssh `key_name` и `key_name.pub`. Только вот, воспользоваться секретным ключом без подключения аппаратного ([Yubikey](Yubikey.md)) не выйдет.
|
||||
Все как с обычными SSH ключами, появится 2 файла в папке ssh `key_name` и `key_name.pub`. Только вот, воспользоваться секретным ключом без подключения аппаратного ([Yubikey](Yubikey.md)) не выйдет.
|
||||
|
||||
Флаги:
|
||||
- `-O verify-required`. Потребует вводить пароль от аппаратного ключа для доступа к SSH ключу.
|
||||
- `-O application=ssh:key_name`. Позволяет установить название ключу, которое можно будет увидеть в приложении Yubico Authentification. ![](../../meta/files/images/Pasted%20image%2020240113100105.png)
|
||||
|
||||
Такой ключ подойдет и для доступа к репозиториям. Но необходимо будет прописать в `~/.ssh/config` информацию о том, какой ключ использовать:
|
||||
Такой ключ подойдет и для доступа к репозиториям. Но необходимо будет прописать в `~/.ssh/config` информацию о том, какой ключ использовать:
|
||||
|
||||
```yaml
|
||||
Host github.com
|
||||
|
37
dev/database/Write-read pattern.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
aliases:
|
||||
- запись-чтение
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
- "[[../../meta/zero/00 Базы Данных|00 Базы Данных]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Ситуация, когда после записи данных в master реплику вы пытаетесь немедленно прочитать те же данные с другой реплики. Это может привести к проблемам из-за задержек синхронизации между основным узлом и репликами.
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240607211343.png)
|
||||
|
||||
Основные причины, почему стоит избегать этого паттерна при репликации:
|
||||
|
||||
- [[../architecture/highload/Отставание реплики БД|Задержки репликации]]: Данные, записанные на основном узле, не сразу реплицируются на все реплики. При чтении с реплики можно получить устаревшую информацию.
|
||||
- Непоследовательность данных: Вы можете получить неконсистентные данные, так как реплика может не успеть синхронизироваться с основным узлом.
|
||||
- [[Race condition|Условие гонки]]: Возникает ситуация, когда операции записи и чтения конкурируют между собой. Это может привести к тому, что операция чтения прочитает данные до того, как завершится операция записи на всех узлах.
|
||||
|
||||
Чтобы избежать этих проблем, рекомендуется:
|
||||
- Чтение данных с основного узла, если требуется сразу после записи.
|
||||
- Использование механизмов согласованности, таких как кворумное чтение и запись, где для подтверждения операции необходимо согласие нескольких узлов.
|
||||
- Настройка задержек или проверок синхронизации для гарантии, что данные были реплицированы перед чтением.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
39
dev/database/mysql/Mixed binlog format.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-02
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
- "[[Репликация в MySQL]]"
|
||||
linked:
|
||||
- "[[Row Based Replication (RBR)]]"
|
||||
- "[[Statement Based Replication (SBR)]]"
|
||||
---
|
||||
Mixed binlog format — это попытка объединить лучшие стороны [[Statement Based Replication (SBR)|SBR]] и [[Row Based Replication (RBR)|RBR]]. В зависимости от ситуации он может работать либо как SBR, либо как RBR. По умолчанию был дефолтным вариантом в MySQL 5.1.
|
||||
|
||||
**Принципы работы**
|
||||
- [[Statement Based Replication (SBR)|SBR]] используется для простых и детерминированных запросов, таких как UPDATE или INSERT, которые не зависят от текущего состояния данных и могут быть воспроизведены на slave без изменений.
|
||||
- [[Row Based Replication (RBR)|RBR]] применяется для сложных запросов или запросов, которые могут быть недетерминированными, например, когда используются функции, такие как NOW() или RAND(), или для запросов, которые изменяют большое количество строк.
|
||||
|
||||
**Плюсы**:
|
||||
- **Гибкость**: Автоматический выбор между SBR и RBR в зависимости от ситуации позволяет использовать преимущества обоих форматов.
|
||||
- **Оптимизация**: В теории, это позволяет оптимизировать использование ресурсов, выбирая наиболее подходящий метод для каждой транзакции.
|
||||
|
||||
**Минусы**
|
||||
- **Редкое использование**: Встречается редко, так как не всегда работает корректно и может приводить к неожиданным проблемам с репликацией.
|
||||
- **Сложность**: Повышенная сложность настройки и диагностики, что может затруднять управление и устранение неполадок.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
|
||||
**Родитель**:: [[Репликация в MySQL]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-02]]
|
||||
### Дополнительные материалы
|
||||
- [[Statement Based Replication (SBR)]]
|
||||
- [[Row Based Replication (RBR)]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
41
dev/database/mysql/Row Based Replication (RBR).md
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
aliases:
|
||||
- RBR
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-02
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
- "[[Репликация в MySQL]]"
|
||||
linked:
|
||||
- "[[Statement Based Replication (SBR)]]"
|
||||
---
|
||||
От мастера к слейву отправляются только измененные строки, сам результат изменений. Основан на журнале [Row-based Binary Log](Журналы%20в%20MySQL.md#Row-based%20Binary%20Log).
|
||||
|
||||
RBR имеет три режима работы:
|
||||
- full: При изменении сохраняются все колонки (до изменения и после), даже если в них не было изменений. Такой режим потребляет много памяти.
|
||||
- noblob: Работает как full, но не передает изменения BLOB и TEXT колонок.
|
||||
- minimal: При изменении строки сохраняются только измененные колонки и колонки Primary Keys.
|
||||
|
||||
**Плюсы:**
|
||||
- Детерминированность: Запрос выполняется на master, а slave получает уже результат. Это устраняет проблемы, связанные с недетерминированными функциями, как в SBR.
|
||||
- Бинарный формат
|
||||
|
||||
**Минусы:**
|
||||
- **Бинарный формат**: Прочитать глазами уже не получится. Однако, есть утилита `mysqlbinlog -v`, которая позволяет читать журнал.
|
||||
- Большое потребление памяти: Потребляет больше памяти, чем SBR, так как нужно сохранять изменения строк до и после.
|
||||
- в mysql есть binlog_row_image, который решает эту проблему
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
|
||||
**Родитель**:: [[Репликация в MySQL]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-02]]
|
||||
### Дополнительные материалы
|
||||
- [[Statement Based Replication (SBR)]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
40
dev/database/mysql/Statement Based Replication (SBR).md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
aliases:
|
||||
- SBR
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-02
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
- "[[Репликация в MySQL]]"
|
||||
linked:
|
||||
- "[[Row Based Replication (RBR)]]"
|
||||
---
|
||||
Первое, что приходит в голову, это сохранять в Binary Log непосредственно SQL-запросы: Statement-based Binary Log. На основе этого журнала работает Statement Based Replication (SBR). В этом случае master сохраняет в журнал SQL-запросы, а slave получает этот список запросов и выполняет их у себя.
|
||||
|
||||
В основе данной репликации лежит журнал [Statement-based Binary Log](Журналы%20в%20MySQL.md#Statement-based%20Binary%20Log).
|
||||
|
||||
**Плюсы:**
|
||||
- Небольшое количество передаваемых данных, при однотипных изменениях. Например, если мы изменяем 5 миллионов строк одним запросом: `UPDATE users SET bonus=bonus+100`, то нужно передать только 1 строку запроса.
|
||||
- В журнале все записано в понятном человеко-читаемом виде.
|
||||
|
||||
**Проблемы:**
|
||||
* Недетерминирован. Каждый запрос самостоятельно исполняется на слейве.
|
||||
* Вызов функций, например функции `now()`. В момент попадания запроса на slave это будет уже другое время.
|
||||
- [Остальные примеры](https://dev.mysql.com/doc/refman/8.0/en/replication-rbr-safe-unsafe.html): uuid(), fund_rows(), rand(), UDF, триггеры на апдейт, auto_increment
|
||||
- Долгое выполнение сложных запросов. Если запрос выполнялся 10 минут на master, то на slave он тоже будет выполняться 10 минут.
|
||||
|
||||
Для того чтобы SBR работала корректно, есть специальный флажок.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
|
||||
**Родитель**:: [[Репликация в MySQL]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-02]]
|
||||
### Дополнительные материалы
|
||||
- [[Row Based Replication (RBR)|Row Based Replication (RBR)]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
48
dev/database/mysql/Архитектура MySQL.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-16
|
||||
zero-link:
|
||||
- "[[../garden/ru/meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
В MysSQL есть логический слой, который занимается общими и изолированными от хранения данных операциями: кэширование, построение плана запроса и так далее. А есть конкретный физический слой, который отвечает за хранение данных. Он использует интерфейс подключения, то есть реализации хранилищ могут быть разными. ^42f122
|
||||
|
||||
Из-за этого возникают проблемы:
|
||||
- [[Репликация в MySQL]]. Вынуждены писать несколько журналов, на логическом и физическом уровне
|
||||
- Индексы. Реализация одного и того же индекса может отличаться в разных хранилищах
|
||||
- Оптимизатор слабо связан с хранилищем, из-за этого он не может использовать какие-то особенности движка для улучшения производительности.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240613195204.png)
|
||||
|
||||
Клиенты, которые обращаются к серверу через функции соответствующего коннектора или C API по протоколу TCP/IP либо UNIX Socket.
|
||||
|
||||
Логический слой, общий для всех движков:
|
||||
- В управлении подключением происходит авторизация. Каждый клиент работает в своем независимом потоке. Каждый поток может кэшироваться сервером.
|
||||
- Кэш запросов. Представлен одним общим потоком для всех клиентов. Может оказаться узким местом.
|
||||
- Парсер проверяет синтаксис запроса, запрашивает у хранилищ наличие данных таблиц и полей, права доступа непосредственно к этим полям и проверяет наличие ответа в кэше запросов, после чего передает распарсенный запрос оптимизатору;
|
||||
- Оптимизатор запрашивает в интерфейсе хранилищ статистику по индексам, на основании которой он строит план запроса, который передает исполнителю;
|
||||
- Исполнитель. Обращается за данными в хранилище согласно плану запроса. Обновляет значения в кэше запросов.
|
||||
## Оптимизатор
|
||||
Выбирает самый производительный план.
|
||||
|
||||
План запроса, который делает оптимизатор, это не какой-то исполняемый код, а набор инструкций, который передается исполнителю. Это некое предположение о том, как запрос будет выполняться. В отличие от PostrgreSQL, мы не можем посмотреть как фактически был выполнен запрос. Данные от 2015 года, может что-то изменилось. ^432879
|
||||
|
||||
Какие проблемы:
|
||||
- Из-за архитектуры MySQL
|
||||
- использует мало статистики по запросам.
|
||||
- не учитывает особенности хранилищ, нагрузку, буфферы соединений и кэши
|
||||
|
||||
Как влиять на оптимизатор?
|
||||
- Переписать запрос.
|
||||
- Использовать [[../../../../../_inbox/Индексы в MySQL|индексы]]
|
||||
- user/force/ignore index. Можем явно указать когда и какие индексы использовать
|
||||
- straight_join. Можем задать жесткий порядок join таблиц
|
||||
- @@optimizer_switch. Позволяет включать/отключать правила, которые использует оптимизатор.
|
||||
- optimizer_prune_level и optimizer_search_depth. Верхняя граница количества вариантов и времени выполнения, которые рассмотрит оптимизатор.
|
||||
|
||||
## Заметки
|
||||
- mariadb - форк Mysql, который пытается исправить архитектурные ошибки MySQL
|
65
dev/database/mysql/Журналы в MySQL.md
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
aliases:
|
||||
- InnoDB
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-05-28
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
- "[[../garden/ru/dev/database/mysql/Архитектура MySQL|Архитектура MySQL]]"
|
||||
linked:
|
||||
- "[[Репликация в MySQL]]"
|
||||
---
|
||||
Изначально в MySQL не было никаких журналов. Был движок MyISAM, а в нем журнала нет.
|
||||
|
||||
![](Pasted%20image%2020240528082025.png)
|
||||
На рисунке вы можете видеть штуку, которая называется Storage Engines: это такая сущность, которая занимается вопросами, как писать данные на диск и как нам их оттуда читать, как по ним искать и пр.
|
||||
|
||||
Потом прикрутили репликацию. Репликация – это одна строчка в самом левом верхнем квадратике – Management Services&Utilites. Для репликации потребовался журнал. Его начали писать. Он называется Binary Log. Никто не думал про то, чтобы его использовать как-то иначе, просто сделали.
|
||||
|
||||
Примерно в это же время MySQL подарили новый Storage Engine, который называется InnoDB. Это широко используемая штука, и в InnoDB свой журнал. Получилось два журнала – InnoDB и Binary Log. Этот момент стал точкой невозврата, после чего появились проблемы, которые решить очень тяжело.
|
||||
|
||||
Binary Log не используется для [Point In Time Recovery](Point%20In%20Time%20Recovery%20(PITR).md), а InnoDB Undo/Redo Log не используется в репликации. Получилось, что у PostgreSQL журнал один, а у MySQL их, как бы, два.
|
||||
## InnoDB Undo/Redo Log
|
||||
## Binary Log
|
||||
У Binary Log, который нужен для репликации, есть два или три формата (типа).
|
||||
### Statement-based Binary Log
|
||||
Самый первый тип, который появился, который было проще всего сделать, это Statement-based Binary Log. Что это такое? Это просто файл, в который последовательно пишутся транзакция за транзакцией. Это выглядит примерно так:
|
||||
|
||||
![](Pasted%20image%2020240528082432.png)
|
||||
|
||||
В транзакции указывается БД, на которой совершаются эти обновления, указывается timestamp времени начала транзакции, и дальше идет сама транзакция.
|
||||
### Row-based Binary Log
|
||||
Второй тип называется Row-based репликация. Это журнал, в который пишутся не сами запросы, а те строчки, которые они меняют. Он состоит из двух частей – BEFORE image и AFTER image:
|
||||
|
||||
![](Pasted%20image%2020240528082516.png)
|
||||
На картинке BEFORE image сверху, а AFTER image – внизу.
|
||||
|
||||
В BEFORE image помещаются те строчки, которые были до выполнения транзакции. Красным цветом помечены строчки, которые удаляются:
|
||||
|
||||
![](Pasted%20image%2020240528082538.png)
|
||||
|
||||
Они из BEFORE image наверху, но их нет внизу – в AFTER image, значит, они удаляются.
|
||||
|
||||
На следующей картинке зеленым помечены строчки, которые добавились:
|
||||
|
||||
![](Pasted%20image%2020240528082552.png)
|
||||
|
||||
Синие UPDATE'ы есть и в BEFORE image, и в AFTER image. Это обновления.
|
||||
|
||||
Проблема такого решения связана с тем, что до недавнего времени в Row-based репликации писались в log все колонки, даже если мы обновили одну. В MySQL 5.6 это починили, и с этим должно стать полегче.
|
||||
### Mixed-based
|
||||
Он работает либо как Statement-based, либо как Row-based, но он широко не распространен.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
|
||||
**Родитель**:: [[Архитектура MySQL]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-05-28]]
|
||||
### Дополнительные материалы
|
||||
- [[Репликация в MySQL]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
127
dev/database/mysql/Репликация в MySQL.md
Normal file
@ -0,0 +1,127 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-05-28
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 MySQL|00 MySQL]]"
|
||||
parents:
|
||||
- "[[../../architecture/highload/Репликация БД|Репликация БД]]"
|
||||
linked:
|
||||
- "[[Журналы в MySQL]]"
|
||||
link:
|
||||
---
|
||||
## Тезисы
|
||||
- На slave можно реализовать другую схему БД, построить другие индексы.
|
||||
- Можно использовать [libslave](libslave.md), чтобы "притвориться" репликой.
|
||||
- Мастер многопоточен, а слейв - нет. Вроде исправлено в новых версиях SQL.
|
||||
- В 5.6 версии можно реплицировать параллельно несколько БД
|
||||
- В 5.7 версии можно реплицировать параллельно одни и те же таблицы
|
||||
- Обязательно убедиться, что работают GUID идентификация транзакций.
|
||||
- **Репликация сильно зависит от версии MySql**
|
||||
- Всегда логическая репликация, модель master-slave, pull распространение
|
||||
- 4.1 = асинхронная, SBR, logposs
|
||||
- 5.1 = +RBR, +mixed. Дефолт mixed
|
||||
- 5.6 = +semisync, +mtslave (per-db), +slavedelay, +GTID
|
||||
- 5.7 = + mtslave, +master-master (plugin), +default-RBR (image=full?!), groupcommit
|
||||
## Схема работы репликации
|
||||
![Архитектура MySQL](Архитектура%20MySQL.md#^42f122)
|
||||
|
||||
Физический слой хранилища должен писать журнал для работы транзакций (Write-Ahead Log). По идее, его можно было бы использовать для репликации, как в PostgreSQL, но логический слой ничего не знает про физический и не может использовать тот же журнал. Поэтому при включении репликации на логическом уровне master начинает вести свой журнал, называемый Binary Log.
|
||||
|
||||
Механизм работы следующий:
|
||||
- **Запись изменений в бинарный лог**: Все изменения данных записываются в бинарный лог (Binary Log) на мастере. Бинарный лог хранит последовательность всех транзакций, которые изменяют данные.
|
||||
- **Передача бинарного лога на реплики**: Мастер передает бинарный лог на реплики. Для этого используются потоки binlog dump на мастере и I/O потоки на репликах. В отличие от PostgreSQL, используется pull модель распространения, то есть реплики сами забирают изменения с master.
|
||||
- **Применение изменений на репликах**: Реплики считывают бинарный лог и применяют изменения к своим копиям данных, поддерживая синхронизацию с мастером.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240712083105.png)
|
||||
|
||||
Binary Log в MySQL может записывать данные в разных форматах, в зависимости от настроек журнала. Рассмотрим основные из них:
|
||||
- [Statement Based Replication (SBR)](Statement%20Based%20Replication%20(SBR).md)
|
||||
- [Row Based Replication (RBR)](Row%20Based%20Replication%20(RBR).md)
|
||||
- [Mixed binlog format](Mixed%20binlog%20format.md)
|
||||
|
||||
**Процесс записи данных операции в MySQL**
|
||||
- INSERT INTO test VALUES (123, 'hello')
|
||||
- Записываем в таблицу на мастере mysqld
|
||||
- Записываем в binary log на мастере
|
||||
- Записываем в relay log на слейве
|
||||
- таблица на слейве mysqld
|
||||
|
||||
Рабочие потоки ([MySQL Replication Threads](https://dev.mysql.com/doc/refman/8.0/en/replication-threads.html)):
|
||||
- binlog dump thread. Сохраняет лог транзакций на master
|
||||
- slave I/O thread. Спуливает изменения на slave с master
|
||||
- slave SQL thread. Применяет изменения на slave
|
||||
|
||||
MySQL не решает из коробки проблемы кластеризации. Из коробки нет переключений со slave на master если мастер сдох, распределения нагрузки и так далее. Можно решить дополнительным софтом:
|
||||
- MHA (MySQL Master HA)
|
||||
- MySQL Failover (Oracle)
|
||||
- Orchestrator
|
||||
## Фильтрация репликации
|
||||
Можно реплицировать данные частично, но это стоит использовать осторожно. Например, это не работает с [Групповая репликация](../../architecture/highload/Групповая%20репликация.md)
|
||||
|
||||
Опции:
|
||||
- replicate_do_db
|
||||
- replicate_ignore_db
|
||||
- replicate_do_table
|
||||
|
||||
[MySQL - CHANGE REPLICATION FILTER Statement](https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html)
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240605091913.png)
|
||||
|
||||
|
||||
***
|
||||
|
||||
- В InnoDB, заметьте, т.е. у нас архитектура разделяет репликацию выше, а storage engine ниже. Но storage engine, для того, чтобы репликация работала, должен, грубо говоря, замедлять insert'ы в таблицу.
|
||||
- Другая проблема состоит в том, что мастер выполняет запросы параллельно, т.е. одновременно, а слэйв их может применять последовательно. Возникает вопрос – а почему слэйв не может применять их параллельно? На самом деле, с этим все непросто. Есть теорема о сериализации транзакций, которая рассказывает, когда мы можем выполнять запросы параллельно, а когда последовательно. Это отдельная сложная тема, разберитесь в ней, если вам интересно и нужно, например, почитав по ссылке – [http://plumqqz.livejournal.com/387380.html](http://plumqqz.livejournal.com/387380.html).
|
||||
- В MySQL репликация упирается в процессор. Это прекрасная картинка – большой, мощный сервер, 12 ядер. Работает одно ядро, заодно занято репликацией. Из-за этого реплика задыхается. Это очень грустно.
|
||||
|
||||
Для того чтобы выполнять запросы параллельно существует группировка запросов. В InnoDB есть специальная опция, которая управляет тем, как именно мы группируем транзакции, как именно мы их пишем на диск. Проблема в том, что мы можем их сгруппировать на уровне InnoDB, а уровнем выше – на уровне репликации – этой функциональности не было. В 2010 г. Кристиан Нельсен из MariaDB реализовал такую фичу, которая называется Group Binary Log Commit. Получается, мы журнал повторяем на двух уровнях – Storage Engine и репликация, и нам нужно таскать фичи из одного уровня на другой. Это сложный механизм. Более того, нам нужно одновременно консистентно писать сразу в два журнала – two-phase-commit. Это еще хуже.
|
||||
|
||||
На следующей картинке мы видим два графика:
|
||||
![](../../../meta/files/images/Pasted%20image%2020240528090119.png)
|
||||
Синий график демонстрирует то, как масштабируется InnoDB, когда мы ему добавляем треды. Накидываем треды – число транзакций, которые он обрабатывает, возрастает. Красная линия показывает ситуацию, когда включена репликация. Мы включаем репликацию и теряем масштабируемость. Потому что лог в Binary Log пишется синхронно, и Group Binary Log Commit это решает.
|
||||
|
||||
Грустно, что приходится так делать из-за разделения – Storage Engine внизу, репликация наверху. С этим все плохо. В MySQL 5.6 и 5.7 эта проблема решена – есть Group Binary Log Commit, и мастер теперь не отстает. Теперь это пытаются использовать для параллелизма репликации, чтобы на слэйве запросы из одной группы запустить параллельно. Тут я написал, что из этого нужно крутить:
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240528090205.png)
|
||||
|
||||
## Параллельная репликация
|
||||
Сценарий ([Estimating potential for MySQL 5.7 parallel replication](https://www.percona.com/blog/estimating-potential-for-mysql-5-7-parallel-replication/)):
|
||||
- 1 мастер, 3 слейва
|
||||
- первый реплицирует в 1 поток
|
||||
- второй в 20 потоков
|
||||
- третий в 100 потоков
|
||||
- вставка в 25 различных таблиц внутри одной базы в 100 потоков
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240606094633.png)
|
||||
|
||||
Полезные опции:
|
||||
- sysvar_replica_parallel_workers - количество потоков
|
||||
- sysvar_replica_parallel_type
|
||||
- DATABASE - транзакции применяются параллельно, если они обновляют разные БД
|
||||
- LOGICAL_CLOCK - транзакции применяются параллельно на реплике на основе timestamp
|
||||
## Отставание реплики
|
||||
- [Отставание реплики БД](../../architecture/highload/Отставание%20реплики%20БД.md)
|
||||
|
||||
Диагностировать причину отставания реплики тяжело. Есть средство диагностики в MySQL, называется log медленных запросов. Вы можете его открыть, найти топ самых тяжелых запросов и исправить их. Но с репликацией это не работает. Нужно проводить статистический анализ – считать статистику – какие таблицы стали чаще использоваться. Вручную это сделать очень тяжело.
|
||||
|
||||
В MySQL 5.6 / 5.7 появилась SLAVE PERFORMANCE SCHEMA, на базе которой такую диагностику провести проще. Мы обычно открываем лог коммитов в puppet и смотрим, что же мы выкатили в то время, когда репликация начала отставать. Иногда даже это не помогает, приходится ходить по всем разработчикам и спрашивать, что они сделали, они ли сломали репликацию. Это грустно, но с этим приходится жить.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]]
|
||||
**Родитель**:: [[../../architecture/highload/Репликация БД|Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-05-28]]
|
||||
### Дополнительные материалы
|
||||
- [Как устроена MySQL-репликация / Андрей Аксенов (Sphinx) - YouTube](https://www.youtube.com/watch?v=lHFaZkJk2O0)
|
||||
- [Асинхронная репликация без цензуры / HighLoad](https://highload.guide/blog/asynchronous-replication.html)
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Row Based Replication (RBR)]]
|
||||
- [[Statement Based Replication (SBR)]]
|
||||
- [[Mixed binlog format]]
|
||||
<!-- SerializedQuery END -->
|
31
dev/database/postgresql/Write-Ahead Log.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
aliases:
|
||||
- WAL
|
||||
- Журнал в PostgreSQL
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-05-26
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]"
|
||||
parents:
|
||||
- "[[../Журнал БД|Журнал БД]]"
|
||||
linked:
|
||||
- "[[Репликация в PostgreSQL]]"
|
||||
---
|
||||
В журнал попадают физические изменения, т.е. обновления страничек. Есть [[../../fundamental/Страница|страница]] в памяти, на ней лежат какие-то данные, мы с ней что-то сделали – вот эту разницу мы записываем в журнал.
|
||||
|
||||
В WAL попадает всё: обновление таблиц, создание триггеров, создание хранимых процедур и так далее.
|
||||
|
||||
![](Pasted%20image%2020240531083602.png)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
|
||||
**Родитель**:: [[../Журнал БД|Журнал БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-05-26]]
|
||||
### Дополнительные материалы
|
||||
- [[Репликация в PostgreSQL]]
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
386
dev/database/postgresql/Настройка репликации в PostgreSQL.md
Normal file
@ -0,0 +1,386 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-06-17
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]"
|
||||
parents:
|
||||
- "[[Репликация в PostgreSQL|Репликация в PostgreSQL]]"
|
||||
linked:
|
||||
---
|
||||
## Физическая репликация
|
||||
Создаем сеть, запоминаем адрес
|
||||
```shell
|
||||
docker network create pgnet
|
||||
docker network inspect pgnet | grep Subnet # Запомнить маску сети
|
||||
```
|
||||
|
||||
Поднимаем мастер
|
||||
```shell
|
||||
docker run -dit -v "$PWD/volumes/pgmaster/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "5432:5432" --restart=unless-stopped --network=pgnet --name=pgmaster postgres
|
||||
```
|
||||
|
||||
Меняем postgresql.conf на мастере
|
||||
```conf
|
||||
ssl = off
|
||||
wal_level = replica
|
||||
max_wal_senders = 4 # expected slave num
|
||||
```
|
||||
|
||||
Подключаемся к мастеру и создаем пользователя для репликации
|
||||
```shell
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
create role replicator with login replication password 'pass';
|
||||
exit
|
||||
```
|
||||
|
||||
Добавляем запись в `pgmaster/pg_hba.conf` с `subnet` с первого шага
|
||||
```
|
||||
host replication replicator __SUBNET__ md5
|
||||
```
|
||||
|
||||
Перезапустим мастер
|
||||
```shell
|
||||
docker restart pgmaster
|
||||
```
|
||||
|
||||
Сделаем бэкап для реплик
|
||||
```shell
|
||||
docker exec -it pgmaster bash
|
||||
mkdir /pgslave
|
||||
pg_basebackup -h pgmaster -D /pgslave -U replicator -v -P --wal-method=stream
|
||||
exit
|
||||
```
|
||||
|
||||
Копируем директорию себе
|
||||
```shell
|
||||
docker cp pgmaster:/pgslave volumes/pgslave/
|
||||
```
|
||||
|
||||
Создадим файл, чтобы реплика узнала, что она реплика
|
||||
```shell
|
||||
touch volumes/pgslave/standby.signal
|
||||
```
|
||||
|
||||
Меняем `postgresql.conf` на реплике `pgslave`
|
||||
```conf
|
||||
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgslave'
|
||||
```
|
||||
|
||||
Запускаем реплику `pgslave`
|
||||
```shell
|
||||
docker run -dit -v "$PWD/volumes/pgslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "15432:5432" --network=pgnet --restart=unless-stopped --name=pgslave postgres
|
||||
```
|
||||
|
||||
Запустим вторую реплику `pgasyncslave`
|
||||
|
||||
Скопируем бэкап
|
||||
```shell
|
||||
docker cp pgmaster:/pgslave volumes/pgasyncslave/
|
||||
```
|
||||
|
||||
Изменим настройки `pgasyncslave/postgresql.conf`
|
||||
```conf
|
||||
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgasyncslave'
|
||||
```
|
||||
|
||||
Дадим знать что это реплика
|
||||
```shell
|
||||
touch volumes/pgasyncslave/standby.signal
|
||||
```
|
||||
|
||||
Запустим реплику `pgasyncslave`
|
||||
```shell
|
||||
docker run -dit -v "$PWD/volumes/pgasyncslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "25432:5432" --network=pgnet --restart=unless-stopped --name=pgasyncslave postgres
|
||||
```
|
||||
|
||||
Убеждаемся что обе реплики работают в асинхронном режиме на `pgmaster`
|
||||
```shell
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
exit;
|
||||
```
|
||||
|
||||
Включаем синхронную репликацию на `pgmaster`
|
||||
|
||||
Меняем файл `pgmaster/postgresql.conf`
|
||||
```conf
|
||||
synchronous_commit = on
|
||||
synchronous_standby_names = 'FIRST 1 (pgslave, pgasyncslave)'
|
||||
```
|
||||
|
||||
Перечитываем конфиг
|
||||
```shell
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
select pg_reload_conf();
|
||||
exit;
|
||||
```
|
||||
|
||||
Убеждаемся, что реплика стала синхронной
|
||||
```shell
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
exit;
|
||||
```
|
||||
|
||||
Создадим тестовую таблицу на `pgmaster` и проверим репликацию
|
||||
```shell
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
create table test(id bigint primary key not null);
|
||||
insert into test(id) values(1);
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Проверим наличие данных на `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Проверим наличие данных на `pgasyncslave`
|
||||
```shell
|
||||
docker exec -it pgasyncslave su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Попробуем сделать `insert` на `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
insert into test(id) values(2);
|
||||
exit;
|
||||
```
|
||||
|
||||
Укладываем репилку `pgasyncslave` и проверяем работу `pgmaster` и `pgslave`
|
||||
```shell
|
||||
docker stop pgasyncslave
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
insert into test(id) values(2);
|
||||
select * from test;
|
||||
exit;
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Укладываем репилку `pgslave` и проверяем работу `pgmaster`, а потом возвращаем реплику `pgslave`
|
||||
|
||||
terminal 1
|
||||
```shell
|
||||
docker stop pgslave
|
||||
docker exec -it pgmaster su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
insert into test(id) values(3);
|
||||
exit;
|
||||
```
|
||||
|
||||
terminal 2
|
||||
```shell
|
||||
docker start pgslave
|
||||
```
|
||||
|
||||
Возвращаем вторую реплику `pgasyncslave`
|
||||
```shell
|
||||
docker start pgasyncslave
|
||||
```
|
||||
|
||||
Убиваем мастер `pgmaster`
|
||||
```shell
|
||||
docker stop pgmaster
|
||||
```
|
||||
|
||||
Запромоутим реплику `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select pg_promote();
|
||||
exit;
|
||||
```
|
||||
|
||||
Пробуем записать в новый мастер `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
insert into test(id) values(4);
|
||||
exit;
|
||||
```
|
||||
|
||||
Настраиваем репликацию на `pgslave` (`pgslave/postgresql.conf`)
|
||||
|
||||
изменяем конфиг
|
||||
```conf
|
||||
synchronous_commit = on
|
||||
synchronous_standby_names = 'ANY 1 (pgmaster, pgasyncslave)'
|
||||
```
|
||||
|
||||
перечитываем конфиг
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select pg_reload_conf();
|
||||
exit;
|
||||
```
|
||||
|
||||
Подключим вторую реплику `pgasyncslave` к новому мастеру `pgslave`
|
||||
|
||||
изменяем конфиг `pgasyncslave/postgresql.conf`
|
||||
```conf
|
||||
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgasyncslave'
|
||||
```
|
||||
|
||||
перечитываем конфиг
|
||||
```shell
|
||||
docker exec -it pgasyncslave su - postgres -c psql
|
||||
select pg_reload_conf();
|
||||
exit;
|
||||
```
|
||||
|
||||
Проверяем что к новому мастеру `pgslave` подключена реплика и она работает
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
insert into test(id) values (5)
|
||||
select * from test;
|
||||
exit;
|
||||
docker exec -it pgasyncslave su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Восстановим старый мастер `pgmaster` как реплику
|
||||
|
||||
Помечаем как реплику
|
||||
```shell
|
||||
touch volumes/pgmaster/standby.signal
|
||||
```
|
||||
|
||||
Изменяем конфиг `pgmaster/postgresql.conf`
|
||||
```conf
|
||||
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgmaster'
|
||||
```
|
||||
|
||||
Запустим `pgmaster`
|
||||
```shell
|
||||
docker start pgmaster
|
||||
```
|
||||
|
||||
Убедимся что `pgmaster` подключился как реплика к `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
select application_name, sync_state from pg_stat_replication;
|
||||
exit;
|
||||
```
|
||||
|
||||
## Логическая репликация
|
||||
Меняем `wal_level` для текущего мастера `pgslave`
|
||||
|
||||
Изменяем настройки `pgslave/postgresql.conf`
|
||||
```conf
|
||||
wal_level = logical
|
||||
```
|
||||
|
||||
Перезапускаем `pgslave`
|
||||
```shell
|
||||
docker restart pgslave
|
||||
```
|
||||
|
||||
Создадим публикацию в `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
GRANT CONNECT ON DATABASE postgres TO replicator;
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator;
|
||||
create publication pg_pub for table test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Создадим новый сервер `pgstandalone` для логической репликации
|
||||
```shell
|
||||
docker run -dit -v "$PWD/volumes/pgstandalone/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "35432:5432" --restart=unless-stopped --network=pgnet --name=pgstandalone postgres
|
||||
```
|
||||
|
||||
Копируем файлы c `pgslave` в `pgstandalone` и восстанавливаем
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres
|
||||
pg_dumpall -U postgres -r -h pgslave -f /var/lib/postgresql/roles.dmp
|
||||
pg_dump -U postgres -Fc -h pgslave -f /var/lib/postgresql/schema.dmp -s postgres
|
||||
exit;
|
||||
|
||||
docker cp pgslave:/var/lib/postgresql/roles.dmp .
|
||||
docker cp roles.dmp pgstandalone:/var/lib/postgresql/roles.dmp
|
||||
docker cp pgslave:/var/lib/postgresql/schema.dmp .
|
||||
docker cp schema.dmp pgstandalone:/var/lib/postgresql/schema.dmp
|
||||
|
||||
docker exec -it pgstandalone su - postgres
|
||||
psql -f roles.dmp
|
||||
pg_restore -d postgres -C schema.dmp
|
||||
exit
|
||||
```
|
||||
|
||||
Создаем подписку на `pgstandalone`
|
||||
```shell
|
||||
docker exec -it pgstandalone su - postgres -c psql
|
||||
CREATE SUBSCRIPTION pg_sub CONNECTION 'host=pgslave port=5432 user=replicator password=pass dbname=postgres' PUBLICATION pg_pub;
|
||||
exit;
|
||||
```
|
||||
|
||||
Убеждаемся что репликация запущена
|
||||
```shell
|
||||
docker exec -it pgstandalone su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Сделаем конфликт в данных
|
||||
|
||||
Вставляем данные в подписчике `pgstandalone`
|
||||
```shell
|
||||
docker exec -it pgstandalone su - postgres -c psql
|
||||
insert into test values(9);
|
||||
exit;
|
||||
```
|
||||
|
||||
Вставляем данные в паблишере `pgslave`
|
||||
```shell
|
||||
docker exec -it pgslave su - postgres -c psql
|
||||
insert into test values(9);
|
||||
insert into test values(10);
|
||||
exit;
|
||||
```
|
||||
|
||||
Убеждаемся что записи с id 10 не появилось на `pgstandalone`
|
||||
```shell
|
||||
docker exec -it pgstandalone su - postgres -c psql
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
|
||||
Посмотрим в логи `pgstandalone` и убедимся что у нас произошел разрыв репликации
|
||||
```shell
|
||||
docker logs pgstandalone
|
||||
|
||||
2023-03-27 16:15:02.753 UTC [258] ERROR: duplicate key value violates unique constraint "test_pkey"
|
||||
2023-03-27 16:15:02.753 UTC [258] DETAIL: Key (id)=(9) already exists.
|
||||
2023-03-28 18:30:42.893 UTC [108] CONTEXT: processing remote data for replication origin "pg_16395" during message type "INSERT" for replication target relation "public.test" in transaction 739, finished at 0/3026450
|
||||
```
|
||||
|
||||
Исправляем конфликт
|
||||
```shell
|
||||
docker exec -it pgstandalone su - postgres -c psql
|
||||
SELECT pg_replication_origin_advance('pg_16395', '0/3026451'::pg_lsn); # message from log + 1
|
||||
ALTER SUBSCRIPTION pg_sub ENABLE;
|
||||
select * from test;
|
||||
exit;
|
||||
```
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
|
||||
**Родитель**:: [[Репликация в PostgreSQL|Репликация в PostgreSQL]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-06-17]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
70
dev/database/postgresql/Репликация в PostgreSQL.md
Normal file
@ -0,0 +1,70 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-05-28
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]"
|
||||
parents:
|
||||
- "[[../../architecture/highload/Репликация БД|Репликация БД]]"
|
||||
linked:
|
||||
---
|
||||
## Тезисы
|
||||
- Реализуется на базе журнала [WAL](Write-Ahead%20Log.md).
|
||||
- Репликация упирается в диск, а не в процессор.
|
||||
- Реплика это точная бинарная копия мастера.
|
||||
- Работает по push модели
|
||||
- При физической репликации фильтрация не возможна
|
||||
***
|
||||
Распространение изменений в PostgreSQL происходит по push модели. То есть, master отправляет [[Write-Ahead Log|WAL]] на реплики, а реплика применяет данные физически, согласно записям в WAL. Таким образом, если остановить запись в master, дождаться синхронизации реплик и сделать бинарное сравнение master и slaves, они будут идентичны.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240606094952.png)
|
||||
|
||||
Производительность репликации в PostgreSQL обычно ограничена производительностью дисков, а не процессора. Поэтому при использовании HDD рекомендуется выделять отдельный диск для WAL.
|
||||
|
||||
Добавление реплики требует остановки работы приложения, чтобы никакие записи не менялись в БД. Хотя, если данные пишутся не так часто, то новая реплика может просто догнать отставание в мастер, которое образуется за время подключения слейва.
|
||||
|
||||
|
||||
## Синхронизация
|
||||
Async:
|
||||
- synchronus_commit =
|
||||
- off - не будет дожидаться даже локального подтверждения, нет гарантии что данные дошли до бд
|
||||
- local - происходит локальный коммит и в этот же момент отправляется подтверждение
|
||||
|
||||
Sync/Semi-symc:
|
||||
- synchronus_commit = remote_write \/ on \/ remote_apply
|
||||
- remote_write - транзакция подтверждается только если получено подтверждение со всех реплик
|
||||
- synchronus_standby_names = \[FIRST \/ ANY\] N (replicas_list)
|
||||
- позволяет настроить от скольких реплик ожидается ответ
|
||||
## Логическая репликация
|
||||
Логическая репликация позволяет более гибко управлять копированием данных. Она предоставляет возможность реплицировать отдельные таблицы или схемы, а не всю базу данных целиком. Это особенно полезно для частичного копирования данных и интеграции с другими системами.
|
||||
|
||||
Logical Log Streaming Replication – это способ трансформировать Write-Ahead Log. Например, мы не хотим реплицировать все таблицы из данной базы, а хотим реплицировать только часть. Logical Log Streaming Replication позволяет мастеру объяснить, что из таблиц будет уезжать на слэйв.
|
||||
|
||||
Logical Decoding – способ визуализировать то, что находится в PostgreSQL Write-Ahead Log. На самом деле, если мы можем напечатать в каком-то виде то, что у нас происходит на слэйве, точнее, что нам пришло через Write-Ahead Log, это значит, что мы можем программно реализовать все то, что делает libslave. Получили insert, update, delete, у нас “дернулся” нужный callback, мы узнали про изменения. Это и есть Logical Decoding.
|
||||
|
||||
![](Pasted%20image%2020240606100439.png)
|
||||
|
||||
**Конфликты:**
|
||||
- Нужно идентифицировать запись для update/delete (по первичному ключу/по уникальному ненуллабельному индексу/по всем столбцам).
|
||||
- В случае возникновения конфликта требуется вручную исправить данные.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]
|
||||
**Родитель**:: [[../../architecture/highload/Репликация БД|Репликация БД]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-05-28]]
|
||||
### Дополнительные материалы
|
||||
- [[Настройка репликации в PostgreSQL]]
|
||||
- [BDR User Guide - PostgreSQL wiki](https://wiki.postgresql.org/wiki/Logical_Log_Streaming_Replication)
|
||||
- [PostgreSQL: Documentation: 16: Chapter 31. Logical Replication](https://www.postgresql.org/docs/current/logical-replication.html)
|
||||
- [PostgreSQL: Documentation: 9.4: Logical Decoding](https://www.postgresql.org/docs/9.4/logicaldecoding.html). Аналог [libslave](libslave.md) в MySQL
|
||||
- [Отладка и устранение проблем в PostgreSQL Streaming Replication / Хабр](https://m.habr.com/ru/company/oleg-bunin/blog/414111/)
|
||||
- [An Overview of Logical Replication in PostgreSQL | Severalnines](https://severalnines.com/blog/overview-logical-replication-postgresql/)
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Настройка репликации в PostgreSQL]]
|
||||
<!-- SerializedQuery END -->
|
49
dev/database/Журнал БД.md
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-05-26
|
||||
zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Основная цель журнала — фиксировать все изменения, происходящие в базе данных, до их окончательного применения. Это позволяет выполнять [[../../../../_inbox/Транзакция БД|транзакции]] и [[../architecture/highload/Репликация БД|репликацию бд]].
|
||||
|
||||
Перед тем как выполнить SQL-запрос, база данных записывает в журнал все действия, которые собирается сделать. После того как журнал зафиксировался на диске, база данных изменяет сами данные в памяти. И только через какое-то время эти данные окажутся на диске в хранилище. Этот алгоритм называется [PITR](Point%20In%20Time%20Recovery%20(PITR).md)
|
||||
|
||||
![](Pasted%20image%2020240528081137.png)
|
||||
Этот процесс обеспечивает два важных аспекта:
|
||||
- **Надежность**: В случае сбоя системы, данные можно восстановить из журнала до последнего зафиксированного состояния.
|
||||
- **Консистентность**: Все транзакции, записанные в журнал, будут применены в базе данных в правильном порядке, что предотвращает потерю данных и сохраняет целостность системы.
|
||||
|
||||
> [!INFO]
|
||||
> Журналы базы данных часто имеют циклическую структуру, где новые данные записываются поверх старых, когда журнал заполняется. Это позволяет эффективно использовать дисковое пространство и упрощает управление журналом.
|
||||
|
||||
Реализации в СуБД:
|
||||
- [[postgresql/Write-Ahead Log|Журнал в PostgreSQL]]
|
||||
- [Журналы в MySQL](mysql/Журналы%20в%20MySQL.md)
|
||||
|
||||
Главные вопросы, которые встают перед разработчиком любой БД:
|
||||
- Как организовать журнал?
|
||||
- Как его писать?
|
||||
- Как писать его меньше?
|
||||
- Как сделать так, чтобы это работало быстрее?
|
||||
- При чем тут репликация?
|
||||
|
||||
Для улучшения производительности желательно под журналы выделять отдельные жесткие диски. Чтобы у журнала был эксклюзивный доступ к ресурсам диска. Менее актуально для SSD.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Базы Данных|00 Базы Данных]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-05-26]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Write-Ahead Log]]
|
||||
<!-- SerializedQuery END -->
|
@ -14,7 +14,7 @@ linked:
|
||||
|
||||
Для решения этой проблемы нужно изменить подсеть Docker по умолчанию. Таким образом, вы можете выбрать те подсети, которые не конфликтует с вашей корпоративной сетью.
|
||||
|
||||
Откройте файл настроек `/etc/docker/daemon.json` и введите IP-адрес сетевой маски:
|
||||
Откройте файл настроек `/etc/docker/daemon.json` и введите IP-адрес сетевой маски:
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Гайдов, как устанавливать docker полно в интернете. [Официальная документации](https://docs.docker.com/engine/install/) написана доступным языком.
|
||||
Гайдов, как устанавливать docker полно в интернете. [Официальная документации](https://docs.docker.com/engine/install/) написана доступным языком.
|
||||
|
||||
Команды установки docker для CentOS 8 и RHEL 8.
|
||||
|
||||
@ -31,7 +31,7 @@ chmod +x ~/.docker/cli-plugins/docker-compose
|
||||
[Актуальная версия docker-compose](https://github.com/docker/compose/releases/)
|
||||
|
||||
> [!INFO]
|
||||
> Эта команда устанавливает Compose V2 для активного пользователя в каталог `$HOME`. Чтобы установить Docker Compose для всех пользователей вашей системы, замените `~/.docker/cli-plugins` на `/usr/local/lib/docker/cli-plugins`.
|
||||
> Эта команда устанавливает Compose V2 для активного пользователя в каталог `$HOME`. Чтобы установить Docker Compose для всех пользователей вашей системы, замените `~/.docker/cli-plugins` на `/usr/local/lib/docker/cli-plugins`.
|
||||
|
||||
Проверяем, что установка прошла успешно.
|
||||
|
||||
@ -41,7 +41,7 @@ Docker Compose 2.2.3
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Также обращаю ваше внимание, что в Compose V1 для работы использовалась команда `docker-compose`, а в V2 отказались от дефиса `docker compose`
|
||||
> Также обращаю ваше внимание, что в Compose V1 для работы использовалась команда `docker-compose`, а в V2 отказались от дефиса `docker compose`
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
|
45
dev/fundamental/Copy-on-write.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
aliases:
|
||||
- COW
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Copy-on-Write (COW) — это техника оптимизации управления памятью, используемая в [[../../../../knowledge/dev/pc/Операционная система|операционных системах]] для эффективного копирования данных, особенно в контексте [[Многозадачность ЦПУ|многозадачности]] и управления виртуальной памятью. Этот метод позволяет нескольким процессам совместно использовать одну и ту же страницу памяти до тех пор, пока данные не нужно будет изменить, что экономит ресурсы и ускоряет выполнение программ.
|
||||
|
||||
**Как работает Copy-on-Write:**
|
||||
- **Совместное использование страниц:** Когда [[Процесс ОС|процесс]] создаёт копию себя (например, при вызове fork() в UNIX-подобных системах), операционная система не копирует все [[Страница|страницы]] памяти сразу. Вместо этого родительский и дочерний процессы продолжают совместно использовать одни и те же страницы памяти.
|
||||
- **Установка флага защиты:** Страницы, используемые в режиме Copy-on-Write, помечаются как «только для чтения» для обоих процессов. Это означает, что оба процесса могут читать данные без необходимости создания отдельных копий для каждого из них.
|
||||
- **Промах страницы** ([[Page Fault]]) при записи: Если один из процессов пытается изменить данные на странице, происходит Page Fault. Операционная система понимает, что требуется изменить данные, которые в данный момент используются совместно, и инициирует Copy-on-Write.
|
||||
- **Создание копии страницы:** Операционная система создаёт отдельную копию страницы только для того процесса, который пытается внести изменения. В результате изменения затрагивают только копию, а остальные процессы продолжают использовать оригинальную страницу без изменений.
|
||||
- **Обновление таблицы страниц:** После создания копии, таблица страниц соответствующего процесса обновляется, чтобы указывать на новую копию страницы, которая теперь доступна для записи.
|
||||
|
||||
**Примеры использования:**
|
||||
- **Процессы и fork():** Когда выполняется fork(), дочерний процесс получает копию адресного пространства родительского процесса. Copy-on-Write позволяет избежать полной копии всех данных сразу, экономя время и память.
|
||||
- **Виртуальные машины и контейнеры:** Виртуальные машины и контейнеры часто используют Copy-on-Write для совместного использования одинаковых библиотек и данных между разными экземплярами.
|
||||
- **Файловые системы (например, Btrfs, ZFS):** Некоторые файловые системы используют Copy-on-Write для создания снимков (snapshot) и клонирования данных без необходимости немедленного копирования всех данных.
|
||||
|
||||
**Преимущества Copy-on-Write:**
|
||||
- **Экономия памяти:** Позволяет избежать дублирования данных до тех пор, пока это действительно не нужно, что снижает расход оперативной памяти.
|
||||
- **Ускорение выполнения:** Процессы могут начинать работать быстрее, поскольку нет необходимости мгновенно копировать большие объемы данных.
|
||||
- **Гибкость и безопасность:** Совместное использование данных безопасно до тех пор, пока нет попыток изменить данные, что упрощает управление памятью.
|
||||
|
||||
**Недостатки Copy-on-Write:**
|
||||
- **Задержки при записи:** При попытке записи возникает задержка из-за необходимости создания копии страницы, что может вызывать временное снижение производительности.
|
||||
- **Усложнение управления памятью:** Операционная система должна отслеживать и обрабатывать копии страниц, что усложняет управление виртуальной памятью.
|
||||
- **Дополнительные Page Faults:** Copy-on-Write приводит к большему числу Page Faults, так как любое изменение данных требует создания новой копии страницы.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
43
dev/fundamental/Tree.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
aliases:
|
||||
- дерево
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
- "[[../garden/ru/meta/zero/00 Разработка|00 Разработка]]"
|
||||
parents:
|
||||
- "[[structure/Структура данных]]"
|
||||
linked:
|
||||
---
|
||||
Дерево — это иерархическая структура данных, состоящая из узлов (вершин), которые связаны друг с другом ребрами. Главные характеристики деревьев:
|
||||
- Корень: Узел, с которого начинается дерево. У него нет родительского узла.
|
||||
- Листья: Узлы, которые не имеют дочерних узлов.
|
||||
- Уровни: Глубина или высота узла относительно корня.
|
||||
- Родители и потомки: В каждом узле, кроме корня, есть родитель, и могут быть дочерние узлы (потомки).
|
||||
|
||||
Виды деревьев:
|
||||
- [[structure/Бинарное дерево поиска|Бинарное дерево]]: Каждый узел имеет не более двух потомков — левый и правый.
|
||||
- Двоичное дерево поиска (Binary Search Tree, BST): [[structure/Бинарное дерево поиска|Бинарное дерево]], в котором левый потомок содержит значения меньше родительского узла, а правый — больше.
|
||||
- AVL-дерево: [[structure/Сбалансированное дерево|Сбалансированное]] [[structure/Бинарное дерево поиска|бинарное дерево поиска]], в котором разница высот левого и правого поддерева любого узла не превышает 1.
|
||||
- Красно-черное дерево: [[structure/Бинарное дерево поиска|Бинарное дерево поиска]], которое поддерживает балансировку путём соблюдения определённых свойств цветных узлов.
|
||||
- [[structure/B-tree]] (B-дерево): Обобщение бинарного дерева для случаев, когда узлы могут иметь больше двух потомков, эффективно используемое для больших данных.
|
||||
- B+-дерево: Вариант B-дерева, в котором все ключи хранятся только в листьях, а внутренние узлы используются только для направления поиска.
|
||||
- Trie: Префиксное дерево, используемое для хранения строк, где каждый узел представляет часть строки.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[structure/Структура данных]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Бинарное дерево поиска]]
|
||||
- [[Сбалансированное дерево]]
|
||||
- [[B-tree]]
|
||||
<!-- SerializedQuery END -->
|
77
dev/fundamental/structure/B-tree.md
Normal file
@ -0,0 +1,77 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-01-29
|
||||
zero-link:
|
||||
parents: []
|
||||
linked:
|
||||
---
|
||||
[Сбалансированное](structure/Сбалансированное%20дерево.md) сильно-ветвистое дерево. Позволяет хранить в узле множество значений.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240205190752.png)
|
||||
|
||||
- Узел содержит множество элементов.
|
||||
- Каждый узел является по факту страничкой на диске, это позволяет уменьшить издержки на чтение с диска.
|
||||
- В каждом узле есть ссылка на следующий и предыдущий узел (B+tree).
|
||||
- В узлах дерева лежат либо данные, либо указатель на данные.
|
||||
|
||||
В таком дереве есть параметр t - минимальная степень. От этого параметра зависит, сколько будет храниться элементов в 1 узле дерева. В каждом узле должно храниться не мене t-1 ключе, и не более 2t-1. Правильно не выполняется для корневого значения.
|
||||
|
||||
Какое t использовать?
|
||||
- Больше t -> меньше высота дерева
|
||||
- зависит от размера блока на диске
|
||||
- зависит от объема ОЗУ
|
||||
- Обычно t выбирается от 50 до 2000.
|
||||
- t = 1001 и 1 млрд. записей => 3 операции для любого ключа
|
||||
|
||||
Элементы в узле бинарного дерева отсортированы.
|
||||
|
||||
Большое количество элементов в узле позволяет делать деревья с большим количеством элементов, но с небольшой высотой.
|
||||
|
||||
**С чем может помочь:**
|
||||
- Поиск по равенству (a=5)
|
||||
- Поиск по открытому диапазон (a > 5 или a < 3)
|
||||
- Поиск по закрытому диапазону (3 < a < 8)
|
||||
- LIKE тоже работает с индексами, но только по префиксам
|
||||
- LIKE 'a%' - хорошо
|
||||
- LIKE '%c' - плохо
|
||||
**С чем НЕ поможет:**
|
||||
- Искать четные/нечетные числа
|
||||
- Искать суффиксы. LIKE '%c' - плохо
|
||||
## Поиск в B-tree
|
||||
Пример поиска 27.
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240129193115.png)
|
||||
|
||||
Важно. Значения в узлах могут быть не уникальными. Например, могло быть 2 числа 27. В таком случае поиск продолжается. При этом стоит учитывать, что количество элементов внутри узла ограничено, а значит следующий элемент (27) может находится в следующем узле. Поэтому для оптимизации этой проблемы блоки на одном уровне линкуют, создавая связный список, чтобы легко перейти в следующий блок.
|
||||
|
||||
- алгоритм аналогичен [бинарному дереву](structure/Бинарное%20дерево%20поиска.md), но выбор не из 2-ух, а из нескольких
|
||||
- поиск за O(t logt(n))
|
||||
- Но обращений к диску O(logt(n))
|
||||
|
||||
## Добавление в B-tree
|
||||
Представим, что у нас уже есть вот такое дерево, и нам надо вставить в него значение 15
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240129194120.png)
|
||||
|
||||
Мы понимаем, что вставка должна быть между 4 и 17, там у нас есть узел 7...16. Но в него мы вставить не можем, так как в данном случае у нас t = 3, а значит в блоке не должно быть больше 5 значений.
|
||||
|
||||
Поэтому блок разбивается начиная с t-1 элементу. В данном случае это 11. Элемент, по которому разбивается блок перемещается в родительский блок. Если в родительском блоке происходит переполнение, то родительский блок тоже разбивается и так далее.
|
||||
|
||||
После вставки мы получим следующее дерево
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240129194629.png)
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]], [[../../../meta/zero/00 Алгоритм|00 Алгоритм]]
|
||||
**Родитель**:: [[Tree]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-01-29]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||
|
38
dev/fundamental/structure/Бинарное дерево поиска.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
aliases:
|
||||
- бинарное дерево
|
||||
- бинарному дереву
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-01-29
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Разработка|00 Разработка]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Дерево у которого выполняется 3 свойства
|
||||
- элемент в левом под-дереве должны быть меньше родительского узла
|
||||
- элементы в правом под-дереве должны быть больше родительского узла
|
||||
- у каждого узла не больше 2 потомков
|
||||
|
||||
![x|400](../../../meta/files/images/Pasted%20image%2020240129190639.png)
|
||||
|
||||
Эти свойства дают
|
||||
- гарантированный порядок элементов
|
||||
- детерминированный алгоритм поиска
|
||||
- в вырожденном случае придется посетить все элементы O(n).
|
||||
|
||||
Чтобы улучшить поиск, можно использовать [сбалансированное](Сбалансированное%20дерево.md) бинарное дерево.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[Tree]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-01-29]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
33
dev/fundamental/structure/Сбалансированное дерево.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
aliases:
|
||||
- сбалансированное дерево
|
||||
- сбалансированное
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date:
|
||||
- - 2024-01-29
|
||||
zero-link:
|
||||
parents: []
|
||||
linked:
|
||||
---
|
||||
Сбалансированное дерево позволяет уменьшить сложность поиска в дереве. В сбалансированном дереве высота левого и правого дерева отличается не больше, чем на единицу.
|
||||
|
||||
Балансировка заключается в
|
||||
|
||||
![](../../../meta/files/images/Pasted%20image%2020240129191116.png)
|
||||
|
||||
Сбалансированное дерево
|
||||
- решает проблему вырожденного случая бинарного дерева
|
||||
- дает поиск за O(высоты дерева)
|
||||
- но требует дополнительных усилий на балансировку
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[Tree|Tree]]
|
||||
**Источник**::
|
||||
**Автор**::
|
||||
**Создана**:: [[2024-01-29]]
|
||||
### Дополнительные материалы
|
||||
-
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
28
dev/fundamental/structure/Структура данных.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Разработка|00 Разработка]]"
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
- [[Tree|Дерево]]
|
||||
- [[structure/Хеш-таблица|Хеш-таблица]]
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- 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) -->
|
||||
- [[Tree]]
|
||||
- [[Хеш-таблица]]
|
||||
<!-- SerializedQuery END -->
|
48
dev/fundamental/structure/Хеш-таблица.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
aliases:
|
||||
- хеш таблица
|
||||
- хеш таблице
|
||||
- хеш-таблице
|
||||
- хеш-таблицу
|
||||
- хеш-таблиц
|
||||
- хеш таблицу
|
||||
- хеш таблиц
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
- "[[../../../meta/zero/00 Разработка|00 Разработка]]"
|
||||
parents:
|
||||
- "[[Структура данных]]"
|
||||
linked:
|
||||
---
|
||||
Хэш-таблица — это [[Структура данных|структура данных]], которая используется для эффективного хранения и поиска данных на основе ключей. Она обеспечивает быстрый доступ к элементам, используя [[../../cryptography/Хеш-функция|хеш-функцию]] для преобразования ключа в индекс массива, где хранится значение. Это делает операции вставки, удаления и поиска очень быстрыми, обычно за время O(1).
|
||||
|
||||
**Основные концепции хэш-таблицы:**
|
||||
- **Ключ и значение:** Каждый элемент в хэш-таблице хранится в виде пары “ключ-значение”. Ключи должны быть уникальными, а значения могут быть любыми. Например, в хэш-таблице можно хранить данные о студентах, где ключом будет идентификационный номер, а значением — информация о студенте.
|
||||
- [[../../cryptography/Хеш-функция|Хеш-функция]] Это основа работы хэш-таблицы. Хеш-функция принимает ключ и вычисляет индекс в массиве, где должно быть размещено значение. Например, для ключа “apple” хэш-функция может вернуть индекс 3, и значение будет сохранено в ячейке с индексом 3.
|
||||
- **Разрешение коллизий:** Поскольку разные ключи иногда могут давать одинаковый хэш (коллизии), нужно уметь их разрешать. Существуют несколько подходов:
|
||||
- **Метод цепочек (Chaining):** В каждой ячейке массива хранится связанный список значений, чьи ключи дали одинаковый хэш. При коллизии элемент добавляется в этот список.
|
||||
- **Открытая адресация (Open Addressing):** При коллизии элемент помещается в следующую свободную ячейку массива по определённому алгоритму (например, линейное пробирование или двойное хэширование).
|
||||
- **Коэффициент загрузки (Load Factor):** Это соотношение количества элементов к размеру массива. Если коэффициент загрузки слишком велик, производительность хэш-таблицы падает, и может понадобиться увеличение массива и перерасчёт всех хешей (рехеширование).
|
||||
|
||||
**Преимущества хэш-таблиц:**
|
||||
- **Быстрый доступ:** Операции вставки, удаления и поиска обычно выполняются за константное время O(1).
|
||||
- **Гибкость ключей:** Могут использоваться любые неизменяемые типы данных в качестве ключей (строки, числа, кортежи и т.д.).
|
||||
|
||||
**Недостатки хэш-таблиц:**
|
||||
- **Память:** Хэш-таблицы могут потреблять много памяти из-за большого размера массива, особенно при низком коэффициенте загрузки.
|
||||
- **Коллизии:** Если хеш-функция некачественная или слишком много элементов, это может замедлить работу из-за коллизий.
|
||||
- **Нет упорядоченности:** Порядок элементов в хэш-таблице не предсказуем и не сохраняется.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**:: [[Структура данных]]
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
40
dev/fundamental/Страница.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
aliases:
|
||||
- страницы
|
||||
- страниц
|
||||
tags:
|
||||
- maturity/🌱
|
||||
date: 2024-09-17
|
||||
zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Страница это непрерывный блок памяти фиксированного размера.
|
||||
|
||||
**Размер страницы:** Обычно размер страницы составляет от 4 КБ до нескольких мегабайт, в зависимости от архитектуры [[Центральный процессор|процессора]] и настроек [[../../../../knowledge/dev/pc/Операционная система|операционной системы]]. Например, в большинстве современных систем страница составляет 4 КБ, но на некоторых системах могут использоваться страницы большего размера, например, 2 МБ или 4 МБ. Большие страницы (так называемые Huge Pages) могут использоваться для повышения производительности, так как они уменьшают накладные расходы на управление памятью и уменьшение количества записей в таблице страниц.
|
||||
|
||||
**Страницы и виртуальная память:** Виртуальная память — это механизм, который позволяет программе использовать больше памяти, чем физически доступно на компьютере. Виртуальное адресное пространство разбивается на страницы, которые могут быть размещены в оперативной памяти (RAM) или на диске (swap file или page file).
|
||||
|
||||
**Таблица страниц:** Операционная система использует таблицу страниц для отслеживания, где находятся страницы виртуальной памяти (в оперативной памяти или на диске). Каждой странице виртуальной памяти соответствует страница в физической памяти.
|
||||
|
||||
**Страницы в физической памяти:** Страницы, загруженные в оперативную память, называются фреймами. Размер фрейма совпадает с размером страницы, что упрощает управление памятью.
|
||||
|
||||
**Защита от записи (Read-Only):** Страницы, содержащие код программы, как правило, защищены от записи. Это делает их доступными только для чтения, предотвращая случайные или злонамеренные изменения в коде программы, что повышает безопасность и стабильность системы.
|
||||
|
||||
**Зачем нужны страницы:**
|
||||
- **Упрощение управления памятью:** Разбиение памяти на страницы позволяет операционной системе эффективно управлять памятью, перемещая страницы между RAM и дисковым пространством по мере необходимости.
|
||||
- **Изоляция процессов:** Использование страниц помогает изолировать [[Процесс ОС|процессы]] друг от друга, так как каждый процесс видит только своё виртуальное адресное пространство.
|
||||
- **Подкачка:** Страницы, которые не используются, могут быть выгружены на диск, освобождая оперативную память для других нужд.
|
||||
- **Обработка ошибок:** Когда процесс пытается обратиться к странице, которой нет в памяти, операционная система обрабатывает [[../../../../_inbox/Page Fault|Page Fault]], загружая нужную страницу с диска.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]]
|
||||
**Родитель**::
|
||||
**Источник**::
|
||||
**Создана**:: [[2024-09-17]]
|
||||
**Автор**::
|
||||
### Дополнительные материалы
|
||||
-
|
||||
|
||||
### Дочерние заметки
|
||||
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
@ -12,7 +12,7 @@ linked:
|
||||
|
||||
В такие моменты главное не поддаваться панике 😅
|
||||
|
||||
В Idea есть [замечательная функция LocalHisotry](https://www.jetbrains.com/help/idea/local-history.html), которая автоматически сохраняет все изменения над файлами. Если затертых файлов было не много, то нажмите ПКМ и в меню выберете `Local History —> Show History`.
|
||||
В Idea есть [замечательная функция LocalHisotry](https://www.jetbrains.com/help/idea/local-history.html), которая автоматически сохраняет все изменения над файлами. Если затертых файлов было не много, то нажмите ПКМ и в меню выберете `Local History —> Show History`.
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240908122428.png)
|
||||
|
||||
|
@ -11,7 +11,7 @@ linked:
|
||||
---
|
||||
Когда-то давным давно скачал [JDK](JDK.md), работает и ладно. Посмотрел доклад про [нативные сборки](Нативные%20сборки%20в%20Java.md), и там упоминалось про [JDK](JDK.md) для Apple Silicon. Решил проверить, а такой ли у меня. Оказалось не такой.
|
||||
|
||||
В итоге вот сколько собирался большой [монолит](../../../../_inbox/Монолитная%20архитектура.md) (с генерацией javadoc), состоящий из 22 модуля на обычной [JDK](JDK.md). Все зависимости были закачены заранее и сборка была запущена в [многопоточном режиме](Параллельная%20сборка%20модулей%20в%20Maven.md).
|
||||
В итоге вот сколько собирался большой [монолит](../../../../_inbox/Монолитная%20архитектура.md) (с генерацией javadoc), состоящий из 22 модуля на обычной [JDK](JDK.md). Все зависимости были закачены заранее и сборка была запущена в [многопоточном режиме](Параллельная%20сборка%20модулей%20в%20Maven.md).
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240908115826.png)
|
||||
|
||||
|
@ -9,9 +9,9 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Столкнулся с неочевидным поведением `@ElementCollection` в связке с `@OneToMany`. Может случиться так, что в `@OneToMany` будет дублирование значений из-за `@ElementCollection`. Проще объяснить на примере.
|
||||
Столкнулся с неочевидным поведением `@ElementCollection` в связке с `@OneToMany`. Может случиться так, что в `@OneToMany` будет дублирование значений из-за `@ElementCollection`. Проще объяснить на примере.
|
||||
|
||||
Допустим у нас есть три таблицы: `user`, `user_nickname`, `address`. Есть сущность `User`:
|
||||
Допустим у нас есть три таблицы: `user`, `user_nickname`, `address`. Есть сущность `User`:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@ -37,15 +37,15 @@ public class User {
|
||||
|
||||
Допустим у нас одна запись про пользователя, у которого есть три адреса и один никнейм. В этом случае все хорошо, все придет корректно.
|
||||
|
||||
==Добавим этому пользователю еще один никнейм. Теперь мы получаем шесть адресов и два никнейма. Откуда взялись еще три лишних адреса, в базе данных их все еще три.== Это дубликаты. При этом, если вы воспользуетесь пагинацией JPA, то дублей уже не будет. It is magic 💫
|
||||
==Добавим этому пользователю еще один никнейм. Теперь мы получаем шесть адресов и два никнейма. Откуда взялись еще три лишних адреса, в базе данных их все еще три.== Это дубликаты. При этом, если вы воспользуетесь пагинацией JPA, то дублей уже не будет. It is magic 💫
|
||||
|
||||
Магии в программировании, как вы понимаете, нет. Они создаются при использовании `FetchType.EAGER` у `@OneToMany` в совокупности с `@ElementCollection(fetch = FetchType.EAGER)`. Hibernate генерирует запрос с двумя-тремя полными соединениями, отсюда и берутся дубли. При этом в пагинации Hibernate не генерирует джойны, а использует кучу селектов, отсюда и отсутствие дублей при пагинации.
|
||||
Магии в программировании, как вы понимаете, нет. Они создаются при использовании `FetchType.EAGER` у `@OneToMany` в совокупности с `@ElementCollection(fetch = FetchType.EAGER)`. Hibernate генерирует запрос с двумя-тремя полными соединениями, отсюда и берутся дубли. При этом в пагинации Hibernate не генерирует джойны, а использует кучу селектов, отсюда и отсутствие дублей при пагинации.
|
||||
|
||||
Эта проблема решается несколькими способами:
|
||||
|
||||
- Переделайте `List` в `Set` у `@OneToMany`.
|
||||
- Уберите `FetchType.EAGER` у `@OneToMany`.
|
||||
- Добавьте `@Fetch(FetchMode.SUBSELECT)` у `@OneToMany`. это аннотация Hibernate, которая вместо JOIN использует подзапрос. О [подзапросах я писал в отдельной статье](https://struchkov.dev/blog/ru/select-subquery).
|
||||
- Переделайте `List` в `Set` у `@OneToMany`.
|
||||
- Уберите `FetchType.EAGER` у `@OneToMany`.
|
||||
- Добавьте `@Fetch(FetchMode.SUBSELECT)` у `@OneToMany`. это аннотация Hibernate, которая вместо JOIN использует подзапрос. О [подзапросах я писал в отдельной статье](https://struchkov.dev/blog/ru/select-subquery).
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../../meta/zero/00 Hibernate|00 Hibernate]]
|
||||
|
@ -12,7 +12,7 @@ linked:
|
||||
---
|
||||
Провозился два дня, но в итоге смог собрать один из микро-сервисов в нативном режиме. Ничего сложного, но было много нюансов в настройке CICD.
|
||||
|
||||
Самое полезное, это вот [эта документация Quarkus](https://quarkus.io/guides/building-native-image). А конкретно флаги:
|
||||
Самое полезное, это вот [эта документация Quarkus](https://quarkus.io/guides/building-native-image). А конкретно флаги:
|
||||
- `-Dquarkus.native.container-build=true`
|
||||
- `-Dquarkus.native.remote-container-build=true`
|
||||
|
||||
@ -46,7 +46,7 @@ CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
||||
|
||||
Сервис стал собираться в 2,5 раза больше, около 5 минут, вместо 2. Но теперь он стартует моментально, наверное за доли секунды. При этом на под выделяется всего 256 mb ОЗУ на старте и 512 mb в момент работы.
|
||||
## Более сложный путь
|
||||
Также слепил образ для GitLab-раннера, который совмещает GraalVM и Docker, осталось добавить в него Gradle, но пока использую `./gradlew`. Оставлю это тут на всякий случай.
|
||||
Также слепил образ для GitLab-раннера, который совмещает GraalVM и Docker, осталось добавить в него Gradle, но пока использую `./gradlew`. Оставлю это тут на всякий случай.
|
||||
|
||||
```Dockerfile
|
||||
FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0
|
||||
|
@ -72,16 +72,16 @@ public class Binary {
|
||||
}
|
||||
```
|
||||
|
||||
Если элемент не найден, то вернется `-1`.
|
||||
Если элемент не найден, то вернется `-1`.
|
||||
|
||||
> [!WARNING] m = l + (r - l) / 2;
|
||||
> Во многих примерах в интернете можно встретить запись `int m = (l + r) / 2;`, вместо `int mid = l + (r - l) / 2;`.
|
||||
> Во многих примерах в интернете можно встретить запись `int m = (l + r) / 2;`, вместо `int mid = l + (r - l) / 2;`.
|
||||
>
|
||||
> Но использование второго варианта является лучшей практикой, так как это помогает избежать переполнения, когда размер массива велик.
|
||||
>
|
||||
> Например, если `l = 2147483647` и `r = 2147483647`, сумма `l` и `r` будет равна 4294967294, что превышает максимальное значение, которое может хранить `int`, вызывая переполнение.
|
||||
> Например, если `l = 2147483647` и `r = 2147483647`, сумма `l` и `r` будет равна 4294967294, что превышает максимальное значение, которое может хранить `int`, вызывая переполнение.
|
||||
>
|
||||
> С другой стороны, если вы используете `mid = l + (r - l) / 2;` это будет работать, как и ожидалось, потому что вычитание будет сделано первым, а результат будет равен нулю, поэтому деление будет равно нулю, а сложение вернет значение `l`.
|
||||
> С другой стороны, если вы используете `mid = l + (r - l) / 2;` это будет работать, как и ожидалось, потому что вычитание будет сделано первым, а результат будет равен нулю, поэтому деление будет равно нулю, а сложение вернет значение `l`.
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
|
@ -9,9 +9,9 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Разработчики Java используют подстановочный знак (`*`) в операторах `import` для добавления всех классов из определенного пакета. Но в ходе ревью большинство из вас, возможно, просили убрать этот подстановочный знак импорта и добавить полное имя класса. Разберемся почему не стоит использовать знак подстановки?
|
||||
Разработчики Java используют подстановочный знак (`*`) в операторах `import` для добавления всех классов из определенного пакета. Но в ходе ревью большинство из вас, возможно, просили убрать этот подстановочный знак импорта и добавить полное имя класса. Разберемся почему не стоит использовать знак подстановки?
|
||||
|
||||
Но прежде, давайте вспомним, что полное имя класса, помимо названия, содержит также пакет, например: `java.util.List`. ==Такая запись позволяет нам иметь классы с одинаковыми именами, которые находятся в разных пакетах.==
|
||||
Но прежде, давайте вспомним, что полное имя класса, помимо названия, содержит также пакет, например: `java.util.List`. ==Такая запись позволяет нам иметь классы с одинаковыми именами, которые находятся в разных пакетах.==
|
||||
|
||||
```java
|
||||
package com.example;
|
||||
@ -26,7 +26,7 @@ public class WithoutImport {
|
||||
}
|
||||
```
|
||||
|
||||
Однако, полная запись весьма непрактична, поэтому в Java существует оператор импорта – `import`. Операторы импорта объявляют компилятору источник имен классов, статических переменных и статических имен методов, используемых в коде. Один раз написали полное имя класса, а дальше используем только название класса.
|
||||
Однако, полная запись весьма непрактична, поэтому в Java существует оператор импорта – `import`. Операторы импорта объявляют компилятору источник имен классов, статических переменных и статических имен методов, используемых в коде. Один раз написали полное имя класса, а дальше используем только название класса.
|
||||
|
||||
```java
|
||||
package com.example;
|
||||
@ -88,13 +88,13 @@ public class com.example.WithWildCard {
|
||||
|
||||
Если сравнить его с байт-кодом прошлого примера, то они оба имеют одинаковый байт-код.
|
||||
|
||||
Во время выполнения Java использует байт-код, а не исходный код. ==В байт-коде нет операторов импорта.== Из этого ясно следует, что использование импорта с подстановочными знаками не влияет на производительность Java-приложения во время выполнения.
|
||||
Во время выполнения Java использует байт-код, а не исходный код. ==В байт-коде нет операторов импорта.== Из этого ясно следует, что использование импорта с подстановочными знаками не влияет на производительность Java-приложения во время выполнения.
|
||||
|
||||
## Недостатки
|
||||
Так если использование подстановочного знака не приводит к проблемам производительности, то почему бы его не использовать?
|
||||
|
||||
### Конфликты имен
|
||||
Самая серьезная проблема это возможные конфликты именования. Представьте, что у нас есть два класса из разных библиотек `org.test.Parser` и `dev.lib.Parser`. В нашем коде мы используем импорт с wildcard:
|
||||
Самая серьезная проблема это возможные конфликты именования. Представьте, что у нас есть два класса из разных библиотек `org.test.Parser` и `dev.lib.Parser`. В нашем коде мы используем импорт с wildcard:
|
||||
|
||||
```java
|
||||
import org.test.*
|
||||
@ -103,7 +103,7 @@ import dev.lib.*
|
||||
|
||||
Компилятор никак не отреагирует на наличие классов с одинаковыми именами в двух разных пакетах, импортируемых таким образом, если только не будет предпринята попытка воспользоваться одним из этих классов.
|
||||
|
||||
Также проблема может возникнуть в будущем, когда вы обновите версию какую-то из библиотек. Допустим у нас была библиотека с классом `org.test.Parser`, а потом разработчик второй библиотеки тоже добавил класс `dev.lib.Parser`, таким образом мы получили конфлик именования в будущем, хотя раньше все было нормально.
|
||||
Также проблема может возникнуть в будущем, когда вы обновите версию какую-то из библиотек. Допустим у нас была библиотека с классом `org.test.Parser`, а потом разработчик второй библиотеки тоже добавил класс `dev.lib.Parser`, таким образом мы получили конфлик именования в будущем, хотя раньше все было нормально.
|
||||
### Чистый код
|
||||
Импорты с подстановочными знаками помогают нам избежать длинного списка импортов. Следовательно, это влияет на читабельность кода, так как читателю может потребоваться прокрутить много страниц в каждом файле исходного кода, прежде чем он доберется до кода, который показывает логику. Несомненно, более читабельный код - это также чистый код.
|
||||
|
||||
|
@ -21,7 +21,7 @@ SonarLint работает так же, как статический анали
|
||||
|
||||
Если ваш проект анализируется в SonarQube или SonarCloud, SonarLint может подключиться к серверу, чтобы получить соответствующие профили качества и настройки для этого проекта.
|
||||
|
||||
**Кому рекомендую:** Если вы Junior, то для вас это незаменимый инструмент, который позволит улучшить ваш код.
|
||||
**Кому рекомендую:** Если вы Junior, то для вас это незаменимый инструмент, который позволит улучшить ваш код.
|
||||
|
||||
**Ссылка для установки:** [SonarLint - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/7973-sonarlint)
|
||||
## Translation
|
||||
@ -37,11 +37,11 @@ SonarLint работает так же, как статический анали
|
||||
- Перевод JavaDoc
|
||||
- Озвучивание текста
|
||||
|
||||
**Кому подойдет:** Этот плагин для тех, кто плохо знает английский язык.
|
||||
**Кому подойдет:** Этот плагин для тех, кто плохо знает английский язык.
|
||||
|
||||
**Ссылка на установку:** [Translation - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/8579-translation)
|
||||
## .ignore
|
||||
Простой плагин, который помогает генерировать файлы исключений, такие как `.gitignore` и `.dockerignore`.
|
||||
Простой плагин, который помогает генерировать файлы исключений, такие как `.gitignore` и `.dockerignore`.
|
||||
|
||||
![](../../meta/files/images/plugin-ignore.gif)
|
||||
|
||||
@ -61,7 +61,7 @@ SonarLint работает так же, как статический анали
|
||||
## Presentation Assistant
|
||||
Этот плагин отлично дополнит ваш live coding, потому что его задача ненавязчиво выводить комбинации клавиш, которые вы нажимаете. Даже если вы не будете нажимать сочетание клавиш, а просто кликаете мышкой, но для этого есть хоткей, то он также будет выведен.
|
||||
|
||||
**Кому подойдет:** Тем кто проводит вебинары. Также он мне больше нравится, чем Key Promoter X для изучения хоткеев.
|
||||
**Кому подойдет:** Тем кто проводит вебинары. Также он мне больше нравится, чем Key Promoter X для изучения хоткеев.
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240908110354.png)
|
||||
|
||||
|
@ -11,16 +11,16 @@ linked:
|
||||
---
|
||||
Многие разработчики в принципе против использования Lombok. В общем, это холиварная тема. Но вы используете Lombok в проекте, то не используйте хотя бы спорные и откровенно вредные аннотации.
|
||||
|
||||
Одна из таких – это `@Data`. Во-первых, [мало кто помнит, что она под собой скрывает](https://projectlombok.org/features/Data).
|
||||
Одна из таких – это `@Data`. Во-первых, [мало кто помнит, что она под собой скрывает](https://projectlombok.org/features/Data).
|
||||
|
||||
- `@ToString`. Не помню, когда последний раз переопределял `toString()`. А если объект содержит чувствительную информацию?
|
||||
- `@EqualsAndHashCode`. Это самая вредная аннотация в @Data. ==Потому что она генерирует `equals()` и `hashCode()` по всем полям.== Обычно вы не хотите, чтобы генерация осуществлялась по всем полям. Например, для сущности достаточно идентификатора.
|
||||
- `@Getter` / `@Setter`. Здесь ничего плохого.
|
||||
- `@ToString`. Не помню, когда последний раз переопределял `toString()`. А если объект содержит чувствительную информацию?
|
||||
- `@EqualsAndHashCode`. Это самая вредная аннотация в @Data. ==Потому что она генерирует `equals()` и `hashCode()` по всем полям.== Обычно вы не хотите, чтобы генерация осуществлялась по всем полям. Например, для сущности достаточно идентификатора.
|
||||
- `@Getter` / `@Setter`. Здесь ничего плохого.
|
||||
- `@RequiredArgsConstructor`. Тоже окей.
|
||||
|
||||
Основная проблема в `@EqualsAndHashCode`. Можно, конечно, использовать `@EqualsAndHashCode.Exclude`. Эта аннотация запрещает использовать поле при генерации, но вы хотите расставлять это над почти всеми полями в сущности? Потому что `@EqualsAndHashCode.Include` просто не сработает, нельзя объявить только нужные поля, нужно будет именно исключать все ненужные.
|
||||
Основная проблема в `@EqualsAndHashCode`. Можно, конечно, использовать `@EqualsAndHashCode.Exclude`. Эта аннотация запрещает использовать поле при генерации, но вы хотите расставлять это над почти всеми полями в сущности? Потому что `@EqualsAndHashCode.Include` просто не сработает, нельзя объявить только нужные поля, нужно будет именно исключать все ненужные.
|
||||
|
||||
Также избегайте всех аннотаций из пакета `experemental`. Все аннотации из этого пакета могут работать не стабильно, и при этом могут быть удалены из следующих версий. Исключением из этого пакета является [@FieldNameConstants](https://projectlombok.org/features/experimental/FieldNameConstants), за пару лет с ней не было никаких проблем, а все имеющиеся альтернативы не очень.
|
||||
Также избегайте всех аннотаций из пакета `experemental`. Все аннотации из этого пакета могут работать не стабильно, и при этом могут быть удалены из следующих версий. Исключением из этого пакета является [@FieldNameConstants](https://projectlombok.org/features/experimental/FieldNameConstants), за пару лет с ней не было никаких проблем, а все имеющиеся альтернативы не очень.
|
||||
|
||||
С Lombok код выглядит чище, но, как и в случае с любым другим магическим инструментом, важно понимать, как именно он работает и когда его использовать. В противном случае производительность приложения может снизиться, либо оно вовсе может перестать работать корректно.
|
||||
***
|
||||
|
@ -22,7 +22,7 @@ mvn -T 1C clean install
|
||||
|
||||
![400](../../meta/files/images/Pasted%20image%2020231120092703.png)
|
||||
|
||||
По факту эти группы модулей зависят только друг от друга. Сначала собирается группа `domain`, от нее зависит группа `context`, потом core и так далее. Без `context` не собрать `core`, думаю суть понятна. Но вот модули core не зависят друг от друга, и могут собираться параллельно.
|
||||
По факту эти группы модулей зависят только друг от друга. Сначала собирается группа `domain`, от нее зависит группа `context`, потом core и так далее. Без `context` не собрать `core`, думаю суть понятна. Но вот модули core не зависят друг от друга, и могут собираться параллельно.
|
||||
|
||||
Для примера вот время сборки в последовательном режиме:
|
||||
|
||||
|
@ -15,19 +15,19 @@ Enum это объект, как и все в Java. Однако это особ
|
||||
enum TestEnum {ONE, TWO, THREE}
|
||||
```
|
||||
|
||||
Если мы создадим 10 переменных `TestEnum.ONE`, то все они будут ссылаться на один и тот же объект. И поэтому enum можно сравнивать с помощью `==` и это корректно и будет работать.
|
||||
Если мы создадим 10 переменных `TestEnum.ONE`, то все они будут ссылаться на один и тот же объект. И поэтому enum можно сравнивать с помощью `==` и это корректно и будет работать.
|
||||
|
||||
Сторонники такого подхода называют следующие преимущества. Давайте их разберем.
|
||||
|
||||
**Вы никогда не получите `NullPointerException`.** И это правда, но если вы будете придерживаться правила ["сравнение константы слева"](Сравнение%20константы%20слева%20в%20Java.md), то и при использовании `.equals()` `NullPointerException` вам не страшен.
|
||||
**Вы никогда не получите `NullPointerException`.** И это правда, но если вы будете придерживаться правила ["сравнение константы слева"](Сравнение%20константы%20слева%20в%20Java.md), то и при использовании `.equals()` `NullPointerException` вам не страшен.
|
||||
|
||||
**Оператор == работает быстрее.** Быстрее чего? Видимо метода `.equals()`. Давайте посмотрим реализацию метода `.equals()` у enum.
|
||||
**Оператор == работает быстрее.** Быстрее чего? Видимо метода `.equals()`. Давайте посмотрим реализацию метода `.equals()` у enum.
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020231120093026.png)
|
||||
|
||||
**Оператор == более понятный синтаксически.** Это еще почему? Для сравнения объектов в Java используется `.equals()`. Enum это объект. Логичнее и очевиднее использовать `.equals()` для сравнения, чтобы не нарушать единообразие сравнения объектов.
|
||||
**Оператор == более понятный синтаксически.** Это еще почему? Для сравнения объектов в Java используется `.equals()`. Enum это объект. Логичнее и очевиднее использовать `.equals()` для сравнения, чтобы не нарушать единообразие сравнения объектов.
|
||||
|
||||
На мой взгляд, правильнее использовать `.equals()`, главное не забывать о правиле "[Сравнение константы слева](Сравнение%20константы%20слева%20в%20Java.md)".
|
||||
На мой взгляд, правильнее использовать `.equals()`, главное не забывать о правиле "[Сравнение константы слева](Сравнение%20константы%20слева%20в%20Java.md)".
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]]
|
||||
|
@ -41,9 +41,9 @@ if (user.getStatus().equals(UserStatus.ONLINE)) {
|
||||
}
|
||||
```
|
||||
|
||||
Вроде бы все отлично, миссия выполнена. Но есть одно НО. Что если `getStatus()` вернет вам `null`? Правильно, вы получите `NullPointerException`.
|
||||
Вроде бы все отлично, миссия выполнена. Но есть одно НО. Что если `getStatus()` вернет вам `null`? Правильно, вы получите `NullPointerException`.
|
||||
|
||||
Чтобы этого избежать следует придерживаться правила "Сравнения константы слева". Оно очень простое. В нашем примере, мы точно уверены, что `UserStatus.ONLINE` существует, поэтому `.equals()` стоит вызывать от него.
|
||||
Чтобы этого избежать следует придерживаться правила "Сравнения константы слева". Оно очень простое. В нашем примере, мы точно уверены, что `UserStatus.ONLINE` существует, поэтому `.equals()` стоит вызывать от него.
|
||||
|
||||
```java
|
||||
if (UserStatus.ONLINE.equals(user.getStatus())) {
|
||||
@ -59,7 +59,7 @@ if ("Иванов".equals(user.getLastName())) {
|
||||
}
|
||||
```
|
||||
|
||||
Это простое правило защитит вас от `NullPointerException`.
|
||||
Это простое правило защитит вас от `NullPointerException`.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]]
|
||||
|
@ -8,13 +8,13 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Ремарка, которую можно пропустить: Помню свой первый день на работе, тогда мне поручили настраивать сервер на CentOS 7. Установить необходимые пакеты, уже не помню точно что, но не суть. Я тогда еще обладатель ПК на windows погуглил и нашел команду `yum install pack_name`.
|
||||
Ремарка, которую можно пропустить: Помню свой первый день на работе, тогда мне поручили настраивать сервер на CentOS 7. Установить необходимые пакеты, уже не помню точно что, но не суть. Я тогда еще обладатель ПК на windows погуглил и нашел команду `yum install pack_name`.
|
||||
|
||||
И как же я был удивлен, когда это не сработало. Корпоративные сервера чаще всего находятся в изоляции от интернета, и для доступа необходимо настраивать прокси. Но я тогда не знал об этом, и устанавливал пакеты вручную, скачивая их сначала к себе и перенося на сервер, то еще занятие, на это ушел целый день 😄
|
||||
|
||||
Потом я узнал о существовании прокси, которое открывало доступ в интернет. Сейчас расскажу, как его настроить.
|
||||
|
||||
Особенность использования прокси в том, что его надо настраивать везде. Недостаточно настроить только на уровне ОС, надо также настроить на уровне каждого приложения, даже у пакетного менеджера типа `yum` и `dnf`, нужно указать прокси.
|
||||
Особенность использования прокси в том, что его надо настраивать везде. Недостаточно настроить только на уровне ОС, надо также настроить на уровне каждого приложения, даже у пакетного менеджера типа `yum` и `dnf`, нужно указать прокси.
|
||||
## Настройка для ОС
|
||||
Первым делом настраиваем прокси на linux машине. Для этого нужно установить значения для некоторых переменных среды.
|
||||
|
||||
@ -41,10 +41,10 @@ export NO_PROXY="127.0.0.1,localhost"
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Если в имени пользователя или пароле используется символ `@`, добавьте обратную косую черту (`\`) перед `@`.
|
||||
> Если в имени пользователя или пароле используется символ `@`, добавьте обратную косую черту (`\`) перед `@`.
|
||||
|
||||
|
||||
Данным способом мы установили временное прокси, ==после перезагрузки подключение пропадет.== Чтобы добавить постоянное прокси, нужно изменить файл `/etc/environment`.
|
||||
Данным способом мы установили временное прокси, ==после перезагрузки подключение пропадет.== Чтобы добавить постоянное прокси, нужно изменить файл `/etc/environment`.
|
||||
|
||||
Если вам повезло и редактор nano был предустановлен, то воспользуйтесь им, добавив следующие строчки:
|
||||
|
||||
@ -76,7 +76,7 @@ export HTTPS_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/"
|
||||
export NO_PROXY="127.0.0.1,localhost"
|
||||
```
|
||||
|
||||
Чтобы сохранинть изменения санчала нажмите `ESC`, а далее наберите `:wq`, чтобы выйти без сохранения нажмите `ESC` и наберите просто `:q`
|
||||
Чтобы сохранинть изменения санчала нажмите `ESC`, а далее наберите `:wq`, чтобы выйти без сохранения нажмите `ESC` и наберите просто `:q`
|
||||
|
||||
Если вам совсем не повезло, и по какой-то причине редакторов совсем не предустановлено, то воспользуйтесь следующей командой:
|
||||
|
||||
@ -91,7 +91,7 @@ export NO_PROXY="127.0.0.1,localhost"
|
||||
EOFXX
|
||||
```
|
||||
## Настройка для пакетных менеджеров
|
||||
Теперь настроим прокси для пакетных менеджеров `yum` и `dnf`. Для этого отредактируем файл `/etc/yum.conf`, добавив в конец следующие строки:
|
||||
Теперь настроим прокси для пакетных менеджеров `yum` и `dnf`. Для этого отредактируем файл `/etc/yum.conf`, добавив в конец следующие строки:
|
||||
|
||||
```toml
|
||||
proxy=http://SERVER:PORT
|
||||
|
@ -31,7 +31,7 @@ ssh username@192.168.0.1
|
||||
|
||||
Первым делом нам надо узнать, какой интерфейс был присвоен нашему соединению на роутере. Если это ваше первое соединение с Wireguard, то скорее всего это Wireguard0. Но давайте убедимся в этом.
|
||||
|
||||
Для этого необходимо ввести `interface Wire` и нажать `Tab`:
|
||||
Для этого необходимо ввести `interface Wire` и нажать `Tab`:
|
||||
|
||||
```shell
|
||||
(config)> interface Wire
|
||||
@ -87,7 +87,7 @@ ssh username@192.168.0.1
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240908112035.png)
|
||||
|
||||
Нужно добавить правило на IN, иначе запросы в локальную сеть будут дропаться. Не забудьте заменить `Wireguard0` на другое значение, если у вас задействован другой интерфейс.
|
||||
Нужно добавить правило на IN, иначе запросы в локальную сеть будут дропаться. Не забудьте заменить `Wireguard0` на другое значение, если у вас задействован другой интерфейс.
|
||||
|
||||
```shell
|
||||
(config)> interface Wireguard0
|
||||
@ -106,9 +106,9 @@ Network::RoutingTable: Added static route: 10.66.67.0/24 via Wireguard0.
|
||||
```
|
||||
|
||||
> [!DANGER]
|
||||
> Не забудьте заменить значения на свои. `10.66.67.0` на свою подсеть Wireguard, а `Wireguard0` на свой интерфейс.
|
||||
> Не забудьте заменить значения на свои. `10.66.67.0` на свою подсеть Wireguard, а `Wireguard0` на свой интерфейс.
|
||||
## Настройка сервера WG
|
||||
Теперь нужно настроить сервер Wireguard. Для этого нужно отредактировать файл конфигурации, обычно он лежит в папке `/etc/wireguard/wg0.conf`. Зайдите под root.
|
||||
Теперь нужно настроить сервер Wireguard. Для этого нужно отредактировать файл конфигурации, обычно он лежит в папке `/etc/wireguard/wg0.conf`. Зайдите под root.
|
||||
|
||||
```shell
|
||||
su
|
||||
@ -136,7 +136,7 @@ PresharedKey = PRESHARED_KEY
|
||||
AllowedIPs = 10.66.67.3/32,fd42:42:43::3/128
|
||||
```
|
||||
|
||||
У нас тут все стандартно. Два пира, один из них роутер, второй телефон. Для роутера необходимо указать в `AllowedIPs` вашу локальную сеть, в данном случае `192.168.1.0/24`.
|
||||
У нас тут все стандартно. Два пира, один из них роутер, второй телефон. Для роутера необходимо указать в `AllowedIPs` вашу локальную сеть, в данном случае `192.168.1.0/24`.
|
||||
|
||||
После этого отключим и включим WG соединение.
|
||||
|
||||
|
@ -19,13 +19,13 @@ linked:
|
||||
![](../../meta/files/images/Pasted%20image%2020240407184611.png)
|
||||
|
||||
## 2. Убедитесь, что процесс сборки использует ваш порт
|
||||
Нажмите `Ctrl+Shift+A` и найдите пункт “Edit Custom VM Options…”
|
||||
Нажмите `Ctrl+Shift+A` и найдите пункт “Edit Custom VM Options…”
|
||||
|
||||
Добавьте новую строку `-Dcompiler.process.debug.port=8000` и ==перезапустите IDEA.==
|
||||
Добавьте новую строку `-Dcompiler.process.debug.port=8000` и ==перезапустите IDEA.==
|
||||
|
||||
![](../../meta/files/images/Pasted%20image%2020240407184626.png)
|
||||
## 3. Включите “Debug build process”
|
||||
Нажмите `Ctrl+Shift+A` и пункт “Debug build process”.
|
||||
Нажмите `Ctrl+Shift+A` и пункт “Debug build process”.
|
||||
|
||||
> [!WARNING]
|
||||
> Вам нужно будет повторять этот шаг каждый раз при перезапуске IDEA.
|
||||
@ -34,7 +34,7 @@ linked:
|
||||
|
||||
![](Pasted%20image%2020240407184705.png)
|
||||
|
||||
Для запуска вашего обработчика аннотаций пересоберите проект: `Build -> Rebuild Project`. ==При выборе пункта Build Project обработчик аннотации может не запуститься.==
|
||||
Для запуска вашего обработчика аннотаций пересоберите проект: `Build -> Rebuild Project`. ==При выборе пункта Build Project обработчик аннотации может не запуститься.==
|
||||
|
||||
Процесс сборки приостановится, и вы сможете подключить отладчик:
|
||||
|
||||
|
@ -81,13 +81,13 @@ public class OkHttpUtil {
|
||||
}
|
||||
```
|
||||
## Как это использовать?
|
||||
Перед получением `OkHttpClient` необходимо инициализировать настройки игнорирования сертификатов. Для этого вызываем метод:
|
||||
Перед получением `OkHttpClient` необходимо инициализировать настройки игнорирования сертификатов. Для этого вызываем метод:
|
||||
|
||||
```java
|
||||
OkHttpUtil.init(true);
|
||||
```
|
||||
|
||||
После этого можете получить `OkHttpClient`:
|
||||
После этого можете получить `OkHttpClient`:
|
||||
```java
|
||||
OkHttpUtil.getClient();
|
||||
```
|
||||
|
@ -8,7 +8,7 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Когда я создаю [обучающие репозитории к своим статьям](https://github.com/Example-uPagge), то использую H2 в качестве базы данных. Проблема с H2 в том, что когда запущено приложение, нельзя просто подключиться и посмотреть что происходит в БД. Эта заметка показывает, как провернуть этот финт.
|
||||
Когда я создаю [обучающие репозитории к своим статьям](https://github.com/Example-uPagge), то использую H2 в качестве базы данных. Проблема с H2 в том, что когда запущено приложение, нельзя просто подключиться и посмотреть что происходит в БД. Эта заметка показывает, как провернуть этот финт.
|
||||
|
||||
Имеем следующее подключение к базе данных:
|
||||
|
||||
@ -25,7 +25,7 @@ spring:
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
```
|
||||
|
||||
В вашем Spring приложении необходимо создать следующий `@Bean`:
|
||||
В вашем Spring приложении необходимо создать следующий `@Bean`:
|
||||
|
||||
```java
|
||||
import org.h2.tools.Server;
|
||||
@ -44,7 +44,7 @@ public class BeanConfig {
|
||||
Это фактически создает сервер для остальных подключений к H2.
|
||||
|
||||
> [!WARNING]
|
||||
> Если класс `org.h2.tools.Server` не находится, то скорее всего у зависимости для H2 установлен scope `runtime`. Удалите значение `scope` и класс появится.
|
||||
> Если класс `org.h2.tools.Server` не находится, то скорее всего у зависимости для H2 установлен scope `runtime`. Удалите значение `scope` и класс появится.
|
||||
|
||||
Теперь можно подсоединиться к H2 используя следующий url:
|
||||
|
||||
@ -54,7 +54,7 @@ jdbc:h2:tcp://localhost:9090/mem:blog
|
||||
|
||||
![Так выглядит окно соединения в IntelliJ Idea](../../meta/files/images/data-sources-in-idea.png)
|
||||
|
||||
Ограничение этого способа в том, что ==нельзя подключиться к базе, если приложение не работает.==
|
||||
Ограничение этого способа в том, что ==нельзя подключиться к базе, если приложение не работает.==
|
||||
|
||||
***
|
||||
## Мета информация
|
||||
|
@ -10,7 +10,7 @@ linked:
|
||||
---
|
||||
PNG и JPG являются хорошими форматами изображений, которые можно [сжать без потери качества](Сжатие%20изображений%20без%20потери%20качества.md). Однако, на сегодняшний день существует более современный формат WebP, который может показать еще более эффективные результаты при сжатии изображений, но с едва заметным ухудшением качества.
|
||||
|
||||
В [документации WebP](https://developers.google.com/speed/webp/docs/cwebp?hl=ru) перечислено множество параметров, которые повлияют на качество получаемого изображения. Вы можете провести экспериментальный подбор параметров онлайн на сайте [https://squoosh.app](https://squoosh.app/).
|
||||
В [документации WebP](https://developers.google.com/speed/webp/docs/cwebp?hl=ru) перечислено множество параметров, которые повлияют на качество получаемого изображения. Вы можете провести экспериментальный подбор параметров онлайн на сайте [https://squoosh.app](https://squoosh.app/).
|
||||
|
||||
Я вы выбрал для себя следующий набор параметров:
|
||||
|
||||
@ -18,17 +18,17 @@ PNG и JPG являются хорошими форматами изображе
|
||||
cwebp -mt -af -progress -m 6 -q 80 -pass 10 input.jpg -o output.webp
|
||||
```
|
||||
|
||||
Это команда преобразует JPG файл `input.jpg` в файл изображения WebP с именем `output.webp`. Команда включает несколько опций, которые управляют процессом кодирования:
|
||||
- `-mt` включает многопоточность, что может улучшить производительность на многоядерных процессорах.
|
||||
- `-af` включает автоматическую фильтрацию, которая применяет алгоритм фильтрации для повышения эффективности сжатия.
|
||||
- `-progress` выводит показывает процент обработки файла.
|
||||
- `-m 6` устанавливает максимальное количество сегментов, используемых в процессе кодирования, равным 6, что может повысить эффективность сжатия за счет увеличения времени кодирования.
|
||||
- `-q 80` устанавливает коэффициент качества на `80`, который контролирует степень сжатия и влияет на визуальное качество выходного изображения.
|
||||
- `-pass 10` устанавливает число проходов кодирования равным 10, что может повысить эффективность сжатия за счет увеличения времени кодирования.
|
||||
Это команда преобразует JPG файл `input.jpg` в файл изображения WebP с именем `output.webp`. Команда включает несколько опций, которые управляют процессом кодирования:
|
||||
- `-mt` включает многопоточность, что может улучшить производительность на многоядерных процессорах.
|
||||
- `-af` включает автоматическую фильтрацию, которая применяет алгоритм фильтрации для повышения эффективности сжатия.
|
||||
- `-progress` выводит показывает процент обработки файла.
|
||||
- `-m 6` устанавливает максимальное количество сегментов, используемых в процессе кодирования, равным 6, что может повысить эффективность сжатия за счет увеличения времени кодирования.
|
||||
- `-q 80` устанавливает коэффициент качества на `80`, который контролирует степень сжатия и влияет на визуальное качество выходного изображения.
|
||||
- `-pass 10` устанавливает число проходов кодирования равным 10, что может повысить эффективность сжатия за счет увеличения времени кодирования.
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> `-lossless` позволяет использовать сжатие без потерь. Но тогда ваше новое изображение может оказаться существенно тяжелее исходного.
|
||||
> `-lossless` позволяет использовать сжатие без потерь. Но тогда ваше новое изображение может оказаться существенно тяжелее исходного.
|
||||
|
||||
Улучшим [скрипт сжатия изображений](Сжатие%20изображений%20без%20потери%20качества.md) и добавим преобразование в webp:
|
||||
|
||||
@ -41,7 +41,7 @@ find ./images/comp -type f -iregex '.*\.\(jpg\|jpeg\|png\)' -not -iregex '.*no-c
|
||||
' _ {} \;
|
||||
```
|
||||
|
||||
Мы берем сжатые изображения из папки `comp` и преобразуем их в WebP, складывая в отдельную папку `webp`. Если вы захотите использовать другие параметры сжатия, вы всегда сможете пересоздать изображения с новыми параметрами.
|
||||
Мы берем сжатые изображения из папки `comp` и преобразуем их в WebP, складывая в отдельную папку `webp`. Если вы захотите использовать другие параметры сжатия, вы всегда сможете пересоздать изображения с новыми параметрами.
|
||||
## Тесты преобразования
|
||||
Продолжим наши эксперименты со сжатием. Теперь сожмем наши файл размером в 2,7 мб и 2.2 в формат WebP с разными параметрами качества:
|
||||
- -q 90: Размер 325 кб.
|
||||
@ -59,7 +59,7 @@ find ./images/comp -type f -iregex '.*\.\(jpg\|jpeg\|png\)' -not -iregex '.*no-c
|
||||
## Nginx
|
||||
Теперь мы научим nginx при запросе изображений сначала пытаться найти WebP файл, и только потом отдавать сжатый PNG/JPG, а если и сжатого нет, то отдавать обычный файл.
|
||||
|
||||
Для этого напишем следующий `location`:
|
||||
Для этого напишем следующий `location`:
|
||||
|
||||
```nginx
|
||||
location ~* ^(/blog/ru/content/images/)(.+)\.(png|jpe?g)$ {
|
||||
@ -71,12 +71,12 @@ location ~* ^(/blog/ru/content/images/)(.+)\.(png|jpe?g)$ {
|
||||
}
|
||||
```
|
||||
|
||||
Данный `location` обрабатывает все запросы к адресам, которые начинаются с `/images/`, за которым следует любое количество символов, затем точка, а затем формат файла png/jpeg/jpg.
|
||||
Данный `location` обрабатывает все запросы к адресам, которые начинаются с `/images/`, за которым следует любое количество символов, затем точка, а затем формат файла png/jpeg/jpg.
|
||||
|
||||
Для запросов, соответствующих этому шаблону, выполняются следующие действия:
|
||||
- Директива `alias` указывает путь к локальной директории, из которой будут отдаваться файлы. В данном случае путь к директории `/images`.
|
||||
- Директивы `set` назначают переменные, которые будут использоваться в последующих директивах. Переменная `$webp_image_subdir` устанавливается в `/webp/`, а переменная `$basename` устанавливается в захваченную подстроку шаблона регулярного выражения (т.е. имя файла без расширения).
|
||||
- Директива `try_files` пытается отдать Webp-версию запрошенного файла изображения, добавляя к переменным `$webp_image_subdir` и `$basename` суффикс `.webp`. Если NGINX сможет найти Webp-версию запрашиваемого файла изображения, он отдаст его. Если он не может найти WebP-версию, то отдаст сжатый JPG/PNG, если и сжатого файла не будет, то отдаст не сжатое.
|
||||
- Директива `alias` указывает путь к локальной директории, из которой будут отдаваться файлы. В данном случае путь к директории `/images`.
|
||||
- Директивы `set` назначают переменные, которые будут использоваться в последующих директивах. Переменная `$webp_image_subdir` устанавливается в `/webp/`, а переменная `$basename` устанавливается в захваченную подстроку шаблона регулярного выражения (т.е. имя файла без расширения).
|
||||
- Директива `try_files` пытается отдать Webp-версию запрошенного файла изображения, добавляя к переменным `$webp_image_subdir` и `$basename` суффикс `.webp`. Если NGINX сможет найти Webp-версию запрашиваемого файла изображения, он отдаст его. Если он не может найти WebP-версию, то отдаст сжатый JPG/PNG, если и сжатого файла не будет, то отдаст не сжатое.
|
||||
***
|
||||
## Мета информация
|
||||
**Область**:: [[../../meta/zero/00 Снипеты на bash|00 Снипеты на bash]]
|
||||
|
@ -9,11 +9,11 @@ parents:
|
||||
- "[[../../../../knowledge/dev/java/other/Jackson|Jackson]]"
|
||||
linked:
|
||||
---
|
||||
Чаще всего по работе я сталкиваюсь с проблемой десериализации и сериализации даты. Многие разработчики отступают от стандартного формата времени `yyyy-MM-dd'T'HH:mm:ss*SSSZZZZ` и изобретают свои форматы.
|
||||
Чаще всего по работе я сталкиваюсь с проблемой десериализации и сериализации даты. Многие разработчики отступают от стандартного формата времени `yyyy-MM-dd'T'HH:mm:ss*SSSZZZZ` и изобретают свои форматы.
|
||||
|
||||
К сожалению, в Jackson не заложены все возможные форматы даты, поэтому необходимо написать свой десериализатор.
|
||||
## Десериализация
|
||||
В данном случае это преобразование json формата в Java объект. Необходимо расширить абстрактный класс `StdDeserializer`.
|
||||
В данном случае это преобразование json формата в Java объект. Необходимо расширить абстрактный класс `StdDeserializer`.
|
||||
|
||||
```java
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
@ -47,7 +47,7 @@ public class CustomDeserializer extends StdDeserializer<LocalDateTime> {
|
||||
}
|
||||
```
|
||||
|
||||
После этого необходимо над полем поставить аннотацию `@JsonDeserialize` c указанием нашего кастомного десериализатора.
|
||||
После этого необходимо над полем поставить аннотацию `@JsonDeserialize` c указанием нашего кастомного десериализатора.
|
||||
|
||||
```java
|
||||
public class Foo {
|
||||
@ -63,7 +63,7 @@ public class Foo {
|
||||
```
|
||||
|
||||
## Сериализация
|
||||
В данном случае это преобразование Java объекта в json формат. Для сериализации необходимо расширить класс `StdSerializer`.
|
||||
В данном случае это преобразование Java объекта в json формат. Для сериализации необходимо расширить класс `StdSerializer`.
|
||||
|
||||
```java
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
@ -93,7 +93,7 @@ public class CustomSerializer extends StdSerializer<LocalDateTime> {
|
||||
}
|
||||
```
|
||||
|
||||
Для работы над полем поставить аннотацию `@JsonSerialize`
|
||||
Для работы над полем поставить аннотацию `@JsonSerialize`
|
||||
|
||||
```java
|
||||
public class Foo {
|
||||
|
@ -40,24 +40,24 @@ touch $file
|
||||
echo "$(date)" > $file
|
||||
```
|
||||
|
||||
Этот скрипт сжимает изображения без потери качества. Он размещается рядом с каталогом `images`, в котором находятся ваши изображения. Разберемся, как он работает.
|
||||
Этот скрипт сжимает изображения без потери качества. Он размещается рядом с каталогом `images`, в котором находятся ваши изображения. Разберемся, как он работает.
|
||||
|
||||
Сначала скрипт проверяет, существует ли в текущем каталоге файл `comp.flag`. Если файл существует, он устанавливает значение `-newer $file` в переменную `option`, которая будет использоваться в качестве фильтра для поиска только тех файлов, которые были изменены после даты создания файла `optimg.flag`. Если файл не существует, переменная `option` будет пустой.
|
||||
Сначала скрипт проверяет, существует ли в текущем каталоге файл `comp.flag`. Если файл существует, он устанавливает значение `-newer $file` в переменную `option`, которая будет использоваться в качестве фильтра для поиска только тех файлов, которые были изменены после даты создания файла `optimg.flag`. Если файл не существует, переменная `option` будет пустой.
|
||||
|
||||
Затем скрипт использует команду `find` для рекурсивного поиска файлов в каталоге `images` и его подкаталогах, которые:
|
||||
Затем скрипт использует команду `find` для рекурсивного поиска файлов в каталоге `images` и его подкаталогах, которые:
|
||||
- `-type f`. Являются обычными файлами.
|
||||
- Имеют расширение имени файла `.png`, `.jpeg` или `.jpg`.
|
||||
- `-not -path`_._ Не находятся в указанных каталогах_._ В данном случае это каталоги `./images/comp`. Мы будем складывать туда сжатые изображения, и мы не хотим заново по ним проходить поиском и сжимать снова.
|
||||
- `! -name "-no-comp."`. Оставим возможность не сжимать изображение, если его имя заканчивается на `-no-comp`.
|
||||
- Имеют расширение имени файла `.png`, `.jpeg` или `.jpg`.
|
||||
- `-not -path`_._ Не находятся в указанных каталогах_._ В данном случае это каталоги `./images/comp`. Мы будем складывать туда сжатые изображения, и мы не хотим заново по ним проходить поиском и сжимать снова.
|
||||
- `! -name "-no-comp."`. Оставим возможность не сжимать изображение, если его имя заканчивается на `-no-comp`.
|
||||
- Для каждого из этих файлов сценарий использует свою команду оптимизации.
|
||||
|
||||
Мы не будем затирать оригиналы изображений. Вместо этого мы создадим дополнительную папку `comp` в каталоге `images`, в которую и сложим преобразованные изображения. Создаваемая структура подкаталогов в `comp` будет повторять структуру подкатологов в `images`.
|
||||
Мы не будем затирать оригиналы изображений. Вместо этого мы создадим дополнительную папку `comp` в каталоге `images`, в которую и сложим преобразованные изображения. Создаваемая структура подкаталогов в `comp` будет повторять структуру подкатологов в `images`.
|
||||
|
||||
Для файлов PNG сначала используется `optipng` для сжатия с самым высоким уровнем оптимизации (`-o7`). Далее используем `advpng` для дальнейшего сжатия с уровнем сжатия 4 (`-z4`). И наконец `pngcrush` для удаления из файла определенных фрагментов, которые можно безопасно удалить для уменьшения размера файла.
|
||||
Для файлов PNG сначала используется `optipng` для сжатия с самым высоким уровнем оптимизации (`-o7`). Далее используем `advpng` для дальнейшего сжатия с уровнем сжатия 4 (`-z4`). И наконец `pngcrush` для удаления из файла определенных фрагментов, которые можно безопасно удалить для уменьшения размера файла.
|
||||
|
||||
Для файлов JPEG используется `jpegoptim` для их оптимизации со сжатием без потерь (`--all-progressive --strip-all`).
|
||||
Для файлов JPEG используется `jpegoptim` для их оптимизации со сжатием без потерь (`--all-progressive --strip-all`).
|
||||
|
||||
После оптимизации всех подходящих изображений сценарий пересоздает файл `comp.flag`. Это гарантирует, что скрипт будет оптимизировать только те файлы, которые были изменены с момента последнего запуска.
|
||||
После оптимизации всех подходящих изображений сценарий пересоздает файл `comp.flag`. Это гарантирует, что скрипт будет оптимизировать только те файлы, которые были изменены с момента последнего запуска.
|
||||
## Тесты на сжатие
|
||||
Возьмем два одинаковых изображения (3456 x 2234): одно форматом jpg и размером 2.2 мб, второе форматом png и размером 2,7 мб.
|
||||
|
||||
|
@ -8,13 +8,13 @@ zero-link:
|
||||
parents:
|
||||
linked:
|
||||
---
|
||||
Для запуска `jar` файла в linux в виде сервиса, необходимо создать файл конфигурации.
|
||||
Для запуска `jar` файла в linux в виде сервиса, необходимо создать файл конфигурации.
|
||||
|
||||
```java
|
||||
sudo nano /etc/systemd/system/app_name_service.service
|
||||
```
|
||||
|
||||
В этот файл вставляем примерно следующее. Не забудьте заменить в выделенных строках `app_path`, `app_name`.
|
||||
В этот файл вставляем примерно следующее. Не забудьте заменить в выделенных строках `app_path`, `app_name`.
|
||||
|
||||
```java
|
||||
[Unit]
|
||||
|
8
index.md
@ -48,16 +48,18 @@ enableToc: false
|
||||
- [Quarkus](meta/zero/00%20Quarkus.md)
|
||||
- [SpringBoot](meta/zero/00%20SpringBoot.md)
|
||||
- [Hibernate](meta/zero/00%20Hibernate.md) / [[meta/zero/00 Hibernate Reactive|Hibernate Reactive]]
|
||||
- Сборщики
|
||||
- [[meta/zero/00 Maven|Maven]]
|
||||
- [[meta/zero/00 Gradle|Gradle]]
|
||||
- Архитектура
|
||||
- [[meta/zero/00 Архитектура ЭВМ|Архитектура ЭВМ]]
|
||||
- [Архитектура ПО](meta/zero/00%20Архитектура%20ПО.md)
|
||||
- [Архитектура ИС](meta/zero/00%20Архитектура%20ИС.md)
|
||||
- [[meta/zero/00 HighLoad|HighLoad]]
|
||||
- [[meta/zero/00 Базы Данных|Базы Данных]]
|
||||
- [[meta/zero/00 PostgreSQL|PostgreSQL]]
|
||||
- [DevOps](meta/zero/00%20DevOps.md)
|
||||
- [Docker](meta/zero/00%20Docker.md)
|
||||
- Сборщики
|
||||
- [[meta/zero/00 Maven|00 Maven]]
|
||||
- [[meta/zero/00 Gradle|00 Gradle]]
|
||||
- [[meta/zero/00 Linux|Linux]]
|
||||
- [Сети](meta/zero/00%20Сети.md)
|
||||
- [Алгоритмы](meta/zero/00%20Алгоритм.md)
|
||||
|
BIN
meta/files/images/Pasted image 20240129190639.png
Normal file
After Width: | Height: | Size: 734 KiB |
BIN
meta/files/images/Pasted image 20240129191116.png
Normal file
After Width: | Height: | Size: 989 KiB |
BIN
meta/files/images/Pasted image 20240129193115.png
Normal file
After Width: | Height: | Size: 743 KiB |
BIN
meta/files/images/Pasted image 20240129194120.png
Normal file
After Width: | Height: | Size: 652 KiB |
BIN
meta/files/images/Pasted image 20240129194629.png
Normal file
After Width: | Height: | Size: 730 KiB |
BIN
meta/files/images/Pasted image 20240205190752.png
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
meta/files/images/Pasted image 20240206195611.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
meta/files/images/Pasted image 20240206195639.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
meta/files/images/Pasted image 20240219184314.png
Normal file
After Width: | Height: | Size: 791 KiB |
BIN
meta/files/images/Pasted image 20240226135429.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
meta/files/images/Pasted image 20240229204146.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
meta/files/images/Pasted image 20240528082025.png
Normal file
After Width: | Height: | Size: 264 KiB |
BIN
meta/files/images/Pasted image 20240528085716.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
meta/files/images/Pasted image 20240528090119.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
meta/files/images/Pasted image 20240528090205.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
meta/files/images/Pasted image 20240605091036.png
Normal file
After Width: | Height: | Size: 434 KiB |
BIN
meta/files/images/Pasted image 20240605091913.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
meta/files/images/Pasted image 20240606094633.png
Normal file
After Width: | Height: | Size: 986 KiB |
BIN
meta/files/images/Pasted image 20240606094952.png
Normal file
After Width: | Height: | Size: 758 KiB |
BIN
meta/files/images/Pasted image 20240607211343.png
Normal file
After Width: | Height: | Size: 625 KiB |
BIN
meta/files/images/Pasted image 20240607211612.png
Normal file
After Width: | Height: | Size: 737 KiB |
BIN
meta/files/images/Pasted image 20240607212223.png
Normal file
After Width: | Height: | Size: 881 KiB |
BIN
meta/files/images/Pasted image 20240613195204.png
Normal file
After Width: | Height: | Size: 1.4 MiB |
BIN
meta/files/images/Pasted image 20240712083105.png
Normal file
After Width: | Height: | Size: 90 KiB |
@ -3,6 +3,6 @@ tags:
|
||||
- type/people
|
||||
link: https://mnogosdelal.ru/
|
||||
---
|
||||
Прокрастинатолог, специалист по продуктивности, тренер. Руководил проектами в компаниях DC BARS, Auriga, в Лаборатории Касперского, проработал в области разработки ПО почти 15 лет.
|
||||
Прокрастинатолог, специалист по продуктивности, тренер. Руководил проектами в компаниях DC BARS, Auriga, в Лаборатории Касперского, проработал в области разработки ПО почти 15 лет.
|
||||
|
||||
С 2013 ведет тренинги по продуктивности. Окончил физический факультет МГУ.
|
||||
С 2013 ведет тренинги по продуктивности. Окончил физический факультет МГУ.
|
@ -32,16 +32,19 @@ aliases:
|
||||
- [Сервис-ориентированная архитектура](Service%20Oreinted%20Architecture.md)
|
||||
- [Вертикальное масштабирование](../../dev/architecture/highload/Вертикальное%20масштабирование.md)
|
||||
- [Горизонтальное масштабирование](../../dev/architecture/highload/Горизонтальное%20масштабирование.md)
|
||||
- [Репликация](../../dev/architecture/highload/Репликация.md)
|
||||
- [[../../dev/architecture/highload/Репликация БД|Репликация БД]]
|
||||
- [[../../dev/database/postgresql/Репликация в PostgreSQL|Репликация в PostgreSQL]]
|
||||
- [[../../dev/database/postgresql/Репликация в PostgreSQL|Репликация в PostgreSQL]]
|
||||
- Отложенные вычисления
|
||||
- Асинхронная обработка
|
||||
- Конвейерная обработка
|
||||
- Использование толстого клиента
|
||||
- [Кэширование](../../dev/architecture/Кэширование.md)
|
||||
- [Функциональное разделение](Функциональное%20разделение.md)
|
||||
- [Шардинг](Шардирование%20в%20БД.md)
|
||||
- [Шардинг](../../../../_inbox/Шардирование%20БД.md)
|
||||
- Виртуальные шарды
|
||||
- Центральный диспетчер
|
||||
- [Репликация](_inbox/Репликация.md)
|
||||
- Партиционирование
|
||||
- Кластеризация
|
||||
- Денормализация
|
||||
|
33
meta/zero/00 MySQL.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
aliases:
|
||||
- MySQL
|
||||
tags:
|
||||
- type/zero-link
|
||||
zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
title: MySQL
|
||||
---
|
||||
- [[../../dev/database/mysql/Архитектура MySQL|Архитектура MySQL]]
|
||||
- [Репликация в MySQL](../../dev/database/mysql/Репликация%20в%20MySQL.md)
|
||||
- [libslave](libslave.md)
|
||||
- [Бекап в MySQL](Бекап%20в%20MySQL.md)
|
||||
- [Индексы в MySQL](Индексы%20в%20MySQL.md)
|
||||
- [Журналы в MySQL](../../dev/database/mysql/Журналы%20в%20MySQL.md)
|
||||
- [Explain в MySQL](Explain%20в%20MySQL.md)
|
||||
## Идентификация транзакций
|
||||
До версии 5.5 идентифицировать транзакцию можно было только по имени файла и позиции в этом файле. Потом появились GTID, но надо явно включить gtid_mode =ON. C 5.6.5 GTID используется по умолчанию.
|
||||
|
||||
binary log position:
|
||||
- Пример: mysql-bin.00078:44
|
||||
- Локальный для сервера
|
||||
- Обязательно сломается
|
||||
|
||||
GTID:
|
||||
- Пример: 7F33BC78-56CA-44B3-5E33-B34CC7689333:44
|
||||
- Глобален, генерируется автоматически при коммите
|
||||
- Бесплатная трассировка
|
||||
- Простой slave promotion
|
||||
- ==Используйте его==
|
||||
|
||||
## Заметки
|
||||
- MySQL пишет на диск в три места – хранилище (tablespace), журнал (undo/redo log), и Binary Log
|
23
meta/zero/00 PostgreSQL.md
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
aliases:
|
||||
- PostgreSQL
|
||||
tags:
|
||||
- type/zero-link
|
||||
zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
title: PostgreSQL
|
||||
---
|
||||
- Устройство PostgreSQL
|
||||
- Журнал: [Write-Ahead Log](../../dev/database/postgresql/Write-Ahead%20Log.md)
|
||||
- [Индекс в PostgreSQL](Индекс%20в%20PostgreSQL.md)
|
||||
- [Репликация в PostgreSQL](../../dev/database/postgresql/Репликация%20в%20PostgreSQL.md)
|
||||
- [Бэкап в PostgreSQL](Бэкап%20в%20PostgreSQL.md)
|
||||
- [Профилирование запросов в PostgreSQL](Профилирование%20запросов%20в%20PostgreSQL.md)
|
||||
- [Explain в PostgreSQL](Explain%20в%20PostgreSQL.md)
|
||||
|
||||
## Заметки
|
||||
- PostgreSQL пишет на диск в два места – в хранилище данных и в журнал.
|
||||
- Если транзакции нужно выполнить операцию с данными, с которыми работает другая транзакция, то она может встать в очередь.
|
||||
|
||||
## Дополнительные материалы
|
||||
- [pg_utils](pg_utils.md)
|
@ -5,6 +5,9 @@ parents:
|
||||
- "[[00 Разработка]]"
|
||||
title: Архитектура ПО
|
||||
---
|
||||
- [[../../../../_inbox/Architecture Significant Requirement|Architecture Significant Requirement]]
|
||||
|
||||
|
||||
- [[../../dev/architecture/CAP теорема|CAP теорема]]
|
||||
- [Трёхзвенная структура](../../dev/architecture/Трёхзвенная%20структура.md)
|
||||
- [Монолитная архитектура](Монолитная%20архитектура.md)
|
||||
|
39
meta/zero/00 Базы Данных.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
tags:
|
||||
- type/zero-link
|
||||
parents:
|
||||
- "[[00 Разработка]]"
|
||||
aliases:
|
||||
- база данных
|
||||
- базу данных
|
||||
linked:
|
||||
- "[[../../../../_inbox/00 In-memory СуБД|00 In-memory СуБД]]"
|
||||
---
|
||||
- [Журнал БД](../../dev/database/Журнал%20БД.md)
|
||||
- [Репликация БД](../../dev/architecture/highload/Репликация%20БД.md)
|
||||
- [Резервные копии БД](Резервные%20копии%20БД.md)
|
||||
- [Транзакция БД](Транзакция%20БД.md)
|
||||
|
||||
СуБД:
|
||||
- [PostgreSQL](00%20PostgreSQL.md)
|
||||
- [MySQL](00%20MySQL.md)
|
||||
## Улучшение производительности
|
||||
- [Репликация БД](../../dev/architecture/highload/Репликация%20БД.md)
|
||||
- [Шардирование БД](../../../../_inbox/Шардирование%20БД.md)
|
||||
|
||||
- Выбирать правильный тип для колонки
|
||||
- Денормализация
|
||||
- Меньше индексов - лучше
|
||||
- Меньше джойнов - лучше
|
||||
|
||||
Приложение работает неограниченное количество времени, с каждым днем количество данных в БД увеличивается. При возрастании объема запросы начинают отрабатывать медленнее, в таком случае возникает необходимость в применении [партиционирования](Партиционирование%20в%20БД.md) и [шардирования](../../../../_inbox/Шардирование%20БД.md).
|
||||
|
||||
- [Производительность SQL запросов](_inbox/Производительность%20SQL%20запросов.md)
|
||||
|
||||
## Заметки
|
||||
- Классические СУБД хранят данные в двух местах: на диске и в памяти.
|
||||
- [[../../dev/fundamental/Страница|Страница]] модифицируется сначала в оперативной памяти, потом попадает на диск.
|
||||
- ![](Pasted%20image%2020240531082744.png)
|
||||
- Часто думают, что реляционная таблица — это массив. Некоторые даже думают, что это двумерный массив. На самом деле, это гораздо более сложная штука. Это мультимножество – набор определенного сорта кортежей, над которым не задано порядка. В SQL-таблице нет порядка. Это важно. И, как результат, когда вы делаете SELECT* из БД (просканировать все записи), результат выполнения запроса может меняться – строчки могут быть в одном порядке, а могут и в другом. Про это нужно помнить.
|
||||
- Профиль нагрузки на реляционную базу данных выглядит следующим образом: 80% запросов это чтение, 20% запросов это запись. Если запросов на запись больше, то возможно реляционная база данных вам не подходит.
|
||||
|
@ -6,5 +6,5 @@ date:
|
||||
parents:
|
||||
title: Криптография
|
||||
---
|
||||
- [[../../dev/cryptography/Криптографическая хеш-функция|Криптографическая хеш-функция]]
|
||||
- [[../../dev/cryptography/Хеш-функция|Хеш-функция]]
|
||||
- [Генерация аппаратного SSH ключа](../../dev/cryptography/Генерация%20аппаратного%20SSH%20ключа.md)
|
@ -5,4 +5,4 @@ title: Образование
|
||||
---
|
||||
- [[../../education/Метапознание|Метапознание]]
|
||||
## Свободные заметки
|
||||
- Согласно исследованиям, оптимальное время для начала обучения и работы [лежит в промежутке 11:00-12:00](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5395635/). Хотя исследователи и признают, что это довольно индивидуально, и важно слушать свои ощущения.
|
||||
- Согласно исследованиям, оптимальное время для начала обучения и работы [лежит в промежутке 11:00-12:00](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5395635/). Хотя исследователи и признают, что это довольно индивидуально, и важно слушать свои ощущения.
|
53
meta/zero/00 Сон.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
tags:
|
||||
- type/zero-link
|
||||
aliases:
|
||||
- сон
|
||||
- сна
|
||||
- сне
|
||||
- сном
|
||||
- спать
|
||||
zero-link:
|
||||
- "[[00 Здоровье|00 Здоровье]]"
|
||||
---
|
||||
- [Качественный сон](Качественный%20сон.md)
|
||||
- [Как наладить сон?](Как%20наладить%20сон?.md)
|
||||
- [[../../../../knowledge/health/болезни/Расстройства сна|Расстройства сна]]
|
||||
- [Как не заснуть?](Как%20не%20заснуть?.md)
|
||||
- [Сновидения](Сновидения.md)
|
||||
- [Утреннее пробуждение](knowledge/health/сон/Утреннее%20пробуждение.md)
|
||||
|
||||
Главные компоненты отвечающие за сон:
|
||||
- [Мелатонин](knowledge/human/гормоны/Мелатонин.md) - гормон "темноты и сна". Вырабатывает [Шишковидная железа](knowledge/human/строение/Шишковидная%20железа.md)
|
||||
- [Циркадные ритмы](knowledge/human/Циркадные%20ритмы.md) - наши внутренние биологические часы
|
||||
- [Супрахиазматическое ядро](Супрахиазматическое%20ядро.md) - следит за временем, ориентируясь на свет
|
||||
- Нейромедиаторы и гормоны: [Кортизол](Кортизол.md), [Адреналин](Адреналин.md), [Норадреналин](Норадреналин.md), [Аденозин](Аденозин.md)
|
||||
- [Фазы сна](Фазы%20сна.md): [Поверхностный сон](_inbox/Поверхностный%20сон.md), [Глубокая фаза сна](Глубокая%20фаза%20сна.md), [REM](Фаза%20быстрого%20сна.md)
|
||||
## Зачем нужен сон?
|
||||
**Сон играет роль уборщика**, [удаляя](https://www.sciencedirect.com/science/article/abs/pii/S2468867319301609#:~:text=The%20discovery%20that,dependence%20on%20glia.) из мозга продукты метаболизма — ненужные белки, которые накапливаются во время бодрствования и приводят к заболеваниям нервной системы. Среди таких белков — бета-амилоид, большая концентрация которого приводит к [гибели](https://med.stanford.edu/news/all-news/2013/09/scientists-reveal-how-beta-amyloid-may-cause-alzheimers.html#:~:text=Scientists%20at%20the%20Stanford%20University%20School%20of%20Medicine%20have%20shown%20how%20a%20protein%20fragment%20known%20as%20beta%2Damyloid%2C%20strongly%20implicated%20in%20Alzheimer%E2%80%99s%20disease%2C%20begins%20destroying%20synapses%20before%20it%20clumps%20into%20plaques%20that%20lead%20to%20nerve%20cell%20death.) нервных клеток и, [вероятно](https://www.medicalnewstoday.com/articles/325493#:~:text=If%20the%20cellular%20system%20became%20overloaded%20or%20slowed%20down%20as%20we%20aged%2C%20metabolic%20garbage%20would%20build%20up%20between%20the%20cells.%20This%20garbage%20includes%20products%20such%20as%20beta%2Damyloid%20%E2%80%94%20the%20protein%20associated%20with%20Alzheimer%E2%80%99s%20disease.), к [[../../../../knowledge/health/болезни/Болезнь Альцгеймера|болезни Альцгеймера]]. Всего одна бессонная ночь значительно [повышает](https://www.pnas.org/doi/10.1073/pnas.1721694115#:~:text=We%20show%20that%20one%20night%20of%20sleep%20deprivation%2C%20relative%20to%20baseline%2C%20resulted%20in%20a%20significant%20increase%20in%20A%CE%B2%20burden%20in%20the%20right%20hippocampus%20and%20thalamus.) объем этого белка в мозге человека.
|
||||
|
||||
**Сон важен для физического самочувствия.** Пока мы спим, [усиливается](https://erj.ersjournals.com/content/38/4/870#:~:text=The%20release%20of%20GH%20is%20greatly%20enhanced%20during%20sleep%2C%20especially%20early%20in%20the%20night) выработка [«гормона роста»](https://ru.wikipedia.org/wiki/%D0%93%D0%BE%D1%80%D0%BC%D0%BE%D0%BD_%D1%80%D0%BE%D1%81%D1%82%D0%B0), который [восстанавливает](https://www.healthline.com/health/hgh-side-effects#:~:text=HGH%20helps%20to%20maintain%2C%20build%2C%20and%20repair%20healthy%20tissue%20in%20the%20brain%20and%20other%20organs.%20This%20hormone%20can%20help%20to%20speed%20up%20healing%20after%20an%20injury%20and%20repair%20muscle%20tissue%20after%20exercise.%20This%20helps%20to%20build%20muscle%20mass%2C%20boost%20metabolism%2C%20and%20burn%20fat.) мышцы после нагрузок и травм. Нехватка этого гормона [приводит](https://academic.oup.com/jcem/article/83/2/382/2865179?login=false#:~:text=1.%20Lean%20Body%20Mass%20(LBM).%20Reduced%20LBM%20is%20an%20important%20feature%20of%20AO%20GH%20deficiency.%20Initial%20studies%20demonstrated%20a%20mean%20reduction%20in%20LBM%20of%207%E2%80%938%25%2C%20corresponding%20to%20approximately%204%20kg%20lean%20tissue%20(6).%20Subsequent%20studies%20have%20confirmed%20these%20results%20(12%2C%2014%E2%80%9316).) к тому, что мышцы атрофируются. Также сон помогает нормализовать артериальное давление.
|
||||
|
||||
**Сон нужен иммунной системе.** Во сне наше дыхание замедляется, а мышцы почти неподвижны, поэтому энергия в организме может [пойти](https://www.sleepfoundation.org/physical-health/how-sleep-affects-immunity#:~:text=During%20sleep%2C%20breathing%20and%20muscle%20activity%20slows%20down%2C%20freeing%20up%20energy%20for%20the%20immune%20system%20to%20perform%20these%20critical%20tasks.) на важные иммунные задачи. Например, [активируются](https://www.sleepfoundation.org/physical-health/how-sleep-affects-immunity#:~:text=Sleep%20is%20an,off%20an%20infection.) воспалительные процессы, помогающие заживлять раны и бороться с инфекциями. [[../../../../knowledge/health/болезни/Недосып|Недосып]] же имеет обратный эффект: те, кто спят меньше семи часов, [простужаются](https://pubmed.ncbi.nlm.nih.gov/19139325/#:~:text=There%20was%20a%20graded%20association%20with%20average%20sleep%20duration%3A%20participants%20with%20less%20than%207%20hours%20of%20sleep%20were%202.94%20times%20(95%25%20confidence%20interval%20%5BCI%5D%2C%201.18%2D7.30)%20more%20likely%20to%20develop%20a%20cold%20than%20those%20with%208%20hours%20or%20more%20of%20sleep.) почти в три раза чаще, чем спящие по восемь часов.
|
||||
|
||||
**Сон [формирует](https://www.pnas.org/doi/10.1073/pnas.2201795119) и закрепляет воспоминания**. Этот процесс называется [консолидация памяти](Консолидация%20памяти.md). Это подтверждается экспериментами: одна группа людей училась утром, а другая вечером. Контрольный тест показал, что чем ближе обучение ко сну, тем лучше усваивается информация.
|
||||
|
||||
Еще во сне мы [продолжаем](https://now.tufts.edu/2021/02/18/new-theory-why-we-dream#:~:text=In%20essence%2C%20that%E2%80%99s,need%20of%20disruption.) искать решение проблем, которые волновали нас днем.
|
||||
## Как возникает сон
|
||||
![](Циркадные%20ритмы.md#^a1a364)
|
||||
![](Мелатонин.md#^381eb3)
|
||||
![](Шишковидная%20железа.md#^31ebf3)
|
||||
|
||||
- [Фазы сна](Фазы%20сна.md)
|
||||
## Что влияет на сон
|
||||
- [Стресс](Стресс.md)
|
||||
- Хронические заболевания
|
||||
- Кофеин
|
||||
- Возраст
|
||||
- Принимаемые препараты
|
||||
- [[../../../../knowledge/health/Физическая нагрузка|Физическая нагрузка]].
|
||||
## Заметки
|
||||
- В одном эксперементе добровольцы спали не больше шести часов. Итог - время реакции на внешние факторы увеличилось в 2 раза, внимательность ухудшилась в 5 раз.
|
||||
|
||||
## Дополнительные материалы
|
||||
- [[../../../../_inbox/Сказки для сна|Сказки для сна]]
|