포스트

2022-04-21-TIL

Today I Learned

JPA Duplicated

JPA 엔티티는 같은 이름으로 여러개 생성할 수 없다.

엔티티 이름은 JPQL에서 엔티티를 가리키는 이름이고, 따로 지정하지 않으면 패키지를 뺀 클래스 이름이 된다. 그래서 다른 패키지에 같은 이름의 클래스(order.domain.Item과 product.domain.Item)를 각각 엔티티로 두면 영속성 유닛 안에서 이름이 겹쳐 애플리케이션 시작 시 오류가 난다. 클래스 이름을 바꾸거나 @Entity(name = "ProductItem")처럼 엔티티 이름을 명시해서 해결한다. 테이블 이름은 @Table로 따로 지정하므로 엔티티 이름을 바꿔도 테이블에는 영향이 없다.

  • https://programmingnote.tistory.com/88

Model Mapper

ModelMapper는 객체 사이의 매핑을 런타임에 리플렉션으로 처리하는 라이브러리다. modelMapper.map(member, MemberDto.class)처럼 호출하면 이름이 비슷한 속성을 규칙에 따라 찾아 값을 옮긴다. 설정 없이 바로 쓸 수 있지만, 매핑 규칙이 암묵적이라 필드 이름이 바뀌면 조용히 값이 빠질 수 있고, 리플렉션 비용이 있다. 매핑 검증이 필요하면 validate()로 매핑되지 않은 속성이 있는지 확인한다.

  • baeldung.com/java-modelmapper

Map Struct

MapStruct는 컴파일 시점에 매핑 구현 코드를 생성하는 애너테이션 프로세서다. ModelMapper와 반대로 생성된 코드가 일반 getter/setter 호출이라 빠르고, 매핑할 수 없는 속성이 있으면 빌드 단계에서 경고나 오류로 알려 준다. Lombok과 함께 쓸 때는 애너테이션 프로세서 순서 설정(lombok-mapstruct-binding)이 필요하다.

  • https://www.youtube.com/watch?v=nvjqtWQ5zj8
  • https://www.youtube.com/watch?v=ZuW38xQYUgc

War and Jar

JAR는 실행 가능한 자바 아카이브, WAR는 서블릿 컨테이너에 배포하기 위한 웹 애플리케이션 아카이브다. Spring Boot는 내장 서버를 포함한 JAR를 기본으로 쓰고, 외부 톰캣에 배포해야 할 때만 WAR로 패키징한다.

  • https://memo-the-day.tistory.com/216

Scrum

스크럼은 복잡한 문제를 짧은 주기로 나눠 점검하고 적응하며 해결하는 애자일 프레임워크다. 스크럼 가이드 2020을 기준으로 정리하면 다음과 같다.

  • 책임(accountabilities): 개발자(Developers), 제품 책임자(Product Owner), 스크럼 마스터(Scrum Master)
  • 이벤트: 스프린트(한 달 이하의 고정 길이), 스프린트 계획, 데일리 스크럼(개발자를 위한 15분), 스프린트 리뷰, 스프린트 회고
  • 산출물: 제품 백로그, 스프린트 백로그, 증분(Increment)

스프린트가 끝나면 이전 스프린트가 끝나자마자 다음 스프린트가 바로 시작된다. 매 스프린트마다 사용할 수 있는 증분을 만들고, 리뷰와 회고로 제품과 일하는 방식을 함께 개선하는 것이 핵심이다.

  • https://asana.com/ko/resources/what-is-scrum?utm_campaign=NB–KO–KR–Catch-All–All-Device–DSA&utm_source=google&utm_medium=pd_cpc_nb&gclid=CjwKCAjwu_mSBhAYEiwA5BBmf09u4pb7frO25nd7m6sufXwrUcter2GkDp-c4Mm1OU8syzwhRCRfsBoCGFwQAvD_BwE&gclsrc=aw.ds

QueryDSL Sorting

Pageable의 Sort필드를 그대로 사용하는 방법으로 정렬을 하는게 가장 적합하고, 요청 쿼리 파라미터에는 sort=regDt,asc와 같은 형식으로 주어지면 Pageable의 Sort에서 받아진다.

위 유틸은 정렬할 필드 이름을 문자열로 받아 Expressions.path로 경로를 만들고 OrderSpecifier로 감싼다. 이를 이용해 Pageable의 Sort를 QueryDSL 정렬 조건으로 바꾸면 다음과 같다.

1
2
3
4
5
6
List<OrderSpecifier<?>> orders = pageable.getSort().stream()
        .map(o -> QueryDslUtil.getSortedColumn(
                o.isAscending() ? Order.ASC : Order.DESC, member, o.getProperty()))
        .collect(Collectors.toList());

query.orderBy(orders.toArray(OrderSpecifier[]::new));

주의할 점은 클라이언트가 보낸 필드 이름을 그대로 경로로 쓰면 엔티티에 없는 필드나 정렬을 허용하지 않을 필드도 들어올 수 있다는 것이다. 허용할 정렬 필드를 화이트리스트로 검사한 뒤 변환하는 편이 안전하다.

1
2
3
4
5
6
7
8
9
10
11
12
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.Expressions;

public class QueryDslUtil {

    public static OrderSpecifier<?> getSortedColumn(Order order, Path<?> parent, String fieldName) {
        Path<Object> fieldPath = Expressions.path(Object.class, parent, fieldName);
        return new OrderSpecifier(order, fieldPath);
    }
}
  • https://joont92.github.io/jpa/QueryDSL/
  • https://kawaii-jordy.tistory.com/99
  • https://uchupura.tistory.com/7
  • https://stackoverflow.com/questions/13072378/how-can-i-convert-a-spring-data-sort-to-a-querydsl-orderspecifier
  • https://dev-racoon.tistory.com/38
  • https://stackoverflow.com/questions/44757218/spring-pagination-request-parameters

QuerydslRepositorySupport

QuerydslRepositorySupport는 Spring Data JPA가 제공하는 추상 클래스로, 상속하면 from()으로 시작하는 QueryDSL 쿼리와 getQuerydsl().applyPagination(pageable, query)를 이용한 페이징을 쓸 수 있다. 다만 select가 아니라 from으로 시작하는 QueryDSL 3 스타일 API이고 JPAQueryFactory를 직접 쓰지 않는다. 그래서 링크된 글처럼 사용자 정의 리포지토리 구현체에서 JPAQueryFactory를 빈으로 주입받아 쓰거나, 이 클래스를 상속해 필요한 기능을 확장한 자체 지원 클래스를 만들어 쓰는 경우가 많다.

  • https://jessyt.tistory.com/55

WebClient vs RestTemplate vs Feign

세 가지 모두 스프링 애플리케이션에서 다른 HTTP API를 호출하는 클라이언트다.

  • RestTemplate: 동기, 블로킹 방식이다. 요청 하나당 스레드 하나가 응답을 기다린다. Javadoc에 따르면 Spring 5.0부터 유지 보수 모드라 사소한 변경과 버그 수정만 받으며, 동기, 비동기, 스트리밍을 모두 지원하는 WebClient를 고려하라고 권한다.
  • WebClient: Spring WebFlux의 논블로킹 리액티브 클라이언트다. 적은 스레드로 많은 요청을 동시에 처리할 수 있고, block()으로 동기식으로도 쓸 수 있다. 대신 WebFlux 의존성과 Reactor의 Mono/Flux 개념이 필요하다.
  • OpenFeign(Spring Cloud OpenFeign): 인터페이스에 @FeignClient와 매핑 애너테이션만 선언하면 구현체가 만들어지는 선언적 클라이언트다. 스프링 MVC 컨트롤러와 비슷한 모양으로 호출 코드를 줄일 수 있고, 서비스 디스커버리(Eureka)와 로드 밸런싱과 쉽게 연결된다. 기본적으로는 블로킹 방식이다.

링크된 우아한형제들 글은 Feign을 실제 서비스에 적용한 사례와 설정을 다룬다.

  • https://stackoverflow.com/questions/46884362/what-are-the-advantages-and-disadvantages-of-using-feign-over-resttemplate#:~:text=Feign%20will%20handle%20your%20server%20requests%20perfectly%20fine.&text=is%20not%20useful-,Show%20activity%20on%20this%20post.,across%20to%20the%20other%20service.
  • https://velog.io/@jifrozen/Microservice-%EA%B0%84-%ED%86%B5%EC%8B%A0-resttemplate-vs-feign-client
  • https://www.baeldung.com/spring-webclient-resttemplate#:~:text=RestTemplate%20uses%20Java%20Servlet%20API,the%20response%20to%20come%20back.
  • https://www.baeldung.com/spring-cloud-openfeign
  • https://lemontia.tistory.com/1044
  • https://techblog.woowahan.com/2630/
  • https://honeyinfo7.tistory.com/236
  • https://velog.io/@yaincoding/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%94%94%EC%8A%A4%EC%BB%A4%EB%B2%84%EB%A6%ACwith-%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4-%EC%9C%A0%EB%A0%88%EC%B9%B4
  • https://covenant.tistory.com/251
  • https://hojak99.tistory.com/482

Reactive

리액티브 프로그래밍은 데이터 흐름과 변경 전파를 중심으로, 비동기 이벤트 스트림을 조합해 처리하는 방식이다. 자바 진영에서는 Reactive Streams 명세가 비동기 스트림 처리와 배압(backpressure, 소비자가 처리할 수 있는 만큼만 요청하는 흐름 제어)을 표준화했고, Project Reactor, RxJava가 이를 구현한다. Spring WebFlux는 Reactor 위에서 동작한다. 블로킹 I/O가 섞이면 이점이 사라지므로 DB 드라이버까지 논블로킹(R2DBC 등)이어야 효과가 크다.

  • https://xzio.tistory.com/1857

CNCF

CNCF(Cloud Native Computing Foundation)는 리눅스 재단 산하의 비영리 재단으로, 클라우드 네이티브 기술의 오픈소스 프로젝트를 벤더 중립적으로 운영한다. Kubernetes, Prometheus, Envoy 등이 CNCF 프로젝트다. 프로젝트는 성숙도에 따라 Sandbox, Incubating, Graduated 단계로 나뉜다. CNCF는 클라우드 네이티브를 퍼블릭, 프라이빗, 하이브리드 클라우드 같은 동적인 환경에서 확장 가능한 애플리케이션을 만들고 운영하게 하는 기술로 정의하고, 컨테이너, 서비스 메시, 마이크로서비스, 불변 인프라, 선언적 API를 그 예로 든다.

  • http://www.opennaru.com/kubernetes/cloud-native-computing-foundation-cncf/
  • https://wonit.tistory.com/490

Redis Command and Data Structure

Redis는 키-값 형태의 인메모리 데이터 저장소이고, 값으로 여러 자료구조를 지원한다.

자료구조대표 명령쓰임
StringSET, GET, INCR캐시, 카운터
ListLPUSH, RPOP, LRANGE큐, 최근 목록
SetSADD, SMEMBERS, SINTER중복 없는 집합, 태그
Sorted SetZADD, ZRANGE, ZRANK랭킹, 우선순위 큐
HashHSET, HGET, HGETALL객체 필드 저장

이 밖에 Stream, Bitmap, HyperLogLog, Geospatial 인덱스도 있다. redis-cli에서 PING으로 서버 연결을 확인하고, 키에는 EXPIRE로 만료 시간을 줄 수 있다. 링크 중 Redis Sentinel 치트시트는 마스터를 감시하다가 장애가 나면 레플리카를 마스터로 승격시키는 Sentinel의 명령을 정리한 것이다.

  • https://www.tutorialspoint.com/redis/redis_commands.htm#:~:text=To%20start%20Redis%20client%2C%20open,you%20can%20run%20any%20command.&text=In%20the%20above%20example%2C%20we,server%20is%20running%20or%20not.
  • https://lzone.de/cheat-sheet/Redis%20Sentinel
  • http://intro2libsys.info/introduction-to-redis/redis-data-types
  • https://docs.deistercloud.com/content/Axional%20development%20libraries.20/Server%20side%20javascript.50/AX%20Library.10/redis/index.xml?embedded=true&navbar=0&param-iframe=index-iframe
  • https://redis.com/redis-enterprise/data-structures/

In-memory Caching

인메모리 캐싱은 자주 읽고 잘 바뀌지 않는 데이터를 메모리에 두어 DB나 외부 API 호출을 줄이는 방법이다. 애플리케이션 프로세스 안에 두는 로컬 캐시(Caffeine, Ehcache)는 가장 빠르지만 서버마다 따로 존재해 데이터가 어긋날 수 있고, Redis나 Memcached 같은 원격 캐시는 여러 서버가 공유하지만 네트워크 비용이 든다.

Spring의 캐시 추상화를 쓰면 @EnableCaching을 켜고 메서드에 @Cacheable("books")를 붙이는 것만으로 같은 인자의 호출 결과를 캐시에서 돌려준다. @CacheEvict, @CachePut으로 캐시를 비우거나 갱신하며, 실제 저장소는 설정에 따라 바꿀 수 있다. 캐시는 원본이 바뀌었을 때의 무효화 전략과 만료 시간을 함께 설계해야 한다.

  • http://cloudinsight.net/data/%EC%9D%B8%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%BA%90%EC%8B%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0/
  • https://spring.io/guides/gs/caching/
  • https://eastglow.github.io/back-end/2020/05/17/Spring-Spring-Boot%EC%97%90%EC%84%9C-memcached-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0.html

Spring HealthCheck

Spring Boot Actuator를 추가하면 /actuator/health로 애플리케이션 상태를 확인할 수 있다. 로드 밸런서나 쿠버네티스의 헬스 체크 대상으로 이 엔드포인트를 지정하면, 상태가 DOWN인 인스턴스에는 트래픽을 보내지 않는다.

  • https://webgori.github.io/spring/2020/08/02/Spring-Boot-Health-Check-%EC%B6%94%EA%B0%80.html

Spring Boot Admin

Spring Boot Admin은 여러 Spring Boot 애플리케이션의 Actuator 엔드포인트를 하나의 웹 UI로 모아 보여 주는 관리 도구다. 헬스 상태, 메트릭, 로그 레벨, 환경 정보를 한 화면에서 확인하고 상태 변화 알림을 받을 수 있다.

  • https://www.baeldung.com/spring-boot-admin#:~:text=Spring%20Boot%20Admin%20is%20a,the%20Spring%20Boot%20Actuator%20endpoints.
참고한 자료외부 출처 4

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다