TFTL · Підсумок виконаних робіт · для Avalon · 09.09.2026

Розумне кешування — швидко і безпечно

Сайт віддає готові сторінки за півсекунди замість кількох секунд, статуси квартир з Salesforce оновлюються за лічені секунди, а запити залогінених користувачів обходять спільний кеш. Усе це працює на тестовому стенді, де ми це перевіряємо, і вимикається одним перемикачем.

Тестовий стенд · 32 із 32 перевірок пройдено

Головні результати

Коротко — що змінилось

Раніше кожна сторінка збиралась заново для кожного відвідувача. Тепер готові сторінки віддаються з памʼяті — але лише анонімним відвідувачам, і лише доки дані не змінились.

10×

швидший перший байт сторінки «Компанія»: 5.7 с → 0.54 с

≤ 5 с

оновлення статусів квартир після зміни в Salesforce, виміряно на стенді

0

витоків у перевірці з 60 змішаних запитів анонімів і залогінених

2 с

щоб одним перемикачем вимкнути все кешування на обох серверах

Як це працює

Три правила, на яких побудовано кеш

Минулі проблеми з кешем на сайті мали дві причини: чужі дані в спільному кеші та застарілі статуси броні. Нова система побудована так, щоб закрити обидві причини — і саме це ми перевіряємо на стенді.

Правило 1

Нічого особистого в спільному кеші

У кеш потрапляє лише те, що бачить анонімний відвідувач. Будь-який запит залогіненого користувача обходить кеш і завжди отримує живу відповідь. Це перевіряється тричі — на CDN, на фронтенді і на API.

Правило 2

Свіжість за версіями, а не за таймером

Кожен вид даних має номер версії. Зміна в Salesforce чи в адмінці підвищує номер — і всі сторінки, зібрані зі старих даних, миттєво стають недійсними. Не треба чекати, поки «спливе» кеш.

Правило 3

У сумніві — віддати живу сторінку

Якщо фронтенд не може підтвердити, що його версії актуальні (звʼязок з API втрачено, систему вимкнено, сервер щойно перезапущено), він не віддає з кешу нічого. Краще повільніша сторінка, ніж застаріла.

Виконані роботи

Що саме ми зробили

✓

Провели повний аудит усіх шарів: Cloudflare, сервери, фронтенд, API, база. Зʼясували, що правило Cloudflare після старого інциденту вимикало кеш для всього сайту, навіть для незмінних файлів.

✓

Спроєктували архітектуру і провели її через три раунди незалежної технічної експертизи. Кілька слабких місць виправлено ще на етапі дизайну.

✓

Виправили порядок запису статусів з Salesforce: статус квартири тепер зберігається до завантаження планувань, тому повільна картинка більше не затримує і не губить зміну статусу.

✓

Закрили витік на рівні фронтенду: сервер більше не передає cookies відвідувачів до API під час збирання сторінки.

✓

Побудували кеш відповідей API для 9 публічних розділів і кеш готових сторінок для 17 сторінок сайту — з версіями, миттєвим оновленням і захистом від збереження чужих даних.

✓

Додали керування й прозорість: один перемикач вимикає все за 2 секунди, кожна відповідь повідомляє, звідки вона прийшла, є статистика влучань і статус синхронізації.

✓

Покрили тестами: 99 автоматичних тестів у коді та приймальний сценарій із 32 перевірок, який прогонимо на стенді однією командою.

✓

Задокументували для розробників: як система працює, як додати новий розділ у кеш, як повідомити про зміну даних, як вимкнути або прибрати її повністю.

Доказ №1 · швидкодія

Сторінки віддаються за півсекунди

Час до першого байта сторінки, виміряний на тестовому стенді: медіана з трьох прогонів, «до» — живе збирання сторінки, «стало» — з кешу. Стенд повільніший за бойовий сервер, тому важливе співвідношення, а не абсолютні цифри.

Сторінка «Компанія»у 10× швидше1.5 MB HTML → з памʼяті
було
5.73 с
стало
0.54 с
Головна сторінкау 8× швидше
було
4.58 с
стало
0.54 с
Новини та акціїу 8× швидше
було
4.3–4.6 с
стало
0.53 с
API: дані сторінок (static-pages), повне перезбиранняу 4× швидше1 MB даних → готова відповідь
було
840 мс
стало
220 мс
API: акціїу 3× швидше
було
316 мс
стало
107 мс

Каталог квартир, сторінки квартир і проєктів у цьому етапі ще не кешуються — навмисно. Спочатку система працює на статичному контенті під наглядом; квартири з окремим живим статусом — окремий етап.

Доказ №2 · безпека і свіжість

32 сценарії — усі пройдено

Приймальний сценарій навмисно ламає систему всіма способами, які колись призводили до проблем, і перевіряє, що вона поводиться правильно.

Витік даних

0 з 60

60 упереміш запитів анонімів і залогінених: жоден запит із cookie чи токеном не отримав відповідь із кешу, жодна анонімна сторінка не містила чужого токена.

Зміна в Salesforce

≤ 6 с

Вебхук Salesforce, редагування в адмінці або ручна команда — і сторінки на фронтенді та відповіді API оновлюються за секунди на обох серверах.

Перемикач

2 с

Одна команда на API вимикає кешування скрізь, включно з фронтендом на іншому сервері. Увімкнення назад — так само за 2 секунди.

Втрата звʼязку

живі сторінки

Коли фронтенд не може дістатись до API, він за 8 секунд перестає віддавати з кешу і збирає сторінки заново, доки звʼязок не повернеться.

Перезапуск

спочатку синхронізація

Після перезапуску сервера кеш порожній і не використовується, доки не підтверджені актуальні версії даних. Синхронізація займає 1 секунду.

Незнайомі параметри

повз кеш

Посилання з рекламними мітками чи будь-якими сторонніми параметрами віддаються живими і в кеш не потрапляють.

Технічна частина

Як це технічно працює

Що саме відбувається з кожним запитом — без оцінок і обіцянок. Уся ця механіка працює на тестовому стенді, і саме її поведінку перевіряє приймальний сценарій із 32 перевірок.

1

Класифікація запиту

Запит спершу проходить класифікатор: GET без cookies і без заголовка Authorization вважається придатним до кешу. Будь-який cookie, токен, не-GET або незнайомий параметр в адресі — запит іде повз кеш, живим. Класифікатор стоїть і на фронтенді, і на API.

2

Версії замість таймера

Кожен тип контенту має тег (static-pages, news, offers, catalogue…) з цілим числом-версією в Redis. Запис у кеші зберігає версії, з якими його зібрали, і віддається лише доки всі вони збігаються з поточними.

3

Запис даних підвищує версію

Збереження в адмінці, вебхук Salesforce або фонове завантаження підвищує версії потрібних тегів одним атомарним інкрементом наприкінці операції (десять збережень в одному вебхуку — один інкремент). Кожне підвищення записується в лог.

4

Фронтенд звіряє версії

Сервер сторінок кожні 5 секунд опитує API про поточні версії (heartbeat), а одразу після зміни ще отримує підписаний push від API. Готова сторінка віддається з памʼяті лише коли її версії збігаються з останніми підтвердженими.

5

У сумніві — живий рендер

Якщо фронтенд не синхронізований (пропущено два heartbeat-и, API недоступне, сервер щойно перезапущено), сторінки збираються заново. Помилка всередині кеш-логіки теж переводить запит у живий режим, а не в помилку чи стару відповідь.

6

Перевірка перед збереженням і мітка

Відповідь потрапляє в кеш лише якщо: статус 200, немає Set-Cookie, немає авторизованого користувача, JSON, розмір у межах ліміту, версії не змінились під час збирання. Кожна відповідь несе заголовок X-Cache-Layer (HIT / MISS / BYPASS із причиною); команда cache-system:off вимикає систему на обох серверах.

Підсумок

Було → стало

Показник
Було
Стало
Кешування сторінок і API
вимкнено повністю після інциденту
увімкнено для статичного контенту на стенді
Перший байт сторінки (стенд)
3.3–5.7 с
0.53–0.54 с
Свіжість після зміни даних
таймер або без кешу
версії + оновлення за ≤ 5 с (стенд)
Захист особистих даних
повне вимкнення кешу
3 незалежні перевірки + тест на витік
Cloudflare
обхід кешу для всього сайту
правило звужене, незмінні файли кешуються*
Вимкнення системи
потребувало змін у коді
одна команда, 2 секунди, обидва сервери
Прозорість
невідомо, що і звідки віддається
мітка на кожній відповіді, статус, статистика
Порядок запису статусів з Salesforce
після завантаження картинок
спочатку статус, потім картинки

* Правило Cloudflare на стенді не змінювалось; його звуження — частина переносу на бойовий сервер. Уся система працює лише на тестовому стенді з повними даними; на бойові сервери нічого не переносилось.