29P by leelou2 12일전 | ★ favorite | 댓글 17개

URL Shortener 프로젝트 만들고 개선하고 또 만들고 또 개선하고... 를 반복하며 드디어 최최최종 v9 오픈소스 프로젝트를 만들게 되었습니다

🚀 Github : https://github.com/lee-lou2/rust-url-shortener


프로젝트를 준비하며 아래 요구사항은 꼭 지키려 노력했습니다

요구 사항

  1. Short URL 은 아주 빠르게 생성되어야한다
  • 데이터가 많아진다고해서 느려져선 안된다
  • 언제 어떠한 상황에서 어떤 데이터를 이용해서 요청하더라도 빨라야한다
  1. Short URL 을 Original URL 로 이동 시킬 때도 빨라야한다
  • 사실 이건 당연한 얘기라... 😅
  1. 다양한 사용자들을 만족 시킬 수 있는 부가 기능들이 포함되어야한다
  • 원하는 경우 플랫폼별로 다른 URL 로 이동시킬 수 있어야한다
  • 원하는 경우 사용자가 생성한 URL 로 인입되는 데이터를 확인할 수 있어야한다

이러한 요구 사항을 충족 시키기위해 아래와 같이 개발하였습니다

반영 사항

Q. Short Key 생성을 어떻게하면 데이터 양과 관계 없이 빠르게 생성 할 수 있을까?
A.
일반적으로 Short Key 를 생성하는 방식은 여러가지가 있습니다.
첫 번째, 임의의 랜덤한 값을 생성해서 데이터베이스에 존재하는지 확인하고 없다면 그걸 그대로 사용하는 방식이 있습니다. 하지만 이 경우 데이터베이스에 확인하고 다시 한 번 생성 해줘야하는 번거로움이 있습니다. 또한 이미 많은 데이터가 있거나 Short Key 의 자리수가 바뀌어야하는 시점에 많은 지연이 발생될 수 있습니다.
두 번째, 미리 임의의 Short Key 를 생성해두고 매칭 시키는 방식이 있습니다. 이건 미리 만들어둔 Short Key 를 매칭만 해주는거다보니 언제나 빠르게 Short URL 을 생성할 수 있습니다. 하지만 이것 역시 답이 될 순 없습니다. 미리 만들어두는 것에 한계가 있을 수 있고 혹시라도 미리 만들어둔 것보다 많은 Short URL 이 생성되었을 때 등 고려해야할 사항들이 추가로 발생될 수 있습니다.
그렇다면 더더 좋은 방법은 없을까?
많은 고민 끝애 아래와 같은 방법을 적용했습니다. 랜덤한 4자리 문자열과 PK 를 이용한 문자열을 조합하여 사용하는 방식입니다. 각 값에 대한 설명은 아래 내용을 참고해주세요. 순서는 다음과 같습니다. 사용자가 Short URL 생성을 요청하면 랜덤한 4자리 문자열을 생성하고 그대로 데이터베이스에 저장합니다. 저장하며 발급되는 PK 를 아래 설명란에 작성된 방법대로 문자열로 생성합니다. 최초 생성한 랜덤한 문자열과 PK 문자열을 조합하여 Short Key 를 만듭니다. 이렇게되면 아무리 많은 데이터가 쌓여있다고하더라도 중복없이 빠르고 안전하게 생성되게됩니다.

  • 랜덤한 4자리 수?
    여기에서 랜던함 4자리 수는 영어 소문자/대문자 숫자로 이뤄진 정말 랜덤한 문자열입니다. 이 문자열은 중복이 발생되어도 괜찮습니다.
  • PK 를 문자열로?
    다음으로 두 번째 값인 PK 문자열입니다. 영어 소문자/대문자, 숫자를 조합해서 문자열을 순서대로 만든다고 해보겠습니다. 순서는 영어 소문자 a -> z, 영어 대문자 A -> Z, 숫자 0 -> 9 순입니다. 그럼 a 는 첫 번째 만들어진 값이 될테고 b 는 2, c 는 3, ... 이렇게 순서대로 임의의 값을 조합해갈 수 있을 것입니다. 9 까지 다 만들어지면 aa, ab, ac 이렇게 자리수도 늘려가며 만들 수 있습니다. 이렇게 순서대로 만들게되면 문자열에 맞는 인덱스가 생기게됩니다. a 의 인덱스는 1 이 되는 셈이죠. 여기에 방법이 있습니다. PK 가 인덱스가 되고 그 PK 에 맞는 문자열르 찾아주기만하면 됩니다.

Q. Short URL 을 Original URL 로 이동 시킬 때 빠르게하려면?
A.
이건 정말 단순하게 캐시를 사용했습니다. 다양한 서비스들이 있지만 위 프로젝트에는 메모리 캐시를 사용해서 빠르게 데이터를 조회할 수 있도록 적용하였습니다. 추가로, 단순히 데이터를 조회하고 이동 시키는 것 외 부가적인 기능들은 경량 쓰레드를 생성하여 처리하였습니다.

Q. 추가적인 부가 기능은 어떤걸 구현했나요?
A.
우선 첫 번째로, 플랫폼 별로 다른 URL 로 이동되도록 구현 했습니다. iOS, Android 각각 기본 DeepLink 를 받아 저장하고 DeepLink 로 이동하지 못했을 때를 대비해 FallbackUrl 을 추가로 받았습니다. 그 외 데스크탑으로 접속 했을 때 이동할 URL 도 받아 모든 케이스에 대비했습니다.
두 번째로, Original URL 로 이동되는 시점에 사용자가 접속 로그를 확인 할 수 있도록 웹훅 URL 을 받아서 Original URL 로 이동 될 때 마다 웹훅 URL 을 호출해주는 기능을 추가했습니다. 지금은 User Agent 와 Short URL 정보만 전달되도록 구현해뒀습니다.
세 번째로, Short URL 생성 시 Head 태그의 정보들은 추가로 입력 할 수 있게했습니다. 이걸 추가한 목적은 og 태그를 커스텀하기 위함입니다. 해당 태그를 입력하지 않으면 Default URL 의 head 정보가 저장되도록 처리해뒀습니다.


해당 프로젝트는 Rust 를 이용했습니다. 사실 Rust 를 배운지 아직 2개월 밖에 되진 않았습니다. URL Shortener 프로젝트를 처음엔 FastAPI 로 개발했다가 그 다음으론 Golang 으로도 개발 했었습니다. 그리고 나서 Rust 를 배우며 너무 큰 매력에 빠져 완전히 고도화된 URL Shortener 프로젝트를 다시 한 번 만들게 되었습니다.

아직은 문법이나 소유권, 생명 주기 등이 익숙하지 않아 코드 상으로 부족한 점이 있을 수 있어 많은 관심과 응원 그리고 피드백 부탁드려요 🙏

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

정성이 보이는 프로젝트네요!
저도 회사에서 비슷한걸 만들어서 사용중인데요, 저 같은 경우에는 인쇄 매체에 실려나가야 해서 모호한 문자를 회피하도록 문자 집합을 설정했습니다.

관련 내용도 긱뉴스에 있더라구요.

https://news.hada.io/topic?id=14479

좋네요!! id나 링크 생성해 줄 때, 저거 고려해 주면 좋긴 하더라고요

우와 감사해요👍

다른 프로젝트도 올렸어요 많은 관심 부탁드려요 🎉
https://news.hada.io/topic?id=18647

너무 훌륭한 프로젝트입니다.
써두신 것처럼 Docker가 지원되면 너무 좋을 것 같아요!

감사합니다 👏 도커는 이번 주중에 추가해서 올려둘게요 🙇‍♂️

혹시 이메일 입력은 필수일까요? 이메일 인증이 안되면 웹훅이나 주소 생성이 안되는 줄 몰랐네요.

혹시 내부에서만 사용하고 커스텀이 필요하다면 해당 프로젝트와 별개로 따로 커스텀해드릴게요!

네, 퍼블릭한 서비스로 사용하려 이메일을 필수로 받게 적용해뒀습니다 (회원 가입 없이 이메일 인증을 사용)

JWT 입력 시 이메일이 없어도 되도록 수정하는 하는 방안도 한 번 고민해볼게요 🙏

호우 우분투 Lightsail 깔고 따라해보는데 SSL이라던가 pkg-config , sqlite, cargo 설치 해야 될게 많네요 :) 저는 https 이 부분을 NPM이 아니라 Cloudflare tunnel을 쓸려고 하긴했는데 역시 전 어려운것 같습니다 ㅎ_ㅎ.. 도커 버전 기대하겠습니다! 안그래도 dynamic link 없어져서 고민중이었는데 너무 좋네요.

Dockerfile 과 실행 할 수 있는 커멘드(deploy.sh) 추가했습니다 🎉

최대한 빨리 도커를 추가하겠습니다ㅋㅋ

오 근데 실행하긴 했습니다! 어떻게 했지? 호엥

Github 레포에 readme 말고 website에도 데모 url 추가해두면 좋을 것 같아요!

보통 홈페이지나 플레이그라운드가 있는지 확인을 레포의 오른쪽 정보를 먼저 보게 되는것 같아서 데모 사이트가 없는 줄 알았습니다 ㅎㅎ

좋은 프로젝트 잘 구경하고갑니다!

앗 놓치고 있었네요 바로 설정해야겠어요 감사해요🤩

러스트를 설치하고 환경 변수만 지정하면 바로 사용이 가능합니다!
Google URL 서비스가 올해 종료되는데 대안으로 사용하세요. 궁금하신 점이나 개선이 필요한 부분, 설치를 위한 방법 등 여러 내용을 모든 메일 환영입니다 👏

https://f-it.kr/ 에서 간단히 사용해보실 수 있습니다 🙇‍♂️