Кеш делает приложение быстрым и экономит трафик, но добавляет главный вопрос: насколько данные устарели и чьи они. На собесе спросят про уровни кеша, стратегии, инвалидацию и кеш картинок.
Уровни
- Память: мгновенно, но ограничена и очищается при нехватке. На iOS
NSCache(сам вытесняет при давлении памяти), на AndroidLruCacheс размером в байтах. - Диск: переживает перезапуск. Файлы в каталоге кеша (система может его очистить) или база.
- HTTP-кеш:
URLCache, кеш OkHttp, учитывают заголовки сервера. - CDN и сервер: не на устройстве, но влияют на скорость.
Стратегии чтения
| Стратегия | Как работает | Где |
|---|---|---|
| Cache first | кеш, сеть при промахе | справочники |
| Network first | сеть, кеш при ошибке | баланс, статусы |
| Stale-while-revalidate | кеш сразу, обновление фоном | ленты, каталоги |
| Без кеша | всегда сеть | коды подтверждения, платежи |
Stale-while-revalidate даёт мгновенный показ и актуальность через секунду: главное обновить список, не сбрасывая позицию скролла.
HTTP-заголовки
Cache-Control: max-age=60: можно не ходить на сервер минуту.no-cache: можно хранить, но перед использованием проверить;no-store: не хранить вообще.ETag+If-None-Match,Last-Modified+If-Modified-Since: условные запросы, сервер отвечает 304 без тела, если ничего не изменилось.
Инвалидация
«Самая сложная задача в программировании» на мобильном решается так:
- TTL по типу данных: курсы минуты, справочник дни;
- версии в ключе:
avatar.jpg?v=17, изменился аватар, изменился URL; - события: пользователь изменил профиль, сбросить его кеш; сервер прислал тихий push об изменениях.
Кеш картинок
Типичная архитектура загрузчика (Kingfisher, SDWebImage, Nuke, Coil, Glide, cached_network_image):
- Память с уже декодированными и уменьшенными картинками.
- Диск с файлами.
- Сеть: картинка нужного размера с CDN (с учётом плотности экрана), формат WebP/AVIF/HEIC.
Плюс: декодирование и уменьшение в фоне, склейка одинаковых запросов, отмена для ушедших с экрана ячеек, prefetch по ходу скролла, лимиты по байтам с вытеснением LRU.
Декодированная картинка занимает ширина × высота × 4 байта: фото 4000×3000 это 48 МБ, поэтому оригиналы в ленте недопустимы.
Пагинация и кеш
Для лент курсорная пагинация лучше номеров страниц: при вставке новых записей страницы сдвигаются, и появляются дубли или пропуски. Дубли на стыке страниц всё равно отсекают по id: ключи списков и diffable data source их не переживут.
Приватность
Персональные ответы (/me/orders) кешируются с учётом пользователя и стираются при выходе. Иначе следующий пользователь устройства увидит чужие данные. Удобно делить кеш на общий (каталог) и пользовательский в скоупе сессии.
Частые ошибки
- Один TTL на всё.
- Кеш без лимита размера.
- Новое содержимое по старому URL.
- Кеш персональных данных, переживающий выход из аккаунта.
- Оригиналы картинок вместо превью.
Что спросят на собесе
- Какие уровни кеша бывают и что где хранить?
- Что такое stale-while-revalidate?
- Как работают
ETagиCache-Control? - Как спроектировать загрузчик картинок для ленты?
- Почему курсорная пагинация лучше номеров страниц?