web/Spring
만들면서 배우는 아키텍처 그리고 매핑 프레임워크 MapStruct를 사용한 매핑
만들면서 배우는 아키텍처 (Get Your Hands Dirty on Clean Architecture) 요새 읽던 책중에 'Get Your Hands Dirty on Clean Architecture' 책이 인상 깊었다. 원서로 팀원들과 스터디 하고 나서 인상깊어서 '만들면서 배우는 아키텍처'라는 번역으로 다시 한번 봤다. 원서는 구어체로 되어있어 내용은 좋았지만 친절하지 못한 느낌이었다면 번역본은 깔끔하게 정리되어있어서 너무 맘에 들었다. 인상깊었던 몇 부분을 정리하면 첫번째로 육각형 아키텍처에서 포트-어댑터 패턴을 사용하여 호출 당하는쪽은 호출하는쪽을 몰라도 되고 port interface로 통신하는 부분이 인상 깊었고 interface가 만드는쪽에서만 명세(설계도)를 알 수 있다는 장점만을 생각했..
@Transactional이 동작하지 않는 이유
개발을 elasticsearch, ddb, redis, mongo등을 사용하여 하다보면 가끔 rdb 자체에 transaction 기능이 너무 부러울 때가 있다. transaction은 '데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다' 사전적 의미와 같이 하나의 작업 단위의 묶음으로 작업이 실패하였을 때 롤백을 할 수 있어 데이터의 완결성을 지켜줄 수 있는 무기이다. 하지만 트랜잭션이 정상적으로 동작하지 못하는 경우가 있는데 이를 제대로 알고 사용하지 못하면 문제가 된다. 동작방식 우선 트랜잭션은 기본적인 동작방식은 AOP의 대표적인 사례라고 할 수 있듯이 AOP로 동작한다. Aop는 핵심기능이 아닌 반복되는 부가적인 기능들을 핵심기능에서 벗어나서 더욱더 핵심기능이 객체지향적인 동작을..
[카카오][세미나] Webflux로 막힘없는 프로젝트 만들기 - 정리
Spring Mvc - 하나의 요청에 하나의 쓰레드만이 사용되기 때문에 직관적 - 요청 하나의 응답이 길어지게 되면 쓰레드 하나가 계속 붙잡히고 이렇게 쓰레드들이 계속 밀리게 되면 쓰레드풀이 고갈되어 전체 시스템에 문제가 발생 Spring Webflux - 외부 시스템의 응답이 늦어져도 쓰레드가 홀딩되는 문제를 예방할 수 있다. - reactor로 개발된 코드가 circuit breaker를 연동하는데 더욱 용이하다는 장점이 있다. Reactor Meltdown - webflux는 netty의 이벤트 루프 방식을 차용한 방식으로 queue에 쌓인 이벤트를 event loop 쓰레드가 이를 처리하는 방식으로 쓰레드풀 고갈 문제를 발생하지 않음 - mvc의 기본 업무 단위는 요청 webflux는 이벤트 - ..
Spring Webflux url length 제한 413 에러 해결 방법
프로젝트에서 사용되는 특정 api에 request param의 길이가 길어지는 api가 현재 구조상 어쩔 수 없이 존재하게 되었다. 그렇게 조심스럽게 운영하다가 request param의 길이가 너무 길어져서 api에서 413에러를 내뱉으면서 결과를 반환 받지 못하는 문제가 생겼다. 우선 nginx에 있는 request param 길이 관련 설정이 문제를 유발하는지 확인해봤다. 우선 테스트를 위한 api를 하나 만들었다. 단순하게 요청을 받고 바로 반환하는 api package com.wedul.reactivetest; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annot..
WebFlux에서 Mono, Flux에 Map 또는 flatMap을 사용할 때 null을 리턴하는 경우
WebFlux로 구성되어 있는 프로젝트에서 Mono, Flux stream에서 map이나 flatMap을 사용해서 특정 데이터를 매핑하는 과정에서 특정한 경우에 대해서 null을 리턴하고 다음 파이프라인에서 filter로 Objects의 nonNull을 사용해서 컨텐츠를 필터링 하려고 했다. 작성하려고 한 코드의 일부 예시를 만들어서 작성해봤다. 만약 resultData를 통해 전달받은 데이터가 예상 대로라면 map과정에서 500보다 큰 5189값만 정상 반환하고 나머지는 null을 반환한 후 filter를 통해 정상적으로 하나의 데이터만 남을 것이라고 예상했다. @Test @DisplayName("map 과정에서 반환된 null이 정상적으로 필터링 되었는지 확인하는 테스트") void mono_null..
Spring Boot version 2.1.x에서 2.2.x (spring frame 5.2 이상)으로 버전업 진행 시 Spring Cloud AWS SnsAutoConfiguration 에서 TypeNotPresentExceptionProxy 가 발생하며 실행안되는 문제
문제 발생 평소 문제가 많았던 webflux 부분 수정을 위해 spring boot 2.1.3에서 2.2.7버전으로 업그레이드를 진행하기 위해 gradle에서 spring boot version을 2.2.7로 변경하고 애플리케이션을 실행 시켰다. 그런데 평소에는 자주본적이 없던 TypeNotPresentExceptionProxy 에러가 발생했다. org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.baemin.bmart.search.BmartSearchAdminApplication]; nested exception is java..
Spring reactor 2.1.2 (netty 0.8.4) Mono.zip readTimeoutException 문제
Mono zip 각 Mono 처리 스레드를 병렬로 실행하고 이를 묶어서 사용할 수 있는게 Mono.zip이다. 근데 Mono zip에서 병렬로 실행되는 작업 중 하나가 empty 또는 error가 발생 되면 바로 error 또는 complete를 내뱉게 되어있다. 하지만 각 Mono 구독 작업에 error와 empty 발생 시 문제에 대해 fallback 처리를 해주면 에러가 발생하더라도 그 로직을 타게 되어있다. 하지만 2.1.2(netty 0.8.4) 버전을 사용하고 있을 때 호출 체인에서 첫 번째 요청의 실패 이후에 두 번째 요청이 정상적으로 이루어 지지 않아서 readTimeout이 발생되는 문제를 경험하였습니다. 이 문제를 해결하기 위해서 알아보던 중 2.1.2버전에 문제가 있는 것을 알게 되어..
Spring boot2 resilience4j를 이용한 circuit breaker 사용
fault tolerance library (장애 허용 시스템) fault tolerance library는 무엇인가? 간단하게 이야기해보자. MSA 환경에서 한 개의 서비스에서 다른 api를 호출 할 때 일시적으로 에러가 발생하고 있다고 가정해보자. 만약 이 시기에 요청이 계속 들어오면 계속 500에러를 내보내게 된다. 그럼 사용자들은 이 서비스에 대해서 신뢰를 잃어 버리게 되고 안좋은 인식을 만들 수 있다. 그래서 특정 api 호출과 같은 작업에 에러가 발생했을 때, 그 횟수를 정해놓고 그 횟수 이상 에러를 초과하면 기존에 설정해 놓은 fallback에 맞게 동작하게 하고 일정 시간 후에 다시 시도하여 진행하는 등에 작업이 필요하다. 이게 바로 fault tolerance library (장애 허용 ..
spring cloud resilience4j 사용시 CircuitBreakerConfiguration 에러
CircuitBreaker 테스트를 위해서 Resilience4j를 사용했다. 버전은 1.3.0을 사용하려고 했다. //Resilience4J compile("io.github.resilience4j:resilience4j-spring-boot2:1.3.0") compile("io.github.resilience4j:resilience4j-reactor:1.3.0") compile("io.github.resilience4j:resilience4j-timelimiter:1.3.0") 그런데 분명 1.3.0을 사용한다고 명시하였고 gradle도 clean하고 사용하는 denpendency도 확인하였는데 계속해서 다음과 같이 1.1.0 라이브러리를 사용하려고 해서 문제가 발행했다. Cannot resolve ..
RestHighLevelClient를 사용하여 search after 기능 구현하기
https://wedul.site/541에서 search after 기능을 사용해서 검색을 하는 이유를 알아봤었다. 그럼 spring boot에서 RestHighLevelClient를 이용해서 search after를 구현을 해보자. 1. Mapping 우선 index가 필요한데 간단하게 상품명과 지역 가격정보들을 가지고 있는 wedul_product 인덱스를 만들어 사용한다. { "settings": { "index": { "analysis": { "tokenizer": { "nori_user_dict": { "type": "nori_tokenizer", "decompound_mode": "mixed", "user_dictionary": "analysis/userdict_ko.txt" } }, "ana..