Tech Blog by hojongs
취소

Redis: Redlock(Distributed lock) 알고리즘 및 Java 구현체, 그리고 비판

Redis에서 제안한 Redlock(DLM implementation) 알고리즘을 이해하기 위해 Redis 공식 문서를 읽으면서 일부 내용을 정리했다. 용어집: Redlock Reference: https://redis.com/glossary/redlock/ Redlock에 대한 간단한 소개 Redis를 사용한 분산 잠금 Referen...

jitter(Retry backoff): jitter 사용 이유 및 레퍼런스들

MSA 또는 MSA 환경이 아니어도 외부 서비스 또는 시스템 장애로 인해 외부 호출이 실패할 수 있다. 일부 서비스와 실패가 시스템 전체 장애로 번지기도 한다. 실패를 완전히 방지할 수는 없다. 하지만 탄력적인 시스템을 구축하여 일부 서비스가 실패하더라도 전체 시스템은 문제없이 동작하도록 할 수는 있다. 탄력적인 시스템을 구축하기 위해 활용할 수 있...

Spring WebFlux: Client disconnection 탐지 동작 방식

Keyword: Spring, WebFlux, Spring MVC, Network, TCP/IP, HTTP, Netty, Servlet Spring WebFlux 서버에서 doOnCancel을 통해 로그를 남겼더니, client가 요청을 끊었을 때 로그를 남길 수 있는 것을 확인할 수 있었다. 이는 client에서 설정된 타임아웃 초과로 인한 연결 ...

Spring Retry: RetryPolicy로 Exception 분기 처리하기

Keyword: Spring Retry, Retryable, RetryPolicy, MaxAttemptsRetryPolicy, Backoff Spring framework에 있는 Retry 기능을 활용하여 Elasticsearch client requset 실패 시 retry하려고 한다. 이 때 ElasticsearchStatusException의...

Spring Async Task vs Kotlin coroutines

Keyword: Spring Framework, Async Task, Kotlin, Coroutine 특정 서비스에서 여러 개의 Elasticsearch query를 요청하는 API가 있다. 이 API는 query를 순차적으로 요청하고 있었고, query의 개수가 증가하면서 latency가 점점 증가하는 문제가 있었다. 쿼리 성능을 높이기 위해 El...

Gradle Test Fixtures Plugin 소개

문제 상황 Gradle 멀티 모듈 프로젝트를 생각해보자 하나의 모듈에서 테스트 코드에서 사용할 용도로 test sourceSet에 테스트 객체 builder 클래스를 만든다 위 모듈을 의존하는 모듈들에서는 해당 builder 클래스를 사용할 수 없다. (test sourceSet의 클래스들은 jar 파일(컴파일된 모듈)에 포함되지 않기 ...

Spring WebFlux WebClient Builder bean 사용 이유 (ObjectMapper bean)

이전 상황 WebClient를 build할 때 WebClient.builder()를 직접 호출해서 WebClient 인스턴르를 생성하고 있었다. 문제 상황 이 경우 Spring bean으로 등록된 ObjectMapper가 WebClient에 사용되지 않는다. 이 자체로는 문제를 유발하지 않지만, ObjectMapper bean의 설정을 변경해도 ...

Spring Response Encoding UTF-8, EUC-KR, KSC5601

Keywords: Spring framework, Kotlin, UTF-8, EUC-KR, KSC5601, KS X 1001, HttpMessageConverter, ObjectMapper, JsonSerialize Response DTO의 인코딩에 대해서 알아볼 일이 있었다. Spring Framework에서 Response DTO를 JSON St...

[TIL] HTTP Redirection with location header

bit.ly 서비스처럼 URL shorten 기능은 어떻게 구현할까? HTTP Location header를 사용하면 된다. Location header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location 실제로 bit.ly에서 생성된 URL로 요청 시 HTTP response...

[TIL] Gradle: Understanding dependency resolution - dynamic version

Gradle의 의존성 resolution에 대해서 쓸 내용이 아주 많은데, 이번 포스트에서는 간단하게 dynamic version에 대해서만 다뤄본다. https://docs.gradle.org/current/userguide/dynamic_versions.html dynamic version은 2.+와 같이 범위로 지정될 수도 있고 latest....

[TIL] Logback 용어들: Appender, Encoder, Layout

Logback XML config를 작성할 때 appender, encoder, layout이라는 용어를 볼 수 있다 이러한 용어들이 무엇인지 간단히 알아보자 Logback Appender https://logback.qos.ch/manual/appenders.html Logback delegates the task of writing a...

[TIL] Gradle: Java(Kotlin) targetCompatibility, jvmTarget

Java 또는 Kotlin으로 구성된 Gradle 프로젝트에서 아래와 같은 빌드 스크립트를 본 적이 있을 것이다. 이 중 targetCompatibility에 대해서 알아볼 것이다. 이 프로젝트의 jar 파일을 실행하는 JVM runtime version 또는 다른 jar artifact를 의존할 때 이 targetCompatibility가 중요하다....

[TIL] Spring MVC: Filter vs HandlerInterceptor

Filter 아래 Spring framework 링크에는 몇몇 유용한 spring-web의 Filter 구현체들을 소개한다. Filter 자체에 대해서는 소개하지 않는다. https://docs.spring.io/spring-framework/reference/web/webmvc/filters.html Filter에 대한 Oracle 문서는 아래...

[TIL] Spring: dependency-management 선언과 적용 우선순위, vs Gradle dependency management 차이점

Spring boot 서버를 개발하고 있다면 Spring dependency management plugin에 대해 들어봤을 것이다. 이 플러그인을 통해 의존성들의 버전을 통합 관리할 수 있다. bom을 import하여 의존성들이 bom에 명시된 버전을 사용하도록 할 수 있다. 이 때, 여러 개의 bom에서 동일한 의존성의 여러 개의 버전을 선언하고...

[TIL] Gradle: dependency cache path in Home directory

현재 회사에서 소속 팀은 서버 플랫폼 팀이다. 우리 팀에서는 내부 라이브러리를 개발하고 maintain하는 일도 하고 있다. 이 라이브러리들은 Nexus에 배포하고 각 서버 저장소에서 “의존성으로서” 의존하여 사용된다. Gradle은 빌드 속도를 높이기 위해 이러한 의존성들을 로컬에 cache한다. cache key는 artifact id, vers...

[TIL] Spring: How to Inject Spring Bean into Static Variable

Spring bean을 static variable(정적 변수)에 저장하는 것이 유용하거나 편리할 경우가 있다. 예를 들면 Environment.activeProfiles의 값을 그렇게 활용할 수 있다. 사실 이렇게 static variable에 의존하는 클래스는 테스트하기 더 어려워지므로 static variable이 아닌 constructor를 ...

[TIL] Elasticsearch: How-to index rollover

지난 포스팅 </posts/til-kibana-index-template/> 에서 index template을 수정하였다. (Kibana에서 특정 column의 값이 full-text search 되지 않는 문제 해결) 이렇게 template을 수정해도 이미 생성된 index에는 영향을 미치지 않는다. 다음 index가 생성(rollove...

Spring Boot: Overriding Dependency Versions with Gradle Properties

의존성 관리는 멋지지 않지만 굉장히 중요하고 컨트롤하기 어려운 문제 중 하나다. 특히 수십 개의 독립적인 모듈로 이루어진, 그리고 수백 개의 의존성을 가진 Spring boot 의존성들은 의존성이 매우 복잡하다. Spring boot를 사용하는 서버의 의존성도 이 복잡한 의존성 그래프를 피해가기 어려운데, 이를 해결하기 위해 Spring boot에...

[TIL] Envoy access log: start_time 정렬 문제

네트워크 로그 분석을 위해 envoy access log를 남기고 Elasticsearch(ES)에 적재하고 있다. 이번 포스트에서는 Envoy access log의 정렬 key 문제에 대해 설명한다. ES의 로그는 Kibana에서 조회하고 있는데 Kibana에서 로그 조회 시 기본적으로 @timestamp 필드로 정렬된다. 이 정렬 방식은 일반...

[TIL] Spring MVC: Multiple ControllerAdvices & Order

ControllerAdvice란? 사용 이유? Controller 이하 level에서 핸들링되지 않은 예외를 핸들링하기 위해 @ControllerAdvice를 사용할 수 있다. IOException과 같은 예외는 보통 이런 방식으로 처리하는 것이 유용하다. 즉, ControllAdvice는 전역적 에러 핸들링 코드 구현을 편리하게 만들어준다. 새...

[TIL] Elasticsearch: Index template과 dynamic/explicit mapping

Problem to resolve 로그를 Elasticsearch에 적재하고 있고, 로그 인덱스는 dynamic mapping을 사용하고 있다 로그 인덱스에서 message.response.body라는 필드가 부분 텍스트 검색이 되지 않는 문제를 발견했다. Background Dynamic mapping에 대해서 간단히 살펴보자. 인덱스의 m...

[TIL] JIT compiler in Java HotSpot VM, and C1 vs C2 compiler mode

JVM C1, C2 compiler 회사 팀원이 갑자기 C1, C2 compiler에 대해 아냐고 질문했다. 사실 JVM의 C1, C2라는 용어는 처음 들어보았다. 그래서 조금 찾아보았고 매우 간단하게 이해한 내용을 정리해본다. (용어 정의 정도) 정말 간단하게 알아봤으므로 갑자기 끝나도 놀라지 말자.. Understanding Java ...

2022년 하반기 회고, Let's focus on impact - 업무편

지난 일상편 회고에 이어서 업무편 회고를 이어서 써보려고 한다. 나는 작년에 이직 후 어떤 점들을 느꼈나? 하반기동안 어떤 일을을 했나? 어떤 문제들을 해결했나? 내 가치를 증명해야 한다는 조급함 가장 크게 느꼈던 것은 조급함이었다. 첫 이직이다보니 더 크게 느꼈던 것 같다. 워낙에 책임감을 강하게 느끼는 성격이어서 그런 것도 있다. 하지만 ...

JPA: optimisstic lock vs pessimistic lock

What is optimistic locking? JPA Spec 문서에서 낙관적 락에 대한 내용 일부를 인용하겠다. Optimistic locking is a technique that is used to insure that updates to the database data corresponding to the state of an en...

Slack Bolt: Socket Mode App Server를 Spring Boot로 통합하기

Slack app server를 개발하고 싶다. 안전하게. 기존에 개발되어 있는 Slack app server는 Slack hook endpoint를 노출한 형태로 개발되어 있었다. 하지만 이 형태는 Public endpoint를 노출할 수 밖에 없다. signing secret으로 인증을 하긴 하지만 API 호출 자체는 누구나 할 수 있다. ...

Spring Cloud: Bootstrap이란? (bootstrap properties vs application properties)

Bootstrap properties vs application properties Application properties https://www.baeldung.com/spring-cloud-bootstrap-properties Spring Boot에서 Application properties 파일은 Spring application conte...

Spring Cloud Config: logback.xml 파일 (plain text non-properties 파일) 제공하기

Serving plain text files via Spring Cloud Config Servers Spring Cloud Config 서버는 properties 파일 뿐만 아니라 그 외의 파일들도 제공할 수 있다. 예를 들면 logback.xml 파일들을 Spring Cloud Config Server에서 중앙화하여 관리할 수 있다. http...

Spring Cloud Config: Label 사용하여 특정 Git branch의 config 사용하기

일반적으로 엔터프라이즈 서버를 운영한다면, 애플리케이션 서버의 환경은 development(dev)와 production(prod) 환경이 분리되어 있을 것이다. 동일한 맥락에서 Cloud config server를 사용할 때, dev 환경과 prod 환경의 설정 파일들도 분리되어 있는 것이 안전하다. 이를 구현하기 위해 Spring Cloud C...

Spring: 환경변수를 @Value 어노테이션, application.properties에서 주입받기

Access environment variables within Spring Boot Spring에서 개발할 때, 환경변수에 접근하는 방법은 여러 가지가 있다. System.getenv() 등등. 보통 환경변수는 서버 설정값을 주입하기 위해 사용한다. 서버 설정값은 application.properties에도 설정되는데, System.getenv(...

Feign: Feign client에 Default header 설정하기 (Request interceptor)

Feign: Feign client에 Default header 설정하기 기존의 코드에서 번거롭게 되어있던 부분을 리팩토링했다. Feign client를 통해 요청을 보낼 때마다 동일한 Authorization 헤더의 토큰값을 파라미터로 전달해야 했다. 이 토큰 값은 DI를 받아야 했기 때문에, 더 번거로웠다. 이 Feign client를 DI받...

애플리케이션 서버 HTTP Client에 도메인 IP 변경 전파하는 방법 (Elasticsearch)

갑자기 Elasticsearch 도메인의 IP가 바뀐다면? 어떤 서비스가 es.example.com 도메인을 통해 Elasticsearch에 연결하고 있었다고 하자. 최초 연결 시에는 도메인에 a.b.c.d IP가 등록되어 있었는데 갑자기 x.y.z.q IP로 변경된다면? 우리 팀에서 운영하는 여러가지 마이크로서비스 중 주소검색 서비스가 있...

Kotlin에서 Kotlin답게 에러 처리하는 방법 (Advanced Error Handling in Kotlin)

많은 Kotlin 코드들이 Exception(예외)를 통해 에러를 출력하고 핸들링하고 있을지도 모른다. 대부분은 Java-style 코딩 방식에서 그대로 온 것이라고 추측한다. Kotlin은 에러 헨들링을 위해 Exception 외의 인터페이스들도 제시한다. 본 포스트에서는 Kotlin에서 간결하게 에러 핸들링 코드를 작성하는 방법을 설명한다. ...

2022년 하반기 회고, Let's focus on impact - 일상편

2022년 7월 11일 이직 후 벌써 6개월이 지나갔다. 벌써 시간이 이렇게 많이 흘렀다는 게 충격적일 정도로 놀랍다. 벌써 2월이 절반도 더 지나갔지만 늦게라도 작년 하반기 회고를 해보려 한다. 회사 적응에 가장 집중했고, 회사에서는 눈앞에 닥친 잡다한 일들을 주로 하며 시간을 보낸 점이 전반적으로 아쉬운 기억으로 남는다. 그렇다보니 “내가 작년...

Gradle file system watching: 동작방식 및 사용법

File system watching: incremental build*를 매우 가속화하는 기능 기본적으로 Gradle은 build 시마다 file system을 polling함 (매번 확인함) File system watching을 활성화하면, Gradle이 build 사이에 file system에 대해 학습한 것들을 메모리에 저장하고...

Ktlint Gradle 플러그인 비교 (ktlint-gradle vs kotlinter-gradle)

Gradle 프로젝트에서 ktlint를 사용할 때는 보통 gradle plugin을 사용한다. ktlint 플러그인 중 가장 많이 사용하는 플러그인 2개 ktlint-gradle, kotlinter-gradle를 소개하고 비교한다. ktlint는 Javascript의 eslint처럼 Kotlin의 lint* tool이다. lint?: 작성한 ...

DNS 동작 방식 이해

웹브라우저에서 google.com 접속을 시도하면, DNS query를 통해 해당 도메인의 IP 정보를 획득하여 요청을 보낸다는 것은 대부분 알고 있을 것이다. 하지만, 그것은 DNS의 빙산의 일각일 뿐이다. DNS에 대해 조금더 깊이 알아보자. Motivation DNS 장애는 꽤나 무서운 일이다. 장애가 한 번 발생되면 DNS 레코드가 수많은 ...

Spring Boot: application properties 파일 override, 적용 우선순위 (+ Cloud Config)

회사에서 팀원이 “Cloud config에서 정의된 property를 application.properties 파일로 override 할 수 있나요?”라고 질문했다. 가능하다는 것은 해봐서 알고 있었지만, Spring Cloud config 공식 문서에서 관련 레퍼런스를 본 적은 없었다. 왜 가능한걸까? Spring Boot는 application ...

Spring Boot Elasticsearch 사용법 및 동작방식

Spring ecosystem에는 대부분의 외부 시스템을 위한 모듈이 있다. Elasticsearch도 마찬가지다. Elasticsearch를 위한 Spring Boot와 Spring Data에 대하여 알아본다. 추가로, 본인이 회사 업무에서 마주했던 use case들도 작성해보았다. Spring boot starter data elasticsear...

Spring Cloud Config: 사용법 소개

Spring Cloud Config는 분산 시스템에서 통합 설정을 중앙화하여 관리할 수 있게 해주는 시스템이다. 보통 여러 개의 Microservice들이 모여 하나의 Application을 구성하는 MSA에 적합한 도구다. 간단한 사용법을 살펴보자. 아래 공식 문서의 Quick start 섹션을 참고헀다. https://docs.spring.io/...

Medium 블로그에서 이사온 이유, 블로그 플랫폼 비교

왜 2년동안 사용하던 Medium을 버리고 github.io로 이사온 이유를 개발자로서 이야기하려 한다. 2021년 1월 (정확히 2년 전) Medium에 첫 글을 publish했다. 내가 Medium에 publish한 포스트는 50개다. (생각보다 많았다) 그리고 2023년 1월 현재, github.io로 블로그를 이사왔다. Medium이 불편하...

My Medium post links

Kotlin: 코루틴 vs Suspending function 차이 Logback: logger additivity=false 플래그 Kotlin: Mono.awaitSingleOrNull()의 non-nullable 반환 문제 Spring Boot: YAML List property 주입 시 Could not resolve place...

AWS EC2 프리티어 ubuntu 인스턴스 생성

Introduction Motivation 회사에서 서비스를 배포하기 위해 AWS를 사용하고 있다 현재 필자가 맡은 프로젝트는 아직 배포 전이지만, 머지않아 AWS를 사용하여 배포될 예정이다 AWS 사용법을 미리 익혀보고 개인 프로젝트를 배포해보기 위해 프리티어 계정을 만들어 사용해보려 한다 ECS, ECR을 사용해보고 싶었지만 프리티...

RDBMS Schema란 무엇인가

회사에서 참여하고 있는 프로젝트가 Exposed SQL Framework와 Flyway DB Migration Tool를 사용하고 있다 이 두 Tool들이 DB Schema를 생성하는 것을 보고, Schema가 구체적으로 무엇인지 호기심이 생겼다 PostgreSQL 문서에 Schema에 대한 내용을 읽고 정리해보았다 P...

Kotlin Object, Companion Object, Anonymous Object

아래 Kotlin 공식 문서에서 관련 내용을 찾을 수 있었다 Objects and companion objects Object Kotlin에서는 language-level에서 singleton pattern이 지원된다 class 대신, object 키워드를 사용하여 선언하면 그 object는 sin...

UUID란? UUID 정의 (aka GUID)

UUID는 Universally unique identifier의 약자로서, 정보 식별을 위하여 사용되는 식별자이다 128-bit 숫자로 이루어져 있으며, xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx 형식으로 표현한다 UUID의 장점 중, 데이터들이 나중에 단일 DB로 통합되거나, 같은 채널에서 전송되더라도 식별자가 ...

Reactor Reference Reading

Spring WebFlux에 내장되어 있는 Reactor를 사용하기 위해 Reactor Reference를 읽으면서 공부하게 되었다 Reactor는 Rx와 같은 Reactive 패러다임의 구현체이며, Reactive Streams sepc의 구현도 포함하고 있는 Java 라이브러리이다 Reactor reference를 읽으면서 공부해보았고...

기술 블로그 시작

글 작성 테스트를 위한 포스트입니다. Github Web에서 작성은 불편해서, Local IDE에서 작성해야겠습니다. 줄바꿈을 하려면, 줄 사이에 여백 라인이 필요합니다. 타 블로그 사이트들에 대한 github.io의 차별점은 아래와 같습니다. 포스팅이 commit log로 남는다. 뿌듯함을 느낄 수 있다 단, for...