[Java, Spring] shorten URL 직접 구현해보자

Arthur·2023년 4월 26일
0
post-thumbnail
post-custom-banner

❓shorten URL이란?


이름에서 알 수 있듯이 말그대로 url을 줄이는 기술을 말한다.



❓shorten URL이 왜 필요할까?


  1. 가독성이 나쁘고, 문자 수가 길어 복사 붙여넣기가 번거롭다.
  2. 소셜 미디어에서 링크 공유 시 긴 URL은 SNS글 혹은 채팅창의 상단 부분을 차지하는 문제가 있다.
  3. URL을 클릭한 사용자의 정보를 수집하고 분석하여 웹 사이트의 효과성을 평가할 수 있다.
  4. 웹 트래픽 감소
    => URL이 짧아진다는 것은 결국에 전송해야 할 데이터의 양이 줄어든다는 것이다.


❓어떻게 URL을 줄일까?


shorten URL을 구현하기 위해서는 URL을 줄여야 한다.
순서는 대략 이렇다.
1. 클라이언트가 줄이려고 하는 URL을 입력한다.
2. 입력한 URL을 줄이는 로직을 수행한다.
3. 줄인 URL을 클라이언트에게 Response
4. 유저가 줄인 URL로 접속 시 원본(Original) URL로 Redirect 하게 해준다.

여기서 URL을 줄이기 위해 어떤 로직을 사용해야 할까?


해시 알고리즘을 사용해 Key에는 해시화 된 값, Value에는 기존(Original) URL을 입력하면 어떨까 생각했다.
하지만 위 사진에도 나오듯이 url이 오히려 길어지기 때문에 제외하게 되었다.



중복될 확률이 적은 UUID 식별자를 생성 후 위와 같이 기존 URL과 uuid를 같이 DB에 저장하면 어떨까?


위 사진의 UUID를 보면 알 수 있듯이 상당히 길다.

결국에 ASCII 문자로 구성되어있는 URL을 줄이는 방법이 떠오르지 않았다.
그래서 새로운 식별자를 찾고 식별자를 인코딩 해서 줄이는 방법을 결정하게 되었다.

그러면 어떤 식별자를 사용 하는게 적절할까?


고유 식별자 Primary Key


Auto Increament하는 PK값을 고려한 이유는 아래와 같습니다.

  • 중복을 최소화 할 수 있다.
  • 기존 URL에 고유한 값을 매핑할 수 있다.
  • PK 값을 사용해서 조회를 할 수 있다.

가장 큰 이유는 복잡한 로직을 생각하지 않고 고유한 값을 가질 수 있다는 장점이였습니다.

여기서 고려해야 할 점은 데이터가 쌓이면 쌓일수록 URL이 길어진다는 점이다.
그래서 이런 문제를 해결하기 위해 PK 값을 인코딩하는 방식을 사용하기로 했다.

여기서 우리는 컴퓨터 기초를 배울 때 한번쯤 본 '2진수보다 16진수가 더 짧고 가독성이 좋다.'
라는 내용을 봤을 것이다.

PK 값을 10진수로 표현이 되어 있는데 이것을 64진수로 표현하면 더욱 짧아질 것이다.


*출처 : 초보 개발자 URL Shortener 서버 만들기 1편 : Base62와 춤을


❓BASE64란?



베이스64 인코딩은 3바이트 데이터를 4문자로 표현한다. 3바이트 데이터의 24비트를 네 가지 6비트 덩어리로 나누고, 각 덩어리의 6비트값에 출력 가능한 문자를 할당해 표현한다.

예전에는 네트워크 통신으로 6bit를 요구했다고 한다.
그 이유는 각 기기별로 특수문자, 제어문자의 처리방식이 달라서 위와 같은 base64를 만들어 알파벳과 일정의 문자를 사용 하도록 처리 한 것 같습니다.
(형식이 정해지면 각 기기별 혹은 나라별로 인코딩과 디코딩의 편의성이 생긴다.)


위와 같은 형식으로 6bit씩 4개의 청크로 분리를 합니다.
*자세한 내용은 참고자료란에 있는 링크에 있습니다.

결국에 base64 즉 64진법을 사용해서 PK값을 더욱 짧게 만들 것입니다.
그런데 여기서 문제가 한 개 있습니다.
base64 표를 보면 알 수 있듯이 62, 63번째 인덱스에 있는 특수문자는 URL 양식에서 사용하는 문자이기 때문에 제외해야 합니다.
그리고 이미 구현되어 있는 base64 함수를 사용하면 '=' 문자인 패딩 값이 붙기 때문에 안됩니다.

그래서 BASE62라는 방법을 사용해야 합니다.


❓BASE62라는 것도 있다?


위 표에서 보면 알 수 있듯이 URL 예약어에 걸리지 않는 문자 혹은 숫자들만으로 이루어져 있습니다.
base62는 위와 같은 62자로 이루어진 인코딩 체계를 말합니다.

아래는 Java로 구현한 base62 코드입니다.

public class Base62 {

    private static final String BASE62_CHARS = 
    							"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    public String encode(long number) {
        if(number == 0) {
            return Character.toString(BASE62_CHARS.charAt(0));
        }

        StringBuilder sb = new StringBuilder();
        while (number > 0) {
            int remainder = (int) (number % 62);
            sb.append(BASE62_CHARS.charAt(remainder));
            number /= 62;
        }
        return sb.reverse().toString();
    }

    public long decode(String str) {
        long result = 0;
        for (int i = 0; i < str.length(); i++) {
            result = result * 62 + BASE62_CHARS.indexOf(str.charAt(i));
        }
        return result;
    }
}

2150000 값이 입력되었다고 하면 4iUi String 값으로 인코딩해서 리턴 해줍니다.
반대로 인코딩된 값을 입력 하면 PK값으로 디코딩해서 리턴해줍니다.


플로우 및 DB 구조


플로우와 DB 구조 상당히 심플하게 되어있다.

구현에 사용된 기술 스택은

  • Java 11
  • Spring boot
  • Spring Data JPA
  • H2 DB
  • lombok

이다.

소스코드 보러가기 => 깃 레포로 이동


🤔구현하면서 부족하다고 느낀 점


DB 부하 위험 : DB 성능을 고려하지 않은 플로우

긴 URL을 저장 하고 나서 PK값을 조회하고, base62로 변환해서 update해야 하는 로직이다.
위 로직은 3번의 과정을 거치는 번거로움을 보이고 있다.
고유 값을 DB가 생성하도록 하는 장점을 취하지만 성능적인 요소를 많이 포기한 방법이다.


서버 부하 위험 : 서버에서 직접 Redirect 하는 것

상당히 라이트하게 구현했기 때문에 서버에서 직접 redirect를 하는 방식을 적용했습니다.
현재 HttpServletResponse를 사용해서 redirect를 하는데,
서블릿 컨테이너가 추가 작업을 수행하게 되기 때문에 트래픽이 많아지면 부하가 높아질 거라고 생각합니다.


보안적인 문제 : 다른 shorten URL 접근이 쉬움

PK값을 단순히 base62로 인코딩 한 것이기때문에 쉽게 PK값을 알 수 있습니다.
그리고 악의적인 사용자가 무작위 URL을 입력해서 기존 URL을 접근 할 수 있습니다.
일정한 패턴으로 값이 저장되고 인코딩 되어 있기 때문에 쉽게 접근이 가능하다는 문제가 있습니다.


이 외에도 상당히 많은 부분에서 부족한 것들이 있습니다.
하지만 배운 것들은 아래와 같습니다.

  • 인코딩에 대한 이해
  • ASCII 양식으로 되어 있는 URL
  • 긴 URL 유저에게 미치는 불편함
  • URL도 데이터이기 때문에 서버에게 부하를 줄 수 있다.
  • base64의 개념과 테이블
  • base62

참고 자료

  • Shorten URL을 구현 방법 => 링크
  • 초보 개발자 URL Shortener 서버 만들기 1편 : Base62와 춤을 => 링크
  • [Base 64] Base64이란 무엇일까? / Base64 사용 이유와 인코딩과 디코딩 => 링크
    -chatGPT
profile
기술에 대한 고민과 배운 것을 회고하는 게임 서버 개발자의 블로그입니다.
post-custom-banner

0개의 댓글