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을 이용하여 리소스를 주고 받아서 서버 부담을 최소화
- 스프링과 간편하게 연동 가능