10월 23일 월요일에 개최된 `흔한 백엔드 개발자 모임` 컨퍼런스에 다녀왔다!
알게 된 경로는 넥스터즈 단톡방이었다.
넥스터즈 활동이 끝난 이후에도 해당 톡방에는 채용공고 모집이나 컨퍼런스 홍보글이 올라오곤 한다.
이 세션은 넥스터즈에서 활동하신 분께서 주최하는 컨퍼런스여서 넥스터즈 단톡방에 홍보가 됐었는데, 꽤나 흥미로운 주제들이 많아보여서 참여신청을 눌렀다.
ZGC는 JDK 17 버전에서 소개되는 GC 정도로만 알고 있었고, Virtual Thread와 Project Loom은 완전 최신에 오픈한 기술 정도로만 알고 있었다.
사실 내가 속한 사내 팀에서는 ZGC, Project Loom을 사용할 만큼 최신 버전을 사용하고 있진 않았다.
그렇지만 Java 릴리즈 노트와 관련된 기술들을 아는 것은 꽤나 중요하다고 생각하는 편이기에, 그리고 스레드와 동시성 관련 주제에 관심이 많았기에 흥미롭게 발표를 들을 수 있었다.
저지연을 위한 최첨단 가비지컬렉터: ZGC
노션에 정리한 내용은 아래와 같다.
https://clean-nutria-44b.notion.site/ZGC-b7fb7c83adbe4f54a973443ee0a321ae?pvs=4
발표를 들을 당시의 나는 G1 GC에 대한 경험이 있는 편이고, ZGC에 대한 경험이 없는 편이었다.
그래서 Young Generation, Old Generation으로 분할하는 게 익숙했는데, ZGC는 세대 별이 아닌 객체 크기 별로 Small, Medium, Large로 분할하는 것이 되게 신기했다. (근데 Generational ZGC에서는 다시 세대 별로 구별 ㅋㅋㅋ)
그리고 별도의 colored pointers를 이용하여 GC 메타데이터를 저장하는 점, 하나의 물리메모리에 3개의 가상 메모리 주소를 매핑시키는 Multi-Mapping, colored pointers가 올바른지 체크하는 load barrier 과정 등. G1 GC에서는 존재하지 않는 방식의 동작원리가 신기하기도 하고, 어렵기도 했다.
GC 메타데이터 저장하는 과정, Marking하고 Remapping하는 과정을 통해 기존 G1 GC의 compact 과정에서 STW가 느린 이슈, 거대 객체로 인한 메모리 단편화 이슈를 최대한 해결할 수 있다고 한다.
Multi-Mapping으로 인해 사이즈가 3배 크게 관측되는 RSS over-reporting 이슈가 좀 재밌었다. 다행히 Generational ZGC 부터는 Multi-Mapping을 사용하지 않아 해결된다 하지만, 다른 GC에서는 발생하지 않는 이슈여서 그런지 좀 흥미롭게 들은 듯하다.
끝나고 조금 더 관련 내용을 찾아보았는데, 아래 글에서 내용설명이 잘돼있어 기록용으로 첨부하려 한다.
https://www.blog-dreamus.com/post/zgc%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
나름 G1 GC보다 장점이 꽤나 보여서 괜찮아보였다.
하지만 아쉬운 점은, G1 GC가 JDK 17 쯤은 돼야 도입하기에 좋아보인다는 점이다.
그리고 발표자분께서도 ZGC를 사내에 적용한 것이 아닌, 학습내용을 공유해주시고자 발표한 것이라 한다. ZGC 트러블 슈팅 썰이나 단점이 궁금하긴 했지만, ZGC에 대해 많이 알고 가는 것 같아 만족스러운 세션이었다.
Java에서 Null을 나이스하게 다루는 법
https://clean-nutria-44b.notion.site/Java-Null-0fc5b39e81234b2aaa43a78c10c03e3c?pvs=4
Null을 예쁘게 처리하는 방법에 대한 세션이다.
우아한테크코스 과정을 통해서 많이 느꼈던 점들에 대해 다시 한 번 상기시킬 수 있었던 세션.
(그리고 kotlin의 장점에 대해 다시 한 번 뼈저리게 느끼게 된 세션 ㅎㅎ null-safe 관련 kotlin 기능들 만세!)
특히 optional.get()을 사용하지 말라는 것에 대해 좋지 않다고 말씀해주셔서 공감이 갔다.
Optional은 null이 올 수 있으므로 조심하라는 안내 차에 쓰는 키워드라 생각하기 때문. get()으로 바로 꺼내버리면 사실상 그 의미가 퇴색되는 것이 아닐까.
그 외에 null check하기 좋은 프레임워크인 jspecify를 소개해주셨다.
그런데 갠적으로 정적 분석 도구에는 크게 흥미가 가지 않아서 꼼꼼하게 기록하지는 않았다.
(소나큐브 사용하고 있기는 한데, 막 엄청 똑똑하거나 좋다는 생각이 들진 않는다. 물론 없는 거 보단 나은 듯)
Project Loom & Kotlin Coroutines
Project Loom을 소개하면서 Virtual Thread, Scoped Values, Structured Concurrency에 대해 얘기해준 세션이다.
근데 Virtual Thread가 JDK 21에 오픈됐고, 나머지는 아직 preview 단계라.... 현재의 나로선 쓸일이 없을 거 같긴 하다ㅋㅋㅋ
Virtual Thread는 OS Thread와 다르게 굉장히 저렴해서 많이 생성가능하다고 해서 흥미가 갔다.
발표자분께서 mac 로컬로 JVM Threads를 생성했을 때는 약 8천개, Virtual Thread를 생성했을 때는 약 380만개까지 생성이 가능했다고 한다. (380만개의 스레드면 거의 무적이겠는데?)
근데 이렇게 생성된 가상 스레드 중, 사용이 끝난 스레드는 GC 대상이 되고 재사용되지 않아 중간중간 멈추는 현상이 발생했다고는 했다.
Virtual Thread는 수많은 가상 스레드끼리 suspension 되면서 왔다리갔다리 동작한다고 한다. 따라서 높은 동시성 i/o 중심 코드에 권장하고, CPU 연산이 많이 요구되는 로직에는 비권장한다고 한다.
컨텍스트 스위칭 비용도 상당히 높은 듯하다.
발표를 듣고 난 후 내 Virtual Thread에 대한 인상은.. 굉장히 매력적으로 느껴지는 동시에, 서버가 의문사해버리는 경우가 좀 많을 거 같아 첫인상은 `양날의 검일 수 있겠는데?` 싶었다.
그리고 코틀린의 코루틴이랑 상당히 비슷한데? 하는 생각이 들 수도 있다.
심지어 Virtual Thread의 힙 사용량이 코루틴의 힙 사용량보다 훨씬 높다고 한다. (역시 kotlin이 짱인건가?)
발표자분께서는 coroutine은 안드로이드 UI (View / 서버 통신 및 로직 개발) 멀티스레드 쪽에, virtual thread는 JVM 애플리케이션 개발에 사용되므로 서로 다른 목적에 쓸 수 있지 않을까? 라고 얘기해주셨다.
하긴, 생각해보니 코루틴을 애플리케이션 서버 개발하면서 많이 쓰진 않긴 했다. (사실 거의 없다시피 한듯?)
만약 사이드프로젝트를 새로 하게 된다거나, 아니면 신규 프로젝트를 사내에서 적용하게 돼 Virtual Thread 기능을 다루게 된다면 한번 여러가지 테스트를 해보아야겠다. Heap Memory 부하라든지, 비동기 관련 로직들 이것저것 넣어봐야겠다.
그 외에 동시성 문제 해결을 위한 Structured Concurrency, Virtual Thread 끼리 효율적으로 데이터를 공유할 수 있도록 Scoped Values에 대해서도 얘기해주셨다. 근데 기록을 잘 해놓지 못해서... 기억이 안난다ㅋㅋㅋㅋ
자바 동시성 처리의 구원투수: Virtual Thread
https://clean-nutria-44b.notion.site/Virtual-Thread-4b5e1113a8e24bfd9974e13d836594cc?pvs=4
스레드의 역사부터 Virtual Thread를 깊게 파고드는 세션이다.
사실 Green Thread (Java 1.3 이전의, User Thread : Kernel Thread = N:1로 매핑되는 시절) 에 대해선 처음 들었는데, 정말 신기했다. 옛날에 하드웨어 성능이 좋지 않은, 코어가 1개이고 컨텍스트 스위칭을 고려하지 않아도 되는 시점에는 오히려 이 방식이 좋았을 거 같기도 하다.
Webflux, RxJava와 같은 event-loop 기반에서 스레드 동작 방식에 대해서도 얘기를 해주셨다.
적은 메모리로도 높은 동시성을 달성할 수 있고 컨텍스트 스위칭 비용이 적다는 장점이 있다고. 하지만 러닝커브가 매우 높고, Blocking 로직을 사용하면 성능이 저하된다는 점 때문에 주류가 되진 못했다고.
이후 Virtual Thread를 코드단으로 깊게 들어가서 Carrier Thread에 N:1로 mount 및 생성되는 과정, yield 되는 과정 및 Virtual Thread가 block 되는 과정을 코드 단으로 확인해보았다.
그리고 현재의 Platform Thread는 user thread : kernal thread 1:1로 매핑되고 OS Schedular에 의해 컨텍스트 스위칭이 발생할 때 kernel 단에서 발생하게 된다. 하지만, Virtual Thread는 컨텍스트 스위칭이 JVM 단에서 발생하기 때문에 유저모드와 커널모드 전환이 불필요하고, 저장 상태 정보를 적게 가져도 된다는 점으로 인해 더 성능이 좋아진다고 한다.
이러한 Virtual Thread를 딥다이브하는 과정들이 있었는데, 한 50% 정도만 이해한 것 같아서 조금 더 공부를 해봐야될 듯 ㅎㅎ..
네 개 세션 중 특정 주제에 대해 가장 딥다이브한 세션이라고 생각된다.
오랜만에 정말 재밌는 컨퍼런스에 참여해서 재밌었다 ㅎㅎ
오늘 나온 세션 4개 중 3개는 매우 최신버전이라 현재 적용할 수 없다는 점이 조금은 아쉬웠지만, 나중에 분명 큰 도움이 되리라 생각한다. 또 최근에 스레드에 대해 관심이 많았는데 스레드의 역사랑 virtual thread 딥다이브하게 돼서 더 흥미있게 들었던 것 같고, cs의 중요성에 대해서도 느끼고 가게 된 세션이었다. 지난 학기에 OS 수업을 들어놔서 다행이다.
네트워킹 시간이 있었으면 더 좋았을 듯!
'JAVA > JAVA | Spring 학습기록' 카테고리의 다른 글
[Spring] Amazon SNS, SQS 이벤트 순서 역전 및 유실에 대처해보자 (8) | 2023.12.02 |
---|---|
[231115] 우아콘 2023 참여 후기 (34) | 2023.11.15 |
[Spring] @async 로직 실패 일대기, ThreadPoolTaskExecutor의 awaitTerminate와 Async (44) | 2023.09.23 |
[Spring] Apache POI 엑셀 다운 vs opencsv CSV 다운 로직 및 성능 비교하기 (feat. parallelStream) (2) | 2023.09.19 |
[230826] 유스콘 2023 컨퍼런스 후기 (51) | 2023.08.27 |