Spring Security Essentials
Thread Per Request 모델과 ThreadLocal
Thread Per Request 모델 개요
- WAS는 ThradPool을 생성함 (Tomcat 기본값 200)
- HTTP 요청이 들어오면 Queue에 적재되고, ThreadPool 내의 특정 Thread가 Queue에서 요청을 가져와 처리하게됨
- HTTP 요청은 처음부터 끝까지 동일한 Thread에서 처리됨
- HTTP 요청 처리가 끝나면 Thread는 다시 ThreadPool에 반납됨
- 즉, WAS의 최대 동시 처리 HTTP 요청의 갯수는 ThreadPool의 갯수와 같음
- Thead 갯수를 늘리면 동시 처리 갯수가 늘어나지만, Thread Context 스위칭에 의한 오버헤드도 커지기 때문에 성능이 선형적으로 증가하지는 않음
- Thread도 CPU의 연산을 소모하는 자원이기 때문에 스레드 갯수가 많아질 수록 스레드 그 자체를 관리하는 오버헤드도 커지게 되고 성능이 스레드 풀의 스레드 개수에 비례해서 올라가지 않는다.
- 최근 소개된 WebFlux 같은 기술은 Thread 갯수를 작은 갯수로 유지하며 HTTP 요청을 동시 처리 할 수 있도록 함
- WebFlux: 최대한 적은 수의 Thread로 최대한 많은 수의 요청을 처리
- 하나의 요청이 완료될 때까지 다수의 Thread에서 처리될 수 있음
- HTTP 요청은 하나 이상의 Thread에 바인딩되어 처리될 수 있음
- Therad per request 모델과는 지향하는 바가 다름
ThreadLocal
- Thread 범위 변수
- 동일 Thread 내에서는 언제든 ThreadLocal 변수에 접근할 수 있음(읽고 쓸 수 있음.)
예제 코드
// TheadLocal 변수를 생성
ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
// ThreadLocal 변수에 값 쓰기
threadLocalValue.set(1);
// ThradLocal 변수에서 값 읽기
Integer result = threadLocalValue.get();
// ThreadLocal 변수 값 제거
threadLocal.remove();
public class ThreadLocalApp {
final static ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
public static void main(String[] args){
System.out.println(getCurrentThreadName() + " ### main set value = 1"); // 1
threadLocalValue.set(1);
//main thread 에서 threadLocal 변수 1에 접근.
a(); // main ### a() get value = 1 -> main 쓰레드의 메소드 a()에서 threadLocal value 에 접근
b(); // main ### b() get value = 1 -> main 쓰레드의 메소드 b()에서 threadLocal value 에 접근
//runAsync(): 메인 thread 가 아닌 다른 thread 에서 수행되도록 하는 람다 코드블럭.
CompletableFuture<Void> task = runAsync(() -> {
a(); // 다른 thread 에서 접근했으므로 null, thread 이름도 main이 아니다.
b(); // a와 마찬가지.
});
task.join();
}
public static void a(){
Integer value = threadLocalValue.get();
System.out.println(getCurrentThreadName() + " ### a() get value = " + value);
}
public static void b(){
Integer value = threadLocalValue.get();
System.out.println(getCurrentThreadName() + " ### b() get value = " + value);
}
public static String getCurrentThreadName(){
return Thread.currentThread().getName();
}
}
- 즉, 동일 Thread내에서 실행되는 Controller, Service, Repository, 도메인 모델 어디에서든 명시적인 파라미터 전달 필요없이 ThreadLocal 변수에 접근할 수 있음
- ThreadPool과 함께 사용하는 경우 Thread가 ThreadPool에 반환되기 직전 ThreadLocal 변수 값을 반드시 제거해야함
- 그렇지 않을 경우 아래와 같은 상황이 발생하고, 미묘한 버그가 생겨날 수 있음
- 요청을 처리하기 위해 ThreadPool에서 Thread를 하나 가져옴
- 요청 처리에 필요한 변수를 ThreadLocal에 set함
- 요청 처리가 완료되고 Thread는 ThreadPool에 반환됨
- 다른 요청을 처리하기 위해 ThreadPool에서 Thread를 하나 가져왔는데 이전 요청 처리에 사용된 ThreadLocal 변수가 남아있고, 이를 참조하여 잘못된 동작을 수행할 수 있음
'Spring' 카테고리의 다른 글
Spring Security: SecurityContextPersistenceFilter (0) | 2023.04.18 |
---|---|
SecurityContextHolder, SecurityContext, Authentication (0) | 2023.04.06 |
Spring Security: AnonymousAuthenticationFilter (0) | 2023.04.06 |
Spring Security: RequestCacheAwareFilter (0) | 2023.04.04 |
Spring Security Architecture (0) | 2023.04.04 |