본문으로 건너뛰기

Redis#

Redis는 캐시나 메시지 브로커로 흔히 사용되는, 가장 인기 있는 인메모리 데이터 구조 저장소 중 하나입니다.

이 라이브러리는 Vapor와 RediStack 사이의 통합으로, RediStack은 Redis와 통신하는 기반 드라이버입니다.

Note

Redis의 기능 대부분은 RediStack에 의해 제공됩니다. RediStack의 문서를 잘 숙지하는 것을 적극 권장합니다.

관련 링크는 적절한 위치에 제공됩니다.

패키지#

Redis를 사용하는 첫 번째 단계는 Swift 패키지 매니페스트에 의존성으로 추가하는 것입니다.

이 예제는 기존 패키지를 대상으로 합니다. 새 프로젝트를 시작하는 방법은 메인 시작하기 가이드를 참고하세요.

dependencies: [
    // ...
    .package(url: "https://github.com/vapor/redis.git", from: "4.0.0")
]
// ...
targets: [
    .target(name: "App", dependencies: [
        // ...
        .product(name: "Redis", package: "redis")
    ])
]

설정#

Vapor는 RedisConnection 인스턴스에 대해 풀링 전략을 사용하며, 개별 연결뿐만 아니라 풀 자체를 설정할 수 있는 다양한 옵션을 제공합니다.

Redis를 설정하는 데 필요한 최소한의 사항은 연결할 URL을 제공하는 것입니다.

let app = Application()

app.redis.configuration = try RedisConfiguration(hostname: "localhost")

Redis Configuration#

API 문서: RedisConfiguration

serverAddresses#

Redis 인스턴스 클러스터와 같이 여러 Redis 엔드포인트가 있는 경우, 대신 초기화 메서드에 전달할 [SocketAddress] 컬렉션을 생성해야 합니다.

SocketAddress를 생성하는 가장 일반적인 방법은 makeAddressResolvingHost(_:port:) 정적 메서드를 사용하는 것입니다.

let serverAddresses: [SocketAddress] = [
  try .makeAddressResolvingHost("localhost", port: RedisConnection.Configuration.defaultPort)
]

단일 Redis 엔드포인트의 경우, 편의 초기화 메서드를 사용하는 것이 더 편할 수 있습니다. 이 메서드가 알아서 SocketAddress를 생성해주기 때문입니다.

password#

Redis 인스턴스가 비밀번호로 보호되어 있다면, 이를 password 인자로 전달해야 합니다.

각 연결은 생성될 때 이 비밀번호를 사용하여 인증됩니다.

database#

이는 각 연결이 생성될 때 선택하고자 하는 데이터베이스 인덱스입니다.

이를 통해 직접 Redis에 SELECT 명령을 보내지 않아도 됩니다.

Warning

데이터베이스 선택 상태는 유지되지 않습니다. 직접 SELECT 명령을 보낼 때는 주의하세요.

연결 풀 옵션#

API 문서: RedisConfiguration.PoolOptions

Note

여기서는 가장 흔히 변경되는 옵션만 다룹니다. 전체 옵션은 API 문서를 참고하세요.

minimumConnectionCount#

이는 각 풀이 항상 유지하기를 원하는 연결 개수를 설정하는 값입니다.

값이 0이면, 어떤 이유로든 연결이 끊어졌을 때 풀은 필요할 때까지 연결을 다시 생성하지 않습니다.

이를 “콜드 스타트(cold start)” 연결이라고 하며, 최소 연결 개수를 유지하는 것보다 약간의 오버헤드가 발생합니다.

maximumConnectionCount#

이 옵션은 최대 연결 개수가 유지되는 방식을 결정합니다.

Seealso

사용 가능한 옵션을 확인하려면 RedisConnectionPoolSize API를 참고하세요.

명령 보내기#

모든 Application 또는 Request 인스턴스의 .redis 속성을 사용하여 명령을 보낼 수 있으며, 이를 통해 RedisClient에 접근할 수 있습니다.

모든 RedisClient는 다양한 Redis 명령에 대한 여러 확장 기능을 제공합니다.

let value = try app.redis.get("my_key", as: String.self).wait()
print(value)
// Optional("my_value")

// or

let value = try await app.redis.get("my_key", as: String.self)
print(value)
// Optional("my_value")

지원되지 않는 명령#

RediStack이 확장 메서드로 특정 명령을 지원하지 않더라도, 여전히 수동으로 보낼 수 있습니다.

// each value after the command is the positional argument that Redis expects
try app.redis.send(command: "PING", with: ["hello"])
    .map {
        print($0)
    }
    .wait()
// "hello"

// or

let res = try await app.redis.send(command: "PING", with: ["hello"])
print(res)
// "hello"

Pub/Sub 모드#

Redis는 “Pub/Sub” 모드에 진입할 수 있는 기능을 지원합니다. 이 모드에서는 연결이 특정 “채널”을 구독(listen)하고, 구독한 채널이 “메시지”(어떤 데이터 값)를 발행(publish)할 때 특정 클로저를 실행할 수 있습니다.

구독에는 정의된 생명주기가 있습니다.

  1. subscribe: 구독이 처음 시작될 때 한 번 호출됩니다

  2. message: 구독한 채널에 메시지가 발행될 때마다 0회 이상 호출됩니다

  3. unsubscribe: 요청에 의해서든 연결 끊김에 의해서든, 구독이 종료될 때 한 번 호출됩니다

구독을 생성할 때는, 구독한 채널이 발행하는 모든 메시지를 처리할 messageReceiver를 최소한 제공해야 합니다.

선택적으로 각 생명주기 이벤트를 처리할 onSubscribeonUnsubscribe를 위한 RedisSubscriptionChangeHandler를 제공할 수도 있습니다.

// creates 2 subscriptions, one for each given channel
app.redis.subscribe
  to: "channel_1", "channel_2",
  messageReceiver: { channel, message in
    switch channel {
    case "channel_1": // do something with the message
    default: break
    }
  },
  onUnsubscribe: { channel, subscriptionCount in
    print("unsubscribed from \(channel)")
    print("subscriptions remaining: \(subscriptionCount)")
  }
이 페이지 편집