환경 설정
Redis를 Laravel 프로젝트에 통합하려면 먼저 Predis 패키지를 설치합니다.
composer require predis/predis
설치 후 config/database.php에서 Redis 연결 정보를 구성합니다. 기본 설정은 다음과 같습니다:
'redis' => [
'client' => 'predis',
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
Predis 클라이언트는 추가 연결 옵션도 지원하며, 필요한 경우 위 배열에 직접 확장할 수 있습니다.
기본 사용법
Redis 기능은 Illuminate\Support\Facades\Redis 파사드를 통해 접근합니다. 파사드는 동적 메서드를 지원하므로 모든 Redis 명령을 직접 호출할 수 있습니다.
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Redis;
use Illuminate\Http\Response;
class MemberController extends Controller
{
public function fetchMember($memberId): Response
{
$cachedData = Redis::get("member:{$memberId}");
return response()->view('member.detail', [
'data' => $cachedData
]);
}
}
데이터 타입별 조작
문자열(String) 처리
// 값 저장 및 만료 시간 설정
Redis::setex('session_token', 3600, 'abc123xyz');
// 단일 키 조작
Redis::set('username', 'honggildong');
$nickname = Redis::get('username');
Redis::del('username');
// 다중 키 일괄 처리
$userBatch = [
'user:1001' => '김철수',
'user:1002' => '이영희',
'user:1003' => '박민수'
];
Redis::mset($userBatch);
$names = Redis::mget(['user:1001', 'user:1002', 'user:1003']);
// 문자열 속성 확인
$length = Redis::strlen('username');
$slice = Redis::substr('username', 0, 4);
// 메타데이터 조회
$matchedKeys = Redis::keys('user:*');
$remainingTime = Redis::ttl('session_token');
$exists = Redis::exists('username');
리스트(List) 구조
// 양방향 삽입
Redis::lpush('task_queue', 'job_alpha');
Redis::rpush('task_queue', 'job_beta');
Redis::rpushx('task_queue', 'job_gamma'); // 존재하는 경우만 추가
// 길이 및 범위 조회
$totalItems = Redis::llen('task_queue');
$items = Redis::lrange('task_queue', 0, -1);
// 인덱스 기반 접근 및 수정
$specificItem = Redis::lindex('task_queue', 1);
Redis::lset('task_queue', 1, 'job_modified');
// 요소 삭제 및 정리
Redis::lrem('task_queue', 1, 'job_alpha');
Redis::ltrim('task_queue', 0, 9);
// 위치 기반 삽입
Redis::linsert('task_queue', 'before', 'job_beta', 'job_new');
// 블로킹 팝
Redis::blpop('task_queue', 30); // 30초 타임아웃
집합(Set) 연산
// 기본 집합 조작
Redis::sadd('tags:php', 'laravel');
Redis::sadd('tags:php', 'symfony', 'codeigniter');
Redis::srem('tags:php', 'codeigniter');
$popped = Redis::spop('tags:php');
// 집합 간 연산
Redis::sadd('tags:frontend', 'react', 'vue');
Redis::smove('tags:php', 'tags:frontend', 'laravel');
// 집합 정보 조회
$count = Redis::scard('tags:php');
$isMember = Redis::sismember('tags:php', 'laravel');
$allMembers = Redis::smembers('tags:php');
// 집합 연산
Redis::sadd('group_a', 'a', 'b', 'c');
Redis::sadd('group_b', 'b', 'c', 'd');
$intersection = Redis::sinter('group_a', 'group_b');
$union = Redis::sunion('group_a', 'group_b');
$difference = Redis::sdiff('group_a', 'group_b');
// 결과 저장
Redis::sinterstore('common_items', 'group_a', 'group_b');
// 랜덤 추출
$randomPick = Redis::srandmember('group_a');
해시(Hash) 저장소
// 단일 필드 조작
Redis::hset('profile:1001', 'email', 'user@example.com');
Redis::hset('profile:1001', 'age', '28');
$emailValue = Redis::hget('profile:1001', 'email');
// 조건부 삽입
Redis::hsetnx('profile:1001', 'email', 'new@example.com'); // 실패, 이미 존재
Redis::hsetnx('profile:1001', 'phone', '010-1234-5678'); // 성공
// 다중 필드 처리
Redis::hmset('profile:1002', [
'name' => '홍길동',
'city' => '서울',
'score' => '85'
]);
$partialData = Redis::hmget('profile:1002', ['name', 'city']);
// 숫자 필드 증가
Redis::hincrby('profile:1001', 'login_count', 1);
Redis::hincrby('profile:1001', 'login_count', 5);
// 해시 메타데이터
$fieldExists = Redis::hexists('profile:1001', 'email');
Redis::hdel('profile:1001', 'temp_field');
$fieldCount = Redis::hlen('profile:1001');
// 전체 데이터 추출
$allFields = Redis::hkeys('profile:1001');
$allValues = Redis::hvals('profile:1001');
$entireHash = Redis::hgetall('profile:1001');
정렬된 집합(Sorted Set) 및 정렬
// 정렬된 데이터 삽입
Redis::zadd('leaderboard', 100, 'player1');
Redis::zadd('leaderboard', 250, 'player2', 80, 'player3');
// 범위 조회
$topPlayers = Redis::zrevrange('leaderboard', 0, 2);
$bottomPlayers = Redis::zrange('leaderboard', 0, 2);
// 순위 및 점수
$rank = Redis::zrevrank('leaderboard', 'player1');
$score = Redis::zscore('leaderboard', 'player1');
// 점수 범위 삭제 및 카운트
Redis::zremrangebyscore('leaderboard', 0, 50);
$countInRange = Redis::zcount('leaderboard', 100, 300);
정렬 명령
Redis::rpush('numbers', 5, 1, 9, 3);
// 기본 오름차순
$sorted = Redis::sort('numbers'); // [1, 3, 5, 9]
// 옵션 조합
Redis::sort('numbers', ['sort' => 'desc']); // [9, 5, 3, 1]
Redis::sort('numbers', ['limit' => [0, 2]]); // 처음 2개
Redis::sort('numbers', ['alpha' => true]); // 사전순
// 외부 키 참조
Redis::sort('numbers', ['get' => 'item:*']); // 관련 데이터 조회
서버 관리 명령
// 정보 조회
$serverInfo = Redis::info();
// 데이터베이스 선택 및 조작
Redis::select(2);
Redis::flushdb(); // 현재 DB 비우기
// 키 이동
Redis::set('temporary', 'data');
Redis::move('temporary', 3);
// 복제 설정
Redis::slaveof('192.168.1.100', 6379);
Redis::slaveof(); // 복제 해제
// 지속성
Redis::save(); // 동기 저장
Redis::bgsave(); // 비동기 저장
$lastSaveTime = Redis::lastsave();
파이프라인 처리
다수의 명령을 한 번의 네트워크 왕복으로 처리하여 성능을 향상시킵니다.
Redis::pipeline(function ($redis) {
for ($idx = 0; $idx < 500; $idx++) {
$redis->set("cache:item:{$idx}", "value_{$idx}");
$redis->expire("cache:item:{$idx}", 600);
}
});
Pub/Sub 메시징
채널 구독
구독 명령은 장기 실행 프로세스이므로 Artisan 커맨드로 구현합니다:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
class NotificationListener extends Command
{
protected $signature = 'notifications:listen';
protected $description = '실시간 알림 채널 구독';
public function handle(): void
{
Redis::subscribe(['alerts', 'updates'], function ($payload) {
$decoded = json_decode($payload, true);
$this->processNotification($decoded);
});
}
private function processNotification(array $data): void
{
// 알림 처리 로직
}
}
패턴 기반 구독
// 모든 채널 감시
Redis::psubscribe(['*'], function ($message, $channel) {
logger()->info("{$channel}: {$message}");
});
// 특정 패턴 감시
Redis::psubscribe(['notifications.*'], function ($message, $channel) {
// notifications.으로 시작하는 모든 채널
});
Redis::psubscribe(['users.*.events'], function ($message, $channel) {
// users.{id}.events 형태의 채널
});
메시지 발행
// 컨트롤러나 서비스에서 발행
Redis::publish('notifications.123', json_encode([
'type' => 'order_shipped',
'order_id' => 'ORD-2024-001',
'timestamp' => now()->toIso8601String()
]));
Redis 파사드의 모든 메서드는 기본 클라이언트의 명령을 직접 노출하므로, Redis 공식 문서의 명령어를 그대로 활용할 수 있습니다.