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

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

이번 글에서는 Upstash Redis, AWS Lambda(Python), 그리고 AWS API Gateway를 기반으로 서버리스 URL 단축 서비스를 구축하는 전 과정을 안내합니다. 이 튜토리얼의 핵심 목표는 Python으로 Lambda 함수를 작성하고, 이를 Redis에 연결한 뒤, API를 통해 해당 기능을 외부에서 사용할 수 있도록 만드는 것입니다.

완성된 프로젝트의 실제 구현 결과는 다음 링크에서 확인할 수 있습니다: URL Shortener

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

참고: 아래에서 보여주는 출력 URL은 데모용입니다. 실제 운영되는 URL 단축 서비스라면 더 짧고 간결한 도메인 주소를 사용하게 되므로, 여기서는 기능 구현 자체에 집중하겠습니다.

프로젝트 개요

이 프로젝트는 Upstash Redis 데이터베이스 하나, 두 개의 Python Lambda 함수, 그리고 AWS API Gateway 하나로 구성됩니다. 사용자는 웹 인터페이스 또는 API를 통해 단축 서비스를 이용할 수 있습니다.

shortener Lambda 함수는 HTTP 요청 쿼리로 전달된 긴 URL(long URL)로부터 단축된 URL 키를 생성합니다. 그런 다음 이 짧은 URL 키와 원본 URL 값을 Upstash Redis에 저장하고, 완성된 단축 URL을 사용자에게 반환합니다.

redirector Lambda 함수는 사용자를 단축 URL에서 원본 URL로 리디렉션하는 역할을 담당합니다. Redis에서 단축 URL 키에 매핑된 원본 URL을 조회한 후, HTTP 302 리디렉션 응답을 사용자 브라우저로 전송합니다. 덕분에 사용자는 긴 URL을 기억하거나 직접 입력할 필요 없이 원하는 콘텐츠에 바로 접근할 수 있습니다.

마지막으로 Lambda 함수들을 호출할 수 있도록 API Gateway를 생성하고, 이 API를 기본적인 URL 단축기 프론트엔드와 연결하겠습니다.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

Upstash Redis 설정하기

Redis 데이터베이스는 Upstash 콘솔에서 손쉽게 생성할 수 있습니다. 로그인 후 Create Database 버튼을 클릭하면 몇 초 만에 데이터베이스가 준비됩니다. 이후 Details 섹션에서 UPSTASH_REDIS_REST_HOST, UPSTASH_REDIS_REST_PORT, UPSTASH_REDIS_REST_PASSWORD 변수를 복사해 파일에 저장해 둡니다. 이 값들은 곧 AWS 환경 변수로 등록하게 됩니다.

AWS Lambda에서 서버리스 함수 만들기

다음으로 서버리스 Python 함수를 생성합니다. AWS에 로그인한 뒤 AWS Lambda 대시보드로 이동하여 새 Lambda 함수를 만들어 주세요.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

URL 단축용 Lambda 함수

가장 먼저 할 일은 환경 변수를 추가하는 것입니다. shortener 함수 개요 화면에서 Configuration > Environment variables > Edit > Add environment variable로 이동하세요. 그런 다음 키로 UPSTASH_REDIS_REST_HOST, UPSTASH_REDIS_REST_PORT, UPSTASH_REDIS_REST_PASSWORD를 입력하고, 값에는 Upstash 콘솔에서 복사한 해당 값들을 넣어줍니다.

이제 코딩을 시작할 차례입니다. shortener 함수의 Code 섹션으로 돌아가 아래 코드를 붙여넣으세요. 이 코드는 Upstash Redis 데이터베이스와의 연결을 담당합니다.

import random
import string
import json
import redis
 
#Create a redis client.
redis_client = redis.Redis(
 host= UPSTASH_REDIS_REST_HOST,
 port= UPSTASH_REDIS_REST_PORT,
 password= UPSTASH_REDIS_REST_PASSWORD
)

그다음 메인 단축 알고리즘을 구현합니다. 아래 코드 스니펫이 수행하는 작업은 다음과 같습니다.

  • API 요청 URL에서 쿼리 파라미터 long_url을 가져옵니다.
  • 단축 URL에 사용할 무작위 7자리 키를 생성합니다.
  • Upstash Redis에 해당 키의 값으로 원본 URL을 저장합니다.
  • 응답 본문에 완성된 단축 URL을 담아 HTTP 200 응답을 반환합니다.

Redis 클라이언트 생성 코드 바로 아래에 generate_short_urllambda_handler 함수를 추가하세요.

def generate_short_url():
 # Define the character set for generating the short URLs
 CHARSET = string.ascii_letters + string.digits
 
 # Generate a random short URL using the character set
 short_url = ''.join(random.choice(CHARSET) for _ in range(7))
 
 # Check if the short URL already exists in Redis
 if redis_client.exists(short_url):
 # If it does, recursively generate a new short URL
 return generate_short_url()
 
 # Otherwise, return the new short URL
 return short_url
 
 
def lambda_handler(event, context):
 long_url = event["queryStringParameters"]['long_url']
 
 base_url = f"https://{event['headers']['Host'] }/{event['requestContext']['stage']}/"
 
 # Generate a unique short URL
 short_url_key = generate_short_url()
 
 # Store the mapping between the short URL and long URL in Redis
 redis_client.set(short_url_key, long_url)
 
 # Return the short URL to the client
 response_body = {
 'short_url' : base_url + short_url_key,
 }
 
 response={
 'statusCode' : 200,
 'headers' : {'ContentType':'application/json',
 "Access-Control-Allow-Origin": "*"},
 'body' : json.dumps(response_body)
 }
 
 return response

이후 Deploy 버튼을 클릭해 배포합니다. 코드가 준비되었더라도 지금 바로 Lambda를 테스트하면 아래와 같은 오류 응답을 받게 됩니다.

Unable to import module 'lambda_function': No module named 'redis'

그 이유는 외부 Python 라이브러리를 사용하려면 라이브러리를 커스텀 패키지 형태로 만들어 Lambda에 연결해야 하기 때문입니다. 해결 방법은 여러 가지가 있지만, 저는 Lambda Layers(레이어)를 사용하는 방법을 추천합니다. 겁먹지 마세요. 생각보다 아주 간단한 과정입니다.

레이어(Layer) 생성하기

먼저 패키지를 생성하고 압축해야 합니다. 로컬 터미널에서 아래 명령어를 순서대로 실행하세요. 이렇게 하면 Redis가 설치된 requirements-package.zip 파일이 packages 폴더 안에 생성됩니다.

mkdir packages
cd packages
python3 -m venv venv
source venv/bin/activate
 
mkdir python
cd python
pip install redis -t .
 
rm -rf *dist-info
cd..
zip -r requirements-package.zip python

이제 AWS의 shortener 함수로 돌아가 사이드바에서 Layers 메뉴로 이동하세요. Create layer를 클릭한 후 필요한 설정을 입력하고 requirements-package.zip 파일을 업로드하면 됩니다. 아래 예시와 같이 진행하면 됩니다.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

레이어가 생성되었다면, 이 레이어를 shortener 함수에 연결해야 합니다. 함수의 Layers 섹션으로 이동해 Add a layer 버튼을 클릭하세요.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

이제 URL 단축 기능이 정상적으로 동작합니다. 남은 작업은 short_url 키로 원본 URL을 조회해 브라우저를 해당 주소로 리디렉션하는 것입니다. 이를 위해 redirector Lambda 함수를 만들겠습니다.

URL 리디렉션용 Lambda 함수

redirector Lambda를 만드는 과정은 앞서 설명한 내용과 동일합니다. 단계를 다시 정리하면 다음과 같습니다.

  • Lambda 대시보드에서 redirector라는 이름의 함수를 생성합니다.
  • 환경 변수를 설정합니다.
  • 아래에 제공된 코드를 입력합니다.
  • requirements-package.zip 파일로 레이어를 생성합니다. (이 경우 요구 사항이 같으므로 앞서 만든 redis-library-layer를 재사용해도 됩니다.)
  • 해당 레이어를 Lambda 함수에 추가합니다.

아래는 redirector Lambda의 핵심 알고리즘입니다.

import json
import redis
 
#Create a redis client.
redis_client = redis.Redis(
 host= UPSTASH_REDIS_REST_HOST,
 port= UPSTASH_REDIS_REST_PORT,
 password= UPSTASH_REDIS_REST_PASSWORD
)
 
def lambda_handler(event, context):
 # Get the short URL from the request path
 short_url = event['pathParameters']['short_url']
 
 # Look up the long URL associated with the short URL in Redis
 long_url = redis_client.get(short_url).decode('utf-8').strip('"')
 
 long_url = format_url_for_redirection(long_url)
 
 # If the short URL doesn't exist, return a 404 error
 if not long_url:
 response = {
 'statusCode': 404,
 'body': json.dumps({'error': 'Short URL not found'})
 }
 return response
 
 # Otherwise, redirect the user to the long URL
 response = {
 'statusCode': 302,
 'headers' : {'Location':long_url},
 'body' : ''
 }
 return response
 
 
def format_url_for_redirection(url):
 if not url.startswith("https://") and not url.startswith("https://"):
 url = "https://" + url
 return url

이것으로 모든 Lambda 함수가 준비되었습니다! 기능 자체는 동작하지만, 이 URL 단축기를 누구나 접근 가능한 서비스로 만들려면 Lambda를 호출할 방법이 필요합니다. Lambda 함수를 실행하는 방법은 여러 가지가 있지만, 이번 구현에서는 AWS API Gateway를 사용하겠습니다.

AWS에서 API Gateway 생성하기

먼저 AWS 콘솔에서 API Gateway로 이동합니다. 대시보드에서 Create API 버튼을 클릭하고 REST API를 빌드하세요. 기본 설정만 마치면 몇 초 안에 API가 생성됩니다.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

다음으로 API Gateway를 Lambda 함수들과 연결해야 합니다. Resources 섹션에서 Actions > Create Resource로 이동한 뒤 resource nameresource path를 입력하세요.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

그다음 Resources에서 /shortener 경로를 클릭하고 Actions > Create Method > GET 선택 > Confirm 순서로 진행합니다. 이 부분이 꽤 중요합니다. 이 설정을 통해 API Gateway에서 Lambda 함수로 요청 데이터를 전달할 수 있기 때문입니다. 설정값을 반드시 정확히 확인하세요!

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

여기까지 하면 shortener 함수가 API에 연결되어 URL 단축이 가능해집니다. 하지만 서비스가 제대로 작동하려면 redirector Lambda 함수도 API에 연결해야 합니다. Resources에서 /를 클릭한 뒤 Actions > Create Resource로 이동하세요.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

이어서 Resources 섹션에서 /{short_url}을 클릭한 후 Actions > Create Method > GET 선택 > Confirm을 진행합니다.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

드디어 API 설정이 끝났습니다. 마지막 단계는 API 배포입니다. Actions > Deploy API > Create New Stage로 이동해 필수 항목을 입력하고 배포하세요. 이제 공개 API가 준비되었습니다. Stages 섹션에서 해당 API의 공개 Invoke URL을 확인할 수 있습니다.

마지막으로 남은 작업은 serverless-shortener-API 게이트웨이를 통해 Lambda 함수들을 트리거하도록 연결하는 것입니다.

shortener Lambda 함수로 이동한 뒤, Function overview 섹션에서 Add Trigger 버튼을 클릭하세요.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

두 함수 모두에 트리거를 추가하면 공개 API와 Lambda 함수가 모두 사용 가능한 상태가 됩니다. shortener 함수의 호출 URL 경로는 다음과 같습니다.

<YOUR_INVOKE_URL>/shortener?short_url="<LONG_URL>"

redirector 함수를 호출하려면 shortener 함수의 응답 결과가 필요합니다. redirector의 호출 URL은 아래 구조를 따릅니다.

<YOUR_INVOKE_URL>/<SHORT_URL_KEY>

이 주소를 클릭하거나 HTTP 요청을 보내면 원본 URL로 리디렉션됩니다.
사실상 여기서 서비스는 이미 완성된 상태지만, 마무리로 멋진 포인트를 더해 웹 인터페이스를 만들어 보겠습니다.

웹 인터페이스 만들기와 함수 사용 처리

프론트엔드는 HTML, Bootstrap, JavaScript를 사용해 구현합니다. 사용자가 URL을 입력하고 Shorten 버튼을 클릭하면 단축 URL이 화면에 표시되며, 해당 링크를 클릭하면 원래 웹사이트로 이동합니다.

AWS Lambda, Python, Upstash Redis로 서버리스 URL 단축기 구축하기

몇 가지 요소로 이루어진 아주 간단한 웹사이트입니다. 먼저 Bootstrap 기능을 사용하기 위해 HTML 코드의 <head> 블록에 아래 한 줄을 추가하세요.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"/>

<body> 블록 안에는 핵심 HTML 요소들이 들어갑니다.

<div class="container mt-5">
 <h1 class="mb-4 text-center">URL Shortener</h1>
 <div class="row justify-content-center">
 <div class="col-md-6">
 <div class="input-group mb-3">
 <input
 type="text"
 class="form-control"
 id="url-input"
 placeholder="Enter URL to shorten"
 />
 <div class="input-group-append">
 <button class="btn btn-primary" type="button" id="shorten-btn">
 Shorten
 </button>
 </div>
 </div>
 <a id="short-url" class="d-none"></a>
 </div>
 </div>
</div>

요소들을 추가했다면 이제 API Gateway에서 데이터를 가져오는 부분만 남았습니다. 이 작업은 JavaScript로 처리합니다. <body> 태그가 끝나기 전에 아래 URL 페칭(fetching) 기능을 삽입하세요. <INVOKE_URL>은 반드시 본인의 AWS API Gateway Invoke URL로 교체하는 것을 잊지 마세요.

<!-- Add Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
 
<!-- Add custom JS -->
<script>
 const shortenBtn = document.getElementById("shorten-btn");
 const urlInput = document.getElementById("url-input");
 const urlOutput = document.getElementById("short-url");
 
 shortenBtn.addEventListener("click", async function () {
 let long_url = urlInput.value;
 const apiUrl = `<INVOKE_URL>/shortener?long_url="${long_url}"`;
 const response = await fetch(apiUrl);
 const data = await response.json();
 shortUrl = data.short_url;
 
 urlOutput.innerHTML = shortUrl;
 urlOutput.href = shortUrl;
 urlOutput.classList.remove("d-none");
 });
</script>

마치며: 프로젝트 발전 아이디어

지금까지 서버리스 URL 단축기 프로젝트의 핵심 기능을 모두 구현했습니다. Python으로 Lambda 함수를 만들고 이를 소비하는 과정이 명확하게 전달되었기를 바랍니다. 이 프로젝트를 계속 발전시키고 싶다면 아래 개선 아이디어도 참고해 보세요.

  • 커스텀 도메인 설정: AWS에서 제공하는 Invoke URL은 다소 복잡합니다. 이 글의 목적이 AWS Lambda와 Upstash Redis 시연에 있었기 때문에 다루지 않았지만, AWS API Gateway에서 URL을 더 짧고 단순한 형태로 변경할 수 있습니다.
  • Upstash Rate Limit 적용: 이 프로젝트는 프리티어(free tier) 서비스로 구현했습니다. 하지만 실제 공개 서비스로 운영할 계획이라면 예상치 못한 비용을 막기 위해 요청 제한(rate limit) 설정을 반드시 고려하세요.
  • Vercel 호스팅: 프론트엔드를 Vercel에 배포하면 더욱 완성도 높은 서비스를 만들 수 있습니다.

끝까지 읽어주셔서 감사합니다!