분류 전체보기 (152) 썸네일형 리스트형 [JVM 밑바닥까지 파헤치기] JVM의 진화: Classic VM에서 HotSpot VM까지 JVM의 진화: Classic VM에서 HotSpot VM까지Java Virtual Machine은 지난 30년간 놀라운 진화를 거쳐왔습니다. 초기의 단순한 인터프리터에서 시작해, 현재는 네이티브 코드에 버금가는 성능을 내는 정교한 시스템으로 발전했죠. 이번 포스트에서는 JVM의 세 가지 주요 세대를 살펴보고, 각 세대가 어떤 기술을 사용했으며 왜 그런 선택을 했는지 알아보겠습니다. 1. Sun Classic VM (1996년)사용된 기술순수 인터프리터 방식 (기본 모드)선택적 JIT 컴파일 (all-or-nothing 방식) 핵심 특징인터프리터 모드 (기본)바이트코드 → 인터프리터 → 실행바이트코드를 한 줄씩 해석하며 실행컴파일 과정 없이 즉시 실행 시작JIT 컴파일 모드 (옵션)바이트코드 → 전체 컴.. [26/01/20] 오늘의 개발 일지 - CI에서 테스트 실행 및 통합 테스트 컨테이너 환경 개선 개발 일지가 꽤나 밀려버렸습니다.일단 오늘 일지부터 작성하고 천천히 밀린 걸 써보겠습니다. 오늘은 드디어 Github Actions의 CI 과정에 테스트를 도입했습니다.사실 지금까지는 gradle의 -x test 옵션으로 테스트 없이 빌드만 진행했었습니다. 검색과 추천 성능평가 및 데이터 셋업 테스트 때문에 바로 옵션을 빼서 테스트를 진행하기가 애매했기에조금 시간이 걸렸네요. 1. Github Actions CI 워크플로우 개선 - name: Build with Gradle run: ./gradlew build -x test --no-daemon기존의 다음과 같은 코드에서 - name: Build with all tests run: ./gradlew build.. [JVM 밑바닥까지 파헤치기] JIT vs AOT 컴파일러, 그리고 JVM과 GraalVM에 대하여 기존에 Spring Initializer를 쓰며 GraalVM이란 용어에 대해 본 적이 있었고,그때는 단순히 이게 뭘까? 라는 생각만 가지고 있었습니다. 그러다가 최근 'JVM 밑바닥부터 파헤치기'라는 책을 읽으며 JIT와 AOT 그리고 JVM과 GraalVM에 대략적으로 파악하게 되었습니다.이 글에서는 이 개념들이 무엇이고, 어떤 차이가 있는지, 그리고 어떻게 선택하면 좋을지 정리해보겠습니다. Java 코드는 어떻게 실행될까?Java의 실행 과정을 먼저 이해해야 합니다..java 파일 → (javac 컴파일) → .class 바이트코드 → (JVM) → 실행 Java는 "Write Once, Run Anywhere"를 위해 바이트코드라는 중간 형태로 컴파일됩니다. 이 바이트코드는 JVM 위에서 실행되는.. [26/01/14] 오늘의 개발 일지 - 카카오 소셜 로그인 구현 1. 의존성01/13(화)는 Spring Security 3.5.7 공식 문서를 정독한 날입니다.LLM의 도움을 받아서 번역하며 핵심을 읽으니 나름 빠르게 이해한 것 같습니다. 저희 서비스는 OAuth + JWT 자체 발급 구조이므로 관련 파트를 중점적으로 읽었습니다. // Securityimplementation 'org.springframework.boot:spring-boot-starter-security'implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'testImplementation 'org.springframework.security:spring-security-test'// JWTimplementation .. [26/01/10] 오늘의 개발일지 - 온보딩 API 수정, 테스트 코드 작성, 엔티티 생성 성능 최적화 1. 온보딩 API 수정기획 단계에서 온보딩 시 닉네임, 이메일, 한 줄 소개 등을 받기로 변경되어 이를 반영했습니다. 테스트 과정에서 온보딩 완료 후 유저 프로필 생성 시 유저 데이터 수집 메서드에서Post 엔티티 -> Keyword 엔티티 접근 과정 중 N+1 문제가 발생하여,페이징이 있는 조회이므로 @BatchSize 을 통해 해결하였습니다.@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)@BatchSize(size = 100)private List keywords = new ArrayList(); 또한 쿼리 최적화 과정에서 JPA 영속성 컨텍스트 문제가 발생하여이를 양방향 매핑으로 해결했습니다. 이 부분의.. [26/01/07] 오늘의 개발 일지 - Resilience4j 설정 개선 및 JdbcTemplate를 활용한 배치 처리 오늘은 Resilience4j의 서킷브레이커와 RateLimiter의 설정을 건드려봤습니다. 오늘의 목표는 두 가지였습니다.1. 네트워크 에러와 RateLimit 에러에는 서킷이 열리지 않도록 하기2. RateLimiter 최적값 탐색 테스트를 하다보니 키워드 INSERT 쿼리가 단일로 나간다는 점을 파악해서3. JdbcTemplate를 활용한 배치 쿼리까지 목표로 잡았습니다. 1. 네트워크 에러와 Rate Limit 에러는 서킷 카운트에서 배제팀원과 서킷 브레이커 설정에 대해 의논을 했었는데단순한 네트워크 장애에서 서킷이 열리는 건 막아야된다고 결론이 났습니다. 물론 failure-rate-threshold 설정값을 좀 더 관대하게 하는 방법도 있었지만,차라리 예외를 try-catch로 잡은 뒤에 .. [26/01/06] 오늘의 개발일지 - AsyncItemProcessor의 도입과 Spring Batch 메타데이터 활용 AsyncItemProcessor와 AsyncItemWriter의 도입기존의 크롤링 파이프라인은RSS 크롤링 -> LLM 호출을 통한 요약 및 키워드 생성 -> 임베딩 및 색인3가지 스텝으로 구성되어 있습니다. 이때 LLM 호출 스텝과 임베딩 및 색인 스텝에서taskExecutor를 활용해 병렬 처리를 하고 있었는데요. 문제는 바로 여기서 발생합니다.Reader에서는 단순히 thread-safe하지 않은 Iterator를 사용하는데멀티스레드로 Processor가 동작하다보니 같은 데이터에 대해 중복 처리가 발생한 것입니다. 이를 해결하기 위해 처음에는 Reader를 thread-safe하도록 synchronized 키워드를 넣을까 싶었는데,이 경우 Reader에서 병목이 발생할 것으로 추측되었습니다. .. [26/01/05] 오늘의 개발 일지 - Resilience4j 도입 크롤링 파이프라인 중에는LLM API와 임베딩 API 호출하는 스텝이 있습니다. 아무래도 외부 API이다보니 장애가 발생할 수 있다는 생각이 들어서서킷 브레이커 패턴을 도입해보자는 생각이 들었습니다. 여기서 서킷 브레이커 패턴은 연속된 요청이 실패할경우서킷을 열어 오픈 상태로 만들어 요청을 외부 API로 보내지 않고,하프-오픈 상태가 되었을 때 테스트 패킷을 보내본 뒤에 성공할 경우 다시 서킷을 닫아 외부 API 콜을 진행하는 패턴입니다. 이와 관련된 라이브러리로는 대표적으로 Resilience4j가 있었는데요.스프링 부트와 통합이 잘 되어있어 바로 도입을 해보았습니다.https://resilience4j.readme.io/docs/getting-started IntroductionResilience.. 이전 1 2 3 4 ··· 19 다음