URL Shorter 제작기

d3fau1t·2022년 8월 23일
0

뻘짓

목록 보기
7/9
post-thumbnail

URL Shorter

특정 URL을 공유하다가 encode된 링크가 지저분해보여서 직접 짧은 도메인을 만들어놓고 연결시켜주는 프록시 서버를 구성하기로 했습니다.

이 문서는 어떤 의사결정을 하면서 서비스를 구성하였는가에 대한 내용이 기록되어있습니다.

필요한 기능

  • URL 단축
  • 단축된 URL의 원본 URL 확인
  • 단축된 URL로 원본 URL에 redirect

대표적으로 위와 같은 기능이 필요해보였고 나머지는 만든 이후에 고도화 하기로 했습니다.

개략적인 구성

웹 서버와 데이터베이스만 있으면 API 서버 자체만으로 서비스 할 수 있지만 사용자 편의성이 떨어집니다.

그런 이유로 SPA 형식의 웹 클라이언트를 작성하여 GUI를 제공하고 사용자가 컴포넌트를 조작하여 API를 호출하는 형식으로 구현하기로 했습니다.

1

여기까지의 내용은 위와 같은 구성을 가집니다.
흔히 알고있는 3-tier 구성으로 꽤 단순합니다.

API 서버

만들어놓고 누구나 사용할 수 있도록 클라우드 환경에 배포하기로 했는데
요청수가 그리 많지 않을 것 같기도 하고 사용안하는 시간동안 서버가 자원을 낭비하는건 맘에 안들어서
AWS Lambda에 API Gateway를 트리거로 구성하여 웹 서버를 구성하기로 했습니다.

2

다만 직접 콘솔에 붙어서 작성하고 설정할 필요 없이 코드만 작성하면 배포할 때 Cloud Formation 템플릿을 적용하여 클라우드 환경을 구성해주는 Serverless 프레임워크를 사용하기로 했습니다.

프레임워크에서 Flask, Node 등의 웹 애플리케이션 서버 템플릿을 제공해주지만, 그것들을 사용하지 않고 FastAPI + Mangum 조합을 사용하여 구성하기로 했습니다.

후보군에서 제외된 제품들

EC2 및 기타 VM 인스턴스
EC2의 경우 만들어서 올리고 요청만 받으면 되기에 제일 무난합니다만 인스턴스 성능을 올린다거나 사용하는만큼 비용이 발생하기 때문에 굳이 사용 안하는시간이 많은데 자원 낭비같아서 후보군에서 제외하였습니다.

Heroku
Heroku의 경우 무료 사용자에게도 컨테이너를 제공하지만 컴퓨팅 파워가 너무 낮다는 단점과 사용하지 않는경우 컨테이너가 종료되기 때문에 요청이 잦지 않은경우 콜드스타트 이슈를 맞이할 수 있었습니다.

물론 그러한 단점을 상쇄하기 위해 Kaffeine으로 컨테이너를 계속 깨워둘 수 있지만 무료사용자의 경우 하루 최대 18시간만 사용할 수 있기 때문에 할당량을 모두 사용하면 요청을 처리할 수 없다는 치명적인 단점이 있습니다.

그래서 이러한 이유로 7불짜리 플랜 하나를 결제하는 것이 컴퓨팅 파워도 어느정도 보장되고 좋습니다만.. 아시아에 위치한 엣지가 없어서 latency가 다소 높다는 단점이 있습니다.

웹 서버

API를 사용자가 직접 호출하여 사용할 수 있지만
사용자 편의성을 위해 유저 인터페이스를 제공할 필요가 있다고 생각했습니다.
Next.js 를 사용하여 페이지를 생성하기로 했습니다.

서버사이드 랜더링 이외에도 Gatsby등의 다른 정적페이지 생성 프레임워크가 해주는 것들을 다 커버하기도하고 이 외에도 제공하는 기능들이 강력하기 때문에 선택하였습니다.

코드도 간결하고 재미있어보이길래.. 이참에 Svelte도 해볼까? 라는 생각도 있었지만 공식문서가 불친절했고, 커뮤니티가 그리 크지 않아서 후보군에서 제외하였습니다.

3

이렇게되면 배포는 Vercel에 하는게 좋겠다는 생각이 들었습니다.

AWS로 배포하는경우엔 웹서버를 VM에 올려놓고 서버에서 랜더링 해둔 페이지를 Cloudfront로 캐싱해줘야합니다.

캐싱하지않으면 매 접속마다 랜더링 조건이 달라질 때마다 페이지를 다시 그려주어서 성능이슈가 발생할 수도 있고 이 외의 신경쓰지 못한부분에서 이슈가 발생할 가능성이 있는데 이러한 이유로 개발 피로도가 늘어나게됩니다.

당연한 내용인 것 같지만 Vercel은 이러한 부분들을 해소해주는 기능들을 포함하고있기도 하고 이외에 편의기능들이 다양하여 개발자가 오로지 개발에만 신경쓸 수 있다는 것이 장점으로 와닿는 것 같습니다.

심지어 개인사용 목적의 취미용 프로젝트엔 비용이 부과되지 않기 때문에 호스팅 비용걱정을 안해도 되는점이 좋았습니다.

Next.js를 만든 조직에서 운영하는 배포 플랫폼? 사용안할 이유가 없어보입니다.

위와 같은 이유로 Netlify, Github Pages 및 기타 다른 배포 플랫폼은 후보군에서 밀렸습니다.

데이터베이스

사실 이부분에서 조금 갈등된 것 같습니다.

MySQL, PostgreSQL 같은 관계형 데이터베이스

vs

MongoDB, Redis 같은 NoSQL 데이터베이스

유저에게 URL을 받아서 생성한 Unique ID와 매핑하고 Unique ID와 조합한 리디레션 링크를 내어준다라고 할 때, 어떤 데이터 구조를 사용해야할까? 라는 생각이 들었습니다.

관계형 데이터베이스에서는 아래와 같이 스키마를 생성할 것 같습니다.

CREATE TABLE url_map (
  id VARCHAR(10) PRIMARY KEY,
  url VARCHAR(255) NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
  • 유저가 원본 URL을 넘겨주면 Unique ID를 만들고 row를 한줄 추가한다.
  • 한 테이블 안에 id와 url이 1:1 매핑되어있기 때문에 url이나 id중 하나만 알아도 서로를 참조할 수 있다.
    • 다만 테이블 크기가 커졌을 때 unique하지 않은 url 컬럼을 기준으로 id를 찾는경우 비효율적일 것 같다.
  • 서비스가 정말 잘되서 id 길이가 너무 늘어날 것을 대비한다면..
    • created_at 기준으로 일정기간이 지난 row를 트리거로 날려버린다거나
    • 다른 row가 추가될때 삭제하는 스크립트를 끼워넣는다거나
    • created_at 기준으로 일정기간 이후에 row를 날려버리는 배치작업을 할 수 있다.

그리고.. 테이블 하나밖에 안쓸건데 굳이 DBMS를 써야하나? 라는 생각도 듭니다.

이럴거면 파일이나 메모리에 저장하는편이 괜찮겠다는 생각도 듭니다.

파일의 경우엔 서비스중에 생성되었다가 인스턴스가 다시 부팅되면서 사라지기 때문에 스토리지에 백업하는 기능을 같이 구현해야하는 번거로움이 있습니다. 그래서 서버리스 아키텍처에서는 더욱이 좋은 선택은 아닌 것 같습니다.

위와같은 이유로 Redis를 연결하여 사용하려고합니다만..

URL과 생성된 Unique ID 사이의 관계를 형성하기위해 아래와 같이 두개의 map을 만들어 사용할 수 있을 것 같아보입니다.

{
  "aX": "https://my.z1p.link",
}

{
  "https://my.z1p.link": "aX",
}

Value를 전달하여 Key를 찾을 수 있는 기능이 있다면 굳이 두개씩 만들어놓지 않을텐데, 그럴 수 없어서 이렇게 하는게 좋겠다고 생각했습니다.

그래도 메모리기반이다보니 성능은 보장될 것 같아서 이정도면 나쁘지 않겠다고 타협하였습니다.

메모리기반 데이터베이스니까 서버에서 장애가 생겨서 다시 부팅되거나 했을 때 데이터가 다 날아가지 않는가? 라는 생각도 할 수 있지만 AOF 기능을 사용하면 이런 상황을 방지할 수 있습니다.

AOF: Append Only File, 레디스 서버에서 파일형식으로 백업해두는 기능

4

그래서 Redis에서 운영하는 공식 클라우드를 사용하기로 했습니다.

5

무료사용자는 30MB의 메모리를 사용할 수 있고, 버전도 그리 낮은편이 아니어서 쓸만해보입니다.

Chrome Extension

원래 이건 계획에 없었는데 만들어보면 좋겠다는 생각이 문득 들어서 해봤습니다.
Chrome API를 사용하지 않았다는 조건하에 어려운 작업은 아니었습니다.

{
  "manifest_version": 3,
  "name": "Z1pLink",
  "version": "1.0.0",
  "description": "It makes your link shorter",
  "action": {
    "default_title": "Z1pLink",
    "default_popup": "index.html"
  }
}

Next.js로 빌드한 정적 페이지에 manifest.json파일을 추가하고 크롬 웹스토어에 배포하면 됩니다.

manifest는 배포하려는 Chrome Extension App의 정보를 알려주기위한 파일입니다.

6

처음 올리는거라 그런지 등록비용 $5 결제하였고, 검수 통과까진 하루 반정도 걸렸습니다.

고도화하게된다면 우클릭 했을때 나타나는 context menu를 활용할 수 있는 방법도 적용할 수 있을 듯 합니다.

결과물

profile
웹 백엔드 합니다.

2개의 댓글

comment-user-thumbnail
2022년 11월 15일

고민이 담겨있어서 좋네요 잘 읽어봤어요
chrome extension과 GitHub 은 Internal Server Error 가 발생하는 상황이네요?

1개의 답글