Redis
소개
Redis는 오픈 소스 고급 키-값 저장소입니다. 키가 문자열, 해시, 리스트, 세트 및 정렬된 세트를 포함할 수 있기 때문에 종종 데이터 구조 서버라고도 합니다.
Laravel과 함께 Redis를 사용하기 전에 PECL을 통해 PhpRedis PHP 확장을 설치하고 사용하는 것이 좋습니다. 이 확장은 "user-land" PHP 패키지에 비해 설치가 더 복잡하지만 Redis를 많이 사용하는 애플리케이션에서 더 나은 성능을 제공할 수 있습니다. Laravel Sail을 사용하는 경우, 이 확장은 애플리케이션의 Docker 컨테이너에 이미 설치되어 있습니다.
PhpRedis 확장을 설치할 수 없는 경우 Composer를 통해 predis/predis 패키지를 설치할 수 있습니다. Predis는 PHP로 완전히 작성된 Redis 클라이언트이며 추가 확장이 필요하지 않습니다.
composer require predis/predis:^2.0
구성
애플리케이션의 Redis 설정은 config/database.php 구성 파일을 통해 구성할 수 있습니다. 이 파일 안에서, 애플리케이션에서 사용되는 Redis 서버를 포함하는 redis 배열을 볼 수 있습니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), ], 'default' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), ], 'cache' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_CACHE_DB', '1'), ], ],
구성 파일에 정의된 각 Redis 서버는 Redis 연결을 나타내는 단일 URL을 정의하지 않는 한 이름, 호스트 및 포트가 있어야 합니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), ], 'default' => [ 'url' => 'tcp://127.0.0.1:6379?database=0', ], 'cache' => [ ], ],
연결 스키마 구성하기
기본적으로 Redis 클라이언트는 Redis 서버에 연결할 때 tcp 스키마를 사용합니다. 그러나 Redis 서버의 구성 배열에 scheme 구성 옵션을 지정하여 TLS / SSL 암호화를 사용할 수 있습니다:
'default' => [ 'scheme' => 'tls', 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'),],
클러스터
애플리케이션에서 Redis 서버 클러스터를 활용하는 경우, Redis 구성의 clusters 키 내에 이러한 클러스터를 정의해야 합니다. 이 구성 키는 기본적으로 존재하지 않으므로 애플리케이션의 config/database.php 구성 파일 내에서 만들어야 합니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), ], 'clusters' => [ 'default' => [ [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), ], ], ], // ...],
기본적으로 Laravel은 options.cluster 구성 값이 redis로 설정되어 있기 때문에 네이티브 Redis 클러스터링을 사용합니다. Redis 클러스터링은 장애 조치를 정상적으로 처리하기 때문에 훌륭한 기본 옵션입니다.
Laravel은 또한 클라이언트 측 샤딩을 지원합니다. 그러나 클라이언트 측 샤딩은 장애 조치를 처리하지 않으므로 다른 기본 데이터 저장소에서 사용할 수 있는 일시적인 캐시 데이터에 주로 적합합니다.
네이티브 Redis 클러스터링 대신 클라이언트 측 샤딩을 사용하려면 애플리케이션의 config/database.php 구성 파일 내에서 options.cluster 구성 값을 제거할 수 있습니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'clusters' => [ // ... ], // ...],
Predis
애플리케이션이 Predis 패키지를 통해 Redis와 상호 작용하도록 하려면 REDIS_CLIENT 환경 변수의 값이 predis인지 확인해야 합니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'predis'), // ...],
기본 구성 옵션 외에도 Predis는 각 Redis 서버에 대해 정의할 수 있는 추가 연결 매개변수를 지원합니다. 이러한 추가 구성 옵션을 활용하려면 애플리케이션의 config/database.php 구성 파일에서 Redis 서버 구성에 추가하십시오:
'default' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), 'read_write_timeout' => 60,],
PhpRedis
기본적으로 Laravel은 Redis와 통신하기 위해 PhpRedis 확장을 사용합니다. Laravel이 Redis와 통신하는 데 사용할 클라이언트는 일반적으로 REDIS_CLIENT 환경 변수의 값을 반영하는 redis.client 구성 옵션의 값에 의해 결정됩니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), // ...],
기본 구성 옵션 외에도 PhpRedis는 name, persistent, persistent_id, prefix, read_timeout, retry_interval, timeout 및 context와 같은 추가 연결 매개변수를 지원합니다. config/database.php 구성 파일에서 Redis 서버 구성에 이러한 옵션을 추가할 수 있습니다:
'default' => [ 'url' => env('REDIS_URL'), 'host' => env('REDIS_HOST', '127.0.0.1'), 'username' => env('REDIS_USERNAME'), 'password' => env('REDIS_PASSWORD'), 'port' => env('REDIS_PORT', '6379'), 'database' => env('REDIS_DB', '0'), 'read_timeout' => 60, 'context' => [ // 'auth' => ['username', 'secret'], // 'stream' => ['verify_peer' => false], ],],
PhpRedis 직렬화 및 압축
PhpRedis 확장은 다양한 직렬화기 및 압축 알고리즘을 사용하도록 구성할 수도 있습니다. 이러한 알고리즘은 Redis 구성의 options 배열을 통해 구성할 수 있습니다:
'redis' => [ 'client' => env('REDIS_CLIENT', 'phpredis'), 'options' => [ 'cluster' => env('REDIS_CLUSTER', 'redis'), 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), 'serializer' => Redis::SERIALIZER_MSGPACK, 'compression' => Redis::COMPRESSION_LZ4, ], // ...],
현재 지원되는 직렬화기는 Redis::SERIALIZER_NONE (기본값), Redis::SERIALIZER_PHP, Redis::SERIALIZER_JSON, Redis::SERIALIZER_IGBINARY 및 Redis::SERIALIZER_MSGPACK입니다.
지원되는 압축 알고리즘은 Redis::COMPRESSION_NONE (기본값), Redis::COMPRESSION_LZF, Redis::COMPRESSION_ZSTD 및 Redis::COMPRESSION_LZ4입니다.
Redis와 상호작용
Redis 파사드에서 다양한 메서드를 호출하여 Redis와 상호 작용할 수 있습니다. Redis 파사드는 동적 메서드를 지원하므로 파사드에서 모든 Redis 명령어를 호출할 수 있으며 해당 명령어는 Redis로 직접 전달됩니다. 이 예에서는 Redis 파사드에서 get 메서드를 호출하여 Redis GET 명령어를 호출합니다:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use Illuminate\Support\Facades\Redis;use Illuminate\View\View; class UserController extends Controller{ /** * 지정된 사용자의 프로필을 표시합니다. */ public function show(string $id): View { return view('user.profile', [ 'user' => Redis::get('user:profile:'.$id) ]); }}
위에서 언급했듯이 Redis 파사드에서 Redis의 모든 명령어를 호출할 수 있습니다. Laravel은 매직 메서드를 사용하여 명령어를 Redis 서버로 전달합니다. Redis 명령어가 인수를 필요로 하는 경우, 해당 인수를 파사드의 해당 메서드로 전달해야 합니다:
use Illuminate\Support\Facades\Redis; Redis::set('name', 'Taylor'); $values = Redis::lrange('names', 5, 10);
또는, Redis 파사드의 command 메서드를 사용하여 서버에 명령어를 전달할 수 있습니다. command 메서드는 명령어 이름을 첫 번째 인수로, 값의 배열을 두 번째 인수로 받습니다:
$values = Redis::command('lrange', ['name', 5, 10]);
여러 Redis 연결 사용
애플리케이션의 config/database.php 구성 파일을 통해 여러 Redis 연결/서버를 정의할 수 있습니다. Redis 파사드의 connection 메서드를 사용하여 특정 Redis 연결에 대한 연결을 가져올 수 있습니다:
$redis = Redis::connection('connection-name');
기본 Redis 연결의 인스턴스를 가져오려면 추가 인수 없이 connection 메서드를 호출할 수 있습니다:
$redis = Redis::connection();
트랜잭션
Redis 파사드의 transaction 메서드는 Redis의 네이티브 MULTI 및 EXEC 명령어에 대한 편리한 래퍼를 제공합니다. transaction 메서드는 클로저를 유일한 인수로 받습니다. 이 클로저는 Redis 연결 인스턴스를 받으며 이 인스턴스에 원하는 명령어를 발행할 수 있습니다. 클로저 내에서 발행된 모든 Redis 명령어는 단일 원자적 트랜잭션으로 실행됩니다:
use Redis;use Illuminate\Support\Facades; Facades\Redis::transaction(function (Redis $redis) { $redis->incr('user_visits', 1); $redis->incr('total_visits', 1);});
Redis 트랜잭션을 정의할 때 Redis 연결에서 값을 검색할 수 없습니다. 트랜잭션은 단일 원자적 연산으로 실행되며 해당 연산은 전체 클로저가 명령어 실행을 완료할 때까지 실행되지 않는다는 점을 기억하십시오.
Lua 스크립트
eval 메서드는 단일 원자적 연산으로 여러 Redis 명령어를 실행하는 또 다른 방법을 제공합니다. 그러나 eval 메서드는 해당 작업 중에 Redis 키 값을 상호 작용하고 검사할 수 있다는 이점이 있습니다. Redis 스크립트는 Lua 프로그래밍 언어로 작성됩니다.
eval 메서드는 처음에는 약간 무서울 수 있지만, 기본 예제를 살펴봄으로써 시작해 보겠습니다. eval 메서드는 여러 인수를 예상합니다. 첫 번째로 Lua 스크립트 (문자열)를 메서드에 전달해야 합니다. 두 번째로 스크립트가 상호 작용하는 키의 수 (정수)를 전달해야 합니다. 세 번째로 해당 키의 이름을 전달해야 합니다. 마지막으로 스크립트 내에서 액세스해야 하는 추가 인수를 전달할 수 있습니다.
이 예에서 우리는 카운터를 증가시키고, 새 값을 검사하고, 첫 번째 카운터 값이 5보다 크면 두 번째 카운터를 증가시킵니다. 마지막으로 첫 번째 카운터의 값을 반환합니다:
$value = Redis::eval(<<<'LUA' local counter = redis.call("incr", KEYS[1]) if counter > 5 then redis.call("incr", KEYS[2]) end return counterLUA, 2, 'first-counter', 'second-counter');
Redis 스크립팅에 대한 자세한 내용은 Redis 설명서를 참조하십시오.
명령어 파이프라이닝
때로는 수십 개의 Redis 명령어를 실행해야 할 수도 있습니다. 각 명령어에 대해 Redis 서버로 네트워크 트립을 만드는 대신 pipeline 메서드를 사용할 수 있습니다. pipeline 메서드는 하나의 인수를 받습니다: Redis 인스턴스를 받는 클로저입니다. 이 Redis 인스턴스에 모든 명령어를 발행할 수 있으며 이 명령어들은 서버로의 네트워크 트립을 줄이기 위해 동시에 Redis 서버로 전송됩니다. 명령어는 발행된 순서대로 실행됩니다:
use Redis;use Illuminate\Support\Facades; Facades\Redis::pipeline(function (Redis $pipe) { for ($i = 0; $i < 1000; $i++) { $pipe->set("key:$i", $i); }});
Pub / Sub
Laravel은 Redis publish 및 subscribe 명령어에 대한 편리한 인터페이스를 제공합니다. 이러한 Redis 명령어를 사용하면 지정된 "채널"에서 메시지를 수신할 수 있습니다. 다른 애플리케이션에서 또는 다른 프로그래밍 언어를 사용하여 채널에 메시지를 게시할 수 있으므로 애플리케이션과 프로세스 간의 쉬운 통신이 가능합니다.
먼저 subscribe 메서드를 사용하여 채널 수신기를 설정해 보겠습니다. subscribe 메서드를 호출하면 장기 실행 프로세스가 시작되므로 이 메서드 호출을 Artisan 명령어 내에 배치합니다:
<?php namespace App\Console\Commands; use Illuminate\Console\Command;use Illuminate\Support\Facades\Redis; class RedisSubscribe extends Command{ /** * 콘솔 명령어의 이름 및 서명입니다. * * @var string */ protected $signature = 'redis:subscribe'; /** * 콘솔 명령어 설명입니다. * * @var string */ protected $description = 'Redis 채널 구독'; /** * 콘솔 명령어를 실행합니다. */ public function handle(): void { Redis::subscribe(['test-channel'], function (string $message) { echo $message; }); }}
이제 publish 메서드를 사용하여 채널에 메시지를 게시할 수 있습니다:
use Illuminate\Support\Facades\Redis; Route::get('/publish', function () { // ... Redis::publish('test-channel', json_encode([ 'name' => 'Adam Wathan' ]));});
와일드카드 구독
psubscribe 메서드를 사용하면 모든 채널의 모든 메시지를 포착하는 데 유용할 수 있는 와일드카드 채널을 구독할 수 있습니다. 채널 이름은 제공된 클로저에 두 번째 인수로 전달됩니다:
Redis::psubscribe(['*'], function (string $message, string $channel) { echo $message;}); Redis::psubscribe(['users.*'], function (string $message, string $channel) { echo $message;});