Spring Framework

Spring @Async를 쓰면서 생각해볼 것들

Tomcat Thread Pool과 Async Thread PoolSpring 기반 애플리케이션을 운영하면 아래와 같은 구조를 기반으로 쓰레드풀을 관리하여 클라이언트 응답을 처리한다.[클라이언트 요청] ↓[Nginx / Load Balancer] ↓[Tomcat 쓰레드풀] ← HTTP 요청 수신, 응답 반환 ↓[Spring MVC Controller → Service] │ ├── 동기 처리 → Tomcat 쓰레드에서 직접 실행, 응답 후 반납 │ └── @Async 호출 → Spring Async 쓰레드풀로 작업 위임 Tomcat 쓰레드는 즉시 응답 반환 후 반납Tomcat 쓰레드풀은 HTTP 요청..

2026.02.13 게시됨

Java & Kotlin

Java 코드의 동작 원리와 JVM 구성 요소

블로그 초창기에 썼던 글이 있긴한데 간단하게 다시 Java 코드의 동작 원리와 JVM에 대해 정리해본다.https://studyandwrite.tistory.com/59 1. Java 코드 동작아래와 같은 Java 코드가 있다.public class Main { public static void main(String[] args) { System.out.println("Hello"); }} 코드 자체는 CPU가 이해할 수 없는 텍스트이기 때문에 Java 컴파일러(javac)는 이 소스 코드를 컴파일하여 .class 파일을 생성한다.javac Main.java .class 파일에는 JVM이 이해할 수 있는 바이트코드가 들어가있으며 한 번 컴파일되면 JVM 위에서 어디서든 실행 가능..

2026.02.05 게시됨

Spring Framework

스프링 배치 SynchronizedItemStreamReader에 대해

공식 문서에 따르면, Spring Batch의 SynchronizedItemStreamReader는 ItemReader의 read() 메서드를 synchronized로 감싸는decorator 클래스로, 본래 thread-safe 하지 않은 ItemReader를 멀티스레드 환경에서도 안전하게 사용할 수 있도록 한다고 한다. 하지만 이미 처리한 아이템이 재처리되는 상황이 문제가 되는 경우, 해당 클래스를 사용하면 배치 잡은 재시작(restart)이 불가능한 구조가 된다고도 말한다. 설명 자체는 복잡하지 않지만 코드를 보면서 실제로 그런지 한 번 공부해보면 좋을 것 같아 정리를 해본다. * 글에서 작성한 코드는 spring batch 5.2.2를 기준으로 한다. SynchronizedItemStreamRead..

2026.01.17 게시됨

Database

MySQL MVCC 언두 로그(Undo log) 실습

MySQL, InnoDB 엔진에서 채택하는 기본 격리 수준은 REPEATABLEREAD 이다.아래 명령어로 확인해볼 수 있다.mysql> SELECT @@SESSION.transaction_isolation;+---------------------------------+| @@SESSION.transaction_isolation |+---------------------------------+| REPEATABLE-READ |+---------------------------------+1 row in set (0.00 sec)REPEATABLE READ 격리 수준에서는 MVCC를 위해 언두 영역에 백업된 이전 데이터를 이용해 동일 트랜잭션에서는 동일한 결과를 보여줄 수 있게..

2026.01.09 게시됨

Thinking

기술 블로그 다시 쓰기

기술 블로그를 2021년 6월에 처음 시작했으니 벌써 올해로 5년차가 되었다. 처음 블로그를 시작할 때 목표는 누적 방문자 수 10만명, 일 방문은 약 500명까지 가보는 것이었다.지금 방문자 수는 10만을 훌쩍 뛰어 넘었지만 일일 방문자 수는 저조하다. 블로그를 시작할 당시, 그리고 불과 1~2년 전만 해도 ChatGPT 같은 AI 서칭이 없었다.그 때는 블로그를 찾아 공부하는 것이 보편적이었기에 나 역시 다른 많은 블로그를 보면서 지식을 얻었고, 필요한 기술들을 배울 수 있었다. 그리고 나도 내가 배운 것들을 한 번 이해한대로 각색하여 전달해보려고 했고 거기서 느낄 수 있는 성장감과 꾸준히 찾아오는 방문자들을 보면서 효용을 느끼기도 했다. 하지만 제작년부터 작년까지는 거의 글을 쓰지 않았다.회사에서..

2026.01.04 게시됨

Database

MySQL binlog 기반 데이터 복구

수동으로 데이터를 보정하거나 배치 작업을 하는 과정 중에서 테이블의 데이터를 오염시키는 일이 발생할 수 있다. 상황마다 복구하는 시나리오는 다르겠지만, 이번 글에서는 MySQL binlog를 통해 오염된 데이터를 되돌리는 기본적인 방법에 대해 정리해보려고 한다. 실제 운영 환경에서는 매우 많은 트랜잭션과 실시간으로 계속 들어오는 트래픽으로 인해 binlog만 가지고 100% 데이터를 복구하는 것은 어렵다. 오히려 수동으로 복구하려는 시도가 데이터를 더 꼬이게 할 수도 있다는 것을 주의해야 하고 필요하다면 반드시 복구 정책(ex. 데이터 오염 이후 발생한 변경은 그대로 둔다, 특정 시간 기준 스냅샷으로 복구한다 등)을 먼저 정해두고 복구 이후 영향도에 대한 고려를 한 뒤 해야 한다. 실습실습 환경은 M..

2025.12.23 게시됨

Java & Kotlin

parallelStream 안에서 다른 ThreadPool을 사용하는 행위

1. Stream스트림은 List, Set과 같은 다양한 데이터 소스(List, Set을 구현하는 컬렉션 클래스들)로부터 생성되어 중간 연산을 통해 새로운 스트림을 반환하고, 최종 연산은 스트림 요소들에 대한 최종적인 작업을 수행하여 리턴하는 구조로 많이 사용된다.// 스트림 생성, 중간 연산, 최종 연산Stream stream = numbers.stream();Stream integerStream = stream.filter(number -> number % 2 == 0);List evenNumbers = integerStream.toList();// 보통 Method Chaining 방식으로 사용한다.List evenNumbers = numbers.stream().filter(number -> num..

2025.12.21 게시됨

Infra, DevOps

ELK Stack으로 Nginx 로그 수집하기

이번 글에서는 ELK Stack을 활용해서 애플리케이션의 Nginx 로그를 수집해보는 프로젝트를 실습해보려고 합니다. ELK StackElasticSearch(es)는 Elastic Stack의 핵심인 분산 검색, 분석 엔진입니다. 고성능에 스키마 없는 JSON 기반 document로 다양한 데이터에 대한 검색과 분석에 용이합니다. Logstash는 데이터를 수집, 집계하고 원하는 곳에 전송할 수 있도록 하는 도구입니다. 특히 es에 데이터를 로드할 때 편리하고 우수한 성능의 인덱싱을 가능하게 하여 es를 사용한다면 Logstash를 동시에 사용하는 것이 보편적입니다. Kibana는 데이터 시각화 및 탐색 도구입니다. 이 역시 es에 저장된 데이터를 시각화할 때 기본적으로 많이 사용되고 있습니다. 결국..

2024.03.15 게시됨

Spring Framework

jackson-databind, AUTO_DETECT_IS_GETTERS 옵션(is getter)

0. 문제 아래 예제 코드를 보겠습니다. @Getter @AllArgsConstructor @NoArgsConstructor @Builder @Entity public class Book implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String title; @Column private int stock; @Column private boolean isSoldOut; // .. 생략 } 간단한 책(Book) Entity 입니다. 설명을 위해 필요한 코드만 작성했습니다. 해당 엔티티에서 주의깊게 볼 부분은 private boolean isSoldOu..

2024.02.14 게시됨

Spring Framework

Spring 5.2.X 버전에서 @RequestParam required = true 옵션은 null safety 하지 않다.

2024년 1월 현재 기준으로 개인 프로젝트나 가까운 시일 내에 시작한 프로젝트라면 Springboot 3.X 버전, Spring 6.X 버전을 사용하게 됩니다. 하지만 프로젝트 개발을 한 지 오래된 서비스라면 Spring, Springboot 버전이 꽤 낮을 수 있는데요. 예를 들어, 3년 전인 2021년에 개발을 시작한 프로젝트만 하더라도 당시 Springboot의 최신 버전은 2.3.1.RELEASE 였으며 이 때 호환되는 Spring 버전은 5.2.X 이었습니다. 이번 글에서는 이런 점을 심각하게 고려하지 않고 개발을 하다가 마주친 문제에 대해 정리해보려고 합니다. 바로 예제 코드를 보겠습니다. @GetMapping("/v1/book") public Book getBook(@RequestPara..

2024.01.28 게시됨