Computer >> 컴퓨터 >  >> 프로그래밍 >> Redis

성능과 비용으로 본 Deno KV vs Upstash Redis 완벽 비교

약 2주 전에 Cloudflare KV와 Upstash Redis의 성능 및 비용을 비교한 글을 소개한 적이 있습니다. 이번에는 Deno의 글로벌 엣지 네트워크에서 동작하는 네이티브 키-값 스토어인 Deno KV를 살펴보겠습니다.

Deno KV는 아키텍처 측면에서 Upstash Redis와 상당히 유사합니다. 두 서비스 모두 모든 쓰기 요청이 전달되는 기본 리전(primary region)이 있고, 해당 데이터가 다른 모든 리전으로 복제됩니다. 읽기는 클라이언트에서 가장 가까운 리전에서 처리됩니다.

다만 Redis는 KV에 없는 다양한 기능을 제공하기 때문에 사용 가능한 기능 면에서는 차이가 많습니다. 이번 글에서는 단순한 읽기와 쓰기 성능에만 집중해서 비교해 보겠습니다.

두 가지 벤치마크를 진행하며, 두 테스트 모두 Deno Deploy에서 코드를 실행했습니다. 두 경우 모두 KV 스토어와 Redis에서 사용 가능한 모든 읽기 리전을 활성화한 상태로 진행했습니다.

  1. planetfall.io를 활용해 전 세계 20개 리전에서 함수 호출
  2. 단일 리전에서 훨씬 높은 부하로 함수 호출

테스트가 끝나면 결과를 비교하고, 각각의 트레이드오프와 가격 정책도 함께 논의하겠습니다.

벤치마크 환경

테스트 환경은 Cloudflare 버전과 사실상 동일하며, Deno KV를 사용하도록 일부 수정한 구성입니다.

  • 키 1,000개
  • 데이터 크기 4KB ~ 64KB (랜덤)
  • 모든 키에 60초 TTL 적용
  • 함수를 호출하는 리전 20개
  • 초당 약 10개 요청(RPS)

RPS를 과도하게 높이지 않고도 캐시 히트가 발생할 수 있도록 의도적으로 작은 키스페이스를 선택했습니다.

테스트 코드

함수 자체는 매우 단순합니다. Redis에서 값을 읽고, KV에서도 값을 읽은 뒤, 두 지연 시간을 반환하여 나중에 평가하는 방식입니다.

app.get("/test", async (c) => {
  const key = Math.floor(Math.random() * 1_000).toString()
  const minValueSize = 4 * 1024
  const maxValueSize = 64 * 1024

  const data = randomBytes(minValueSize, maxValueSize)

  const ttlSeconds = 60

  const beforeRedis = performance.now()
  const redisResponse = await fetch(Deno.env.get("UPSTASH_REDIS_REST_URL")!, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${Deno.env.get("UPSTASH_REDIS_REST_TOKEN")}`,
    },
    body: JSON.stringify(["GET", key])
  })
  const redisLatency = performance.now() - beforeRedis

  if (!redisResponse) {
    await fetch(Deno.env.get("UPSTASH_REDIS_REST_URL")!, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${Deno.env.get("UPSTASH_REDIS_REST_TOKEN")}`,
      },
      body: JSON.stringify(["SET", key, data, "EX", ttlSeconds])
    })
  }

  const kv = await Deno.openKv();

  const beforeKV = performance.now()
  const kvResponse = await kv.get([key])
  const kvLatency = performance.now() - beforeKV
  if (!kvResponse.value) {
    const setRes = await kv.set([key], data, { expireIn: ttlSeconds })
    console.log({ setRes })
  }

  return c.json({
    redisLatency,
    kvLatency,
  });
});

결과 1 - 글로벌 지연 시간

30분간 테스트를 진행한 결과입니다. 여기서 측정된 지연 시간은 Deno Deploy의 함수에서 스토어까지의 시간만 포함하며, 함수를 호출하는 네트워크 왕복 시간은 제외되었습니다.

구분Deno KVUpstash Redis
P90265ms76ms
P99494ms94ms

Deno KV가 데이터를 읽을 때 상당히 느린 것을 확인할 수 있습니다. 처음 든 생각은 아마 전 세계에 충분한 수의 읽기 리전이 분포하지 않아서가 아닐까 하는 것이었습니다.

벤치마크 당시 Deno KV의 리전은 gpc-us-east4, gcp-asia-southeast1, gcp-europe-west3, gcp-southamerica-east1, gcp-us-west2였습니다.

상당수 요청이 데이터를 가져오기 위해 여러 리전을 거쳐야 하는 것이 높은 지연 시간의 원인일 수 있습니다. 그렇다면 같은 클라우드, 심지어 같은 데이터센터 안에서 컴퓨팅과 스토리지를 모두 통제할 수 있다는 Deno의 강점이 사실상 무의미해집니다. 반면 Upstash는 AWS 위에서 운영되므로, Deno에서 Redis로 향하는 모든 요청은 클라우드 제공업체의 경계를 넘어야 합니다.

결과 2 - 단일 리전

이 가설을 검증하기 위해 두 번째 벤치마크를 진행했습니다. 이번에는 단일 위치(제 집)에서만 함수를 호출하고, 모든 요청이 프랑크푸르트를 경유하도록 했습니다. Deno KV와 Upstash Redis 모두 해당 위치에 읽기 복제본을 두고 있는데, 각각 GCP의 gcp-europe-west3, AWS의 eu-central-1입니다.

이 시나리오에서는 두 서비스 모두 훨씬 빨라졌지만, 여전히 Deno KV가 Upstash Redis보다 느렸습니다. 단일 리전 기준 지연 시간과, 괄호 안에는 글로벌 지연 시간 대비 개선 폭(델타)을 표시했습니다.

구분Deno KVUpstash Redis
P90132ms (-133)16ms (-60)
P99154ms (-340)26ms (-68)

154ms는 494ms보다 확실히 훨씬 낫지만, 이는 모든 트래픽이 단일 리전에서 온다는 전제 하에 가능한 수치입니다. 이는 글로벌 엣지 네트워크의 존재 의의와 정반대되는 상황입니다. 글로벌 API를 운영한다면 전 세계 곳곳에서 트래픽이 유입되며, KV의 데이터에 접근해야 하는 모든 요청이 이런 지연의 영향을 받게 됩니다.

가격 비교

Deno와 Upstash 모두 주로 사용량 기반으로 과금합니다. 두 서비스 모두 좋은 무료 티어를 제공하므로, 비용 없이 먼저 사용해 볼 수 있습니다.

구분Deno KVUpstash Redis
기본 요금$20/월 (읽기 리전 추가 시)무료
스토리지$0.50 / GB$0.25 / GB
읽기$1 / 백만 건 / 4KB$2 / 백만 건 (크기 무관)
쓰기$2.50 / 백만 건 / 1KB$2 / 백만 건 (크기 무관)
대역폭$0.50 / GB$0.03 / GB

가장 큰 차이점은 Deno의 가격 정책이 생각보다 투명하지 않다는 점입니다. 비용을 계산하려면 내 요청이 얼마나 큰지 미리 알아야 하기 때문입니다. Upstash는 모든 요청이 동일하게 과금되므로 이런 문제가 없습니다. 기본적으로 Upstash에서는 요청당 최대 1MB까지 읽거나 쓸 수 있으며, 고정 요금을 내면 이 한도를 늘릴 수도 있습니다.

결론적으로, 요청당 8KB 이상을 읽는 경우에는 대부분 Upstash 쪽이 더 저렴합니다.

결론

Deno KV는 같은 플랫폼에 있다는 점에서 사용 경험이 상당히 좋습니다. 별도의 계정을 관리할 필요가 없고, 추가 설정 없이 바로 사용할 수 있기 때문입니다. 하지만 성능과 비용 측면에서는 Upstash에 크게 미치지 못합니다.

또한 할 수 있는 작업의 폭도 제한적입니다. 값을 설정하고 가져오는 것이 가장 흔한 작업이긴 하지만, Redis로 할 수 있는 것이 전부는 아닙니다. 저희 예제들을 확인하시면 Redis를 활용할 수 있는 다양한 아이디어와 유스케이스를 찾을 수 있습니다.

Discord 또는 X(Twitter)로 놀러 오셔서 이 내용에 대해 궁금한 점을 자유롭게 물어보세요!