라벨이 자바(java)인 게시물 표시

About JVM Warm up

이미지
Class Loading JVM 프로세스가 시작하면, 필요한 모든 클래스들은 클래스로더가  세가지 단계를 거쳐 메모리로 로드 한다. 이 과정은 lazy loading 기반으로 동작한다. - Bootstrap Class Loading: Bootstrap Class Loader 가 Java Class 들을 올린다. java.lang.Object 와 같이 JRE/lib/rt.jar 에 있는 필수적인 클래스를 올린다. - Extension Class Loading: ExtClassLoader 는 java.ext.dirs 경로에 있는 모든 JAR 파일들을 책임진다. ㅎGradle 혹은 Maven 기반 application 이 아닌, 개발자가 수동으로 추가한 JAR 들이다. - Application  Class Loading: AppClassLoader 가 application class path 에 있는 모든 클래스들을 올린다. Execution Engine Java 는 Interpret 과 Compile 을 모두 사용하는 Hybrid 이다. Java code 를 javac 를 통해서 컴파일하면 platform 독립적인 bytecode 로 변환된다. 이를 실행 시 JVM 은 runtime 에 interpret 통해서 native code 로 실행한다. Just-In-Time Compiler 는 runtime 에 자주 실행되는 코드(method 전체)를 native code 로 compile 한다. 이후에 재실행 시 바로 compiled 된 native code 를 사용한다. 이를 hotspot 이라 부른다. C1 - Client Compiler 빠른 시작과 좋은 반응 속도에 중점을 두고 있다. 최적화 수준은 C2 에 비해 낮지만 컴파일 시간이 짧아 초기 실행 속도를 빠르게 하여 사용자에게 더 빠른 반응을 제공할 수 있다. 복잡하지 않은 최적화로 짧은 시간에 코드를 컴파일하여, 어플리케이션이 빨리 실행될 수 있도록한다. C2- Server ...

About ZGC

 Z Garbage Collector JDK 11 에서 실험적인 기능으로 소개했다. JDK 15 에서 정식으로 출시 되었다. 물론 JDK 21에서도 사용할 수 있다. ZGC 어플리케이션 스레드 실행을 10ms 이상 중단하지 않고 고비용 작업을 동시에 수행한다. 지연 시간은 힙 사이즈와 무관하며, 몇백 MB의 작은 힙부터 16테라의 매우 큰 힙을 사용해도 잘 작동하낟. JDK 11 에서 JDK 15 이하 버전에서는  -XX:+UnlockExperimentalVMOptions 와 -XX:+UseZGC 옵션을 동시에 사용하여 활성화한다. JDK 15 이상 버전에서는 -XX:+UseZGC 하나의 옵션으로 사용할 수 있다. 아래의 핵심 기능을 사용하며 ZGC 또한 G1 GC 와 마찬가지로 concurrent 가비지 컬렉터이다. Concurrent Region-based Compacting NUMA-aware Using colored pointers Using load barriers Using store barriers (in the generational mode) Configuration & Tuning ZGC 도 G1 GC 와 유사하게 최소한의 설정을 필요로 하며, 어플리케이션이 실행하는 과정에서 스스로 적응하는 기능이 있다. ZGC 은 동적으로 세대를 리사이징하고, GC 스레드수도 조절하며, tenuring thresholds 도 조절한다. 주요 튜닝 포인트는 최대 힙 사이즈를 늘리는 것이다. (-Xmx) ZGC 는 generational version 과 non-generational version 이 있는데 non-generational version 은 레거시이며, 실행중에 세대 개념을 사용하지 않는다. JDK 21부터 최신 버전인 generational version 이 출시 되었으며 최신 버전 사용을 권장한다. generational version 은 -XX:+UseZGC 옵션과 -XX:+ZGenerational 옵션을 사용한다....

About G1 GC

이미지
G1 GC 소개 Java7 부터 사용이 가능했고, Java9 부터 기본 GC 로 선정되었다. G1 GC 는 큰 메모리를 사용하는 멀티 프로세스 머신에 적합한 GC 이다.  설정된 목표 stop the world 시간을 높은 확률로 달성하려고 시도한다. 최대한 정지 시간을 예측 가능하고 짧게 유지하려는 목적이다.  높은 처리량을 목표로 하고 있으며, 사용자의 설정 필요성을 최소화하려고 한다. 개발자가 성능을 최적화하기 위해 많은 시간을 소비하지 않도록 하는것을 목표로 한다. 적용 대상으로는 - heap 크기가 수 GB ~ 최대 10GB 환경 - 실시간으로 객체 할당 및 프로모션 비율이 크게 변할 수 있는 환경 - heap 내에서 상당한 수준의 조각화(fragmentation)가 발생할 수 있는 환경 - 수백 밀리초를 넘지 않는 예측 가능한 stop the world 시간 목표가 필요한 경우 CMS(Concurrent Mark-Sweep) GC 을 대체한다. heap 을 여러 영역으로 나누고, 가비지 컬렉션을 수행하는 동안 영역들을 동시에 처리하여 고성능을 달성하고자 한다. G1 GC 활성화 기본 GC 로 별도의 설정이 필요하지는 않다. 명시적으로 -XX:+UseG1GC 통해 가능하다. 기본 개념 G1 도 다른 GC 와 마찬가지로 young generation, old generation 으로 메모리 생명주기에 세대 개념을 사용한다. 그리고 여러 스레드를 사용하여 점진적으로 가비지 컬렉션을 수행한다. 처리량 개선을 위해서 일부 가비지 컬렉션 작업은 어플리케이션이 실행중에도 진행할 수 있으며 일부 중요한 작업은 stop the world 를 발생시킨다. Heap Layout G1은 힙을 동일한 크기의 힙 영역 집합으로 분할하고, 각 영역은 인접한 범위의 가상 메모리로 구성된다. 영역은 메모리 할당 및 메모리 회수의 단위이다. 언제든지 영역은 비어있거나, young generation, old generation 으로 할당 할 수 있다. 메모리 요청이...

sneak peek jitpack

이미지
 생산성을 위해서 여러 프로젝트에서 반복적으로 사용되고 있거나 앞으로 사용될 프로젝트 코드를 효과적으로 관리하기 위해서 라이브러리로 관리하는 방법을 선택할 수 있다. 그렇다면 라이브러리를 어떻게 관리하는 것이 좋을까? java, kotlin 을 사용하여 개발을 할 경우, maven, gradle 을 통해서 의존성을 관리한다. 이 때 의존성들의 저장소는 Maven Central 혹은 jCenter(현재는 지원 중단) 처럼 공개 레포지토리일 수도 있고, 단체에서만 사용하는 사설 레포지토리일 수도 있다. 이러한 레포지토리를 지원하는 여러 툴이 있다.  Maven Central 에서 아티팩트를 올리기 위해서는 요건이 엄격하다. 따라서 JitPack 을 사용하여 찍먹해보겠다. 먼저 github 레포지토리 2개를 판다. 하나는 라이브러리용이고, 나머지는 라이브러리를 사용한다. 라이브러리 :  https://github.com/ndgndg91/hello-jitpack 아래는 build.gradle.kts 파일이다. maven-publish 플러그인을 사용해야 하며, publishing 을 설정해야한다. 아래는 재사용할 코드를 간단하게 작성해보았다. 그리고 git tag 를 통해 버전을 관리한다. https://github.com/ndgndg91/hello-jitpack/releases/tag/0.0.2 사용할 라이브러리를 작성하고 git tag 를 땄으면 1차 준비는 완료했다. 다음은 https://jitpack.io  에 가서 내가 작성한 github repository 를 검색한다. 0.0.2 이라는 git tag 를 확인할 수 있다. 그리고 build Log 를 확인할 수 있다. 여기까지 성공했다면 다음은 쉽다. https://jitpack.io/com/github/ndgndg91/hello-jitpack/0.0.2/build.log 사용:  https://github.com/ndgndg91/use-jitpack build....

Spring Boot Actuator readiness, liveness probes on k8s

이미지
Spring Boot 를 사용하여 서버 어플리케이션을 개발하고 Kubernetes 상에서 운영할 때 Container 의 상태를 확인하고 복구가 불가능한 경우 재시작 시켜야 되는지 알 필요가 있다. 또한 Container 가 트래픽을 받아들일 준비가 되었는지 상태를 알아야한다. 이때 각각 liveness, readiness probes 를 사용한다. 아래와 같이 Kubernetes deployment 에 liveness 와 readiness probes 를 설정한다. initialDelaySeconds 는 Container 가 실행되고 90초 이후에 설정된 path 에 Get 요청을 통해서 정상상태를 확인한다. 200 ~ 399 status code 를 5초이내에 응답 받으면 성공으로 확인한다. periodSeconds 는 10초 주기로 확인한다. 연속해서 3번 비정상 응답을 받을 경우 liveness 는 실패로 돌아가고 Kubelet 은 Container 를 재시작시킨다. 이번엔 Spring Boot 어플리케이션을 보자. gradle 을 사용할 때 아래와 같이 의존성을 추가한다. 그리고 application.yaml 에 아래와 같이 설정한다. 유의해야할 점은 exposure.include 에 * 를 쓰게되면 불필요한 정보가 모두 노출되어 보안에 취약해진다. 예를 들어, heapdump 또는 shutdown 같은 기능을 노출하게 되면 외부에서 공격점이 될 수 있다. /actuator path 요청시 아래와 같이 응답을 받는다.  exposure 에 health, info 만 설정해서 두가지만 확인할 수 있다. /actuator/health 를 확인해보자. endponint.health.probes.enabled=true 로 설정해서 liveness, readiness 를 지원한다. /actuator/health/liveness 와 /actuator/health/readiness 를 확인해보자.  spring boot application 에...

About Websocket minimize data size and data transfer cost on cloud

이미지
웹소켓은 클라이언트와 서버간의 양방향으로 상호작용할 수 있게 만들어준다. 주로 채팅, 게임, 금융 거래 시스템 등 실시간 데이터 처리를 위해서 사용한다. 웹소켓을 사용하지 않고 롱폴링과 같은 방법을 사용할 수 있지만, 매 데이터 교환마다 새로운 요청을 보내야 한다. 웹소켓은 한번의 커넥션으로 지속해서 통신할 수 있어서 낮은 latency 를 보장한다. 따라서, 더 빠르고 유려한 사용자 경험을 제공할 수 있다. 내가 운영하는 서비스에서 웹소켓을 사용하고 있다고 가정해보자. 그리고 추가로 사용자가 접속할 때 항상 웹소켓을 사용해야 한다. 예를 들어, 주식 시장이나 코인 시장의 가격을 실시간으로 확인하거나, 교통의 흐름을 추적한다고 가정해보자. 실시간으로 제공해야 하는 제공해야 하는 데이터가 많아진다. 사용자가 많아질수록 또한 제공해야 하는 데이터가 많아진다. AWS와 같은 클라우드를 사용하여 서비스를 운영하는 상황일 때 데이터의 양이 많아질 경우 비용 증가로 이어지게 된다. AWS Data Transfer Cost 가 부과되는 방법은 다양하지만 이번 경우에서는 AWS 환경에서 Internet 환경으로 data 가 전송되는 구간에 대해서 정리해보겠다. 2023-03-12 기준 서울 region 에서 인터넷으로 데이터 송신 비용이다. 처음 100GB 전송은 무료이며 이후 부터 전송량 별 비용이 감소한다. 0 ~ 100GB 무료 100GB ~ 10340GB  0.126USD/GB 10340GB ~ 41060GB 0.122UDS/GB ... 생략 이렇게 산정되는데 10TB를 꽉 사용했다는 가정하에 가격은 1302.84 USD 이다.  2023-03-12 기준 1달러 환율은 1,320.64원이다.  1720582.6176 원으로 172만 5백원이다. 무시할 수 있는 비용이 아니다. 어떻게 해당 비용을 줄일 수 있을까?  Data Serialization json 일반적으로 WebSocket 으로 데이터를 교환할 때 흔히 사용한다. text...

About Binary Number

이미지
이번 글에서는 기초로 돌아가는 시간을 가진다. 컴퓨터에서 정수와 실수를 어떻게 다루고 있는지에 대해서 정리하려고 한다. 우리는 일상생활에서는 10진법을 사용한다. 아무래도 손가락이 10개라서 이지 않을까?  하지만 컴퓨터에서는 2진법을 사용한다. 컴퓨터는 10진법을 이해하지 못한다.  컴퓨터가 사용하는 2진법 컴퓨터는 손가락이 2개만 있다.  컴퓨터는 전압을 사용하여 동작한다. data 가 있을 경우 전압을 올리고 없을 경우 내린다. on / off 로 부를 수 있는데 이러한 과정을 계속해서 반복한다. 전압을 올린 곳은 1 로 표현할 수 있고, 전압이 없을 경우 0으로 표현한다. 이러한 data 를 연결할 경우 101101 과 같은 data 가 된다. 이러한 data 0 또는 1 을 bit 라고 부른다. 1bit 는 0 또는 1 두가지 경우를 나타낼 수 있다. 1bit = 0, 1 = pow(2, 1) = 0 ~ 1 2bit = 00, 01, 10, 11 = pow(2,2) = 0 ~ 3 4bit = 0000, 0001, 0010, ... 1111 = pow(2,4) = 0 ~ 15 8bit = 0000 0000, .... 1111 1111 = pow(2,8) = 0 ~ 255 bit 가 8개 8bits 는 1 byte 가 된다. 8bits 의 절반인 4bit 를 nibble 이라고 부른다. 컴퓨터가 저장하는 최소단위가 byte 이다. 8 bits = 2 nibble = 1 byte 이다. nibble 은 4bits 이다. nibble  단위가 16진수의 단위가 된다.  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, a, b, c, d, e, f 1111 1111 은 10진수로 15 15 이고 16진수로 표현하자면 f f 가 된다. 0xFF 가 된다. 0xFF 는 1 byte 가 된다. 정수 2진 표현 Kotlin 을 기준으로 Int 는 4 bytes 로 32 bits 이다. 양의 정수 5028 을 2진...

Time Business Logic Testing on Spring (Kotlin, Java)

이미지
올해에 너무 글쓰는 것을 소홀히 했던것을 반성하며 남은 한 달 동안 글을 몇 개라도 조금 써보려고한다! Java, Kotlin 기반 Spring 프레임워크 환경에서 개발을 하다보면 시간과 관련된 로직이 필요할 수 있다. 이 때 어떻게 해결하면 좋을 지 테스트 코드는 어떻게 구성하면 좋을지 정리하려고 한다. 예를 들어, 특정 기간동안만 액션이 가능한 요구사항이 있다고 가정하자. 해당 기간이 시작하기전에 액션을 진행하지 못하도록 막아야 되고, 기간인 경우 가능하도록 그리고 기간이 끝났을 때 더이상 액션이 불가능하도록 막아야 한다. 이 예제를 바탕으로 간단한 샘플 코드를 정리해보았다. - Kotlin - Spring Boot 2.7.5 - Junit 5 우선 아래와 같이 zoneId 를 인자로 받는 now 함수를 작성하였다. CHANGEABLE_CLOKC 이 null 이 아닐경우 해당 Clock 을 기준으로 LocalDateTime 인스턴스를 생성한다. 그리고 now 를 테스트하기 위한 코드. CHANGEABLE_CLOCK 이 null 인 경우와 null 이 아닌 경우 두 가지 테스트 케이스이다. null 인경우에는 zoneId 에 따라서 인스턴스를 생성하기 때문에 빈 인자인 경우 UTC 기준, Kst ZoneId 제공시 kst 시간 인스턴스를 생성하여 9시간 차이를 확인하는 코드이다. 두번 째는 Clock 을 2025 년 1월 1일로 설정하여 now 함수 호출 시 CHANGEABLE_CLOCK 기준으로 인스턴스를 생성하게 되어있다. 자 그렇다면 기간과 관련된 로직과 해당 로직을 테스트하는 코드를 작성해보자. 아래와 같이 property 에서 기간을 주입받는 Service 를 test code 를 작성해보자. ReflectionTestUtils 를 통해서 Mocking 하는 service 에 기간을 주입한다. 그리고 CHANGEABLE_CLOCK 을 통해서 now() 함수가 기간에 속할 때와 아닐 때로 지정하여서 올바른 값을 반환하는지 검증한다. 또 다른 방법중 하...