Архитектура кэша
На этой странице представлен технический обзор архитектуры сервиса кэширования Tuist. Она предназначена в первую очередь для пользователей, использующих самостоятельное размещение, и участников проекта, которым необходимо понять внутреннее устройство сервиса. Обычным пользователям, которые хотят только использовать кэш, читать её не нужно.
Сервис кэширования Tuist — это отдельный сервис, который предоставляет хранилище с адресацией по содержимому (CAS) для артефактов сборки и хранилище ключ-значение для метаданных кэша.
Обзор#
Сервис использует двухуровневую архитектуру хранения плюс локальные метаданные SQLite:
- Локальный диск: основное хранилище для быстрых попаданий в кэш
- S3: надёжное хранилище, которое сохраняет артефакты и позволяет восстанавливать их после удаления с диска
- SQLite: локальные метаданные для отслеживания доступа к артефактам, очистки orphan-файлов, фоновых задач и данных кэша ключ-значение
flowchart LR
CLI[Tuist CLI] --> NGINX[Nginx]
NGINX --> APP[Cache service]
NGINX -->|X-Accel-Redirect| DISK[(Local Disk)]
APP --> S3[(S3)]
APP -->|auth| SERVER[Tuist Server]
Компоненты#
Nginx#
Nginx выступает точкой входа и обеспечивает эффективную передачу файлов с помощью X-Accel-Redirect:
- Загрузки: сервис кэша проверяет аутентификацию, затем возвращает заголовок
X-Accel-Redirect. Nginx отдаёт файл напрямую с диска или проксирует из S3. - Выгрузки: Nginx проксирует запросы к сервису кэша, который потоково записывает данные на диск.
Хранилище с адресацией по содержимому#
Артефакты хранятся на локальном диске в шардированной структуре каталогов:
- Путь:
{account}/{project}/cas/{shard1}/{shard2}/{artifact_id} - Шардирование: первые четыре символа идентификатора артефакта образуют двухуровневый шард (например,
ABCD1234→AB/CD/ABCD1234)
Метаданные SQLite#
Сервис кэша использует две базы данных SQLite:
- Основная БД метаданных: хранит
cache_artifacts, курсоры сканирования orphan-файлов, задачи Oban и другие служебные метаданные. - БД ключ-значение: хранит
key_value_entriesиkey_value_entry_hashesв выделенном файле SQLite.
Хранилище ключ-значение вынесено в отдельную базу данных, чтобы можно было использовать инкрементальное автоматическое освобождение места в SQLite без влияния на метаданные артефактов и состояние очистки orphan-файлов.
Интеграция с S3#
S3 обеспечивает надёжное хранение:
- Фоновые выгрузки: после записи на диск артефакты ставятся в очередь на загрузку в S3 через фоновый воркер, который запускается каждую минуту
- Гидратация по запросу: если локальный артефакт отсутствует, запрос сразу обслуживается через предподписанный URL S3, пока артефакт ставится в очередь на фоновую загрузку на локальный диск
Удаление с диска#
Сервис управляет дисковым пространством с помощью нескольких фоновых процессов:
- Удаление артефактов CAS с диска использует семантику LRU на основе
cache_artifacts - Когда использование диска превышает 85%, самые старые артефакты удаляются, пока использование не снизится до 70%
- Артефакты остаются в S3 после удаления с локального диска
- Удаление записей KV удаляет старые записи ключ-значение по сроку хранения и может также уменьшать размер выделенной БД KV, когда она превышает заданный лимит размера
Очистка orphan-файлов#
Сервис также запускает воркер очистки orphan-файлов для артефактов на диске:
- Он сканирует дерево хранилища в поисках файлов, которые существуют на диске, но не имеют соответствующей строки в
cache_artifacts. - Это может произойти, если файл записан на диск, но запись метаданных потеряна до завершения сброса буфера SQLite.
- Файлы, созданные позже безопасного интервала, игнорируются, чтобы избежать конфликтов с выполняющимися загрузками.
- Если orphan-файл удалён и позже запрошен снова, следующий промах кэша приведёт к его повторной загрузке, поэтому система самовосстанавливается.
Аутентификация#
Кэш делегирует аутентификацию серверу Tuist, вызывая конечную точку /api/projects и кэшируя результаты (10 минут при успехе, 3 секунды при ошибке).
Потоки запросов#
Загрузка#
sequenceDiagram
participant CLI as Tuist CLI
participant N as Nginx
participant A as Cache service
participant D as Disk
participant S as S3
CLI->>N: GET /api/cache/cas/:id
N->>A: Proxy for auth
A-->>N: X-Accel-Redirect
alt On disk
N->>D: Serve file
else Not on disk
N->>S: Proxy from S3
end
N-->>CLI: File bytes
Выгрузка#
sequenceDiagram
participant CLI as Tuist CLI
participant N as Nginx
participant A as Cache service
participant D as Disk
participant S as S3
CLI->>N: POST /api/cache/cas/:id
N->>A: Proxy upload
A->>D: Stream to disk
A-->>CLI: 201 Created
A->>S: Background upload
Конечные точки API#
| Конечная точка | Метод | Описание |
|---|---|---|
/up | GET | Проверка работоспособности |
/metrics | GET | Метрики Prometheus |
/api/cache/cas/:id | GET | Скачать артефакт CAS |
/api/cache/cas/:id | POST | Загрузить артефакт CAS |
/api/cache/keyvalue/:cas_id | GET | Получить запись ключ-значение |
/api/cache/keyvalue | PUT | Сохранить запись ключ-значение |
/api/cache/module/:id | HEAD | Проверить наличие артефакта модуля |
/api/cache/module/:id | GET | Скачать артефакт модуля |
/api/cache/module/start | POST | Начать многокомпонентную загрузку |
/api/cache/module/part | POST | Загрузить часть |
/api/cache/module/complete | POST | Завершить многокомпонентную загрузку |