172 build - обновленно чтение данных с сайта КХЛ
173 build - sql запросы сокрещенны
This commit is contained in:
151
README_BUILD172_RU.md
Normal file
151
README_BUILD172_RU.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Build172 — ночное обновление КХЛ, отчёт и повтор неудачных записей
|
||||
|
||||
Версия приложения: 2026.09.29.9. Основа: build171 (2026.09.29.8).
|
||||
|
||||
## Установка
|
||||
|
||||
В архиве только 5 рабочих файлов и эта инструкция. Остановите приложение, скопируйте файлы с сохранением структуры папок, затем запустите приложение и обновите браузер через Ctrl+F5:
|
||||
|
||||
- app.py
|
||||
- khl_site/khl_data_center.py
|
||||
- khl_site/khl_site_collector.py
|
||||
- khl_site/update_runtime.py — новый обязательный модуль
|
||||
- khl_site/web/index.html
|
||||
|
||||
Для стандартного Linux-развёртывания имя службы — khl-data.service. После замены файлов: `sudo systemctl restart khl-data.service`. Если служба называется иначе, используйте её имя.
|
||||
|
||||
Рабочие настройки, базы данных, .env и сохранённые архивы КХЛ в пакет не включены. Файлы данных на сервере заменять не требуется.
|
||||
|
||||
## Что изменено
|
||||
|
||||
1. Загрузчик КХЛ по умолчанию работает одним потоком вместо трёх. Перед сетевыми запросами используется пауза 0,5 секунды. Эти значения применяются и к ручным обновлениям в веб-интерфейсе.
|
||||
2. Полное обновление игроков, тренеров и судей автоматически запускается ежедневно в 03:00 по Москве. Браузер открывать не нужно; сервер приложения должен работать.
|
||||
3. Дата автоматического запуска сохраняется перед стартом. В тот же день он не запускается снова после ошибки или перезапуска сервера. Ручной запуск и ночное обновление защищены от одновременного выполнения общей блокировкой.
|
||||
4. Во вкладке «КХЛ сайт» появилась кнопка «Отчёт обновлений»: время, длительность, результат по разделам, число полученных карточек, проблемы, состояние импорта в БД и следующая дата запуска. Отчёт можно скачать. Смотреть его могут операторы; запуск обновлений сохраняет прежнее ограничение для администраторов.
|
||||
5. Ошибки сохраняются с разделом и ID. Кнопка «Повторить неудачные» загружает только карточки из очереди. Уже успешно записанные карточки пропускаются. Если не удалось прочитать список участников, список перечитывается, после чего из него исключаются ранее успешно загруженные карточки.
|
||||
6. Ошибка сети или разбора карточки сохраняет её прежние данные. Если статистику не удалось разобрать целиком, используется предусмотренное сохранение прежней статистики, а карточка остаётся в очереди повтора. Успех удаляется из очереди только после записи файла данных. При полном отказе загрузки прежний архив не перезаписывается.
|
||||
7. Если файлы загрузились, но импорт в БД завершился ошибкой, кнопка повтора может повторить только импорт сохранённых файлов, без обращения к КХЛ.
|
||||
8. Отчёт, очередь ошибок и отметка ночного запуска сохраняются после перезапуска. В отчёте показываются первые 50 ошибок; скачиваемый файл содержит полную очередь.
|
||||
|
||||
Повтор — ручной, через кнопку в отчёте. Бесконечного автоматического повтора при недоступности КХЛ нет. Следующее плановое обновление — следующей ночью.
|
||||
|
||||
После аварийного завершения незавершённые карточки остаются в очереди. Если результат обработки находился только в памяти и ещё не был записан, такая карточка также требует повтора.
|
||||
|
||||
## Настройки и расписание
|
||||
|
||||
При первом запуске автоматически создаётся файл `settings/local/khl_updates.json`, если его ещё нет:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "03:00",
|
||||
"workers": 1,
|
||||
"request_delay_seconds": 0.5,
|
||||
"window_minutes": 60
|
||||
}
|
||||
```
|
||||
|
||||
Время всегда московское (Europe/Moscow), независимо от часового пояса ОС. Планировщик проверяет время каждые 30 секунд. При перезапуске между 03:00 и 03:59 пропущенный запуск может начаться в этом окне, если сегодня ещё не запускался. Если сервер всё это окно был выключен, днём загрузка не стартует: следующий запуск — следующей ночью. Если другое обновление занимает всё окно, ночной запуск пропускается.
|
||||
|
||||
Настройки перечитываются без перезапуска; изменение числа потоков и задержки применяется к следующей загрузке. Для снижения нагрузки оставьте workers=1. Выключение автоматического запуска: enabled=false. Уже выполняющийся сбор это не прерывает.
|
||||
|
||||
Создаваемые рабочие файлы:
|
||||
|
||||
- `settings/local/khl_update_state.json` — последний запуск, отчёт, импорт и дата ночного запуска;
|
||||
- `settings/local/khl_update_state.lock` — блокировка выполняющегося задания;
|
||||
- `khl_site/data/khl_update_pending.json` — очередь неудачных/незавершённых записей;
|
||||
- `khl_site/data/khl_update_report.json` — диагностика последнего запуска загрузчика;
|
||||
- прежние `khl_site/data/khl_*_all.json` — сами данные.
|
||||
|
||||
Эти файлы создаются приложением и не входят в обновление. Каталоги settings/local и khl_site/data должны быть доступны для записи пользователю службы. Очередь умеет восстановить ошибки из архивов предыдущей версии, если отдельного файла очереди ещё нет.
|
||||
|
||||
## Результаты проверки CPU
|
||||
|
||||
Аудит проведён по исходному коду build171/172. Доступа к метрикам действующего сервера не было; причина конкретного сигнала «100% CPU» на сервере пока не подтверждена.
|
||||
|
||||
Подтверждён существенный источник лишней работы в `hockey_data/service.py`: при изменении JSON онлайн-матча `sync_live_game()` вызывает `sync_match_details()`, который повторно разбирает справочники и сохраняет профили всего турнира. Кэш справочника хранит ответ источника, но не исключает повторный разбор и запись. Даже неизменившимся профилям обновляется время синхронизации. Полная карточка матча также собирается до и после обновления. В этой версии данный участок Stat2TV не оптимизирован.
|
||||
|
||||
Изолированный замер реального метода сохранения справочника, синтетические профили, локальная SQLite, три повторных сохранения неизменившихся данных:
|
||||
|
||||
| Профилей | SQL-вызовов за повтор | Из них SELECT / UPDATE | Медиана CPU-времени процесса |
|
||||
|---|---:|---:|---:|
|
||||
| 100 | 600 | 300 / 300 | 0,095 с |
|
||||
| 500 | 3 000 | 1 500 / 1 500 | 0,537 с |
|
||||
| 1 000 | 6 000 | 3 000 / 3 000 | 0,911 с |
|
||||
|
||||
Это замер одного участка, без сетевых задержек, PostgreSQL, полного матча и других пользователей. Он не является нагрузочным тестом сервера и не задаёт гарантированную пропускную способность. В онлайн-режиме новый запрос запускается примерно через секунду после завершения предыдущего; несколько браузеров могут выполнять работу по одному матчу повторно.
|
||||
|
||||
Дополнительные источники нагрузки:
|
||||
|
||||
- через 15 секунд после старта сервера начинается фоновая синхронизация расписаний; далее она выполняется примерно раз в час;
|
||||
- автообновление Mapping повторяет SQL-источники; отправка только изменившихся значений в vMix не отменяет сами SQL-запросы;
|
||||
- клиент Stat2TV создаёт новый HTTP-клиент на каждый запрос, без повторного использования соединения между вызовами;
|
||||
- полный сбор КХЛ и последующий импорт больших архивов в БД могут давать пики. В build172 сбор перенесён на ночь и уменьшен до одного потока, но один поток тоже способен занять одно ядро на обработке данных.
|
||||
|
||||
Следующие приоритетные оптимизации Stat2TV: не перезаписывать неизменившийся справочник, объединить одновременные обновления одного матча, повторно использовать HTTP-соединения. Добавление RAM или ядер само по себе не устраняет эти причины.
|
||||
|
||||
## Ориентир по серверу
|
||||
|
||||
Ниже инженерная оценка для планирования, а не гарантированные минимальные требования. Точный размер зависит от числа открытых матчей/браузеров, объёма архивов, SQL Mapping и размещения БД. vMix и обработка видео в эти цифры не входят.
|
||||
|
||||
| Размещение | CPU | Оперативная память | Диск |
|
||||
|---|---|---|---|
|
||||
| Тестовый стенд, PostgreSQL отдельно | 2 vCPU | 4 ГБ | SSD от 40 ГБ |
|
||||
| Рабочий веб-сервер, PostgreSQL отдельно | 4 vCPU с гарантированным ресурсом | 8 ГБ | SSD/NVMe 60–80 ГБ |
|
||||
| Приложение и PostgreSQL на одном сервере | 6–8 vCPU | 16 ГБ | SSD/NVMe 100–150 ГБ |
|
||||
|
||||
Для начала я бы выбрал 4 vCPU / 8 ГБ RAM при отдельной БД либо 8 vCPU / 16 ГБ RAM при совместном размещении. Для большого числа матчей и операторов сначала нужен замер после оптимизации указанного участка, затем масштабирование.
|
||||
|
||||
ОС: 64-битный Linux. Python 3.12 подходит для проверенного окружения; зависимости устанавливаются из requirements.txt. База — PostgreSQL. GPU веб-приложению не требуется. Нужен стабильный интернет для КХЛ/Stat2TV; при отдельной БД важна небольшая задержка между приложением и БД. Диск резервируется также под HTML-кэш, архивы, журналы и резервные копии, поэтому его фактический расход следует измерять отдельно.
|
||||
|
||||
Для текущей архитектуры используйте один процесс Uvicorn: WebSocket-подключения Agent и часть состояния хранятся в памяти процесса. Простое увеличение `--workers` может разделить подключения между процессами и продублировать фоновые задания. Ночной сбор КХЛ получил собственную межпроцессную защиту, но это не делает всё приложение готовым к нескольким процессам.
|
||||
|
||||
Пример запуска из виртуального окружения:
|
||||
|
||||
```bash
|
||||
.venv/bin/python -m uvicorn app:app --host 0.0.0.0 --port 8000 --workers 1
|
||||
```
|
||||
|
||||
В production не используйте `--reload`. Это режим разработки с наблюдением за изменениями файлов. Если `--workers` не указан, Uvicorn может взять число процессов из WEB_CONCURRENCY.
|
||||
|
||||
Официальные справки: [настройки Uvicorn](https://www.uvicorn.org/settings/), [повторное использование соединений HTTPX](https://www.python-httpx.org/advanced/clients/).
|
||||
|
||||
## Что запросить у администратора для точного диагноза
|
||||
|
||||
Нужны текущие vCPU/RAM, расположение PostgreSQL, число одновременно открытых матчей/браузеров и уточнение, где показаны 100%: у отдельного процесса, одного ядра, контейнера или всего сервера.
|
||||
|
||||
На Linux можно снять:
|
||||
|
||||
```bash
|
||||
nproc
|
||||
free -h
|
||||
ps -eo pid,ppid,comm,%cpu,%mem,rss --sort=-%cpu | head -15
|
||||
vmstat 1 5
|
||||
top -b -n 2 -d 2
|
||||
```
|
||||
|
||||
Для стандартной службы:
|
||||
|
||||
```bash
|
||||
systemctl show khl-data.service -p NRestarts -p MemoryCurrent -p CPUUsageNSec
|
||||
```
|
||||
|
||||
CPUUsageNSec — накопленное CPU-время, не процент текущей нагрузки. В обычном top 100% у одного процесса может означать одно полностью занятое ядро; показания панели VPS могут иметь другую шкалу.
|
||||
|
||||
Для размера базы администратор PostgreSQL может выполнить:
|
||||
|
||||
```sql
|
||||
SELECT pg_size_pretty(pg_database_size(current_database()));
|
||||
```
|
||||
|
||||
Сравнение процессов покажет, где сосредоточена нагрузка: Python веб-сервера, отдельный загрузчик КХЛ или PostgreSQL. Только после этого можно подтвердить причину предупреждения о CPU.
|
||||
|
||||
## Проверка обновления
|
||||
|
||||
- 10 новых проверок расписания, блокировки, сохранения данных/ошибок, точечного повтора и скачивания отчёта;
|
||||
- вместе с актуальными регрессионными проверками КХЛ: 46 успешных проверок;
|
||||
- два старых текстовых ожидания исключены: прежние три потока (заменено проверкой одного потока) и прежнее расположение КХЛ в настройках, изменённое ещё до этой версии;
|
||||
- интерфейс проверен в браузере: отчёт, московское время, повтор, блокировка кнопок при загрузке, ограничения зрителя и стабильность списка при фоновом опросе;
|
||||
- проверены синтаксис Python и JavaScript.
|
||||
|
||||
Проверки использовали локальные данные и имитации ответов. Реальный ночной запуск на вашем сервере и доступность КХЛ из его сети ещё не проверены. Снижение нагрузки КХЛ не означает, что все причины 100% CPU уже устранены.
|
||||
Reference in New Issue
Block a user