보여지는 시간대(타임존)은 누구의 책임인가
·
서버 개발(생각과 구현)
기본적으로 애플리케이션을 타임존 설정 없이는 시스템에 설정된 기본 타임존을 따라간다. 내용은 아래와 같다.JVM은 시작 시 운영 체제에서 설정된 시스템 타임존을 읽어 들여 초기화한다.예를 들어, Linux, macOS, Windows에서 각각 설정된 타임존 (/etc/localtime 또는 GUI 설정 등)이 JVM의 기본 타임존으로 설정된다.이 값은 JVM의 시스템 속성 user.timezone에 저장된다.기본 시간대코드로 확인해 보자.val defaultTimeZone = TimeZone.getDefault()println("기본 타임존 (TimeZone): ${defaultTimeZone.id}")// java.time.ZoneId를 사용한 기본 타임존 확인val defaultZoneId = Zon..
단일 프로젝트 구조와 멀티 모듈 구조
·
서버 개발(생각과 구현)
처음 개발을 시작하는 단계에서는 보통 단일 프로젝트 구조에서 시작한다. 하지만 그 크기가 증대하고 각각의 역할들이 무수히 많아지면 관리와 복잡도도 매우 증가하게 된다. 그렇기 때문에 이를 해결하고자 나오는 해결책으로 대부분 모듈 구조화를 얘기하곤 한다.문제점은?예를 들어 Member라는 도메인이 존재한다. 단일 프로젝트 구조라면 Member라는 하나의 큰 도메인을 중심으로 여러 개의 서버들이 이에 대해 깊은 의존관계를 띄며 (ex - Internal Service (application serving..), Admin Serving, Exception, Utils..)등 여러 가지가 한 도메인 구조에서 존재하게 된다.⇒ 즉, 여러 개의 IDE를 켜서 하나의 도메인을 바라보는 코드를 수정해서 배포하고 이를..
Custom Swagger를 통해 협업, 업무 효율성 동시에 잡기
·
서버 개발(생각과 구현)
Swagger는 개발한 Rest API를 편리하게 문서화해주고, 이를 통해서 관리 및 제3의 사용자가 편리하게 API를 호출해 보고 테스트할 수 있는 OpenApi에서 만든 양식이다.OpenAPI Specification - Version 3.1.0 | Swagger OpenAPI Specification - Version 3.1.0 | Swagger swagger.io 일반적으로 굉장히 많이 쓰이고 이를 통해 클라이언트, 모바일 개발자 분들과 소통하며 개발을 이어나가곤 한다. 그래서 Swagger는 서버 개발자의 의도를 명확하게 나타내야 한다.이에 따라 각각 서버에서 사용하는 양식들은 굉장히 많다. 대표적으로 REST Docs와 Swagger annotation으로 나타내는 경우가 많다.문제그 중 살펴..
JPA N+1의 의도와 문제 해결
·
서버 개발(생각과 구현)
JPA를 사용하다 보면 N+1 문제를 생각보다 많이 마주치게 된다. 대부분 이는 구글링을 통해 블로그 글이나 레퍼런스로 해결할 수 있는 방법을 알려주고 있다. 하지만 개인적으로 N+1에 대한 문제점이나 원인 혹은 JPA N+1을 의도한 바가 있는지를 면밀히 살펴볼 것이다.JPA N+1 문제대부분의 사람들이 정의하는 N+1이란 아래와 같다.연관관계가 있는 엔티티를 조회할 때 조회된 개수 N개만큼의 쿼리가 추가로 발생하는 것 위와 같이 Team-Member는 1:N 양방향 매핑 관계이다. 이때 N+1이 발생하는 상황은 다음과 같다.Team A, Team B 2개의 Team 엔티티가 존재하는 상황각 팀에 엔티티에 비어있는 멤버가 없다고 가정, 즉 2팀에 모두 멤버가 있는 것.여기서 TeamRepository의..
외부 API와 트랜잭션의 관계를 조심하자
·
서버 개발(생각과 구현)
Spring을 활용하여 트랜잭션을 관리하다 보면 @Transaction Annotation을 사용하게 된다.그런데 만약 해당 Annotation이 적용된 로직에서 외부 API Call이 있다면 어떻게 될까?롤백가장 먼저 고민이 드는 부분이 롤백이다.만약 중간에 Exception이 발생하여 rollback이 되었다고 외부 호출은 rollback 될까?@Transactionalfun test() { testRepository.save(Test().apply { name = "test" }) apiCallClient.testCall() throw RuntimeException()}@Serviceclass ApiCallClient { private val restClient = RestCl..
락의 필요성과 실제 사용을 위한 분산 락, 낙관적 락, 비관적 락 탐구
·
서버 개발(생각과 구현)
보통 서버 개발을 하다 보면 자주 마주치는 단어들이 존재한다. 동시성, 정합성 등… 특정 동시성 상황에서 데이터 정합성을 보장할 때 특히 락들을 활용하는 타이밍이 자주 온다. 그래서 크게 자주 사용되는 락들을 알아보고 어떻게 동작하는지 어떤 상황에 적합한지를 예제를 통해 알아볼 것이다.1. 락이 필요한 이유예를 살펴보자.알리익스프레스 같은 쇼핑 어플의 월간 사용자수는 약 4억 명정도이다. 그 이유는 가격이 저렴한 것도 있지만, 추가적인 할인을 해주는 쿠폰을 나눠주기도 한다. 이 쿠폰까지 사용하면 어느 쇼핑몰보다 저렴하게 상품을 구매할 수 있다. 그러나 쿠폰 재고 소진으로 쿠폰을 못 받을 수 있다. 여기서 생각을 해보면, 쿠폰 이벤트를 시작할 때 동시에 수많은 사용자가 쿠폰 발행을 할 텐데 쿠폰 잔여 개수..
서킷 브레이커(CircuitBreaker)가 필요한 경우
·
서버 개발(생각과 구현)
만약 특정 서버에서 장애가 발생했을 때, 해당 장애가 전파되고 여러 서비스에 영향을 끼친다면 어떻게 할까? 이럴 때 사용하는 것이 서킷 브레이커(CircuitBreaker)이다.서킷 브레이커란?단순한 개념은 다음과 같다.서킷 브레이커는 문제가 발생할 경우 서비스의 호출을 차단하고 fallback 메서드를 이용할 수 있도록 하는 패턴으로 서비스 호출이 실패하거나 지정된 임계값을 초과할 때, 서킷 브레이커는 OPEN 상태가 되어 후속 호출을 차단하고, 시스템이 회복될 때까지 대기한다. 서킷 브레이커의 상태는 3가지로 분류 된다. (이미지 출처)닫힘(Closed) 상태:서킷 브레이커는 기본적으로 닫힌 상태에서 시작.(정상 상태)실패율이 정해진 값을 초과하면 서킷 브레이커는 OPEN 상태로 전환된다.열림(Ope..
Spring Retry(재시도)가 필요한 경우
·
서버 개발(생각과 구현)
Spring Retry란실패할 경우 그 동작을 자동으로 다시 호출하는 기능이 담긴 라이브러리로, Spring Retry 라이브러리를 통해 사용한다. 간단하게 예를 들어, 특정 비즈니스 로직에서 실패 후 재시도 처리가 필요한 경우가 존재한다. 특정 A라는 로직이 실패한 경우 재시도하는 경우가 될 것이다. 이는 비즈니스 요구 사항에 따라 사용되기도 하며 일시적인 에러가 발생했을 때 재시도 메커니즘을 활용하기도 한다.Guide to Spring Retry | Baeldung Guide to Spring Retry | BaeldungA quick and practical guide to implementing retry logic with Spring Retrywww.baeldung.com Spring Retr..
외부 API 호출을 위한 OpenFeign, RestClient, WebClient들의 차이점
·
서버 개발(생각과 구현)
Spring을 통해 개발을 하다 보면 필연적으로 외부 API 호출이 필요한 경우가 있다. 특히 특정 API에 대한 정보가 필요하거나 SaaS 제품 혹은 서버간 통신에서 굉장히 많이 사용하게 된다.그 중 가장 많이 사용되는 OpenFeign, RestClient, WebClient들을 살펴볼 것이고, 차이점과 실제로 어떤 상황에서 사용되고 있는지를 알아볼 것 이다.OpenFeginOpenFegin은 NetFlixd에 의해 처음 개발 되었으며, 선언적 HTTP Client 도구이다.외부 API 호출을 간편하게 할 수 있게 도와주며 선언적이기 때문에 직관성이 높다. 조금 더 부연설명을 하자면, Netflix OSS 프로젝트의 일부로써 Netflix OSS가 공개되고 나서 Spring Cloud 진영은 Spri..
Kotest를 활용한 유닛 테스트 구성
·
서버 개발(생각과 구현)
Kotest(코테스트)란?코틀린에서 사용 가능한 언어의 특징을 이용함으로써, Kotest는 더욱 강력하지만 간단한 테스트 정의 방법을 제공한다.KoTest에서 테스트는 테스트 로직을 담고 있는 단순한 함수일 뿐이며, 테스트 메서드는 번거롭게 수동으로 정의하는 것이 아니라 Kotest의 DSL을 사용해서 정의한다.class TestClass : FunSpec({ test("Hello") { 2 + 2 shouldBe 4 }})위 같이 코틀린에서는 test를 여러 개 중첩적으로 사용할 수 있는 여러개의 Spec들이 있다. Java에서는 여러 가지의 테스트들을 모두 정의하여 해야 했지만, 코테스트를 사용하면 쉽게 테스트 환경을 구축할 수 있다. 공식 문서에서 여러 가지의 Spec들을 확인할 수..