일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Greedy
- 알고리즘
- jpa
- pointcut
- JPQL
- Thymeleaf
- java
- Servlet
- 김영한
- JDBC
- QueryDSL
- 스프링 핵심 기능
- http
- 스프링 핵심 원리
- Proxy
- Exception
- 백준
- springdatajpa
- Android
- spring
- Spring Boot
- 스프링
- 인프런
- 자바
- SpringBoot
- transaction
- kotlin
- AOP
- 그리디
- db
- Today
- Total
목록인프런/[인프런] 스프링 핵심 원리 - 고급 (105)
개발자되기 프로젝트
1. 동시성 문제 사실 이 문제는 동시성 문제이다. FieldLogTrace 는 싱글톤으로 등록된 스프링 빈이다. 이 객체의 인스턴스가 애플리케이션에 딱 1 존재한다. 이렇게 하나만 있는 인스턴스의 FieldLogTrace.traceIdHolder 필드를 여러 쓰레드가 동시에 접근하기 때문에 문제가 발생한다. 실무에서 한번 나타나면 개발자를 가장 괴롭히는 문제도 바로 이러한 동시성 문제이다. 아래 예시와 같이 동시성 문제를 발생시켜보았다. traceId는 같은데 여러 Thread에서 접근했다. 하나의 객체(싱글톤)에 여러 thread가 접근했다.. [nio-8080-exec-5] h.advanced.trace.logtrace.FieldLogTrace : [9a3bac90] | | | | | | | | |..
1. LogTrace 스프링 빈 등록 FieldLogTrace가 싱글톤으로 스프링 빈으로 등록됨. @Configuration public class LogTraceConfig { @Bean public LogTrace logTrace(){ return new FieldLogTrace(); } } 2. Controller @RestController //@Controller +@ResponseBody @RequiredArgsConstructor public class OrderControllerV3 { private final OrderServiceV3 orderService; private final LogTrace trace; @GetMapping("/v3/request") public String r..
앞서 로그 추적기를 만들면서 다음 로그를 출력할 때 트랜잭션ID 와 level 을 동기화 하는 문제가 있었다. 이 문제를 해결하기 위해 TraceId 를 파라미터로 넘기도록 구현했다. 이렇게 해서 동기화는 성공했지만, 로그를 출력하는 모든 메서드에 TraceId 파라미터를 추가해야 하는 문제가 발생했다. TraceId 를 파라미터로 넘기지 않고 이 문제를 해결할 수 있는 방법은 없을까? 1. LogTrace Interface public interface LogTrace { TraceStatus begin(String message); void end(TraceStatus status); void exception(TraceStatus status, Exception e); } 2. FieldLogTra..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/dwkaQY/btrlDB7rwbu/yiIZYLLAHmFUUSkZIc0LJk/img.png)
1. V2 적용하기 메서드 호출의 깊이를 표현하고, HTTP 요청도 구분해보자. 이렇게 하려면 처음 로그를 남기는 OrderController.request() 에서 로그를 남길 때 어떤 깊이와 어떤 트랜잭션 ID를 사용했는지 다음 차례인 OrderService.orderItem() 에서 로그를 남기는 시점에 알아야한다. 결국 현재 로그의 상태 정보인 트랜잭션ID 와 level 이 다음으로 전달되어야 한다. 이 정보는 TraceStatus.traceId 에 담겨있다. 따라서 traceId 를 컨트롤러에서 서비스를 호출할 때 넘겨주면 된다. 2. Controller Controller에서 로그를 처음 남김. 현재 status의 TraceId 정보를 Service계층에 넘겨줌. @RestController ..
트랜잭션ID와 메서드 호출의 깊이를 표현하는 하는 가장 단순한 방법은 첫 로그에서 사용한 트랜잭션ID 와 level 을 다음 로그에 넘겨주면 된다. 현재 로그의 상태 정보인 트랜잭션ID 와 level 은 TraceId 에 포함되어 있다. 따라서 TraceId 를 다음 로그에 넘겨주면 된다. 1. OrderControllerV2 기존 begin()외에 동기화기능이 추가된 beginSync()를 추가해주자. 간단하게 이전의 TraceId를 받아와서 createNextId()를 호출해준다. /** * v2에서 추가 */ public TraceStatus beginSync(TraceId beforeTraceId, String message){ //TraceId traceId = new TraceId(); Tra..
![](http://i1.daumcdn.net/thumb/C150x150/?fname=https://blog.kakaocdn.net/dn/lB80V/btrlDxjGls7/9jkkmdWN3b3URb8S154J71/img.png)
앞서 만든 로그추적기를 적용해보자. 1. OrderControllerV1 앞의 테스트 처럼 단순하게 trace.begin(), trace.end()로 끝나는 것이 아니라 예외 처리를 위해 try-catch 구문을 사용한다. 예외가 발생해도 로그를 남길 수 있어야 한다. 이 때 예외 상황에서 로그를 남기기 위해 프로그램 흐름을 변경해서는 안된다. 즉, 예외를 먹어버리지 말고 다시 던져줘야 한다. @RestController //@Controller +@ResponseBody @RequiredArgsConstructor public class OrderControllerV1 { private final OrderServiceV1 orderService; private final HelloTraceV1 tra..
애플리케이션의 모든 로직에 직접 로그를 남겨도 되지만, 그것보다는 더 효율적인 개발 방법이 필요하다. 특히 트랜잭션ID와 깊이를 표현하는 방법은 기존 정보를 이어 받아야 하기 때문에 단순히 로그만 남긴다고 해결할 수 있는 것은 아니다. 요구사항에 맞추어 애플리케이션에 효과적으로 로그를 남기기 위한 로그 추적기를 개발해보자. 먼저 프로토타입 버전을 개발해보자. 아마 코드를 모두 작성하고 테스트 코드까지 실행해보아야 어떤 것을 하는지 감이 올 것이다. 먼저 로그 추적기를 위한 기반 데이터를 가지고 있는 TraceId , TraceStatus 클래스를 만들어보자. 1. TraceId 로그 추적기는 트랜잭션ID와 깊이를 표현하는 방법이 필요하다. 트랜잭션ID와 깊이를 표현하는 level을 묶어서 TraceId ..
1. 로그 추적기를 만들어 보자. 애플리케이션이 커지면서 점점 모니터링과 운영이 중요해지는 단계라고 가정. 특히 최근 자주 병목이 발생하고있다고 해보자. 어떤 부분에서 병목이 발생하는지, 그리고 어떤 부분에서 예외가 발생하는지를 로그를 통해 확인하는 것이 점점 중요할 것이다. 기존에는 개발자가 문제가 발생한 다음에 관련 부분을 어렵게 찾아서 로그를 하나하나 직접 만들어서 남겼는데 이 부분을 개선하고 자동화 해보자. 2. 요구사항 모든 PUBLIC 메서드의 호출과 응답 정보를 로그로 출력 애플리케이션의 흐름을 변경하면 안됨 로그를 남긴다고 해서 비즈니스 로직의 동작에 영향을 주면 안됨 메서드 호출에 걸린 시간 정상 흐름과 예외 흐름 구분 예외 발생시 예외 정보가 남아야 함 메서드 호출의 깊이 표현 HTTP..