캐시
번역일: 2026년 6월 25일
캐시
소개
애플리케이션에서 데이터를 조회하거나 처리하는 작업 중에는 CPU 자원을 많이 소모하거나 완료까지 수 초가 걸리는 작업이 있을 수 있습니다. 이런 경우 조회한 데이터를 일정 시간 동안 캐시에 저장해 두면, 동일한 요청이 들어왔을 때 훨씬 빠르게 응답할 수 있습니다. 캐시된 데이터는 보통 Memcached나 Redis와 같이 매우 빠른 인메모리 데이터 저장소에 보관됩니다.
Laravel은 다양한 캐시 백엔드를 위한 통일된 표현력 있는 API를 제공합니다. 이를 통해 각 캐시 저장소의 빠른 데이터 조회 능력을 최대한 활용하여 웹 애플리케이션의 응답 속도를 높일 수 있습니다.
설정
캐시 설정 파일은 config/cache.php에 위치합니다. 이 파일에서 애플리케이션 전체에 기본으로 사용할 캐시 저장소를 지정할 수 있습니다. Laravel은 Memcached, Redis, DynamoDB, 관계형 데이터베이스 등 널리 사용되는 캐시 백엔드를 기본 지원합니다. 파일 기반 캐시 드라이버도 사용할 수 있으며, array와 null 드라이버는 자동화 테스트 시 편리하게 쓸 수 있는 백엔드입니다.
설정 파일에는 이 외에도 다양한 옵션이 있으니 살펴보기를 권장합니다. Laravel의 기본 캐시 드라이버는 database로, 직렬화된 캐시 객체를 애플리케이션 데이터베이스에 저장합니다.
드라이버 사전 준비
Database
database 캐시 드라이버를 사용하려면 캐시 데이터를 저장할 데이터베이스 테이블이 필요합니다. 보통 Laravel의 기본 마이그레이션 파일인 0001_01_01_000001_create_cache_table.php가 이 테이블을 생성합니다. 만약 해당 마이그레이션 파일이 없다면, Artisan 명령어로 직접 만들 수 있습니다.
php artisan make:cache-tablephp artisan migrateMemcached
Memcached 드라이버를 사용하려면 Memcached PECL 패키지가 설치되어 있어야 합니다. config/cache.php 설정 파일의 memcached.servers 항목에 Memcached 서버 목록을 지정합니다.
'memcached' => [
// ...
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],필요하다면 host 옵션에 UNIX 소켓 경로를 지정할 수도 있습니다. 이 경우 port는 반드시 0으로 설정해야 합니다.
'memcached' => [
// ...
'servers' => [
[
'host' => '/var/run/memcached/memcached.sock',
'port' => 0,
'weight' => 100
],
],
],Redis
Laravel에서 Redis 캐시를 사용하려면 PECL을 통해 PhpRedis PHP 확장을 설치하거나, Composer로 predis/predis 패키지(~2.0)를 설치해야 합니다. Laravel Sail에는 이 확장이 이미 포함되어 있으며, Laravel Cloud와 Laravel Forge에도 PhpRedis 확장이 기본 설치되어 있습니다.
Redis 설정에 대한 자세한 내용은 Laravel Redis 문서를 참고하세요.
DynamoDB
DynamoDB 캐시 드라이버를 사용하려면 먼저 캐시 데이터를 저장할 DynamoDB 테이블을 생성해야 합니다. 테이블 이름은 보통 cache로 설정하지만, cache 설정 파일의 stores.dynamodb.table 값이나 환경 변수 DYNAMODB_CACHE_TABLE에 따라 달라질 수 있습니다.
테이블의 파티션 키는 문자열 타입이어야 하며, cache 설정 파일의 stores.dynamodb.attributes.key 값에 해당하는 이름을 사용해야 합니다. 기본값은 key입니다.
DynamoDB는 기본적으로 만료된 항목을 자동으로 삭제하지 않습니다. 따라서 테이블에 TTL(Time to Live)을 활성화해야 합니다. TTL 속성 이름은 expires_at으로 설정하세요.
다음으로, Laravel 애플리케이션이 DynamoDB와 통신할 수 있도록 AWS SDK를 설치합니다.
composer require aws/aws-sdk-php그리고 DynamoDB 캐시 저장소 설정 옵션에 필요한 값들을 지정해야 합니다. AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 등은 .env 파일에 정의하는 것이 일반적입니다.
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],MongoDB
MongoDB를 사용하는 경우, 공식 패키지 mongodb/laravel-mongodb에서 제공하는 mongodb 캐시 드라이버를 활용할 수 있습니다. MongoDB는 TTL 인덱스를 지원하므로 만료된 캐시 항목을 자동으로 삭제할 수 있습니다.
설정에 대한 자세한 내용은 MongoDB의 캐시 및 잠금 문서를 참고하세요.
캐시 사용법
캐시 인스턴스 가져오기
캐시 저장소 인스턴스를 얻으려면 Cache 파사드를 사용하면 됩니다. 이 문서 전반에 걸쳐 Cache 파사드를 기준으로 설명합니다. Cache 파사드는 Laravel 캐시 컨트랙트의 내부 구현에 간결하게 접근할 수 있게 해줍니다.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* 애플리케이션의 전체 사용자 목록을 반환합니다.
*/
public function index(): array
{
$value = Cache::get('key');
return [
// ...
];
}
}여러 캐시 저장소 접근하기
Cache 파사드의 store 메서드를 사용하면 여러 캐시 저장소에 접근할 수 있습니다. store 메서드에 전달하는 키는 cache 설정 파일의 stores 배열에 정의된 저장소 이름과 일치해야 합니다.
$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); // 10분캐시에서 항목 조회하기
Cache 파사드의 get 메서드를 사용해 캐시에서 항목을 조회합니다. 항목이 존재하지 않으면 null을 반환합니다. 두 번째 인수로 기본값을 지정할 수도 있습니다.
$value = Cache::get('key');
$value = Cache::get('key', '기본값');기본값으로 클로저를 전달할 수도 있습니다. 지정한 항목이 캐시에 없을 때 클로저가 실행되며, 그 결과가 반환됩니다. 클로저를 사용하면 데이터베이스나 외부 서비스에서 기본값을 조회하는 작업을 필요한 시점까지 미룰 수 있습니다.
$value = Cache::get('key', function () {
return DB::table(/* ... */)->get();
});항목 존재 여부 확인
has 메서드로 캐시에 항목이 존재하는지 확인할 수 있습니다. 항목이 존재하더라도 값이 null이면 false를 반환합니다.
if (Cache::has('key')) {
// ...
}값 증가 / 감소
increment와 decrement 메서드를 사용해 캐시에 저장된 정수 값을 조정할 수 있습니다. 두 번째 인수로 증감할 양을 지정할 수 있습니다.
// 값이 없으면 초기화...
Cache::add('key', 0, now()->plus(hours: 4));
// 값 증가 또는 감소...
Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);조회 후 저장 (Remember)
캐시에서 항목을 조회하되, 없을 경우 기본값을 저장하는 패턴이 자주 쓰입니다. 예를 들어 캐시에서 전체 사용자 목록을 가져오되, 없으면 데이터베이스에서 가져와 캐시에 저장하고 싶을 때 Cache::remember를 사용할 수 있습니다.
$value = Cache::remember('users', $seconds, function () {
return DB::table('users')->get();
});캐시에 항목이 없으면 클로저가 실행되고, 그 결과가 캐시에 저장됩니다.
만료 시간 없이 영구적으로 저장하려면 rememberForever를 사용하세요.
$value = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});오래된 값 허용 후 백그라운드 갱신 (Stale While Revalidate)
Cache::remember를 사용하면 캐시가 만료된 순간에 요청이 들어온 사용자는 새 값을 계산하는 동안 느린 응답을 경험할 수 있습니다. 일부 데이터는 약간 오래된 값을 잠시 허용하면서 백그라운드에서 새 값을 계산하는 방식이 더 적합합니다. 이를 "stale-while-revalidate" 패턴이라고 하며, Cache::flexible 메서드가 이를 구현합니다.
flexible은 캐시 값이 "신선(fresh)"한 기간과 "오래된(stale)" 상태로 허용되는 기간을 배열로 받습니다. 첫 번째 값은 신선한 기간(초), 두 번째 값은 오래된 값을 허용하는 기간(초)입니다.
- 신선 기간 내 요청: 즉시 캐시 값 반환, 재계산 없음
- 오래된 기간 내 요청: 오래된 값을 즉시 반환하고, 응답 전송 후 백그라운드에서 값 갱신(지연 함수 등록)
- 오래된 기간 초과 후 요청: 캐시 만료로 즉시 재계산 (응답이 느려질 수 있음)
$value = Cache::flexible('users', [5, 10], function () {
return DB::table('users')->get();
});조회 후 삭제 (Pull)
캐시에서 항목을 가져온 뒤 즉시 삭제하려면 pull 메서드를 사용하세요. get과 마찬가지로, 항목이 없으면 null을 반환합니다.
$value = Cache::pull('key');
$value = Cache::pull('key', '기본값');캐시에 항목 저장하기
Cache 파사드의 put 메서드로 캐시에 항목을 저장합니다.
Cache::put('key', 'value', $seconds = 10);만료 시간을 지정하지 않으면 항목이 무기한 저장됩니다.
Cache::put('key', 'value');초(seconds) 대신 DateTime 인스턴스로 만료 시각을 직접 지정할 수도 있습니다.
Cache::put('key', 'value', now()->plus(minutes: 10));없을 때만 저장 (Add)
add 메서드는 캐시에 해당 항목이 없을 때만 저장합니다. 실제로 저장되면 true, 이미 존재하면 false를 반환합니다. add는 원자적(atomic) 연산입니다.
Cache::add('key', 'value', $seconds);영구 저장
forever 메서드를 사용하면 만료 없이 항목을 영구적으로 저장합니다. 이렇게 저장된 항목은 forget 메서드로 직접 삭제해야 합니다.
Cache::forever('key', 'value');NOTE
Memcached 드라이버를 사용하는 경우, 캐시가 최대 용량에 도달하면 "영구" 저장 항목도 삭제될 수 있습니다.
캐시에서 항목 삭제하기
forget 메서드로 특정 항목을 삭제합니다.
Cache::forget('key');만료 시간을 0 또는 음수로 지정해도 해당 항목이 삭제됩니다.
Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);캐시 전체를 비우려면 flush 메서드를 사용합니다.
Cache::flush();WARNING
flush 메서드는 설정된 캐시 "prefix"를 무시하고 캐시 저장소의 모든 항목을 삭제합니다. 여러 애플리케이션이 하나의 캐시 저장소를 공유하는 환경에서는 특히 주의가 필요합니다.
캐시 메모이제이션
Laravel의 memo 캐시 드라이버는 단일 요청 또는 Job 실행 중에 조회된 캐시 값을 메모리에 임시로 보관합니다. 같은 실행 컨텍스트 내에서 동일한 키를 반복 조회하더라도 실제 캐시 저장소에는 처음 한 번만 접근하므로, 성능을 크게 향상시킬 수 있습니다.
메모이제이션 캐시를 사용하려면 memo 메서드를 호출하세요.
use Illuminate\Support\Facades\Cache;
$value = Cache::memo()->get('key');memo 메서드에 캐시 저장소 이름을 선택적으로 전달할 수 있으며, 이 저장소가 메모이제이션의 실제 백엔드로 사용됩니다.
// 기본 캐시 저장소 사용...
$value = Cache::memo()->get('key');
// Redis 캐시 저장소 사용...
$value = Cache::memo('redis')->get('key');특정 키에 대해 처음 get을 호출하면 실제 캐시 저장소에서 값을 가져오지만, 이후 같은 요청이나 Job 내에서 동일한 키를 조회하면 메모리에 저장된 값을 바로 반환합니다.
// 캐시 저장소 접근...
$value = Cache::memo()->get('key');
// 메모이제이션된 값 반환 (캐시 저장소 미접근)...
$value = Cache::memo()->get('key');put, increment, remember 등 캐시 값을 변경하는 메서드를 호출하면, 메모이제이션된 값이 자동으로 무효화되고 실제 캐시 저장소에 새 값이 기록됩니다.
Cache::memo()->put('name', 'Taylor'); // 실제 캐시에 저장...
Cache::memo()->get('name'); // 실제 캐시 접근...
Cache::memo()->get('name'); // 메모이제이션, 캐시 미접근...
Cache::memo()->put('name', 'Tim'); // 메모이제이션 무효화, 새 값 저장...
Cache::memo()->get('name'); // 실제 캐시 재접근...캐시 헬퍼 함수
Cache 파사드 외에도, 전역 cache 헬퍼 함수를 사용해 캐시를 조회하거나 저장할 수 있습니다. 문자열 하나를 인수로 전달하면 해당 키의 값을 반환합니다.
$value = cache('key');키/값 쌍 배열과 만료 시간을 함께 전달하면 해당 기간 동안 캐시에 저장합니다.
cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->plus(minutes: 10));인수 없이 호출하면 Illuminate\Contracts\Cache\Factory 구현 인스턴스를 반환하므로, 다른 캐시 메서드도 이어서 호출할 수 있습니다.
cache()->remember('users', $seconds, function () {
return DB::table('users')->get();
});NOTE
테스트 코드에서 전역 cache 함수를 호출하는 경우, 파사드 테스트와 동일하게 Cache::shouldReceive 메서드를 활용할 수 있습니다.
캐시 태그
WARNING
캐시 태그는 file, dynamodb, database 캐시 드라이버에서는 지원되지 않습니다.
태그와 함께 캐시 저장하기
캐시 태그를 사용하면 관련 항목들을 묶어서 태그로 일괄 삭제할 수 있습니다. 태그 이름의 순서가 있는 배열을 tags 메서드에 전달해 태그가 지정된 캐시에 접근합니다.
use Illuminate\Support\Facades\Cache;
Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);태그로 캐시 항목 조회하기
태그를 지정해 저장한 항목은 반드시 동일한 태그 목록을 지정해야 조회할 수 있습니다.
$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');태그로 캐시 항목 삭제하기
특정 태그 또는 태그 목록에 해당하는 모든 항목을 한 번에 삭제할 수 있습니다. 예를 들어 아래 코드는 people 또는 authors 태그로 지정된 모든 캐시를 삭제하므로, Anne과 John 모두 삭제됩니다.
Cache::tags(['people', 'authors'])->flush();반면 아래 코드는 authors 태그만 지정했으므로, Anne만 삭제되고 John은 남아 있습니다.
Cache::tags('authors')->flush();원자적 잠금(Atomic Locks)
WARNING
이 기능을 사용하려면 애플리케이션의 기본 캐시 드라이버가 memcached, redis, dynamodb, database, file, 또는 array 중 하나여야 합니다. 또한 모든 서버가 동일한 중앙 캐시 서버와 통신해야 합니다.
잠금 관리
원자적 잠금을 사용하면 경쟁 조건(race condition) 걱정 없이 분산 잠금을 관리할 수 있습니다. 예를 들어 Laravel Cloud는 원자적 잠금을 활용해 서버에서 하나의 원격 작업만 동시에 실행되도록 보장합니다. Cache::lock 메서드로 잠금을 생성하고 관리할 수 있습니다.
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// 10초 동안 잠금 획득...
$lock->release();
}get 메서드에 클로저를 전달하면 클로저 실행이 끝난 후 Laravel이 자동으로 잠금을 해제합니다.
Cache::lock('foo', 10)->get(function () {
// 10초 잠금 획득 후 자동 해제...
});잠금을 즉시 획득할 수 없는 경우, 지정한 시간(초) 동안 대기하도록 할 수 있습니다. 제한 시간 내에 잠금을 획득하지 못하면 Illuminate\Contracts\Cache\LockTimeoutException이 발생합니다.
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// 최대 5초 대기 후 잠금 획득...
} catch (LockTimeoutException $e) {
// 잠금 획득 실패...
} finally {
$lock->release();
}block 메서드에 클로저를 전달하면 코드를 더 간결하게 작성할 수 있습니다. 지정한 시간 동안 잠금 획득을 시도하고, 클로저 실행이 끝나면 자동으로 잠금을 해제합니다.
Cache::lock('foo', 10)->block(5, function () {
// 최대 5초 대기 후 10초 잠금 획득...
});프로세스 간 잠금 관리
한 프로세스에서 잠금을 획득하고, 다른 프로세스에서