first commit
This commit is contained in:
517
replication_service/README.md
Normal file
517
replication_service/README.md
Normal file
@@ -0,0 +1,517 @@
|
||||
# Data Replication Service
|
||||
|
||||
Сервис репликации данных из множественных источников (MSSQL, PostgreSQL) в целевую PostgreSQL базу с использованием DLT (Data Load Tool), FastAPI и планировщика задач APScheduler.
|
||||
|
||||
## Особенности
|
||||
|
||||
- ✅ **Динамическое управление источниками данных** - Добавляйте и удаляйте источники через REST API без перезагрузки сервиса
|
||||
- ✅ Поддержка множественных типов источников (MSSQL, PostgreSQL)
|
||||
- ✅ Репликация таблиц с использованием DLT для оптимальной производительности
|
||||
- ✅ Обработка логов изменений (Life таблицы с INSERT, UPDATE, DELETE операциями)
|
||||
- ✅ Индивидуальное расписание для каждой таблицы (Cron выражения)
|
||||
- ✅ Управление конфликтами времени выполнения (очередь задач)
|
||||
- ✅ REST API для полного управления процессом репликации
|
||||
- ✅ Кеширование подключений для оптимизации производительности
|
||||
- ✅ Логирование и мониторинг задач репликации
|
||||
- ✅ Health check и статистика
|
||||
|
||||
## Архитектурные улучшения
|
||||
|
||||
### Переход на DataSource-based конфигурацию
|
||||
|
||||
**Раньше (static конфигурация):**
|
||||
- Источники данных определялись в `.env` файле
|
||||
- Требовалась перезагрузка сервиса для изменения конфигурации
|
||||
- Одна MSSQL и одна PostgreSQL база фиксированно
|
||||
|
||||
**Теперь (динамическая конфигурация):**
|
||||
- Источники хранятся в БД (таблица `data_sources`)
|
||||
- Полное управление через REST API
|
||||
- Поддержка множественных источников каждого типа
|
||||
- Без необходимости перезагрузки сервиса
|
||||
- Кеширование подключений с TTL = 5 минут
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
replication_service/
|
||||
├── main.py # Главное приложение FastAPI
|
||||
├── config.py # Конфигурация и переменные окружения
|
||||
├── models.py # ORM модели (SQLAlchemy) - включая DataSource
|
||||
├── database.py # Управление подключениями с кешированием
|
||||
├── api.py # REST API endpoints (DataSource + Migration)
|
||||
├── replication.py # Логика репликации данных
|
||||
├── scheduler.py # Планировщик задач с управлением конфликтами
|
||||
├── migrate_to_data_sources.py # Скрипт миграции из старой конфигурации
|
||||
├── examples_api.py # Примеры использования новой API
|
||||
├── requirements.txt # Зависимости Python
|
||||
├── DATA_SOURCES.md # Документация по управлению источниками
|
||||
├── .env.example # Пример файла переменных окружения
|
||||
└── README.md # Документация
|
||||
```
|
||||
|
||||
## Установка
|
||||
|
||||
### 1. Создать виртуальное окружение
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # Linux/Mac
|
||||
# или
|
||||
venv\Scripts\activate # Windows
|
||||
```
|
||||
|
||||
### 2. Установить зависимости
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 3. Настроить переменные окружения
|
||||
|
||||
Скопировать `.env.example` в `.env` и заполнить данные целевой базы данных PostgreSQL:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
```env
|
||||
# PostgreSQL Connection (целевая база для всех репликаций)
|
||||
POSTGRES_HOST=your_postgres_host
|
||||
POSTGRES_DATABASE=replication_db
|
||||
POSTGRES_USERNAME=postgres
|
||||
POSTGRES_PASSWORD=your_password
|
||||
POSTGRES_PORT=5432
|
||||
```
|
||||
|
||||
**Важно:** Источники данных больше НЕ конфигурируются через `.env` файл!
|
||||
|
||||
### 4. Инициализировать базу данных
|
||||
|
||||
```bash
|
||||
python -c "from database import DatabaseManager; DatabaseManager.init_postgres_db()"
|
||||
```
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
или
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
Сервис будет доступен по адресу: `http://localhost:8000`
|
||||
|
||||
## Быстрый старт с новой API
|
||||
|
||||
### 1. Создать источник данных
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/v1/data-sources \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "MSSQL Production",
|
||||
"source_type": "mssql",
|
||||
"host": "mssql-server.example.com",
|
||||
"port": 1433,
|
||||
"database": "MyDatabase",
|
||||
"username": "sa",
|
||||
"password": "Password123!"
|
||||
}'
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "MSSQL Production",
|
||||
"source_type": "mssql",
|
||||
"host": "mssql-server.example.com",
|
||||
"port": 1433,
|
||||
"database": "MyDatabase",
|
||||
"default_schema": "dbo",
|
||||
"is_active": true,
|
||||
"created_at": "2024-01-15T10:30:00",
|
||||
"updated_at": "2024-01-15T10:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Проверить подключение
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/v1/data-sources/1/test
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"source_id": 1,
|
||||
"connection_ok": true
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Создать расписание репликации
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/v1/migration-tables \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"table_name": "Orders",
|
||||
"source_id": 1,
|
||||
"cron_schedule": "0 2 * * *",
|
||||
"source_schema": "dbo",
|
||||
"target_schema": "public"
|
||||
}'
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"table_name": "Orders",
|
||||
"source_id": 1,
|
||||
"source_schema": "dbo",
|
||||
"target_schema": "public",
|
||||
"cron_schedule": "0 2 * * *",
|
||||
"is_active": true,
|
||||
"created_at": "2024-01-15T10:35:00",
|
||||
"updated_at": "2024-01-15T10:35:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Запустить примеры API
|
||||
|
||||
```bash
|
||||
python examples_api.py
|
||||
```
|
||||
|
||||
Этот скрипт демонстрирует все основные операции с API.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Health Check
|
||||
|
||||
- `GET /api/v1/health` - Проверка здоровья сервиса
|
||||
|
||||
**Ответ:**
|
||||
"status": "healthy",
|
||||
"mssql_connected": true,
|
||||
"postgres_connected": true,
|
||||
"timestamp": "2026-03-29T10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### Управление таблицами миграции
|
||||
|
||||
#### Создать таблицу для миграции
|
||||
|
||||
```bash
|
||||
POST /api/v1/migration-tables
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"table_name": "Orders",
|
||||
"cron_schedule": "0 2 * * *", # Каждый день в 2:00
|
||||
"source_schema": "dbo",
|
||||
"target_schema": "public"
|
||||
}
|
||||
```
|
||||
|
||||
#### Получить список всех таблиц
|
||||
|
||||
```bash
|
||||
GET /api/v1/migration-tables
|
||||
```
|
||||
|
||||
#### Получить информацию о конкретной таблице
|
||||
|
||||
```bash
|
||||
GET /api/v1/migration-tables/{table_id}
|
||||
```
|
||||
|
||||
#### Удалить таблицу из миграции
|
||||
|
||||
```bash
|
||||
DELETE /api/v1/migration-tables/{table_id}
|
||||
```
|
||||
|
||||
### Управление планировщиком
|
||||
|
||||
#### Получить статус планировщика
|
||||
|
||||
```bash
|
||||
GET /api/v1/scheduler/status
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"is_running": true,
|
||||
"migration_tables_count": 5,
|
||||
"running_jobs": {
|
||||
"1": 1680000000.123
|
||||
},
|
||||
"queued_jobs": []
|
||||
}
|
||||
```
|
||||
|
||||
#### Запустить планировщик
|
||||
|
||||
```bash
|
||||
POST /api/v1/scheduler/start
|
||||
```
|
||||
|
||||
#### Остановить планировщик
|
||||
|
||||
```bash
|
||||
POST /api/v1/scheduler/stop
|
||||
```
|
||||
|
||||
#### Получить список задач планировщика
|
||||
|
||||
```bash
|
||||
GET /api/v1/scheduler/jobs
|
||||
```
|
||||
|
||||
### История и статистика
|
||||
|
||||
#### Получить список задач репликации
|
||||
|
||||
```bash
|
||||
GET /api/v1/replication-jobs?limit=100&offset=0&status=success
|
||||
```
|
||||
|
||||
#### Получить информацию о конкретной задаче
|
||||
|
||||
```bash
|
||||
GET /api/v1/replication-jobs/{job_id}
|
||||
```
|
||||
|
||||
#### Получить статистику
|
||||
|
||||
```bash
|
||||
GET /api/v1/statistics
|
||||
```
|
||||
|
||||
**Ответ:**
|
||||
```json
|
||||
{
|
||||
"total_jobs": 150,
|
||||
"successful_jobs": 148,
|
||||
"failed_jobs": 2,
|
||||
"success_rate": 98.67,
|
||||
"timestamp": "2026-03-29T10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
## Примеры использования
|
||||
|
||||
### 1. Добавить таблицу для репликации с расписанием
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/api/v1/migration-tables" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"table_name": "Customers",
|
||||
"cron_schedule": "*/30 * * * *",
|
||||
"source_schema": "dbo",
|
||||
"target_schema": "public"
|
||||
}'
|
||||
```
|
||||
|
||||
Это расписание означает: "выполнять репликацию каждые 30 минут"
|
||||
|
||||
### 2. Добавить несколько таблиц с разным расписанием
|
||||
|
||||
```bash
|
||||
# Orders - каждый день в 2:00 AM
|
||||
curl -X POST "http://localhost:8000/api/v1/migration-tables" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"table_name": "Orders", "cron_schedule": "0 2 * * *"}'
|
||||
|
||||
# Products - каждый день в 3:00 AM
|
||||
curl -X POST "http://localhost:8000/api/v1/migration-tables" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"table_name": "Products", "cron_schedule": "0 3 * * *"}'
|
||||
```
|
||||
|
||||
### 3. Контролировать расписание при конфликтах
|
||||
|
||||
Если две таблицы имеют пересекающееся расписание, они будут автоматически добавлены в очередь и выполняться последовательно:
|
||||
|
||||
```bash
|
||||
# Таблица 1: каждый день в 2:00 AM
|
||||
# Таблица 2: каждый день в 2:15 AM
|
||||
# Таблица 3: каждый день в 2:30 AM
|
||||
|
||||
# Все три задачи начнут выполняться в порядке очереди
|
||||
```
|
||||
|
||||
## Спецификация Cron для расписания
|
||||
|
||||
**Формат:** `<минуты> <часы> <день месяца> <месяц> <день недели>`
|
||||
|
||||
**Примеры:**
|
||||
|
||||
- `0 2 * * *` - Каждый день в 2:00 AM
|
||||
- `*/30 * * * *` - Каждые 30 минут
|
||||
- `0 0 * * 0` - Каждое воскресенье в полночь
|
||||
- `0 9,12,15 * * *` - В 9:00, 12:00 и 15:00 каждый день
|
||||
- `0 */4 * * *` - Каждые 4 часа
|
||||
- `0 0 1 * *` - Первый день каждого месяца в полночь
|
||||
|
||||
## Life таблицы
|
||||
|
||||
**Life таблицы** - это таблицы в MSSQL, которые хранят логи транзакций для оригинальных таблиц.
|
||||
|
||||
**Соглашение по именованию:**
|
||||
- Оригинальная таблица: `Orders`
|
||||
- Life таблица: `LifeOrders`
|
||||
|
||||
Сервис автоматически обрабатывает следующие операции:
|
||||
- **INSERT** - Добавление новых записей
|
||||
- **UPDATE** - Обновление существующих записей
|
||||
- **DELETE** - Удаление записей
|
||||
|
||||
## Мониторинг и отладка
|
||||
|
||||
### Логи приложения
|
||||
|
||||
Логи выводятся с информацией о каждом этапе репликации:
|
||||
|
||||
```
|
||||
2026-03-29 10:00:00 - scheduler - INFO - Starting replication for table Orders
|
||||
2026-03-29 10:00:15 - replication - INFO - Successfully replicated 1250 rows from Orders
|
||||
2026-03-29 10:00:25 - scheduler - INFO - Processing queued job for Products
|
||||
```
|
||||
|
||||
### API Documentation
|
||||
|
||||
После запуска приложения, интерактивная документация доступна по адресам:
|
||||
- Swagger UI: `http://localhost:8000/docs`
|
||||
- ReDoc: `http://localhost:8000/redoc`
|
||||
|
||||
## Конфигурация
|
||||
|
||||
### DatabaseManager
|
||||
|
||||
```python
|
||||
from database import DatabaseManager
|
||||
|
||||
# Проверить подключение к MSSQL
|
||||
DatabaseManager.test_mssql_connection()
|
||||
|
||||
# Проверить подключение к PostgreSQL
|
||||
DatabaseManager.test_postgres_connection()
|
||||
|
||||
# Инициализировать таблицы PostgreSQL
|
||||
DatabaseManager.init_postgres_db()
|
||||
```
|
||||
|
||||
### SchedulerManager
|
||||
|
||||
```python
|
||||
from scheduler import scheduler_manager
|
||||
|
||||
# Добавить таблицу
|
||||
scheduler_manager.add_migration_table(
|
||||
table_name="Orders",
|
||||
cron_schedule="0 2 * * *"
|
||||
)
|
||||
|
||||
# Получить список таблиц
|
||||
tables = scheduler_manager.get_migration_tables()
|
||||
|
||||
# Получить текущие выполняющиеся задачи
|
||||
running = scheduler_manager.get_running_jobs()
|
||||
|
||||
# Получить задачи в очереди
|
||||
queued = scheduler_manager.get_queued_jobs()
|
||||
```
|
||||
|
||||
## Производительность
|
||||
|
||||
- **Асинхронная обработка**: Использует APScheduler для фонового выполнения
|
||||
- **Очередь задач**: Автоматическое управление конфликтами расписания
|
||||
- **Оптимизация DLT**:批量 обработка данных для минимизации операций с БД
|
||||
- **Connection pooling**: Эффективное использование подключений к БД
|
||||
|
||||
## Безопасность
|
||||
|
||||
- Используйте переменные окружения для конфиденциальных данных (не коммитьте `.env`)
|
||||
- Настройте `.env.example` как шаблон для других разработчиков
|
||||
- Рассмотрите использование API ключей для защиты endpoints
|
||||
- Логируйте все операции репликации для аудита
|
||||
|
||||
## Развертывание на производстве
|
||||
|
||||
### Docker
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.11
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
replication-service:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
MSSQL_SERVER: mssql
|
||||
POSTGRES_HOST: postgres
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
postgres:
|
||||
image: postgres:15
|
||||
environment:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
```
|
||||
|
||||
## Решение проблем
|
||||
|
||||
### Ошибка подключения к MSSQL
|
||||
|
||||
1. Проверить, запущен ли сервер MSSQL
|
||||
2. Проверить правильность USER/PASSWORD в `.env`
|
||||
3. Убедиться, что брандмауэр не блокирует порт 1433
|
||||
4. Проверить права доступа sa пользователя
|
||||
|
||||
### Ошибка подключения к PostgreSQL
|
||||
|
||||
1. Проверить, запущен ли сервер PostgreSQL
|
||||
2. Проверить правильность HOST/PORT в `.env`
|
||||
3. Убедиться, что база данных с заданным именем существует
|
||||
4. Проверить права доступа пользователя
|
||||
|
||||
### DLT ошибки
|
||||
|
||||
1. Убедиться, что таблица существует в MSSQL
|
||||
2. Проверить права доступа на чтение таблицы
|
||||
3. Проверить, что целевая схема существует в PostgreSQL
|
||||
|
||||
## Лицензия
|
||||
|
||||
MIT
|
||||
|
||||
## Поддержка
|
||||
|
||||
Для сообщений об ошибках и предложений создавайте Issues в репозитории.
|
||||
Reference in New Issue
Block a user