-
Notifications
You must be signed in to change notification settings - Fork 0
2주차 일지 김규원
- JVM 이 프로그램을 실행할 때, 클래스 파일을 찾는데 기준이 되는 파일 경로를 말하는 것
Path
(java.nio.file.Path)
파일 시스템 경로를 나타내는 객체. 운영체제와 관련되어 있는 개념으로 파일 또는 디렉토리의 위치를 추상적으로 표현하고 파일 시스템 작업을 수행할 때 작업
→ jar 파일 내부에 포함된 리소스는 파일 시스템 경로가 아니라 JAR 파일 내의 경로로 접근해야 하기 때문에 차이가 있음
ClassPath
자바 클래스 로더가 클래스를 찾기 위해 검색하는 경로 또는 JAR 파일의 집합. JVM 에 의해 사용되며 Jar 파일 내부의 파일은 압축된 상태로 포함되기 때문에 File 클래스는 제대로 인식을 하지 못함
- 스레드 생성 수거는 시스템콜을 동반하기 때문에 오버헤드가 크게 발생
- 미리 생성해두어 컨텍스트 스위치 비용을 줄이는 것이 목적
-
Executors
정적 팩토리 메서드로 ExecutorService 인터페이스 구현체 중 하나를 생성 - ExecutorService 대신 ThreadPoolExecutor 를 사용하면
prestartAllCoreThreads
메소드를 통해 미리 쓰레드를 생성해둘 수 있음
- corePoolSize : 동시에 수행할 수 있는 최수 Thread 수
- maximumPoolSize : 최대 수행할 수 있는 Thread 수
- keepAliveTime: corePoolSize 를 초과하여 생성된 쓰레드가 작업을 대기할 시간. 시간을 초과하면 corePoolSize 를 초과한 개수의 쓰레드를 정리
여기서 중요한 사실은 corePoolSize 만큼 다 차면 workQueue 에 넣어지고 이것을 넘어서면 maxPoolSize 만큼 생성한다는 것이다.
-
직접 전달 (Direct handoffs): 작업 큐에 대한 기본 선택으로
SynchronousQueue
를 사용하는 것이 좋습니다. 이 큐는 작업을 스레드에 직접 전달하며, 스레드를 따로 보유하지 않습니다. 이 경우, 즉시 실행할 스레드가 없으면 작업 큐에 추가하려는 시도가 실패하고 새로운 스레드가 생성됩니다. 이 정책은 내부 의존성이 있을 수 있는 요청 세트를 처리할 때 교착 상태를 방지합니다. 직접 전달은 일반적으로 새로운 작업 제출이 거부되지 않도록 무제한 최대 풀 크기를 필요로 합니다. 이는 명령이 처리될 수 있는 속도보다 빠르게 도착할 경우 무제한 스레드 증가 가능성을 허용합니다.- Executors.newCachedThreadPool
-
무제한 큐 (Unbounded queues): 무제한 큐(예: 사전 정의된 용량이 없는
LinkedBlockingQueue
)를 사용하면 모든corePoolSize
스레드가 바쁘면 새로운 작업이 큐에서 대기하게 됩니다. 따라서corePoolSize
이상의 스레드는 생성되지 않습니다. (따라서maximumPoolSize
의 값은 영향을 미치지 않습니다.) 이 방법은 각 작업이 다른 작업에 영향을 미치지 않는 경우에 적합합니다. 예를 들어 웹 페이지 서버의 경우입니다. 이 큐잉 스타일은 일시적인 요청 폭주를 완화하는 데 유용할 수 있지만, 명령이 처리될 수 있는 속도보다 빠르게 도착하면 무제한 작업 큐 증가 가능성을 허용합니다.- newSingleThreadExecutor
-
제한된 큐 (Bounded queues): 제한된 큐(예:
ArrayBlockingQueue
)는 유한한 최대 풀 크기와 함께 사용할 때 자원 소모를 방지하는 데 도움이 되지만, 조정 및 제어가 더 어려울 수 있습니다. 큐 크기와 최대 풀 크기는 서로 상호 교환될 수 있습니다: 큰 큐와 작은 풀을 사용하면 CPU 사용, 운영 체제 자원, 컨텍스트 스위칭 오버헤드를 최소화하지만 인위적으로 낮은 처리량을 초래할 수 있습니다. 작업이 자주 블록되는 경우(예: I/O 바운드인 경우) 시스템은 더 많은 스레드에 시간을 할당할 수 있습니다. 작은 큐를 사용하면 일반적으로 더 큰 풀 크기가 필요하여 CPU를 더 바쁘게 만들지만, 이는 허용할 수 없는 스케줄링 오버헤드를 초래할 수 있으며, 이는 처리량을 감소시킵니다.
execute() 는 작업 처리 중에 예외가 발생하면 해당 스레드가 종료되고 스레드 풀에서 제거한 뒤, 새로운 스레드를 생성하여 다른 작업을 처리. 처리결과를 반환하지 않음
submit() 은 작업 처리 중에 예외가 발생하더라도 스레드가 종료되지 않고 다음 작업에 사용됨. 처리결과를 Future로 반환
예전에는 웹서버를 통해 정적 페이지로만 응답이 가능했던 시절이 있었습니다. 하지만 동적으로 웹페이지를 서빙할 일이 많아지면서 서블릿이 등장했습니다. 즉, 서블릿은 웹서버로부터 요청을 받아서 처리하고 서버에 다시 응답을 하는 자바 API입니다.
Servlet Container 는 서블릿을 관리하는 컨테이너입니다. 그리고 서블릿 컨테이너의 대표 오픈소스가 톰캣이고요.
- 서블릿 컨테이너는 서블릿과 웹서버가 손쉽게 통신할 수 있게 해주어, 소켓을 만들고 listen, accpet 등을 api 로 제공
- 서블릿 생명주기 관리
- 서블릿 클래스 로딩 인스턴스화
- 초기화 메소드 호출
- 요청이 들어오면 적절한 소블릿 메소드 호출
- 서블릿 소멸시 GC
- 멀티쓰레드 지원 및 관리
-
Accept 스레드
: 클라이언트 요청을 수신하고 Worker 쓰레드에 전달하는 역할. 큐에 추가하면 워커 쓰레드가 요청을 가져감
-
Thread Pool
: 요청을 실제로 처리하는 스레드. 하나의 클라이언트 요청에 하나의 Worker 스레드가 할당되어 처리.- 큐에서 요청을 가져와 처리
- 서블릿을 호출하여 처리
- 내부적으로
package java.util.concurrent;
패키지 사용함
classpath 가 아니라 경로를 직접 박아서 File 로 불러왔더니 정적 파일이 제대로 로딩이 안되는 문제가 발생했다. classpath 를 써야하는 이유에 대해 다시 살펴보며 다시는 경로를 직접 넣는 일은 없어야됨을 느꼈다.
MVC 패턴이 블락킹인 이유를 톰캣이 Blocking 이기 때문으로 알고 있었는데 이번에 공부하면서 Tomcat Blocking-IO 는 이미 오래 전에 드랍되었음을 알게되었다. 이에 대해서 블로그 글을 쓰면서 공부를 해봤는데 생각보다 어려운 주제같다. 최대한 고도화해서 BIO NIO 소켓에 대해 자세히 공부하고 발표해보고 싶다.
우테캠에 면접관님한테 좋은 코드를 쓰고있는지 모르겠다는 말씀을 드렸는데 기준은 주관적이지만 마음에 안든다 😇. 그리고 스프링부트는 복잡한 것이고, 나는 그 동안 아주 편하게 써왔음을 느꼈다. 이번 교육을 통해 WAS 에 대한 기본기를 다져서 가는 것 같다.
네트워크 시간에 교수님이 'sync 를 맞춘다' 라는 말을 자주 쓰셨었다. 나는 지금 부족한 상황이지만 캠퍼분들의 지식에 싱크를 맞추고 있는 과정을 거치고 있는 것 같다. 처음에 모르는 것은 괜찮으니 지금이라도 잘 알아서 퇴소하도록 노력해보자!