
자바애플리케이션에서 JVM을 모니터링하기 위해 가장 많이 쓰이는 VisualVM을 연동을 하여 어떠한 지표들을 보아야하는지, 트러블을 일으키고 해결하는 것을 실습해보도록 하자. 여기서 애플리케이션은 스프링 부트 웹 애플리케이션을 이용하도록 하겠다. 1. 설치 VisualVM: Download 이곳에 가서 각 운영체제 맞는 VisualVM을 설치하도록 하자. 필자는 Windows여서 Zip파일을 받아서 압축해제하였다. 2. 실행 압축해제를 진행하면 bin폴더에 visualvm.exe 파일이 존재한다. 실행시키고 라이센스에 동의한다. 실행에 성공하면 다음과 같은 화면이 나오게 된다. 현재 구동중인 자바 애플리케이션이 존재하지 않아서 Local밑에 나오는 자바애플리케이션이 VisualVM외에 존재하지 않는다...

개발을 진행하면서 설정을 위해 성능을 측정해보거나 사용자의 경험을 위해 좋은 성능의 서비스를 제공해야하는데, 이를 위해 모니터링을 해야하는 부분과 제공하는 프로그램(툴)들을 Chat-GPT와 함께 확인(공부)해보도록 하자. 1. 모니터링 목록 1) CPU 사용량 CPU 프로파일링: 가장 많은 CPU 시간을 소비(점유)하는 코드부분이나 메서드를 식별 2) 메모리사용량 힙 분석: Java 힙 메모리 사용량을 모니터링 하여 메모리 누수, 과도한 객체 생성, 불필요한 메모리 소비 식별 GC 분석: 가비지 수집(GC) 로그를 분석하여 가비지 수집 설정을 최적화하고 stop-the-world를 최소화한다. 3) 스레드 활동 스레드 덤프 분석: 스레드 덤프를 캡처하고 분석하여 스레드 경합, 교착 상태 또는 장기 실행..

1. 발견 실무에서 복잡한 비즈니스를 다루는 로직에서 도저히 이해가 안가는 상황이 나오게 되었다. 상황은 이렇다. 첫 번째로 조회한 객체에는 객체 내부에 컬렉션을 가지고 있는데, 다음 메서드가 실행되기 전에는 비어있는 컬렉션인 것을 확인하였으나 메서드 실행 직후 내부 컬렉션에 객체들이 존재하는 것을 확인하였다. 분명 해당 객체를 어디선가 수정메서드를 통해 변경하는일이 없는데도 말이다. 도저히 납득이 가지 않아서 객체를 파라미터로 넘겨주고 복잡한 비즈니스를 파고파고 들어가서 해당 상태가 바뀌는 시점을 체크해보았으나 해당 메서드에서 바뀌는 이유를 종 잡을 수 없었다. 그때 혹시나 스쳐가는 생각이 JPA에서 캐시 기능을 사용하여 동일성을 보장해주는 것이 생각났다. 위에서 사용한 비즈니스에 조건의 범위가 다른 ..
트랜잭션의 격리 수준 이란 여러 트랜잭션이 동시에 처리 될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것이다. 격리 수준을 알기 전에 용어 부터 정리해보자 1. DIRTY READ 한 트랜잭션이 다른 트랜잭션에 의해 수정되었지만 커밋되지 않은 데이터를 읽어오는 상황 만약 커밋되지 않고 롤백되어버린다면 데이터가 일관되지 않은 상태여서 잘못된 결과가 도출될 수 있다. 2. NON-REPEATABLE READ 동일한 트랜잭션 내에서 처음 조회한 데이터가 다른 트랜잭션에 의해 수정되고 커밋되고나서 다시 조회한 경우 수정된 데이터를 읽어오는 상황 3. PHANTOM READ 트랜잭션이 특정조건을 만족하는 행 집합 을 읽은 후 에 동일한 트랜잭션 내에서 ..

1) InnoDB 스토리지 엔진의 잠금 InnoDB스토리지 엔진은 레코드 기반의 잠금을 제공한다. 잠금 정보가 상당히 작은 공간으로 관리되기 때문에 레코드락이 페이지 락 혹은 테이블락으로 레벨업(락 에스컬레이션) 는 존재하지 않는다. InnoDB엔진에서는 레코드와 레코드 사이의 간격을 잠그는 갭(GAP) 락이라는 것이 존재한다. 1. 레코드락 레코드 자체만을 잠그는것을 레코드 락이라고 하며, InnoDB엔진은 레코드 자체가 아니라 인덱스 레코드를 잠근다. 만약 인덱스가 존재하지 않더라도 내부적으로 자동 생성된 클러스터 인덱스를 이용해 잠금을 설정한다. 보조 인덱스를 이용한 변경 작업은 넥스트 키 락 혹은 갭 락을 사용하지만 프라이머리 키 혹은 유니크 인덱스에 의한 변경 작업에서는 갭에 대해서는 잠그지 않..
● 잠금 잠금은 동시성을 제어하기 위한 기능이다. 하나의 회원 정보 레코드를 여러 커넥션에서 동시에 변경하려고 하는것을 방지한다. 이것을 해주지 않으면 해당 레코드 값을 예측해줄 수 없다. 1) 트랜잭션 트랜잭션은 작업의 완전성을 보장해주는 것, 논리적인 작업 셋을 완벽히 처리하거나 처리하지 못할 경우 원상태로 복구해서 작업의 일부만 적용되는 현상(Partial update)이 발생하지 않게 해준다. ● 격리 수준 하나의 트랜잭션 내에서 혹은 여러 트랜잭션 간의 작업 내용을 어떻게 공유하고 차단할 것인지 결정하는 레벨 1. MySQL에서의 트랜잭션 트랜잭션은 하나의 논리적인 작업셋에 하나의 쿼리가 있든지, 두 개 이상의 쿼리가 있든 관계없이 해당 논리적인 작업 셋 자체가 100% 적용 혹은 아무것도 적용..

③ MyISAM 스토리지 엔진 아키텍처 1) 키 캐시 InnoDB의 버퍼풀과 비슷한 역할을 하지만, 인덱스 대상으로만 작동한다. 그리고 쓰기 작업에 대해서만 부분적 버퍼링 역할을 한다. 키캐시 히트율은 100 - (Key_reads / Key_read_requests * 100) 로 알 수 있다. Key_reads 는 인덱스를 디스크에서 읽어들이는 횟수를 저장하는 상태 변수, Key_read_requests는 키캐시로부터 인덱스를 읽은 횟수를 저장하는 상태 변수이다. (SHOW GLOBAL STATUS로 알수 있다.) 키 캐시 히트율은 99% 이상을 권장하며 미만이면 키 캐시 공간을 늘려야한다. 키 캐시는 영역설정을 해주어야 하는데, 어떤 스키마의 어떤 테이블의 인덱스를 캐시할지 설정을 해주어야한다. 2..

1) 프라이머리 키에 의한 클러스터링 InnoDB엔진의 모든 테이블은 프라이머리 키값 순서대로 디스크에 저장되며, 모든 세컨더리의 인덱스는 레코드의 주소 대신 프라이머리 키의 값을 논리적 주소로 사용한다. 프라이머리 키가 클러스터링 인덱스이기 때문에 해당 키를 이용한 레인지스캔은 상당히 빠르다. 또한 쿼리 실행계획에서 프라이머리키가 다른 보조 인덱스보다 선택될 확률이 높다. MyISAM엔진에서는 클러스터링 키를 지원하지 않아서 프라이머리 키와 세컨더리 인덱스와의 구조적 차이가 없다. 단지 유니크키를 가진 세컨더리 인덱스일 뿐이다. 2) 외래키 지원 MyISAM이나 MEMORY 엔진은 외래 키를 지원하지 않는다. InnoDB에서 외래 키는 부모 테이블과 자식테이블 모두 해당 컬럼에 인덱스 생성이 필요하고 ..