BE 프로젝트 기술검토 - 100-hours-a-week/20-real-wiki GitHub Wiki

JAVA

JAVA 8

  • 람다 표현식과 스트림 API 도입
  • Optional 클래스 추가
  • var 같은 키워드 없음
  • 스프링부트 3버전대 지원x
  • 24년 1월 31일부로 업데이트 종료

JAVA 11

  • var 정식 지원
  • HTTP/2를 지원하는 API 추가
  • 스프링부트 3버전대 지원x

JAVA 17

  • Record 타입 추가
    • 불변 데이터를 저장하는 클래스
    • 데이터를 일시적으로 저장하고 긴 코드 작성이 필요 없기 때문에 주로 DTO에 사용
  • 패턴 매칭 도입으로 스위치문에 화살표 도입, instanceof로 확인시 명시적 형변환 불필요 등 코드의 가독성 향상
  • 텍스트 블록을 지원하여 멀티라인 문자열을 쉽게 작성 가능해짐
  • 이전 버전들에 비해 코드 간결성, 표현력이 크게 향상됨
  • 클래스 로딩 최적화와 메모리 공간 재활용으로 메모리 풋프린트 개선
    • 자바 16부터 elastic metaspace를 지원하여 사용하지 않는 메타스페이스 메모리를 즉시 os에 반환하여 메모리 성능 향상
    • JVM간에 표준 라이브러리 클래스의 메타데이터를 미리 캐시해서 시작 시간을 단축하고, 메모리를 절약
  • 가비지 컬렉터의 최적화로 JAVA11에 비해 성능이 약 8% 증가.

JAVA 21

  • switch문 패턴 매칭이 JAVA17에서는 프리뷰였는데, 21부터 정식 지원하여 타입과 조건에 따른 패턴 매칭을 간결하게 작성할 수 있어서 편의성 증가
  • 가상 스레드 도입
    • 많은 동시 요청을 처리하기 위해 복잡한 비동기 코드를 작성할 필요 없이 기존의 순차적이고 직관적인 코드 흐름으로 작성해도 동시 처리가 가능
    • 즉, 요청마다 가상 스레드를 생성하여 처리를 하는데 심지어 가상 스레드는 경량화 되어서 부담도 없음
    • 스프링부트 3.2부터는 application.properties의 설정 코드 한 줄로 Loom 지원
    • 당장 가상 스레드를 사용하진 않지만, 새 프로젝트를 시작할때는 21을 사용하는게 좋음. 추후에 문제가 생겨서 21로 업그레이드 하는데 소모하는 시간을 고려.
    • 비동기 알림 처리, 퀴즈, 공지 조회 등에서 요청을 처리하는데에 가상 스레드를 사용하여 부하를 줄일 수 있음
    • jdbc, jpa 등이 내부적으로 스레드를 고정시키는 문제 (pinning)
      • 주로 jdbc에서 발생. 긴 JDBC 작업을 별도 스레드풀(Executor)로 분리하여 사용.
  • CRaC
    • JVM의 상태를 체크포인트로 저장하고 나중에 복원해서 애플리케이션을 즉시 구동
    • 애플리케이션을 한 번 완전히 기동하여 필요한 클래스 로드, JIT 컴파일, 캐시 초기화 등을 마친 상태를 스냅샷 떠놓았다가, 이후에는 해당 스냅샷을 메모리로 곧바로 올려서 재시작함
    • 아직 리눅스 전용이긴 함

Spring Boot 3.x

목적

  • 백엔드 서버 프레임워크

사용 이유

  • 가장 많이 사용되고, 커뮤니티가 잘 활성화되어있음
  • 복잡한 환경설정을 대신 해줌
  • 자동화 테스트 기능 제공
  • 내장 서버를 이용하여 별도의 배포 필요 없이 애플리케이션 실행이 가능
  • Gradle에서 의존성 버전관리를 해서 간편
  • 가상 스레드를 사용하기 위해서는 JDK 21을 사용해야 하는데 2.x 버전에서는 JDK 21을 사용할 수 없음

OAuth 2.0

목적

  • 카카오 소셜 로그인 기능 구현

선정 이유

  • 인증을 위임하여 사용자 편의성 향상, 회원가입 장벽 감소
  • 추후에 자체 로그인 기능 구현 확장성을 생각하면 Spring Security와의 연동이 간편
  • 카카오뿐만 아니라 다양한 소셜 로그인 확장 가능

1.0과 2.0의 차이

  • 1.0에서 세션 고정 보안 문제가 발생하여 2.0으로 대대적 개선이 됨
    • 세션 고정 공격
    • 공격자가 세션 id를 생성하여 서비스 사용자가 강제로 사용하게 만든다.
    • 사용자가 해당 세션 id로 인증 절차(로그인 등)를 완료하면 공격자가 그 세션을 다시 탈취한다.
    • 공격자는 그 사용자의 권한으로 사용자의 정보를 얻는 등 접근이 가능해진다.
  • 1.0은 구현이 복잡하고, access token이 만료되지 않아서 보안이 많이 취약함
    • 1.0은 디지털 서명 기반이었지만, 2.0은 암호화를 http에 맡겨서 복잡한 디지털 서명이 생략됨

Mysql

목적

  • 메인 데이터 저장소

사용 이유

  • 안정성이 높고, 많은 레퍼런스를 보유 중
  • JPA와 호환성이 높고, 복잡한 트랜잭션에도 대응이 가능

대체 기술(PostgreSQL)

  • 단순 select에서 mysql이 더 빠름
  • 시스템 구조가 Mysql보다 복잡하다. 그렇기 때문에 빠른 MVP 개발에 용이하지 않다.

Redis

목적

  • 조회수, 좋아요 수처럼 변경이 자주 발생하는 데이터에 대한 부담을 분산시킴
  • 비동기 처리나 캐싱, 세션 관리 등 다양한 활용이 가능함
  • 읽지 않은 공지 상태를 Redis를 활용하여 효율적으로 임시 저장 및 처리 가능

사용 이유

  • In-memory 기반의 Key-Value Store로, 디스크 기반 RDBMS보다 훨씬 빠른 응답속도를 제공
  • 단일 키 명령에 대해서는 Atomic 연산을 지원하여 동시성 문제를 줄일 수 있음
  • 영속성이 요구되지 않는 임시성 데이터(읽음 처리 등)에 적합
  • 트래픽 분산 및 병목 제거에 효과적 (ex. DB Write 지연 감소)

대체 기술

Memcached

  • Memcached는 단순 캐시용도로 제한되기 때문에 추후에 읽지 않은 공지뿐만 아니라 운영진이 보내는 메시지를 pub/sub 기능이 있는 redis를 사용.
  • 다양한 자료구조를 지원하기 때문에 확장성이 용이

Kafka

  • 전송 시간은 별 차이 없음. 엄밀하게는 디스크 flush설정에 따라 redis가 더 빠를 수 있음.
  • redis의 Pub/sub을 사용하면 놓치는 알림이 생길 수 있지만 stream 사용하면 해결 가능
  • 주로 대용량 이벤트 파이프라인에 사용. 경험으로 사용하기에는 좋지만 백엔드가 혼자라 쉽지 않을 것이라 예상
  • 일반적으로 프로젝트 초기에는 redis를 사용하다 규모가 커지면 kafka로 마이그레이션

JPA

목적

  • Java 객체와 데이터베이스 간의 ORM 매핑
  • 코드와 쿼리 간의 간극을 줄여 생산성 향상

사용 이유

  • SQL을 직접 작성하지 않고도 CRUD 로직 구현 가능 → 생산성 증가
  • Dirty Checking, 지연 로딩(Lazy Loading), Fetch 전략 등을 통해 최적화 가능
  • Spring Data JPA와 결합 시 구현해야 할 DAO 코드의 양을 크게 줄일 수 있음

대체 기술 (Mybatis)

  • 반복되는 작업을 매 번 SQL문을 작성하지 않아도 돼서 생산성이 높음
  • 필요한 경우에는 Native Query 사용하여 유연하게 대처 가능
  • Mybatis는 복잡한 통계 쿼리나 보고서 쿼리가 많을 때 주로 사용

S3 버킷

목적

  • 사용자 프로필 이미지, 첨부 파일 등 정적 리소스 저장소

사용 이유

  • 정적 파일을 안정적으로 저장 가능
  • URL을 이용하여 리소스를 주고 받아서 서버 부담을 최소화
  • 스프링과 간편하게 연동 가능