포스트

2023-02-16-TIL

2023-02-16-TIL

Today I Learned

Java Excel Library

자바에서 엑셀 파일을 다루는 사실상의 표준은 Apache POI다. .xls(BIFF 바이너리)는 HSSF, .xlsx(OOXML)는 XSSF가 담당하고, 둘을 공통 Workbook 인터페이스로 다룰 수 있다. 문제는 대용량이다. 참고한 글처럼 XSSFWorkbook은 추가한 셀을 저장할 때까지 모두 메모리에 들고 있어서, 행이 많아지면 느려지고 메모리가 부족해진다.

쓰기에서는 POI의 스트리밍 API인 SXSSFWorkbook이 해법이다. 생성할 때 지정한 윈도 크기만큼의 행만 메모리에 두고, 넘치는 행은 임시 파일로 내보낸다. 대신 이미 내보낸 행에는 다시 접근할 수 없다. 읽기에서는 monitorjbl/excel-streaming-reader가 POI 위에서 스트리밍 방식으로 시트를 읽어, 워크북 전체를 올릴 때 생기는 메모리 급증을 피한다. dhatim/fastexcel은 POI에 의존하지 않고 xlsx를 직접 쓰는 가벼운 라이브러리로, 기능은 적지만 대용량 내보내기에 빠르다.

  • https://github.com/apache/poi/tree/trunk/poi/src/main/java/org/apache/poi
  • https://poi.apache.org/
  • https://jaimemin.tistory.com/2191
  • https://andriymz.github.io/misc/apache-poi-slow-excel-generation/
  • https://www.baeldung.com/java-microsoft-excel
  • https://www.guru99.com/all-about-excel-in-selenium-poi-jxl.html
  • https://www.grapecity.com/blogs/12-reasons-to-use-grapecity-documents-for-excel-java-over-apache-poi
  • https://howtodoinjava.com/java/library/read-write-large-excel-files/
  • https://zetcode.com/java/fastexcel/
  • https://deepakschoudhary.medium.com/how-i-escaped-apache-poi-and-found-my-dream-3rd-party-excel-writer-5e56dd73e407
  • https://codoid.com/automation-testing/java-excel-libraries/
  • https://products.fileformat.com/spreadsheet/java/
  • https://products.fileformat.com/spreadsheet/java/fastexcel/
  • https://github.com/monitorjbl/excel-streaming-reader
  • https://monitorjbl.github.io/

Hang

행(hang) 또는 프리즈(freeze)는 프로세스나 시스템이 입력에 더 이상 반응하지 않는 상태다. 프로그램이 죽은 것은 아니지만 응답하지 못한다는 점에서 크래시와 다르다. Wikipedia는 소프트웨어 원인으로 종료 조건이 잘못된 무한 루프, 결코 오지 않을 이벤트를 기다리는 스레드, 프로세스 간 통신의 경쟁 상태를 든다. 서버 애플리케이션에서는 데드락이나 커넥션 풀 고갈로 모든 스레드가 대기에 빠지는 경우가 대표적이고, 이때는 스레드 덤프로 각 스레드가 무엇을 기다리는지 확인한다. 저장해 둔 맨텍 페이지는 지금 404를 반환한다.

  • https://www.mantech.co.kr/hang-solutions/#:~:text=%ED%96%89(hang)%EC%9D%B4%EB%9E%80%20%EC%8B%9C%EC%8A%A4%ED%85%9C%2C,%EB%B6%88%EA%B0%80%EB%8A%A5%ED%95%9C%20%EC%83%81%ED%83%9C%EB%A5%BC%20%EB%9C%BB%ED%95%A9%EB%8B%88%EB%8B%A4.

Graceful Shutdown

graceful shutdown은 종료 신호를 받으면 새 요청은 더 받지 않고, 처리 중인 요청과 정리 작업을 마친 뒤 프로세스를 끝내는 방식이다. 하던 일을 그 자리에서 끊는 hard shutdown과 대비된다. Spring Boot는 server.shutdown=graceful로 이를 켤 수 있고, 내장 서버 네 가지(Jetty, Reactor Netty, Tomcat, Undertow) 모두 지원한다. 문서에 따르면 Jetty, Reactor Netty, Tomcat은 네트워크 계층에서 새 요청을 막고, Undertow는 요청을 받되 바로 503으로 응답한다. 기존 요청을 기다리는 최대 시간은 spring.lifecycle.timeout-per-shutdown-phase로 정한다.

1
2
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=20s

JVM 수준에서는 SIGTERM을 받으면 등록된 셧다운 훅이 실행되고, 스프링 컨텍스트 종료도 이 훅에서 시작된다. kill -9(SIGKILL)는 훅을 실행할 기회조차 주지 않으므로 graceful shutdown이 동작하지 않는다.

  • https://www.techtarget.com/whatis/definition/graceful-shutdown-and-hard-shutdown
  • https://bravenamme.github.io/2020/10/06/graceful-shutdown/
  • https://2kindsofcs.tistory.com/53
  • https://effectivesquid.tistory.com/entry/JVM%EC%9D%98-%EC%A2%85%EB%A3%8C%EC%99%80-Graceful-Shutdown

core-js

core-js는 최신 ECMAScript 기능을 오래된 JavaScript 엔진에서도 쓸 수 있게 해 주는 폴리필(polyfill) 라이브러리다. 대부분의 개발자는 Babel 같은 트랜스파일러를 통해 간접적으로 쓰고 있어서 존재를 모르는 경우가 많다. 2월 14일 메인테이너 Denis Pushkarev(zloirock)가 올린 “So, what’s next?”는 이렇게 웹 전반이 의존하는 프로젝트를 혼자 풀타임으로 유지해 왔지만 금전적 후원이 거의 없었고, 그 사이 겪은 개인적인 어려움까지 털어놓는 글이다. 오픈소스 지속 가능성 문제를 보여 주는 사례로 많이 회자되었다.

  • https://github.com/zloirock/core-js/blob/master/docs/2023-02-14-so-whats-next.md

JavaScript SICP

MIT의 고전 교재 『Structure and Interpretation of Computer Programs』(SICP)를 Scheme 대신 JavaScript로 옮긴 판이다. 원저자 Abelson, Sussman과 함께 Martin Henz, Tobias Wrigstad가 각색했고, MIT Press에서 2022년에 책으로 나왔다. Source Academy 사이트에서 본문을 무료로 읽으며 예제를 브라우저에서 바로 실행해 볼 수 있다.

  • https://sourceacademy.org/sicpjs/index

Fallback

fallback은 주 경로가 실패했을 때 대신 실행하는 대체 동작이다. 참고한 글은 Netflix Hystrix 기준으로 fallback이 호출되는 경우를 정리한다. 서킷이 열려 있을 때, 실행 중 예외가 났을 때, 스레드 풀이나 큐, 세마포어가 가득 찼을 때, 타임아웃이 났을 때다. 외부 API 호출이 실패하면 캐시된 값이나 기본값을 돌려주는 식으로 장애가 호출자에게 번지지 않게 막는 것이 목적이다.

  • https://velog.io/@sweet_sumin/Fallback

Query Projection Builder

QueryDSL에서 @QueryProjection 애너테이션으로 생성한 Q프로젝션 클래스는 기본적으로 생성자만 포함하므로 사용할 때 new 키워드를 통해서만 생성 가능하다. 여기에 빌더를 적용시켜서 사용할 수는 없을까?

@QueryProjection이 만드는 Q 클래스는 ConstructorExpression을 상속하고, 생성자 인자 순서대로 표현식을 받는다. 필드가 많으면 인자 순서를 헷갈리기 쉽고, 어떤 값이 어느 필드인지 읽기 어렵다. keencho 블로그의 글은 별도 애너테이션 프로세서를 만들어 Q 클래스와 함께 빌더 형태의 클래스를 생성하는 방법을 보여 준다. 기본 기능만으로 하려면 Projections.fields()나 Projections.bean()처럼 이름으로 매핑하는 방식을 쓸 수 있지만, 이 경우 컴파일 시점 타입 검사의 이점이 줄어든다.

  • https://keencho.github.io/posts/querydsl-qbuilder-qsetter-2/
  • https://velog.io/@hyunho058/JPA
  • https://velog.io/@mmy789/QueryDSL-%EC%8B%A4%EB%AC%B4-%ED%99%9C%EC%9A%A9-%EC%88%9C%EC%88%98-JPA%EC%99%80-Querydsl
  • https://whitepro.tistory.com/450

Redis

Redis는 데이터를 메모리에 두는 키-값 데이터베이스다. 단순 문자열 외에 리스트, 해시, 셋 같은 자료구조를 명령어 수준에서 제공해서 캐시, 세션 저장소, 순위표, 카운터 등에 쓴다. 메모리에 있으므로 빠르지만 프로세스가 죽으면 데이터가 사라질 수 있어서, 디스크 영속화(RDB 스냅숏, AOF)와 복제를 함께 구성한다. 스프링에서는 Spring Data Redis로 RedisTemplate이나 저장소 추상화를 통해 접근한다.

  • https://wildeveloperetrain.tistory.com/21
  • https://devlog-wjdrbs96.tistory.com/374
  • https://aws.amazon.com/ko/elasticache/what-is-redis/
  • https://steady-coding.tistory.com/586
  • https://redis.io/docs/reference/
  • https://redis.io/docs/about/
  • https://redis.io/commands/
  • https://docs.redis.com/latest/rs/references/
  • https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/
  • https://github.com/redis/redis

Redis Sentinel vs Cluster

둘 다 장애 대응을 위한 구성이지만 목적이 다르다. Redis 문서에 따르면 Sentinel은 클러스터를 쓰지 않는 Redis에 고가용성을 제공한다. 마스터와 레플리카를 계속 감시하고, 문제가 생기면 알리고, 마스터가 죽으면 레플리카 하나를 마스터로 승격시키는 자동 장애 조치(failover)를 하며, 클라이언트에게 현재 마스터 주소를 알려 주는 설정 제공자 역할을 한다. 데이터는 마스터 한 대에 모두 있으므로 용량과 쓰기 처리량은 늘지 않는다.

Redis Cluster는 여기에 샤딩을 더한다. 키 공간을 16384개의 해시 슬롯으로 나누고, 각 마스터 노드가 슬롯의 일부를 맡는다. 마스터마다 레플리카를 붙여 장애 조치도 클러스터가 스스로 한다. 대신 여러 키를 다루는 명령은 키들이 같은 슬롯에 있어야 한다는 제약이 생긴다. 데이터가 한 대의 메모리에 들어가면 Sentinel, 넘치거나 쓰기 부하를 나눠야 하면 Cluster를 고른다.

  • https://www.baeldung.com/redis-sentinel-vs-clustering
  • https://cloudinfrastructureservices.co.uk/redis-sentinel-vs-cluster/
  • https://recordsoflife.tistory.com/904#:~:text=Redis%20Sentinel%EC%9D%80%20%ED%91%9C%EC%A4%80%20Redis,%EC%88%98%20%EC%9E%88%EB%8A%94%20%EC%83%A4%EB%94%A9%20%EA%B8%B0%EB%8A%A5%EC%9E%85%EB%8B%88%EB%8B%A4.
  • https://velog.io/@always/Redis-%EC%9A%B4%EC%98%81-%EB%B0%A9%EC%8B%9D-Cluster-vs-Sentinel-%EC%96%B4%EB%96%A4-%EA%B2%83%EC%9D%84-%EC%84%A0%ED%83%9D%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C
  • https://coding-start.tistory.com/128
  • https://www.letmecompile.com/redis-cluster-sentinel-overview/
  • https://meetup.nhncloud.com/posts/226
  • https://great-song2.tistory.com/8
  • https://programming-workspace.tistory.com/73
  • https://programming-workspace.tistory.com/73
참고한 자료외부 출처 7

외부 출처

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

댓글

아직 댓글이 없습니다