Перейти к содержимому

Архитектура кэша

Note

На этой странице представлен технический обзор архитектуры сервиса кэширования 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#

Конечная точкаМетодОписание
/upGETПроверка работоспособности
/metricsGETМетрики Prometheus
/api/cache/cas/:idGETСкачать артефакт CAS
/api/cache/cas/:idPOSTЗагрузить артефакт CAS
/api/cache/keyvalue/:cas_idGETПолучить запись ключ-значение
/api/cache/keyvaluePUTСохранить запись ключ-значение
/api/cache/module/:idHEADПроверить наличие артефакта модуля
/api/cache/module/:idGETСкачать артефакт модуля
/api/cache/module/startPOSTНачать многокомпонентную загрузку
/api/cache/module/partPOSTЗагрузить часть
/api/cache/module/completePOSTЗавершить многокомпонентную загрузку