Java - Grafana + K6 + Jaeger로 부하테스트 해보기
·
etc
개요부하 테스트의 목적은 목표 부하에서 SLO(서비스 수준 목표)를 지키며 얼마나 안정적·효율적으로 운영할 수 있는지를 수치로 확인하고, 그 근거로 용량·설정·코드를 결정하는 데 있다. 사용 툴K6: 부하 테스트 진행 (v1.2.3)InfluxDB: 부하 테스트 결과 데이터 저장할 시계열 DB (v1.11)Grafana: 부하테스트 결과를 대시보드 형태로 시각화 (v11.6.1)Jaeger: 트레이스 시각화를 통해 병목 구간 판단 아키텍처 개요개발자가 작성한 시나리오로 K6가 HTTP 트래픽을 생성하여 부하 발생각 요청에 대한 메트릭 데이터를 InfluxDB에 저장Grafana가 InfluxDB에 쿼리를 날려 실시간 대시보드 표시(p95, 에러율, RPS 등 주요 지표 시각화)Jaeger는 Spirng ..
Querydsl - Cannot invoke "com.querydsl.core.types.Expressions.accept(com.querydsl.core.types.Visitor, Object)" because "arg" is null" 원인과 해결 방법
·
나의 에러 일지
Cannot invoke "com.querydsl.core.types.Expressions.accept(com.querydsl.core.types.Visitor, Object)" because "arg" is nullQuerydsl에서 @QueryProjection을 사용해 DTO를 조회하는 과정에서 발생한 예외이다. 원인Querydsl에서 DTO를 @QueryProjection으로 조회할 때, select 절에 일부 필드를 null로 반환하고자 직접 null을 명시하면 아래와 같은 예외가 발생할 수 있다. 예외가 발생한 코드는 아래와 같다.import com.querydsl.core.types.dsl.Expressions;import com.querydsl.core.types.Projections;QM..
Spring - ContentCachingRequestWrapper에서 getContentAsByteArray가 빈 값을 반환하는 이유와 해결 방법
·
나의 에러 일지
배경실제 프로젝트에서 Request Body로부터 traceId를 전달받아 이를 저장하고, 이후 로깅이나 트레이싱 등에 활용해야 하는 요구사항이 있었다. 이를 위해 Spring에서 제공하는 ContentCachingRequestWrapper를 사용하기로 했다. ContentCachingRequestWrapper는 원래 InputStream, Reader, 혹은 @RequestBody로 Request Body를 한번 읽고 나면 다시 읽을 수 없다는 한계를 깔끔하게 해결해 주는 유용한 클래스이다. 덕분에 traceId 같은 중요한 데이터를 여러 계층에서 반복적으로 로깅하거나 재사용할 수 있다. 그런데 실제로 적용하는 과정에서, ContentCachingRequestWrapper로 감쌌음에도 불구하고 Requ..
Spring - 딸깍으로 쉽게 Request 로그 남기기(CommonsRequestLoggingFilter)
·
Spring
배경애플리케이션을 운영하다 보면, 클라이언트의 요청이 어떻게 들어오는지, 어떤 데이터가 전달되는지 로그를 남겨둬야 할 때가 있다. 특히, 복잡한 API를 개발하거나, 에러 대응 및 디버깅이 필요할 때 요청 정보를 간단하게 로깅할 수 있다면 작업 효율이 크게 올라갈 것이다. 현재 진행중인 프로젝트에서 Request에 대한 로깅이 필요했고, Spring에서 제공하는 CommonsRequestLoggingFilter라는 도구를 알게되었다. 복잡한 설정 없이 손쉽게 Request 정보를 로깅할 수 있다는 장점이 있다. 이 글에서는 CommonsRequestLoggingFilter를 이용해 딸깍 한 번으로 쉽게 Request 요청을 로그로 남길 수 있는지 공유하려고 한다. 코드는 아래 링크에서 확인할 수 있다. ..
JPA - SemanticException: Query specified join fetching, but the owner of the fetched association was not present in the select List 원인과 해결 방법
·
나의 에러 일지
배경Querydsl을 작성하여 테스트하던 중 아래와 같은 에러를 만났다.public Optional searchPartnerByMerNo(String merNo) { return Optional.ofNullable( query.select(partner) .from(merchant) .innerJoin(merchant.partner, partner).fetchJoin() .where(merchant.merchantNo.eq(merNo)) .fetchOne() );}SemanticException: Query specified join fetching, but the owner of the fetc..
MySQL - Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.
·
나의 에러 일지
배경테스트에 사용할 더미 데이터 생성을 위해 MySQL에서 재귀 CTE를 사용하다가 아래와 같은 에러를 만났었다.WITH RECURSIVE seq AS ( SELECT 1 AS seq UNION ALL SELECT seq + 1 FROM seq WHERE seq Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value. 테스트 데이터를 대량으로 만들기 위해 WITH RECURSIVE 구문으로 시퀀스를 생성했는데, 1001번째에서 쿼리가 중단되는 문제가 발생했었다. 원인알고 보니 MySQL은 무한 루프를 방지하기 위해 재귀 CTE의 최대 반복 횟수를 1000으..
소프트웨어 버전 관리
·
etc
{Major}.{Minor}.{PATCH} 구조 Major 버전: 이전 버전과 호환되지 않는 API 변경 시 증가 Minor 버전: 하위 호환 가능한 새로운 기능 추가 시 증가 Patch 버전: 하위 호환 가능한 버그 수정 시 증가 버전 증가 규칙 각 버전 번호는 음수가 아닌 정수여야 함 상위 버전이 증가하면 하위 버전은 0으로 리셋 (예: 1.9.0 → 1.10.0 → 2.0.0) 버전 배포 후 해당 버전의 내용은 절대 변경 금지. 변경사항이 있다면 반드시 새로운 버전으로 배포
Spring - Spring Data Envers로 엔티티 변경 이력을 쉽게 관리해보기
·
Spring
배경사이드 프로젝트나 실제 서비스에서 데이터 변경 이력 관리가 필요할 때가 많다. “누가, 언제, 무엇을, 어떻게 바꿨는지” 추적이 필요하다면, Spring Data Envers가 딱이다. 이번 글에서는 Spring Data Envers를 실제로 적용하는 방법을, 내가 직접 해보면서 겪은 시행착오와 함께 정리해본다. Envers란?Hibernate Envers는 JPA 엔티티의 변경 이력을 자동으로 관리해준다. Spring Data Envers는 이를 Spring Data JPA와 자연스럽게 통합해주기 때문에, 기존 Repository 패턴을 그대로 쓰면서도 이력 관리가 가능하다 프로젝트에 Envers 적용하기의존성 추가build.gradle에 아래 의존성을 추가한다.implementation 'org...
Docker - standard_init_linux.go:xxx: exec user process caused "exec format error“ 원인과 해결 방법
·
나의 에러 일지
배경기존에는 Dockerfile에서 Java 애플리케이션을 실행할 때 ENTRYPOINT에 모든 JVM 옵션과 실행 명령어를 길게 나열해서 작성했었다. 하지만 JVM 옵션이 많아지고 환경별로 다른 설정이 필요해지면서 관리가 어려워졌다. 그래서 별도의 쉘 스크립트 파일에서 이런 복잡한 실행 로직을 관리할 수 있도록 entrypoint.sh를 만들게 되었다. entrypoint.sh를 추가하여 Docker 컨테이너를 실행하자 entrypoint.sh에서 예상치 못한 format 에러가 발생했다.standard_init_linux.go:xxx: exec user process caused "exec format error“ 개발 환경DockerPortainerLinuxJava 17Spring Boot 3.4..
HTTP - 프록시 환경에서 실제 클라이언트 IP 찾기 (X-Forwarded-For, X-Real-IP)
·
Network
배경새로운 프로젝트에서 화이트리스트 IP 검증 로직(IP 기반 접근 제한)을 구현하게 되었다. 처음에는 단순하게 request.getRemoteAddr()를 사용하면 될 줄 알았는데, 실제 운영 환경에서는 중간에 프록시를 거치다보니 실제 클라이언트 IP가 아닌 프록시 IP가 조회되는 문제가 있었다. 이 문제를 해결하기 위해 알게된 X-Forwarded-For와 X-Real-IP에 대해 알아보자 문제 상황웹 애플리케이션을 개발하다 보면 클라이언트의 실제 IP 주소가 필요한 경우가 많다. 특히 보안 정책, 접근 제어, 로깅 및 분석 등의 목적으로 사용된다. 하지만 실제 운영을 위한 웹 아키텍처에서는 클라이언트와 서버 사이에 다양한 중간 계층들이 존재한다. 로드 밸런서, 리버스 프록시, CDN 등을 거치면서 ..
Cold Bean
'분류 전체보기' 카테고리의 글 목록