포스트

2022-04-25-TIL

Today I Learned

ZGC vs G1GC

둘 다 HotSpot JVM의 가비지 컬렉터이고, 목표가 다르다.

  • G1(Garbage-First): 힙을 같은 크기의 리전으로 나누고, 쓰레기가 많은 리전부터 수집한다. 처리량과 정지 시간 사이의 균형을 목표로 하며 -XX:MaxGCPauseMillis로 목표 정지 시간을 지정한다. JEP 248로 JDK 9부터 서버 환경의 기본 GC가 되었다. JEP는 대부분의 사용자에게 처리량을 최대화하는 것보다 정지 시간을 제한하는 것이 더 중요하다는 점을 이유로 든다.
  • ZGC: 확장 가능한 저지연 GC다. JEP 333은 목표로 GC 정지 시간이 10ms를 넘지 않을 것, 수백 MB에서 수 TB까지의 힙을 다룰 것, G1 대비 애플리케이션 처리량 감소가 15% 이내일 것을 내세운다. 컬러 포인터와 로드 배리어로 객체 이동(압축)까지 애플리케이션 스레드와 동시에 수행하기 때문에, 정지 시간이 힙 크기에 거의 비례하지 않는다. JDK 11에서 실험 기능으로 들어왔고 JEP 377로 JDK 15에서 정식 기능이 되었다. -XX:+UseZGC로 켠다.

정지 시간이 응답 지연에 직접 영향을 주는 대용량 힙 서비스라면 ZGC를, 일반적인 서버 애플리케이션이라면 기본값인 G1부터 시작하는 것이 보통이다. 링크된 Red Hat 글도 처리량, 지연 시간, 메모리 사용량 중 무엇을 우선하는지에 따라 GC를 고르라고 정리한다. 어느 쪽이든 GC 로그(-Xlog:gc*)를 남겨 실제 정지 시간과 빈도를 보고 판단해야 한다.

  • https://huisam.tistory.com/entry/jvmgc
  • https://www.diva-portal.org/smash/get/diva2:1466940/FULLTEXT01.pdf
  • https://www.dynatrace.com/resources/ebooks/javabook/impact-of-garbage-collection-on-performance/
  • https://www.ibm.com/docs/no/aix/7.2?topic=monitoring-garbage-collection-impacts-java-performance
  • https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/performissues003.html
  • https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/index.html
  • https://www.overops.com/blog/improve-your-application-performance-with-garbage-collection-optimization/
  • https://medium.com/leadkaro/z-garbage-collector-zgc-in-java-14-bd8a2fff4943
  • https://developers.redhat.com/articles/2021/11/02/how-choose-best-java-garbage-collector
  • https://www.linkedin.com/pulse/choosing-best-garbage-collection-algorithm-better-java-prasad
  • https://kstefanj.github.io/2021/11/24/gc-progress-8-17.html
  • https://www.baeldung.com/jvm-garbage-collectors

e.printStackTrace() 단점

e.printStackTrace()는 스택 트레이스를 표준 에러(System.err)로 바로 출력한다. 그래서 로깅 프레임워크의 레벨, 포맷, 출력 대상 설정을 전혀 따르지 않고, 로그 파일이나 로그 수집 시스템에 남지 않을 수 있으며, 요청 ID 같은 문맥 정보도 붙지 않는다. 여러 스레드의 출력이 섞이기도 한다. 예외는 log.error("주문 처리 실패 orderId={}", orderId, e)처럼 로거에 예외 객체를 마지막 인자로 넘겨 스택 트레이스와 함께 기록하는 것이 맞다.

  • https://tgyun615.com/59

@RequestPart

@RequestPart는 multipart/form-data 요청의 파트 하나를 메서드 인자에 바인딩한다. MultipartFile뿐 아니라 일반 객체도 받을 수 있는데, 이때는 @RequestBody처럼 파트의 Content-Type을 보고 HttpMessageConverter로 변환한다. @RequestParam도 파트를 받을 수 있지만, 문자열이나 파일이 아닌 타입은 등록된 Converter로 변환한다는 점이 다르다. 그래서 Javadoc은 이름-값 형태의 폼 필드에는 @RequestParam을, JSON이나 XML처럼 복잡한 내용을 담은 파트에는 @RequestPart를 쓰라고 안내한다.

1
2
3
@PostMapping(value = "/posts", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void create(@RequestPart("post") PostRequest post,
                   @RequestPart(value = "image", required = false) MultipartFile image) { }

클라이언트는 post 파트에 Content-Type: application/json을 지정해서 보내야 JSON 변환이 된다.

  • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestPart.html
  • https://www.baeldung.com/sprint-boot-multipart-requests
  • https://ykh6242.tistory.com/115
  • https://stackoverflow.com/questions/16230291/requestpart-with-mixed-multipart-request-spring-mvc-3-2

Config file processingin Spring Boot 2.4

Spring 블로그 글은 Spring Boot 2.4에서 application.properties/application.yml 처리 방식이 바뀐 이유와 내용을 설명한다. 쿠버네티스의 ConfigMap처럼 볼륨으로 마운트된 설정을 지원하려다 보니, 기존 코드에서 프로파일별 문서가 다른 프로파일을 추가로 활성화할 수 있고 문서가 추가되는 순서를 예측하기 어렵다는 문제가 걸림돌이 되었다고 한다. 바뀐 점은 다음과 같다.

  • 여러 문서로 나눈 설정 파일은 위에서 아래로 적힌 순서대로 처리되고, 뒤의 문서가 앞의 값을 덮어쓴다. .properties 파일에서도 #---로 문서를 나눌 수 있다.
  • 문서 활성화 조건은 spring.profiles 대신 spring.config.activate.on-profile로 쓴다. 프로파일별 문서 안에서 다른 프로파일을 활성화할 수 없다.
  • spring.config.import로 다른 설정 파일이나 configtree:/etc/config/ 같은 볼륨 마운트 설정 트리를 불러올 수 있다.
  • spring.config.activate.on-cloud-platform으로 특정 클라우드 플랫폼(예: 쿠버네티스)에서만 활성화되는 문서를 만들 수 있다.

예전 방식이 필요하면 spring.config.use-legacy-processing=true로 되돌릴 수 있다.

  • https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4
참고한 자료외부 출처 4

외부 출처

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

댓글

아직 댓글이 없습니다