Введение
Кэширование - это ключевой механизм оптимизации производительности веб-приложений. Правильная реализация кэширования может значительно улучшить скорость загрузки и отзывчивость приложения. В этой статье мы рассмотрим различные уровни кэширования и их реализацию.
Почему важно кэширование?
- Скорость: Быстрая загрузка контента
- Нагрузка: Снижение нагрузки на сервер
- Пользовательский опыт: Мгновенный доступ к данным
- Масштабируемость: Эффективное использование ресурсов
Уровни кэширования
1. Кэширование браузера
HTTP-заголовки кэширования
1
2
3
4
5
6
7
8
9
10
11
| # Настройка кэширования в Nginx
location /static/ {
expires 1y;
add_header Cache-Control "public, no-transform";
add_header ETag "";
}
location /api/ {
expires 1h;
add_header Cache-Control "private, no-cache";
}
|
Стратегии кэширования
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Пример использования localStorage
const cache = {
set: (key, value, ttl = 3600) => {
const item = {
value,
expiry: Date.now() + (ttl * 1000)
};
localStorage.setItem(key, JSON.stringify(item));
},
get: (key) => {
const item = localStorage.getItem(key);
if (!item) return null;
const { value, expiry } = JSON.parse(item);
if (Date.now() > expiry) {
localStorage.removeItem(key);
return null;
}
return value;
}
};
|
2. Кэширование на сервере
Redis кэширование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| const redis = require('redis');
const client = redis.createClient();
async function getCachedData(key) {
// Проверка кэша
const cached = await client.get(key);
if (cached) return JSON.parse(cached);
// Получение данных
const data = await fetchData();
// Сохранение в кэш
await client.set(key, JSON.stringify(data), 'EX', 3600);
return data;
}
|
Memcached кэширование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| $memcached = new Memcached();
$memcached->addServer('localhost', 11211);
function getCachedData($key) {
global $memcached;
$data = $memcached->get($key);
if ($memcached->getResultCode() === Memcached::RES_SUCCESS) {
return $data;
}
$data = fetchData();
$memcached->set($key, $data, 3600);
return $data;
}
|
3. Кэширование приложения
Кэширование в памяти
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| class MemoryCache {
constructor() {
this.cache = new Map();
}
set(key, value, ttl = 3600) {
const expiry = Date.now() + (ttl * 1000);
this.cache.set(key, { value, expiry });
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}
return item.value;
}
}
|
Стратегии кэширования
1. Кэширование на стороне клиента
Service Worker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| const CACHE_NAME = 'v1';
const urlsToCache = [
'/',
'/styles.css',
'/app.js',
'/images/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request);
})
);
});
|
2. Кэширование на стороне сервера
Кэширование запросов
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| const cache = new Map();
async function handleRequest(req) {
const cacheKey = req.url;
// Проверка кэша
if (cache.has(cacheKey)) {
const { data, timestamp } = cache.get(cacheKey);
if (Date.now() - timestamp < 3600000) { // 1 час
return data;
}
}
// Получение данных
const data = await fetchData(req);
// Сохранение в кэш
cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
}
|
Оптимизация кэширования
1. Инвалидация кэша
Версионирование
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| const CACHE_VERSION = 'v1';
const CACHE_NAME = `app-cache-${CACHE_VERSION}`;
// Обновление кэша при изменении версии
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
|
2. Стратегия обновления
Stale-While-Revalidate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| async function getData(key) {
const cache = await caches.open('data-cache');
const cachedResponse = await cache.match(key);
// Возвращаем кэшированные данные сразу
if (cachedResponse) {
fetchAndUpdateCache(key, cache);
return cachedResponse.json();
}
// Если нет в кэше, получаем новые данные
const response = await fetch(key);
await cache.put(key, response.clone());
return response.json();
}
|
Мониторинг кэширования
1. Метрики кэширования
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| const cacheMetrics = {
hits: 0,
misses: 0,
errors: 0
};
function trackCacheAccess(hit) {
if (hit) {
cacheMetrics.hits++;
} else {
cacheMetrics.misses++;
}
}
function getCacheStats() {
const total = cacheMetrics.hits + cacheMetrics.misses;
const hitRate = (cacheMetrics.hits / total) * 100;
return {
hits: cacheMetrics.hits,
misses: cacheMetrics.misses,
hitRate: hitRate.toFixed(2) + '%'
};
}
|
Заключение
Эффективное кэширование - это ключ к высокой производительности веб-приложений. Используйте различные уровни кэширования, следите за метриками и регулярно оптимизируйте стратегии кэширования.
#