Compare commits
49 Commits
17f4d4caf2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 98004bcb67 | |||
| f7e0663d3e | |||
| 756607fbb9 | |||
| ce9454d518 | |||
| 038d71be6e | |||
| 039eeb40e5 | |||
| cd480c69a9 | |||
| 34d17c9c9b | |||
| 351d80d3ff | |||
| 5a017ac47a | |||
| f438203912 | |||
| ce0d02d0b0 | |||
| caf80d3c20 | |||
| 17f6f8ac98 | |||
| 902ee9d5fb | |||
| 3905acf5b1 | |||
| 92a2df6b73 | |||
| 5118268045 | |||
| a9c1d87b38 | |||
| 3310c3143e | |||
| 91e73ffbef | |||
| 3f10edf636 | |||
| 5d7f0eb094 | |||
| 6864921ba2 | |||
| 695d095133 | |||
| f8c68fc017 | |||
| 24027d9d7c | |||
| ca2c0ecb0d | |||
| 3c01fb220c | |||
| 7813c906b6 | |||
| 54e0280d36 | |||
| 8291eabd96 | |||
| 5f53344c8d | |||
| fffbc19277 | |||
| 5eab9c24f8 | |||
| 82f1fe3ebe | |||
| 8b96c3784f | |||
| ad86c1410a | |||
| 52ea4eb4c8 | |||
| d56d13dfa4 | |||
| ec880e8d5d | |||
| 49c3a582f1 | |||
| a400048ef3 | |||
| 672a33d6f9 | |||
| e5977484af | |||
| 62fe0e0ca1 | |||
| 1ea6770013 | |||
| 8047021a44 | |||
| 198d6d22a7 |
164
DevOps/Clickhouse/Cluster/0-Bases-and-query.md
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
title: 0. Основы и запросы
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-15T20:02:37.600Z
|
||||
tags: clickhouse
|
||||
editor: markdown
|
||||
dateCreated: 2025-05-15T20:01:45.285Z
|
||||
---
|
||||
|
||||
## Структура кластера
|
||||
|
||||
### Найдено на просторах инета:
|
||||
##### Выбор решения:
|
||||
- Если **диск загружен на запись (INSERT)** → **шардирование (Distributed)**.
|
||||
- Если **диск загружен на чтение (SELECT)** → **репликация (Replicated)**.
|
||||
- Если **один сервер, но много дисков** → **JBOD или RAID 0/10**.
|
||||
|
||||
#### Реализуем такую структуру тестового кластера:
|
||||
- сервер clickhouse-1
|
||||
- сервер clickhouse-2
|
||||
- сервер clickhouse-keeper
|
||||
Для того, чтобы это было надежно и работало быстро с записью в БД, необходимо сделать репликацию (Replicated) таблиц и распределенный (Distributed) доступ к таблицам.
|
||||
Если делать несколько шардов (shard) в настройках кластера, то это значит, что часть данных будет находится на одном сервере, другая часть на другом. При выходе из строя сервера мы потеряем всю базу.
|
||||
Поэтому настраиваем shard1 на обоих серверах, а также replica1 и replica2 для дублирования данных на серверах.
|
||||
|
||||
### Репликация поддерживается только для таблиц семейства MergeTree:
|
||||
https://clickhouse.com/docs/ru/engines/table-engines/mergetree-family/replication
|
||||
- ReplicatedMergeTree
|
||||
- ReplicatedSummingMergeTree
|
||||
- ReplicatedReplacingMergeTree
|
||||
- ReplicatedAggregatingMergeTree
|
||||
- ReplicatedCollapsingMergeTree
|
||||
- ReplicatedVersionedCollapsingMergeTree
|
||||
- ReplicatedGraphiteMergeTree
|
||||
|
||||
### Для одиночного сервера и кластера
|
||||
#### Получение списка всех баз данных на сервере
|
||||
```sql
|
||||
SHOW DATABASES;
|
||||
```
|
||||
#### Просмотр всех таблиц в конкретной базе default
|
||||
```sql
|
||||
SHOW TABLES FROM default;
|
||||
```
|
||||
#### Получить запрос на создание таблицы из существующей
|
||||
```sql
|
||||
show create table default.event;
|
||||
```
|
||||
#### Создание базы данных
|
||||
```sql
|
||||
CREATE DATABASE IF NOT EXISTS my_database ENGINE = Atomic;
|
||||
```
|
||||
Создает новую базу данных с именем `my_database`. Если такая база уже существует, ничего не произойдет благодаря условию `IF NOT EXISTS`.
|
||||
Параметр `ENGINE = Atomic` используется для новых версий ClickHouse и позволяет создавать транзакционно безопасные базы данных. В ранних версиях использовался простой синтаксис без указания движка.
|
||||
#### Создание таблицы
|
||||
```sql
|
||||
CREATE TABLE my_table (
|
||||
event_date Date,
|
||||
user_id UInt32,
|
||||
page_views Int32,
|
||||
revenue Float64
|
||||
)
|
||||
ENGINE = MergeTree()
|
||||
ORDER BY (event_date);
|
||||
```
|
||||
##### Вставка данных
|
||||
```sql
|
||||
INSERT INTO my_table VALUES ('2023-08-01', 1, 10, 100.5), ('2023-08-02', 2, 15, 150.75);
|
||||
```
|
||||
##### Выборка данных
|
||||
```sql
|
||||
SELECT * FROM my_table WHERE event_date >= '2023-08-01' AND event_date <= '2023-08-31';
|
||||
```
|
||||
#### Показ структуры таблицы
|
||||
```sql
|
||||
DESCRIBE TABLE my_database.my_table;
|
||||
```
|
||||
или подробнее:
|
||||
```sql
|
||||
SELECT * FROM system.columns WHERE table='my_table' AND database='my_database';
|
||||
```
|
||||
### Узнать сколько занимают места базы
|
||||
```sql
|
||||
SELECT
|
||||
database,
|
||||
formatReadableSize(sum(bytes_on_disk)) AS total_size
|
||||
FROM system.parts
|
||||
WHERE active
|
||||
GROUP BY database
|
||||
ORDER BY sum(bytes_on_disk) DESC;
|
||||
```
|
||||
#### Узнать сколько занимают места таблицы в базе
|
||||
default
|
||||
```sql
|
||||
SELECT
|
||||
name AS table_name,
|
||||
formatReadableSize(total_bytes) AS size_readable,
|
||||
total_rows AS rows_count
|
||||
FROM system.tables
|
||||
WHERE database = 'default'
|
||||
ORDER BY total_bytes DESC;
|
||||
```
|
||||
system
|
||||
```sql
|
||||
SELECT
|
||||
name AS table_name,
|
||||
formatReadableSize(total_bytes) AS size_readable,
|
||||
total_rows AS rows_count
|
||||
FROM system.tables
|
||||
WHERE database = 'system'
|
||||
ORDER BY total_bytes DESC;
|
||||
```
|
||||
#### Очистка базы event_replicated
|
||||
```sql
|
||||
TRUNCATE TABLE default.event_replicated;
|
||||
```
|
||||
#### Очистка старых данных от определенной даты
|
||||
```sql
|
||||
ALTER TABLE my_table DELETE WHERE event_date < '2023-08-01';
|
||||
```
|
||||
#### Безопасное удаление таблицы
|
||||
```sql
|
||||
DROP TABLE IF EXISTS my_database.my_table;
|
||||
```
|
||||
Безопасно удаляет указанную таблицу, если она существует.
|
||||
|
||||
|
||||
### Для кластера
|
||||
|
||||
#### Вывести список серверов в кластере
|
||||
```sql
|
||||
SELECT hostName() FROM clusterAllReplicas('smvu2_cluster', 'system', 'one')
|
||||
```
|
||||
#### Получение списка Replicated таблиц
|
||||
```sql
|
||||
SELECT
|
||||
database,
|
||||
name AS table,
|
||||
engine
|
||||
FROM system.tables
|
||||
WHERE engine LIKE 'Replicated%';
|
||||
```
|
||||
#### Получение списка Distributed таблиц
|
||||
```sql
|
||||
SELECT
|
||||
database,
|
||||
name AS table,
|
||||
engine
|
||||
FROM system.tables
|
||||
WHERE engine LIKE 'Distributed%';
|
||||
```
|
||||
#### Проверить распределение данных базы event на серверах кластера
|
||||
```sql
|
||||
SELECT
|
||||
hostName() AS host,
|
||||
count() AS count
|
||||
FROM clusterAllReplicas(smvu2_cluster, default.event)
|
||||
GROUP BY host;
|
||||
```
|
||||
#### Удалить таблицу в кластере
|
||||
```sql
|
||||
DROP TABLE event_replicated ON CLUSTER smvu2_cluster SYNC;
|
||||
```
|
||||
228
DevOps/Clickhouse/Cluster/1-Install-Clickhouse-cluster.md
Normal file
@@ -0,0 +1,228 @@
|
||||
---
|
||||
title: 1. Создание кластера Clickhouse
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-15T20:11:12.215Z
|
||||
tags: clickhouse, cluster
|
||||
editor: markdown
|
||||
dateCreated: 2025-05-15T18:04:57.423Z
|
||||
---
|
||||
|
||||
https://clickhouse.com/docs/guides/sre/keeper/clickhouse-keeper
|
||||
## Установка и настройка clickhouse, clickhouse-keeper
|
||||
### Установка clickhouse-keeper
|
||||
```bash
|
||||
apt-get install -y apt-transport-https ca-certificates curl gnupg
|
||||
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
|
||||
ARCH=$(dpkg --print-architecture)
|
||||
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
|
||||
apt-get update
|
||||
apt-get install -y clickhouse-keeper
|
||||
```
|
||||
|
||||
#### Готовим конфиг clickhouse-keeper
|
||||
```
|
||||
nano /etc/clickhouse-keeper/keeper_config.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<clickhouse>
|
||||
<logger>
|
||||
<level>warning</level>
|
||||
<log>/var/log/clickhouse-keeper/clickhouse-keeper.log</log>
|
||||
<errorlog>/var/log/clickhouse-keeper/clickhouse-keeper.err.log</errorlog>
|
||||
<size>1000M</size>
|
||||
<count>10</count>
|
||||
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
|
||||
</logger>
|
||||
|
||||
<max_connections>4096</max_connections>
|
||||
<listen_host>0.0.0.0</listen_host>
|
||||
<listen_host>::1</listen_host>
|
||||
|
||||
<keeper_server>
|
||||
<tcp_port>9181</tcp_port>
|
||||
<server_id>1</server_id>
|
||||
|
||||
<log_storage_path>/var/lib/clickhouse/coordination/logs</log_storage_path>
|
||||
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
|
||||
|
||||
<coordination_settings>
|
||||
<operation_timeout_ms>10000</operation_timeout_ms>
|
||||
<session_timeout_ms>30000</session_timeout_ms>
|
||||
<raft_logs_level>warning</raft_logs_level>
|
||||
<compress_logs>true</compress_logs>
|
||||
</coordination_settings>
|
||||
|
||||
<!-- enable sanity hostname checks for cluster configuration (e.g. if localhost is used with remote endpoints) -->
|
||||
<hostname_checks_enabled>false</hostname_checks_enabled>
|
||||
<raft_configuration>
|
||||
<server>
|
||||
<id>1</id>
|
||||
<hostname>localhost</hostname>
|
||||
<port>9234</port>
|
||||
</server>
|
||||
</raft_configuration>
|
||||
</keeper_server>
|
||||
</clickhouse>
|
||||
```
|
||||
|
||||
#### Пароль пользователя
|
||||
```
|
||||
nano /etc/clickhouse-server/users.d/default-password.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<yandex>
|
||||
<users>
|
||||
<default>
|
||||
<password>SuperPass</password>
|
||||
<networks>
|
||||
<ip>::/0</ip>
|
||||
<ip>127.0.0.1</ip>
|
||||
<ip>172.16.212.0/24</ip>
|
||||
</networks>
|
||||
</default>
|
||||
</users>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
### Готовим конфиги clickhouse на серверах SMVU2-DEV14 и SMVU2-Click-DEV
|
||||
|
||||
```bash
|
||||
nano /etc/clickhouse-server/config.d/remote_servers.xml
|
||||
```
|
||||
##### server 1
|
||||
```xml
|
||||
<yandex>
|
||||
<display_name>smvu2_cluster node 1</display_name>
|
||||
<remote_servers replace="true">
|
||||
<smvu2_cluster>
|
||||
<!--<secret>mysecretphrase</secret> -->
|
||||
<shard>
|
||||
<internal_replication>true</internal_replication>
|
||||
<replica>
|
||||
<host>172.16.212.14</host>
|
||||
<port>9000</port>
|
||||
<priority>1</priority>
|
||||
<secure>0</secure>
|
||||
<user>default</user>
|
||||
<password>SuperPass</password>
|
||||
</replica>
|
||||
<replica>
|
||||
<host>172.16.212.42</host>
|
||||
<port>9000</port>
|
||||
<priority>2</priority>
|
||||
<secure>0</secure>
|
||||
<user>default</user>
|
||||
<password>SuperPass</password>
|
||||
</replica>
|
||||
</shard>
|
||||
</smvu2_cluster>
|
||||
</remote_servers>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
```
|
||||
nano /etc/clickhouse-server/config.d/shard.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<yandex>
|
||||
<macros>
|
||||
<shard>1</shard>
|
||||
<replica>replica1</replica>
|
||||
</macros>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
##### server 2
|
||||
```xml
|
||||
<yandex>
|
||||
<display_name>smvu2_cluster node 2</display_name>
|
||||
<remote_servers replace="true">
|
||||
<smvu2_cluster>
|
||||
<!--<secret>mysecretphrase</secret> -->
|
||||
<shard>
|
||||
<internal_replication>true</internal_replication>
|
||||
<replica>
|
||||
<host>172.16.212.42</host>
|
||||
<port>9000</port>
|
||||
<priority>2</priority>
|
||||
<secure>0</secure>
|
||||
<user>default</user>
|
||||
<password>SuperPass</password>
|
||||
</replica>
|
||||
<replica>
|
||||
<host>172.16.212.14</host>
|
||||
<port>9000</port>
|
||||
<priority>1</priority>
|
||||
<secure>0</secure>
|
||||
<user>default</user>
|
||||
<password>SuperPass</password>
|
||||
</replica>
|
||||
</shard>
|
||||
</smvu2_cluster>
|
||||
</remote_servers>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
```
|
||||
nano /etc/clickhouse-server/config.d/shard.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<yandex>
|
||||
<macros>
|
||||
<shard>1</shard>
|
||||
<replica>replica2</replica>
|
||||
</macros>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
```
|
||||
nano /etc/clickhouse-server/config.d/keeper.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<yandex>
|
||||
<zookeeper>
|
||||
<node>
|
||||
<host>172.16.212.41</host>
|
||||
<port>9181</port>
|
||||
</node>
|
||||
</zookeeper>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
```
|
||||
nano /etc/clickhouse-server/config.d/distributed_ddl.xml
|
||||
```
|
||||
|
||||
```xml
|
||||
<yandex>
|
||||
<distributed_ddl>
|
||||
<task_max_lifetime>86400</task_max_lifetime>
|
||||
<profile>default</profile>
|
||||
<cleanup_delay>60</cleanup_delay>
|
||||
<max_workers>16</max_workers>
|
||||
</distributed_ddl>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
### Проверить сервера, что они в кластере
|
||||
|
||||
#### Показать кластер
|
||||
```sql
|
||||
SHOW clusters;
|
||||
```
|
||||
|
||||
#### Вывести список серверов в кластере
|
||||
```sql
|
||||
SELECT hostName() FROM clusterAllReplicas('smvu2_cluster', 'system', 'one')
|
||||
```
|
||||
|
||||
#### Keeper status
|
||||
```sql
|
||||
SELECT * FROM system.zookeeper WHERE path = '/';
|
||||
```
|
||||
646
DevOps/Clickhouse/Cluster/3-Create-manual.md
Normal file
@@ -0,0 +1,646 @@
|
||||
---
|
||||
title: 3. Создание таблиц вручную
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-15T20:07:34.738Z
|
||||
tags: clickhouse
|
||||
editor: markdown
|
||||
dateCreated: 2025-05-15T20:07:34.738Z
|
||||
---
|
||||
|
||||
Можно создать все таблицы для кластера вручную.
|
||||
Запрашиваем структуру каждой таблицы, создаем под другим именем и копируем данные с исходника.
|
||||
|
||||
##### Может возникнуть проблема, что таблицы содержат много данных, поэтому внизу статьи будет решение
|
||||
|
||||
## Создаем реплицированные таблицы
|
||||
|
||||
**Разберем первую таблицу подробно**
|
||||
### 1. api_request_log_replicated
|
||||
|
||||
Запрашиваем структуру
|
||||
```sql
|
||||
show create table default.api_request_log
|
||||
```
|
||||
|
||||
Выход:
|
||||
```sql
|
||||
CREATE TABLE default.api_request_log
|
||||
(
|
||||
`uuid` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`ver` UInt8,
|
||||
`request_ts` DateTime64(3) DEFAULT '0000000000.000',
|
||||
`duration` Float64,
|
||||
`endpoint` String,
|
||||
`method` FixedString(5),
|
||||
`status_code` UInt32,
|
||||
`remote_addr` String,
|
||||
`username` Nullable(String),
|
||||
`error` Nullable(String),
|
||||
`request_body` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1),
|
||||
`query_params` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1),
|
||||
`response_body` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1)
|
||||
)
|
||||
ENGINE = MergeTree(ver)
|
||||
PARTITION BY toYYYYMM(request_ts)
|
||||
ORDER BY uuid
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
|
||||
Дорабатываем запрос, чтобы получилась на выходе реплицируемая таблица
|
||||
```sql
|
||||
CREATE TABLE default.api_request_log_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`uuid` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`ver` UInt8,
|
||||
`request_ts` DateTime64(3) DEFAULT '0000000000.000',
|
||||
`duration` Float64,
|
||||
`endpoint` String,
|
||||
`method` FixedString(5),
|
||||
`status_code` UInt32,
|
||||
`remote_addr` String,
|
||||
`username` Nullable(String),
|
||||
`error` Nullable(String),
|
||||
`request_body` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1),
|
||||
`query_params` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1),
|
||||
`response_body` Nullable(String) TTL toDateTime(request_ts) + toIntervalMonth(1)
|
||||
)
|
||||
ENGINE = ReplicatedReplacingMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/api_request_log_replicated',
|
||||
'{replica}',
|
||||
ver
|
||||
)
|
||||
PARTITION BY toYYYYMM(request_ts)
|
||||
ORDER BY uuid
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.api_request_log_replicated
|
||||
SELECT * FROM default.api_request_log
|
||||
```
|
||||
|
||||
### 2. event_replicated
|
||||
```sql
|
||||
show create table default.event
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`event_id` UUID,
|
||||
`unipoll_id` UUID,
|
||||
`sensor_id` UUID,
|
||||
`sensor_type_id` UUID,
|
||||
`sensor_type_name` String,
|
||||
`sensor_activation_status_name` String,
|
||||
`sensor_logic_status_id` UUID,
|
||||
`sensor_logic_status_name` String,
|
||||
`sensor_comment` Nullable(String),
|
||||
`command` String,
|
||||
`priority_name` String,
|
||||
`pub_ts` DateTime,
|
||||
`sub_ts` DateTime64(3, 'Europe/Moscow'),
|
||||
`state_id` UInt8,
|
||||
`state_name` String,
|
||||
`status_id` UInt8,
|
||||
`status_name` String,
|
||||
`unitype_id` UInt16,
|
||||
`unitype_name` String,
|
||||
`system_id` UInt16,
|
||||
`system_short_name` String,
|
||||
`system_name` String,
|
||||
`checked` UInt8,
|
||||
`object_id` UUID,
|
||||
`object_type_name` String,
|
||||
`data_id` UInt8,
|
||||
`value` Nullable(String),
|
||||
`raw_value` Nullable(String),
|
||||
`data` String,
|
||||
`region_id` UUID,
|
||||
`region_name` String,
|
||||
`complex_id` UUID,
|
||||
`complex_name` String,
|
||||
`collector_id` Nullable(UUID),
|
||||
`collector_name` Nullable(String),
|
||||
`control_room_id` Nullable(UUID),
|
||||
`control_room_name` Nullable(String),
|
||||
`picket_id` Nullable(UUID),
|
||||
`picket_name` Nullable(String),
|
||||
`picket_n` Nullable(UInt32),
|
||||
`cstate_id` UUID,
|
||||
`cstate_name` String,
|
||||
`cstate_color_id` UInt8,
|
||||
`sub_ms` UInt64,
|
||||
`linked_channel_state` Nullable(String),
|
||||
`on_guard` Nullable(UInt8),
|
||||
`internal_id` Nullable(String),
|
||||
`floor_number` Nullable(Int32)
|
||||
)
|
||||
ENGINE = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/event_replicated',
|
||||
'{replica}'
|
||||
)
|
||||
PARTITION BY toYYYYMM(pub_ts)
|
||||
ORDER BY (priority_name, sensor_type_id, cstate_id, object_id, sensor_id, pub_ts, sub_ts, event_id)
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.event_replicated
|
||||
SELECT * FROM default.event
|
||||
```
|
||||
|
||||
### 3. event_automation_replicated
|
||||
```sql
|
||||
show create table default.event_automation
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_automation_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`event_id` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`unipoll_id` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`automation_id` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`automation_name` String,
|
||||
`automation_mode` UInt8,
|
||||
`pub_ts` DateTime DEFAULT '0000000000',
|
||||
`sub_ts` DateTime64(3) DEFAULT '0000000000.000',
|
||||
`sub_ms` UInt64,
|
||||
`state_id` UInt8,
|
||||
`state_name` String,
|
||||
`status_id` UInt8,
|
||||
`unitype_id` UInt8,
|
||||
`unitype_name` String,
|
||||
`group_id` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`group_name` String,
|
||||
`data` String,
|
||||
`cstate_id` UUID DEFAULT '00000000-0000-0000-0000-000000000000',
|
||||
`cstate_name` String,
|
||||
`cstate_color_id` UInt8
|
||||
)
|
||||
ENGINE = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/event_automation_replicated',
|
||||
'{replica}'
|
||||
)
|
||||
PARTITION BY toYYYYMMDD(pub_ts)
|
||||
ORDER BY (event_id, pub_ts, sub_ts)
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.event_automation_replicated
|
||||
SELECT * FROM default.event_automation
|
||||
```
|
||||
|
||||
### 4. event_confirmation_replicated
|
||||
```sql
|
||||
show create table default.event_confirmation
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_confirmation_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`uuid` UUID,
|
||||
`event_id` UUID,
|
||||
`reason` String DEFAULT '',
|
||||
`event_checked` Int8,
|
||||
`username` String,
|
||||
`datetime` DateTime,
|
||||
`confirmation_group` String,
|
||||
`node_id` UUID
|
||||
)
|
||||
ENGINE = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/event_confirmation_replicated',
|
||||
'{replica}'
|
||||
)
|
||||
PARTITION BY toYYYYMM(datetime)
|
||||
ORDER BY datetime
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.event_confirmation_replicated
|
||||
SELECT * FROM default.event_confirmation
|
||||
```
|
||||
|
||||
### 5. event_objects_replicated
|
||||
```sql
|
||||
show create table default.event_objects
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_objects_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`event_id` UUID,
|
||||
`node_id` UUID,
|
||||
`pub_ts` DateTime,
|
||||
`sub_ts` DateTime64(3, 'UTC'),
|
||||
`cstate_id` UUID,
|
||||
`source_id` UUID,
|
||||
`source_name` String DEFAULT '',
|
||||
`source_type_id` UUID,
|
||||
`event_data` String,
|
||||
`complex_id` UUID
|
||||
)
|
||||
ENGINE = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/event_objects_replicated',
|
||||
'{replica}'
|
||||
)
|
||||
PARTITION BY toYYYYMM(pub_ts)
|
||||
PRIMARY KEY event_id
|
||||
ORDER BY (event_id, pub_ts, sub_ts)
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.event_objects_replicated
|
||||
SELECT * FROM default.event_objects
|
||||
```
|
||||
### 6. infi_clickhouse_orm_migrations_replicated
|
||||
|
||||
```sql
|
||||
show create table default.infi_clickhouse_orm_migrations
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.infi_clickhouse_orm_migrations_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`package_name` String,
|
||||
`module_name` String,
|
||||
`applied` Date DEFAULT '1970-01-01'
|
||||
)
|
||||
ENGINE = ReplicatedMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/infi_clickhouse_orm_migrations_replicated',
|
||||
'{replica}'
|
||||
)
|
||||
PARTITION BY toYYYYMM(applied)
|
||||
ORDER BY (package_name, module_name)
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем данные
|
||||
```sql
|
||||
INSERT INTO default.infi_clickhouse_orm_migrations_replicated
|
||||
SELECT * FROM default.infi_clickhouse_orm_migrations
|
||||
```
|
||||
|
||||
### 7. unchecked_event_replicated
|
||||
|
||||
```sql
|
||||
show create table default.unchecked_event
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.unchecked_event_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`event_id` UUID,
|
||||
`unipoll_id` Nullable(UUID),
|
||||
`sensor_id` Nullable(UUID),
|
||||
`sensor_type_id` Nullable(UUID),
|
||||
`sensor_type_name` Nullable(String),
|
||||
`sensor_activation_status_name` Nullable(String),
|
||||
`sensor_logic_status_id` Nullable(UUID),
|
||||
`sensor_logic_status_name` Nullable(String),
|
||||
`sensor_comment` Nullable(String),
|
||||
`command` Nullable(String),
|
||||
`priority_name` Nullable(String),
|
||||
`pub_ts` Nullable(DateTime),
|
||||
`sub_ts` DateTime64(3),
|
||||
`state_id` Nullable(UInt8),
|
||||
`state_name` Nullable(String),
|
||||
`status_id` Nullable(UInt8),
|
||||
`status_name` Nullable(String),
|
||||
`unitype_id` Nullable(UInt16),
|
||||
`unitype_name` Nullable(String),
|
||||
`system_id` Nullable(UInt16),
|
||||
`system_short_name` Nullable(String),
|
||||
`system_name` Nullable(String),
|
||||
`checked` Nullable(UInt8),
|
||||
`object_id` Nullable(UUID),
|
||||
`object_type_name` Nullable(String),
|
||||
`data_id` Nullable(UInt8),
|
||||
`data` Nullable(String),
|
||||
`region_id` Nullable(UUID),
|
||||
`region_name` Nullable(String),
|
||||
`complex_id` Nullable(UUID),
|
||||
`complex_name` Nullable(String),
|
||||
`collector_id` Nullable(UUID),
|
||||
`collector_name` Nullable(String),
|
||||
`control_room_id` Nullable(UUID),
|
||||
`control_room_name` Nullable(String),
|
||||
`picket_id` Nullable(UUID),
|
||||
`picket_name` Nullable(String),
|
||||
`picket_n` Nullable(UInt32),
|
||||
`cstate_id` Nullable(UUID),
|
||||
`cstate_name` Nullable(String),
|
||||
`cstate_color_id` Nullable(UInt8),
|
||||
`sub_ms` Nullable(UInt64),
|
||||
`linked_channel_state` Nullable(String),
|
||||
`on_guard` Nullable(UInt8),
|
||||
`internal_id` Nullable(String),
|
||||
`floor_number` Nullable(Int32),
|
||||
`sign` Int8,
|
||||
`value` Nullable(String),
|
||||
`raw_value` Nullable(String)
|
||||
)
|
||||
ENGINE = ReplicatedCollapsingMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/unchecked_event_replicated',
|
||||
'{replica}',
|
||||
sign
|
||||
)
|
||||
PARTITION BY toYYYYMM(sub_ts)
|
||||
PRIMARY KEY event_id
|
||||
ORDER BY event_id
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем
|
||||
```sql
|
||||
INSERT INTO default.unchecked_event_replicated
|
||||
SELECT * FROM default.unchecked_event;
|
||||
```
|
||||
|
||||
### 8. unchecked_objects_event_replicated
|
||||
```sql
|
||||
show create table default.unchecked_objects_event;
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.unchecked_objects_event_replicated ON CLUSTER smvu2_cluster
|
||||
(
|
||||
`event_id` UUID,
|
||||
`node_id` Nullable(UUID),
|
||||
`complex_id` Nullable(UUID),
|
||||
`pub_ts` Nullable(DateTime),
|
||||
`sub_ts` DateTime64(3, 'UTC'),
|
||||
`cstate_id` Nullable(UUID),
|
||||
`source_id` Nullable(UUID),
|
||||
`source_name` Nullable(String),
|
||||
`source_type_id` Nullable(UUID),
|
||||
`event_data` Nullable(String),
|
||||
`sign` Int8
|
||||
)
|
||||
ENGINE = ReplicatedCollapsingMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/unchecked_objects_event_replicated',
|
||||
'{replica}',
|
||||
sign
|
||||
)
|
||||
PARTITION BY toYYYYMM(sub_ts)
|
||||
PRIMARY KEY event_id
|
||||
ORDER BY event_id
|
||||
SETTINGS index_granularity = 8192;
|
||||
```
|
||||
Копируем
|
||||
```sql
|
||||
INSERT INTO default.unchecked_objects_event_replicated
|
||||
SELECT * FROM default.unchecked_objects_event;
|
||||
```
|
||||
|
||||
|
||||
### Проверка состояния репликации после создания:
|
||||
```sql
|
||||
SELECT database, table, is_leader, total_replicas, active_replicas
|
||||
FROM system.replicas
|
||||
WHERE database = 'default'
|
||||
```
|
||||
### Узнаем и сравниваем сколько занимают места таблицы в базе default
|
||||
```sql
|
||||
SELECT
|
||||
name AS table_name,
|
||||
formatReadableSize(total_bytes) AS size_readable,
|
||||
total_rows AS rows_count
|
||||
FROM system.tables
|
||||
WHERE database = 'default'
|
||||
ORDER BY total_bytes DESC;
|
||||
```
|
||||
|
||||
### Переименовываем исходные таблицы
|
||||
```sql
|
||||
rename table api_request_log to api_request_log_old;
|
||||
rename table event to event_old;
|
||||
rename table event_objects to event_objects_old;
|
||||
rename table event_confirmation to event_confirmation_old;
|
||||
rename table audit_new to audit_new_old;
|
||||
rename table event_automation to event_automation_old;
|
||||
rename table infi_clickhouse_orm_migrations to infi_clickhouse_orm_migrations_old;
|
||||
rename table unchecked_event to unchecked_event_old;
|
||||
rename table unchecked_objects_event to unchecked_objects_event_old;
|
||||
```
|
||||
|
||||
### Создаем Distributed-таблицы
|
||||
```sql
|
||||
CREATE TABLE default.event ON CLUSTER smvu2_cluster AS default.event_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, api_request_log_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event ON CLUSTER smvu2_cluster AS default.event_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, event_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.audit_new ON CLUSTER smvu2_cluster AS default.audit_new_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, audit_new_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_objects ON CLUSTER smvu2_cluster AS default.event_objects_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, event_objects_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_automation ON CLUSTER smvu2_cluster AS default.event_automation_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, event_automation_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.event_confirmation ON CLUSTER smvu2_cluster AS default.event_confirmation_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, event_confirmation_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.infi_clickhouse_orm_migrations ON CLUSTER smvu2_cluster AS default.infi_clickhouse_orm_migrations_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, infi_clickhouse_orm_migrations_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.unchecked_event ON CLUSTER smvu2_cluster AS default.unchecked_event_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, unchecked_event_replicated, rand());
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE default.unchecked_objects_event ON CLUSTER smvu2_cluster AS default.unchecked_objects_event_replicated
|
||||
ENGINE = Distributed(smvu2_cluster, default, unchecked_objects_event_replicated, rand());
|
||||
```
|
||||
|
||||
|
||||
### Решение проблемы размера таблицы
|
||||
#### 1. Используя ограничение отправляемых строк, прикладываю скрипт, который делает в автоматическом режиме
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Список таблиц для репликации
|
||||
TABLES=(
|
||||
api_request_log
|
||||
audit_new
|
||||
event
|
||||
event_automation
|
||||
event_confirmation
|
||||
event_objects
|
||||
infi_clickhouse_orm_migrations
|
||||
)
|
||||
|
||||
PASSWORD="q1"
|
||||
BATCH_SIZE=100000 # Размер порции для вставки
|
||||
MAX_THREADS=4 # Максимальное количество потоков для вставки
|
||||
|
||||
for table in "${TABLES[@]}"; do
|
||||
replicated_table="${table}_replicated"
|
||||
echo "Processing $table to $replicated_table"
|
||||
|
||||
# 1. Получаем общее количество строк
|
||||
total_rows=$(clickhouse-client --password "$PASSWORD" --query="
|
||||
SELECT count() FROM remote('localhost', 'default', '$table')")
|
||||
|
||||
echo "Total rows to copy: $total_rows"
|
||||
|
||||
# 2. Копируем данные порциями
|
||||
for ((offset=0; offset<total_rows; offset+=BATCH_SIZE)); do
|
||||
echo "Copying rows $((offset+1))-$((offset+BATCH_SIZE))..."
|
||||
|
||||
clickhouse-client --password "$PASSWORD" --query="
|
||||
INSERT INTO default.$replicated_table
|
||||
SELECT * FROM remote('localhost', 'default', '$table')
|
||||
LIMIT $BATCH_SIZE OFFSET $offset
|
||||
SETTINGS
|
||||
max_insert_threads=$MAX_THREADS,
|
||||
max_memory_usage='10Gi'"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error copying batch $((offset/BATCH_SIZE+1))"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. Проверяем количество скопированных строк
|
||||
copied_rows=$(clickhouse-client --password "$PASSWORD" --query="
|
||||
SELECT count() FROM default.$replicated_table")
|
||||
|
||||
echo "Successfully copied $copied_rows/$total_rows rows from $table to $replicated_table"
|
||||
done
|
||||
```
|
||||
|
||||
#### 2. Копирование с помощью программы clickhouse-copier
|
||||
Создается конфиг подключения к кластеру (keeper)
|
||||
config.xml
|
||||
```xml
|
||||
<yandex>
|
||||
<logger>
|
||||
<level>warning</level>
|
||||
<log>/var/log/clickhouse-server/clickhouse-copier.log</log>
|
||||
<errorlog>/var/log/clickhouse-server/clickhouse-copier.err.log</errorlog>
|
||||
</logger>
|
||||
|
||||
<zookeeper>
|
||||
<!-- Для ClickHouse Keeper (рекомендуется) -->
|
||||
<node>
|
||||
<host>172.16.212.41</host>
|
||||
<port>9181</port>
|
||||
</node>
|
||||
</zookeeper>
|
||||
|
||||
<distributed_ddl>
|
||||
<path>/clickhouse/task_queue/ddl</path>
|
||||
</distributed_ddl>
|
||||
|
||||
<http_port>9999</http_port>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
Создается папка tasks и там размещаются файлы для каждой таблицы, например api_request_log.xml
|
||||
```xml
|
||||
<yandex>
|
||||
<!-- Configuration of clusters as in an ordinary server config -->
|
||||
<remote_servers>
|
||||
<source_cluster>
|
||||
<shard>
|
||||
<internal_replication>true</internal_replication>
|
||||
<replica>
|
||||
<host>172.16.212.14</host>
|
||||
<port>9000</port>
|
||||
<user>default</user>
|
||||
<password>q1</password>
|
||||
<secure>0</secure>
|
||||
</replica>
|
||||
</shard>
|
||||
</source_cluster>
|
||||
|
||||
<destination_cluster>
|
||||
<shard>
|
||||
<internal_replication>true</internal_replication>
|
||||
<replica>
|
||||
<host>172.16.212.14</host>
|
||||
<port>9000</port>
|
||||
<user>default</user>
|
||||
<password>q1</password>
|
||||
<secure>0</secure>
|
||||
</replica>
|
||||
</shard>
|
||||
</destination_cluster>
|
||||
</remote_servers>
|
||||
|
||||
<!-- How many simultaneously active workers are possible. If you run more workers superfluous workers will sleep. -->
|
||||
<max_workers>2</max_workers>
|
||||
|
||||
<!-- Setting used to fetch (pull) data from source cluster tables -->
|
||||
<settings_pull>
|
||||
<readonly>1</readonly>
|
||||
</settings_pull>
|
||||
|
||||
<!-- Setting used to insert (push) data to destination cluster tables -->
|
||||
<settings_push>
|
||||
<readonly>0</readonly>
|
||||
</settings_push>
|
||||
|
||||
<!-- Common setting for fetch (pull) and insert (push) operations. Also, copier process context uses it.
|
||||
They are overlaid by <settings_pull/> and <settings_push/> respectively. -->
|
||||
<settings>
|
||||
<connect_timeout>3</connect_timeout>
|
||||
<!-- Sync insert is set forcibly, leave it here just in case. -->
|
||||
<insert_distributed_sync>1</insert_distributed_sync>
|
||||
</settings>
|
||||
|
||||
<tables>
|
||||
<!-- A table task, copies one table. -->
|
||||
<event>
|
||||
<!-- Source cluster name (from <remote_servers/> section) and tables in it that should be copied -->
|
||||
<cluster_pull>source_cluster</cluster_pull>
|
||||
<database_pull>default</database_pull>
|
||||
<table_pull>api_request_log</table_pull>
|
||||
|
||||
<!-- Destination cluster name and tables in which the data should be inserted -->
|
||||
<cluster_push>destination_cluster</cluster_push>
|
||||
<database_push>default</database_push>
|
||||
<table_push>api_request_log_replicated</table_push>
|
||||
|
||||
<engine>
|
||||
ENGINE = ReplicatedReplacingMergeTree(
|
||||
'/clickhouse/tables/{shard}/default/api_request_log_replicated',
|
||||
'{replica}',
|
||||
ver
|
||||
)
|
||||
PARTITION BY toYYYYMM(request_ts)
|
||||
ORDER BY uuid
|
||||
SETTINGS index_granularity = 8192;
|
||||
</engine>
|
||||
<sharding_key>rand()</sharding_key>
|
||||
</event>
|
||||
</tables>
|
||||
</yandex>
|
||||
```
|
||||
|
||||
В каждом файле меняется название базы в разделе **tables**
|
||||
После этого запускается копирование, где --task-path должен быть уникальным для каждой таблицы
|
||||
```bash
|
||||
clickhouse-copier --config config.xml --task-file ./tasks/api_request_log.xml --task-path /clickhouse/copier/task1
|
||||
```
|
||||
44
DevOps/Docker/converter.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Конвертация строки в compose
|
||||
description:
|
||||
published: true
|
||||
date: 2025-06-17T09:20:55.103Z
|
||||
tags: docker
|
||||
editor: markdown
|
||||
dateCreated: 2025-06-17T09:20:07.483Z
|
||||
---
|
||||
|
||||
Я попал на сайт к какому-то девопсу, где были материалы по Playwright. Я немного походил по нему и набрёл на раздел DevTools (https://ray.run/tools). Он там собрал то ли свои, то ли просто open source инструменты для решения простых прикладных задач. Вроде ничего особенного, но некоторые вещи я просто не знал, что вообще существуют. Всегда их делал вручную.
|
||||
|
||||
Покажу сразу на примерах, что мне показалось полезным:
|
||||
|
||||
- Docker Run to Docker Compose Converter (https://ray.run/tools/docker-run-to-docker-compose)
|
||||
Отправляем в форму однострочник с docker run и получаем файл для docker compose. Вроде мелочь, но я всегда это делал вручную. Не думал, что кому-то придёт в голову написать конвертер.
|
||||
|
||||
- Docker Compose to Docker Run Converter (https://ray.run/tools/docker-compose-to-docker-run)
|
||||
И соответственно в обратную сторону преобразование из docker compose в однострочник для docker run. Не припоминаю, чтобы мне приходилось такие преобразования делать, но в тему к первому упоминаю.
|
||||
|
||||
- Bash Command Formatter (https://ray.run/tools/bash-command-formatter)
|
||||
Эта штука тоже очень понравилась. Она длинный однострочник разбивает на строки с переходами через \ То есть вот такую колбасу:
|
||||
```
|
||||
curl -v --url "smtp://mail.server.ru:25" --mail-from "root@server.ru" --mail-rcpt "user@gmail.com" --user 'root@server.ru:password123' --upload-file ~/mail.txt
|
||||
```
|
||||
Нарезает на кусочки:
|
||||
```
|
||||
curl -v \
|
||||
--url "smtp://mail.server.ru:25" \
|
||||
--mail-from "root@server.ru" \
|
||||
--mail-rcpt "user@gmail.com" \
|
||||
--user 'root@server.ru:password123' \
|
||||
--upload-file ~/mail.txt
|
||||
```
|
||||
Я тоже всегда это вручную делал, особенно для публикации сюда. Можно упростить себе задачу.
|
||||
|
||||
- URL Extractor (https://ray.run/tools/url-extractor)
|
||||
Просто кидаешь сюда любой текст, а на выходе получаешь набор ссылок, если они в нём присутствуют.
|
||||
|
||||
Там много всяких конвертеров и анализаторов синтаксиса для json, yaml, toml, csv. Не стал обращать на них внимание, так как их существует десятки. Обычно просто в гугле ищут что-то подобное, когда надо преобразовать. Посмотрите список, может вам что-то ещё приглянётся. Меня впечатлили только эти четыре штуки.
|
||||
|
||||

|
||||

|
||||
.jpg)
|
||||
82
DevOps/PostgreSQL/instruments.md
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: Инструменты для обслуживания postgresql
|
||||
description:
|
||||
published: true
|
||||
date: 2025-06-17T09:33:07.672Z
|
||||
tags: postgresql
|
||||
editor: markdown
|
||||
dateCreated: 2025-06-17T09:33:07.672Z
|
||||
---
|
||||
|
||||
Расскажу про парочку инструментов, которые упростят обслуживание сервера PostgreSQL. Начну с наиболее простого - pgBadger (https://pgbadger.darold.net/examples/sample.html). Это анализатор лога, который на его основе генерирует отчёты в формате html. На выходе получаются одиночные html файлы, которые можно просто открыть в браузере. Сделано всё аккуратно и добротно, легко настраивается, отчёты наглядные и информационные.
|
||||
|
||||
🔹Чтобы было что анализировать, необходимо включить логирование интересующих вас событий. Для разовой отладки это всё можно включать на ходу, либо постоянно через файл конфигурации `postgresql.conf` и перезапуск сервера. Он обычно хорошо прокомментирован. Вас будут интересовать параметры, начинающие с log_*. Они собраны все в отдельном блоке. Для примера я включил почти всё:
|
||||
```
|
||||
log_min_duration_statement = 0
|
||||
log_checkpoints = on
|
||||
log_connections = on
|
||||
log_disconnections = on
|
||||
log_duration = on
|
||||
log_line_prefix = '%m [%p] %q%u@%d '
|
||||
log_lock_waits = on
|
||||
log_temp_files = 0
|
||||
log_timezone = 'Europe/Moscow'
|
||||
```
|
||||
Вся включенная статистика стала писаться в общий лог-файл `/var/log/postgresql/postgresql-17-main.log`. С ним и будем работать. Устанавливаем pgBadger:
|
||||
```
|
||||
# wget https://github.com/darold/pgbadger/archive/refs/tags/v13.1.tar.gz
|
||||
# tar xzvf v13.1.tar.gz
|
||||
# cd pgbadger-*
|
||||
# apt install make
|
||||
# make && make install
|
||||
```
|
||||
Анализируем лог файл:
|
||||
```
|
||||
# pgbadger /var/log/postgresql/postgresql-17-main.log
|
||||
```
|
||||
Тут же в директории, где его запускали, увидите файл out.html. Забирайте его к себе и смотрите. Там будет информация с общей статистикой сервера, информация по запросам и их типам, времени исполнения, подключениям, по пользователям, базам и хостам откуда подключались и много всего остального.
|
||||
|
||||
PgBadger удобен тем, что по сути это одиночный скрипт на Perl. Можно включить логирование в конфигурации, применить её через `SELECT pg_reload_conf();` без перезапуска сервера СУБД. Пособирать некоторое время данные, забрать лог и анализировать его. Логирование отключить и снова перечитать конфиг. В итоге всё будет сделано без перезапуска сервера.
|
||||
|
||||
🔹Второй инструмент - PgHero (https://github.com/ankane/pghero), он показывает примерно то же самое, только в режиме реального времени и работает в виде веб сервиса. Для него уже надо создавать пользователя, настраивать доступ, отдельную базу. Немного другой подход. Надо будет дёргать сервер с СУБД.
|
||||
|
||||
Надо перейти в консоль и создать необходимые сущности:
|
||||
```sql
|
||||
# su postgres
|
||||
# psql
|
||||
> CREATE USER pghero WITH PASSWORD 'pgheropass';
|
||||
> CREATE DATABASE pgherodb OWNER pghero;
|
||||
> \q
|
||||
```
|
||||
Разрешаем этому пользователю подключаться. Добавляем в `pg_hba.conf` строку:
|
||||
```
|
||||
host pgherodb pghero 172.17.0.0/24 md5
|
||||
```
|
||||
`172.17.0.0/24` - подсеть, из которой будет подключаться PgHero. В данном случае это Docker контейнер, запущенный на этом же хосте. PostgreSQL должен принимать запросы с локального IP адреса, к которому будет доступ из Docker сети. Можно добавить в конфиг `postgresql.conf` параметр:
|
||||
```
|
||||
listen_addresses = 'localhost,172.17.0.1'
|
||||
```
|
||||
Перезапускаем PotgreSQL:
|
||||
```
|
||||
# systemctl restart postgresql
|
||||
```
|
||||
Запускаем PgHero в Docker контейнере:
|
||||
```
|
||||
# docker run -ti -e DATABASE_URL=postgres://pghero:pgheropass@172.17.0.1:5432/pgherodb -p 8080:8080 ankane/pghero
|
||||
```
|
||||
Идём на порт севера 8080, где запущен контейнер и смотрим информацию о PostgreSQL. Если у вас не настроено расширение **pg_stat_statements**, которое использует PgHero для сбора статистики, то установите его. Для этого в конфигурацию `postgresql.conf` добавьте параметры:
|
||||
```
|
||||
shared_preload_libraries = 'pg_stat_statements'
|
||||
pg_stat_statements.track = all
|
||||
pg_stat_statements.max = 10000
|
||||
track_activity_query_size = 2048
|
||||
```
|
||||
Перезапустите Postgresql и выполните в консоли СУБД:
|
||||
```sql
|
||||
> CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
||||
> GRANT pg_read_all_stats TO pghero;
|
||||
```
|
||||
Теперь можно возвращаться в веб интерфейс и смотреть информацию. По умолчанию, пользователь pghero не будет видеть запросы других пользователей, если ему не дать права superuser. Это можно исправить, выдав ему набор прав и ролей из этой инструкции (https://github.com/ankane/pghero/blob/master/guides/Permissions.md).
|
||||
|
||||

|
||||
.jpg)
|
||||
BIN
DevOps/attachments/photo_2025-05-16_16-20-53.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
DevOps/attachments/photo_2025-05-16_16-20-54.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
DevOps/attachments/photo_2025-05-16_16-20-54_(2).jpg
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
DevOps/attachments/photo_2025-05-21_20-48-32.jpg
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
DevOps/attachments/photo_2025-05-21_20-48-32_(2).jpg
Normal file
|
After Width: | Height: | Size: 72 KiB |
20
Hypervisors/Proxmox/Cluster/DestroyCluster.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<!--
|
||||
title: Удаление кластера Proxmox
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-21T11:31:51.721Z
|
||||
tags: proxmox, cluster
|
||||
editor: ckeditor
|
||||
dateCreated: 2025-05-21T11:31:51.721Z
|
||||
-->
|
||||
|
||||
<p>systemctl stop pve-cluster.service</p>
|
||||
<p>systemctl stop corosync.service</p>
|
||||
<p>pmxcfs -l</p>
|
||||
<p>rm -rf /etc/pve/corosync.conf</p>
|
||||
<p>rm -rf /etc/corosync/</p>
|
||||
<p>killall pmxcfs</p>
|
||||
<p>systemctl restart pve-cluster.service</p>
|
||||
<p>cd /etc/pve/nodes</p>
|
||||
<p>ls</p>
|
||||
<p>rm -rf /etc/pve/nodes/pve-01/</p>
|
||||
68
Hypervisors/Proxmox/Cluster/DestroyCluster.md
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: Как удалить ноду из кластера Proxmox?
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-22T09:28:25.522Z
|
||||
tags: proxmox, cluster
|
||||
editor: markdown
|
||||
dateCreated: 2025-05-21T11:31:51.721Z
|
||||
---
|
||||
|
||||
|
||||
Перед удалением ноды важно убедиться в том, что все виртуальные машины и данные безопасно мигрированы или созданы резервные копии, чтобы избежать потери данных и поддерживать целостность кластера.
|
||||
1. Остановите службу "pve-cluster" на изолируемой ноде
|
||||
```
|
||||
systemctl stop pve-cluster.service
|
||||
systemctl stop corosync.service
|
||||
```
|
||||
2. Запустите команду для перевода файловой системы кластера на изолируемой ноде в локальный режим
|
||||
```
|
||||
pmxcfs -l
|
||||
```
|
||||
3. Запустите команду для удаления файлов конфигурации Corosync:
|
||||
```
|
||||
rm -rf /etc/pve/corosync.conf
|
||||
rm -rf /etc/corosync/*
|
||||
```
|
||||
4. Запустите команду для перезапуска службы файловой системы кластера:
|
||||
```
|
||||
killall pmxcfs
|
||||
systemctl start pve-cluster.service
|
||||
```
|
||||
5. Удалите файлы неисправной ноды:
|
||||
```
|
||||
cd /etc/pve/nodes
|
||||
ls
|
||||
rm -rf /etc/pve/nodes/pve2 # Path corresponding to the faulty node
|
||||
```
|
||||
6. Очистите остаточную информацию о кластере:
|
||||
```
|
||||
pvecm delnode NodeName
|
||||
```
|
||||
Здесь приведена информация по устранению распространенных проблем, с которыми вы можете столкнуться.
|
||||
|
||||
Нода не отвечает: Если нода, которую вы хотите удалить, не отвечает из-за проблем с сетью или по другим причинам, вы можете использовать опцию Force для принудительного удаления ее из кластера:
|
||||
```
|
||||
pvecm delnode <NODE_NAME> --force
|
||||
```
|
||||
Застревание процесса удаления: В случае возникновения проблем с выполнением команды или застревания процесса во время удаления, вы можете диагностировать проблему, просмотрев системный журнал:
|
||||
```
|
||||
journalctl -xe
|
||||
```
|
||||
После устранения потенциальной проблемы попробуйте удалить ноду еще раз.
|
||||
|
||||
```
|
||||
systemctl stop pve-cluster.service
|
||||
systemctl stop corosync.service
|
||||
pmxcfs -l
|
||||
rm -rf /etc/pve/corosync.conf
|
||||
rm -rf /etc/corosync/
|
||||
killall pmxcfs
|
||||
systemctl restart pve-cluster.service
|
||||
cd /etc/pve/nodes
|
||||
ls
|
||||
rm -rf /etc/pve/nodes/pve-01/
|
||||
pvecm delnode pve-01
|
||||
pvecm delnode pve-01 --force
|
||||
systemctl restart corosync.service
|
||||
```
|
||||
14
Hypervisors/Proxmox/Disable-ProxMox-Subscription-Notice.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Disable ProxMox Subscription Notice
|
||||
description:
|
||||
published: true
|
||||
date: 2025-04-11T07:57:37.999Z
|
||||
tags: proxmox
|
||||
editor: markdown
|
||||
dateCreated: 2025-04-11T07:53:49.776Z
|
||||
---
|
||||
|
||||
Proxmox 8.3
|
||||
```bash
|
||||
sed -Ezi.bak "s/(function\(orig_cmd\) \{)/\1\n\torig_cmd\(\);\n\treturn;/g" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && systemctl restart pveproxy.service
|
||||
```
|
||||
80
Monitoring/VictoriaLogs-setup.md
Normal file
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: VictoriaLogs - установка и настройка
|
||||
description:
|
||||
published: true
|
||||
date: 2025-04-28T07:27:29.722Z
|
||||
tags: victorialogs
|
||||
editor: markdown
|
||||
dateCreated: 2025-04-28T07:25:56.957Z
|
||||
---
|
||||
|
||||
Пару лет назад у VictoriaMetrics вышел продукт, который является частью именного стека, – VictoriaLogs. Руки не доходили раньше на него посмотреть и вот дошли. Сразу скажу, что всё очень понравилось за простоту, функциональность и удобство. Покажу сразу с примерами.
|
||||
|
||||
Отдельно перечислю особенности VictoriaLogs:
|
||||
|
||||
▪️По своей сути это одиночный бинарник, который можно сконфигурировать ключами запуска, не нужен даже конфигурационный файл.
|
||||
▪️В бинарнике есть всё, что надо для сбора и просмотра логов: веб интерфейс, метрики для мониторинга за системой, все типы приёмников логов.
|
||||
▪️Для бэкапа достаточно скопировать директорию с данными, например, с помощью rsync. То есть вообще никаких проблем и заморочек с бэкапом.
|
||||
▪️Есть плагин для datasource в Grafana, чтобы делать оттуда запросы к логам, а также готовый дашборд для визуализации метрик хранилища.
|
||||
▪️Простая, короткая документация, где есть всё необходимое для запуска и настройки.
|
||||
|
||||
Покажу примеры сбора логов в VictoriaLogs от Journald, Syslog и Vector. Для этого подготовил небольшой docker-compose.yml с некоторыми параметрами:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
victoria-logs:
|
||||
image: victoriametrics/victoria-logs:latest
|
||||
volumes:
|
||||
- ./victoria-logs-data:/victoria-logs-data
|
||||
command:
|
||||
- --storageDataPath=/victoria-logs-data
|
||||
- --retentionPeriod=90d
|
||||
- --syslog.listenAddr.tcp=:514
|
||||
ports:
|
||||
- 9428:9428
|
||||
- 514:514
|
||||
restart: always
|
||||
```
|
||||
Запускаем проект, переходим на порт 9428, чтобы убедиться в том, что всё запустилось. По умолчанию открывается страница с некоторыми ссылками на Web UI, Метрики и ключи запуска.
|
||||
|
||||
Отправим в VictoriaLogs логи от systemd от любого сервера, локального или внешнего. Для этого понадобится служба systemd-journal-remote (https://t.me/srv_admin/3136). Ставим её:
|
||||
|
||||
`# apt install systemd-journal-remote`
|
||||
|
||||
Редактируем конфиг /etc/systemd/journal-upload.conf, добавляя один параметр:
|
||||
```
|
||||
[Upload]
|
||||
URL=http://localhost:9428/insert/journald
|
||||
```
|
||||
URL, соответственно, измените, если у вас сбор логов не с локального сервера, а удалённого. Запускаем службу и проверяем, что она успешно начала отправку логов:
|
||||
|
||||
`# systemctl start systemd-journal-upload`
|
||||
`# systemctl status systemd-journal-upload`
|
||||
|
||||
Идём в веб интерфейс VictoriaLogs - http://212.193.59.87:9428/select/vmui и смотрим там логи.
|
||||
|
||||
Переходим к Syslog. Я уже добавил параметр syslog.listenAddr.tcp=:514. Убедитесь, что указанный порт прослушивается:
|
||||
|
||||
`# ss -tulnp | grep 514`
|
||||
|
||||
Если у вас этот порт уже занят syslog сервером, то измените порт для VictoriaLogs. В общем-то настраивать больше ничего не надо. Теперь в любом софте, который умеет отправлять данные в формате syslog, укажите в качестве сервера IP вашего VictoriaLogs. Например, в том же Микротике: System ⇨ Logging ⇨ Actions ⇨ Add Type Remote.
|
||||
|
||||
Для сбора логов от всех популярных агентов, типа Filebeat, Fluentd, Vector (https://t.me/srv_admin/2388) и т.д. тоже ничего специально настраивать не надо. Делаете всё точно так же, как для отправки логов в Elasticsearch, только в качестве endpoint указываете URL от вашего сервера VictoriaLogs. Вот пример для Vector:
|
||||
|
||||
```yaml
|
||||
sinks:
|
||||
vlogs:
|
||||
inputs:
|
||||
- nginx_access_logs
|
||||
type: elasticsearch
|
||||
endpoints:
|
||||
- http://212.193.59.87:9428/insert/elasticsearch/
|
||||
api_version: v8
|
||||
compression: gzip
|
||||
```
|
||||
Решение очень понравилось своей простотой, универсальностью и скоростью настройки. Буквально за час со всем разобрался и настроил. Никаких затруднений. Отдельно нужно решать вопрос доступа к приёмнику логов и веб интерфейсу. С уровня приложения никаких решений нет. Нужно либо firewall, либо proxy использовать.
|
||||
|
||||
Отдельно отмечу, что те же логи syslog и journald сразу парсятся по основным полям, типа hostname, time, cmdline и т.д. Ничего для этого настраивать не надо. Сразу в веб интерфейсе можно поиск и группировку по ним делать. Получается очень функциональное решение по простоте и скорости настройки на уровне обычного syslog сервера, но с гораздо большими возможностями.
|
||||

|
||||

|
||||

|
||||
11
NAS/Synology/Disable-check-hdd.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Отключение проверки совместимости дисков в Synology
|
||||
description:
|
||||
published: true
|
||||
date: 2025-04-21T09:51:56.904Z
|
||||
tags: synology, check, hdd
|
||||
editor: markdown
|
||||
dateCreated: 2025-04-21T09:51:56.903Z
|
||||
---
|
||||
|
||||
https://github.com/007revad/Synology_HDD_db?tab=readme-ov-file
|
||||
48
NAS/Synology/brtfs-or-ext-for-synology.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: Какую файловую систему выбрать brtfs или ext4 для synology ?
|
||||
description:
|
||||
published: true
|
||||
date: 2025-04-05T10:07:48.849Z
|
||||
tags: brtfs, ext4
|
||||
editor: markdown
|
||||
dateCreated: 2025-04-05T10:07:48.849Z
|
||||
---
|
||||
|
||||
Выбор между **Btrfs** и **ext4** для Synology зависит от ваших потребностей в функциональности, надёжности и производительности.
|
||||
|
||||
### **1. Btrfs (Рекомендуется для Synology)**
|
||||
**Плюсы:**
|
||||
✅ **Снимки (snapshots)** – возможность создавать мгновенные копии файлов для защиты от случайного удаления или ransomware.
|
||||
✅ **Самовосстановление данных** – проверка целостности данных и автоматическое исправление ошибок (если используется SHR-1/SHR-2 или RAID с избыточностью).
|
||||
✅ **Эффективное сжатие** – экономия места без потери производительности (особенно полезно для текстовых файлов, логов, баз данных).
|
||||
✅ **Дедупликация** (вручную или через сторонние утилиты) – экономия места при дублировании файлов.
|
||||
✅ **Поддержка копирования при записи (CoW)** – уменьшает риск повреждения данных.
|
||||
|
||||
**Минусы:**
|
||||
❌ **Требует больше ресурсов** (CPU, RAM) – на слабых моделях (например, DS220j) может работать медленнее.
|
||||
❌ **Не поддерживается на всех моделях** (старые или бюджетные Synology могут не иметь Btrfs).
|
||||
❌ **Чувствителен к внезапному отключению питания** (но Synology использует журналирование для минимизации рисков).
|
||||
|
||||
---
|
||||
|
||||
### **2. ext4 (Классический вариант)**
|
||||
**Плюсы:**
|
||||
✅ **Высокая скорость** – особенно на слабом железе.
|
||||
✅ **Стабильность** – проверенная временем файловая система.
|
||||
✅ **Меньше накладных расходов** – не требует много оперативной памяти.
|
||||
|
||||
**Минусы:**
|
||||
❌ **Нет снимков (snapshots)** – нельзя быстро откатить изменения.
|
||||
❌ **Нет самовосстановления данных** – при повреждении файлов потребуется проверка вручную (fsck).
|
||||
❌ **Нет сжатия и дедупликации** – занимает больше места.
|
||||
|
||||
---
|
||||
|
||||
### **Вывод: что выбрать?**
|
||||
- **Btrfs** – если у вас **NAS с двухдисковой (или более) конфигурацией (SHR-1/SHR-2, RAID 1/5/6)** и вы хотите **защиту от повреждения данных, снимки и сжатие**.
|
||||
- **ext4** – если у вас **однодисковый NAS** или **очень слабое железо** (например, серия **"j"**), и вам важна **максимальная скорость без дополнительных функций**.
|
||||
|
||||
#### **Рекомендация для большинства пользователей:**
|
||||
**Btrfs** – лучший выбор для Synology, если ваша модель его поддерживает. Он даёт больше возможностей для защиты данных и экономии места.
|
||||
|
||||
Если сомневаетесь, выбирайте **Btrfs**, но убедитесь, что у вас **достаточно оперативной памяти** (минимум **1-2 ГБ** для комфортной работы).
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: Synology - консольные команды
|
||||
title: Synology - reindex photo
|
||||
description:
|
||||
published: true
|
||||
date: 2024-11-27T20:02:21.508Z
|
||||
tags: ssh, synology
|
||||
date: 2025-04-05T10:09:59.015Z
|
||||
tags: ssh, synology, reindex, photo
|
||||
editor: markdown
|
||||
dateCreated: 2024-11-27T08:35:34.807Z
|
||||
---
|
||||
11
NAS/Synology/synology_app_mover.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!--
|
||||
title: Перенос приложений на другой том
|
||||
description:
|
||||
published: true
|
||||
date: 2025-04-05T12:08:46.013Z
|
||||
tags: synology, app, move
|
||||
editor: ckeditor
|
||||
dateCreated: 2025-04-05T12:08:46.013Z
|
||||
-->
|
||||
|
||||
<p>https://github.com/007revad/Synology_app_mover</p>
|
||||
BIN
monitoring/victorialogs-1.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
monitoring/victorialogs-2.png
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
monitoring/victorialogs-3.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
39
sysadmin/supermicro/fan.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Регулировка скорости вращения вентиляторов
|
||||
description:
|
||||
published: true
|
||||
date: 2025-05-19T09:26:33.340Z
|
||||
tags: ipmi, fan
|
||||
editor: markdown
|
||||
dateCreated: 2025-05-19T08:49:19.082Z
|
||||
---
|
||||
|
||||
https://forums.servethehome.com/index.php?resources/supermicro-x9-x10-x11-fan-speed-control.20/
|
||||
https://forums.servethehome.com/index.php?threads/supermicro-x9-x10-x11-fan-speed-control.10059/page-8
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# IPMI settings
|
||||
IPMI_IP="192.168.88.221" # Replace with your BMC IP
|
||||
IPMI_USER="ADMIN" # Replace with your IPMI username
|
||||
IPMI_PASS="JYGEABVVCV" # Replace with your IPMI password
|
||||
|
||||
# Fan settings (for FAN3)
|
||||
FAN_ID="0x02" # 0x02 = FAN3 (0x00=FAN1, 0x01=FAN2, etc.)
|
||||
FAN_SPEED="0x32" # 0x32 = 50% (0x01=FULL, 0x24=37%, 0x16=25%)
|
||||
|
||||
# Set FULL
|
||||
ipmitool -I lanplus -H $IPMI_IP -U $IPMI_USER -P $IPMI_PASS raw 0x30 0x45 0x01 0x01
|
||||
|
||||
sleep 3
|
||||
|
||||
# Set manual control mode
|
||||
ipmitool -I lanplus -H $IPMI_IP -U $IPMI_USER -P $IPMI_PASS raw 0x30 0x70 0x66 0x01 0x00 0x16
|
||||
|
||||
# Set fan speed
|
||||
ipmitool -I lanplus -H $IPMI_IP -U $IPMI_USER -P $IPMI_PASS raw 0x30 0x70 0x66 0x01 $FAN_ID $FAN_SPEED
|
||||
|
||||
# Log the action (optional)
|
||||
#echo "$(date) - Set FAN3 speed to 50%" >> /var/log/fan_control.log
|
||||
```
|
||||