Upstash는 AWS Lambda 함수에 가장 적합한 데이터베이스가 되겠다는 미션으로 여정을 시작했습니다. 그 과정에서 우리는 서버리스 함수를 구축할 수 있는 또 다른 강력한 선택지, 바로 Cloudflare Workers를 발견했습니다. 전 세계 어디서나 더 나은 지연 시간을 보장하면서도 비용은 낮고 콜드 스타트(cold start)조차 없다는 점에서 매우 매력적인 제품입니다. 다만 AWS Lambda에 비해 여러 제약 사항이 있고, 이러한 제약은 사용 가능한 데이터베이스 선택지를 더욱 좁게 만듭니다. 우리는 이를 기회로 삼아 Upstash를 다음 질문에 대한 최적의 해답으로 자리매김하고자 했습니다. Cloudflare Workers는 상태를 저장하지 않습니다(stateless). 그렇다면 데이터는 어디에 보관해야 할까요?
Cloudflare Workers 환경의 세 가지 과제
접근성(Accessibility)
Cloudflare Workers는 AWS보다 폐쇄적인 환경입니다. AWS처럼 같은 리전에 직접 데이터베이스를 구축하고 VPC를 통해 접속할 수 없으며, 반드시 Workers 함수 내부에서 외부 데이터베이스에 접근해야 합니다. Cloudflare Workers는 V8 Isolate를 런타임으로 사용하기 때문에 TCP 연결이 허용되지 않으므로, 데이터베이스는 HTTP를 통해 접근 가능해야 합니다.
글로벌 복제(Global Replication)
Workers의 가장 큰 장점은 전 세계 어디든 배포될 수 있다는 것입니다. 함수 자체는 전 세계에서 낮은 지연 시간으로 접근할 수 있지만, 데이터베이스 접근에 수백 밀리초가 소요된다면 그 장점이 무색해집니다. 데이터베이스는 함수가 실행되는 위치와 가까워야 하며, 이는 데이터를 여러 리전과 대륙에 복제함으로써 실현할 수 있습니다.
낮은 지연 시간(Low Latency)
개발자들이 엣지 컴퓨팅 솔루션을 선호하는 이유는 어디서든 낮은 지연 시간을 제공하기 때문입니다. 데이터베이스가 병목 지점이 되어서는 안 됩니다. Redis와 같은 인메모리 데이터베이스는 밀리초 미만(sub-millisecond)의 지연 시간을 제공합니다.
Upstash의 여정
REST API
Upstash는 네이티브 Redis API 지원과 함께 출시되었습니다. 모든 Redis 클라이언트를 지원하기 때문에 기존 레거시 Redis 애플리케이션에도 완벽하게 동작합니다. 그러나 곧 서버리스 함수 환경에서 연결 문제를 겪는 사용자들이 늘어났고, Cloudflare Workers에서는 아예 접근조차 불가능했습니다.
이에 우리는 먼저 GraphQL API를 구현했습니다. 하지만 프록시 레이어로 인한 성능 오버헤드가 부담스러웠고, Redis 명령어를 실행하는 방법으로서 GraphQL 역시 가장 간편한 방식은 아니었습니다. 결국 성능 오버헤드를 최소화하기 위해 데이터베이스 엔진 내부에 REST 서버를 직접 구축하기로 결정했습니다. 우리는 REST가 Redis에 더 잘 어울린다고 믿습니다. REST API 출시 후, Cloudflare Workers나 WebAssembly에서 Redis에 접근하려는 개발자들 사이에서 큰 호응을 얻었습니다.
엣지 캐싱(Edge Caching)
REST API 덕분에 Workers에서 Upstash에 접근할 수 있게 되었지만, 지연 시간은 여전히 만족스럽지 않았습니다. 일부 개발자들은 Cloudflare의 자체 캐싱 기능으로 Redis 응답을 캐시하려 했지만 상당히 복잡한 방법이었습니다. 애초에 Redis는 충분히 빠르기 때문에 이를 다른 곳에 캐시하는 구조는 어색하게 느껴졌습니다. 그래서 우리는 모든 엣지 로케이션에서 Redis REST 응답을 캐시하는 엣지 캐싱 기능을 개발했습니다. CDN 제공사를 활용해 Redis 응답을 캐싱한 결과, 엣지 지연 시간이 크게 개선되어 최대 80%의 성능 향상을 달성했습니다.
글로벌 데이터베이스(Global Database)
엣지 캐싱은 글로벌 지연 시간 문제에 대한 훌륭한 해결책이지만, 일부 사용 사례에서는 한계가 있었습니다. 첫째, 캐시 무효화(purge)를 지원하지 않습니다. 캐시 만료 시간이 30초라면 클라이언트가 30초 동안 오래된(stale) 데이터를 읽을 수 있는 구간이 생깁니다. 많은 웹 사용 사례에서는 감수할 수 있지만 모든 경우에 그렇지는 않습니다. 둘째, 엣지 캐싱은 REST API에서만 지원되므로 Redis 클라이언트 사용자는 그 혜택을 받을 수 없습니다.
그래서 우리는 데이터를 여러 리전에 복제하는 새로운 데이터베이스 유형을 설계했습니다. 높은 가용성과 충분한 일관성을 갖추도록 설계하는 것은 매우 어려운 작업이었습니다. 현재 Upstash는 데이터를 5개의 AWS 리전(북미 동부·서부, 유럽, 아시아, 남미)에 복제하는 글로벌 데이터베이스를 제공합니다. 글로벌 데이터베이스는 캐시가 아니기 때문에 캐시 무효화 문제가 없으며, 쓰기 작업은 즉시 모든 복제본에 전파됩니다. 성능과 가용성을 위해 글로벌 데이터베이스는 최종 일관성(eventual consistency) 모델로 설계되었습니다.
엣지 캐싱 vs 글로벌 데이터베이스 (또는 둘 다)
엣지 솔루션에 단순한 캐시만 필요하다면 엣지 캐싱이 좋은 선택이 될 수 있습니다. 하지만 쓰기 작업이 즉시 캐시를 무효화하길 원한다면 글로벌 데이터베이스를 선택해야 합니다. 또한 캐싱 용도 외에도 글로벌 데이터베이스는 고가용성 글로벌 데이터 스토어로 활용할 수 있습니다. 엣지 캐싱은 REST 호출에서만 지원된다는 점도 기억하세요. Redis 클라이언트를 사용한다면 엣지에서 낮은 지연 시간을 얻을 수 있는 유일한 방법은 글로벌 데이터베이스입니다.
두 기능 모두 읽기 지연 시간을 최소화하도록 설계되었습니다. 사용 사례의 90%가 쓰기 작업이라면 단일 리전 구성이 더 합리적입니다. 쓰기 지연 시간은 멀티 리전과 단일 리전 데이터베이스가 동일하지만, 글로벌 구성에서는 비용이 5배 더 많이 듭니다.
엣지 캐싱이 활성화되면 Upstash는 첫 번째 요청을 오리진(origin)에서 가져온 뒤 엣지에 캐시합니다. 오리진이 가까이 있지 않다면 첫 요청의 지연 시간이 높을 수 있습니다. 모든 경우에 최상의 지연 시간을 원한다면 글로벌 데이터베이스에서 엣지 캐싱을 함께 활성화하는 방법도 있습니다.
엣지 캐싱과 글로벌 데이터베이스의 지연 시간을 비교하는 벤치마크 애플리케이션도 참고해 보세요.
앞으로의 계획
엣지 환경에서 Upstash를 더욱 개선하기 위해 준비 중인 과제는 다음과 같습니다:
- 낮은 쓰기 지연 시간: 현재 글로벌 데이터베이스는 단일 리더(single leader) 아키텍처로 읽기 지연 시간에 최적화되어 있습니다. 이것이 대부분의 사용 사례를 커버한다고 판단하지만, 피드백과 새로운 사용 사례에 따라 쓰기 역시 낮은 지연 시간을 제공하는 아키텍처를 검토할 예정입니다.
- Kafka 지원: 몇 주 안에 Redis에 더해 Kafka도 출시할 계획입니다. Kafka는 클릭스트림 분석, 서버리스/엣지 함수에서 Kafka로 로그를 전송하는 등 새로운 엣지 사용 사례를 열어줄 것입니다.
여러분의 피드백에 귀 기울이며 Upstash를 지속적으로 발전시켜 나가겠습니다. Twitter나 Discord를 통해 자유롭게 의견을 들려주세요.