Skip to content

[4단계 - Tomcat 구현하기] 재즈(함석명) 미션 제출합니다.#738

Merged
nak-honest merged 12 commits intowoowacourse:seokmyunghamfrom
seokmyungham:step3
Sep 18, 2024
Merged

[4단계 - Tomcat 구현하기] 재즈(함석명) 미션 제출합니다.#738
nak-honest merged 12 commits intowoowacourse:seokmyunghamfrom
seokmyungham:step3

Conversation

@seokmyungham
Copy link
Copy Markdown
Member

@seokmyungham seokmyungham commented Sep 13, 2024

낙낙 안녕하세요~ 😀
시간이 정말 빠르네요 벌써 마지막 4단계 리뷰 요청이라니.. ㅠㅠ

이번 마지막 미션은 스레드 풀을 생성해서 매 요청마다 스레드를 무제한 생성하지 않도록 제한을 두고
동시성을 고려하여 동기화 컬렉션을 사용하는 것이 목표였어요.

기능 요구 사항이 복잡하지는 않았기에 구현은 간단하게 끝났었는데요
오늘 하루 종일 다 같이 삽질한 ㅋㅋ 스레드 풀과 acceptCount, Socket accept 에 관한 내용은 아직도 의문으로 남아있어요.

현재는 새로운 클라이언트 요청이 들어오는 시점마다 소켓의 listen() 함수 호출 후 백로그를 거치지 않고 바로 accept()가 호출되어 스레드 풀로 submit 되고 있는데요. 스레드 풀의 대기 큐 크기 초과 정책으로 추가 요청을 거절한다고 해도, accept() 호출 시점이 고려되지 않기 때문에 요청이 단시간에 폭발했을 시에 심각한 메모리 낭비를 유발할 것 같다는 생각이 들어요.

유휴 스레드가 생겨서 백로그로부터 사용자 요청을 처리하는 시점에 accept()를 처리 하도록 하는게 더 나은 방안일 것 같기도한데 아직은 정확하게 근거를 못찾겠네요. 어플리케이션의 스레드 풀이 OS 소켓 자원을 일방적으로 조절하는 방식이 가장 나은 대안인지도 의문이 들어요. 두 레벨간의 적절한 조화를 찾는 방법이 있을 것 같은데 지금 학습 단계에서는 아직까지는 어렵네요. 😅

낙낙도 여전히 같은 생각이신지 궁금하고, 혹시나 새롭게 알게된 지식이 있다면 알려주세요ㅎㅎ

마지막 리뷰도 잘 부탁드립니다 낙낙
즐거운 추석 연휴 보내세요 !! 😁

@seokmyungham seokmyungham self-assigned this Sep 13, 2024
Copy link
Copy Markdown
Member

@nak-honest nak-honest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 재즈!! 추석 잘 보내셨을까요 ㅎㅎ 저는 거의 노트북을 피지 못해 이제서야 리뷰 남겨드리네요..! 늦어서 죄송합니다 ㅠㅠ

현재는 새로운 클라이언트 요청이 들어오는 시점마다 소켓의 listen() 함수 호출 후 백로그를 거치지 않고 바로 accept()가 호출되어 스레드 풀로 submit 되고 있는데요. 스레드 풀의 대기 큐 크기 초과 정책으로 추가 요청을 거절한다고 해도, accept() 호출 시점이 고려되지 않기 때문에 요청이 단시간에 폭발했을 시에 심각한 메모리 낭비를 유발할 것 같다는 생각이 들어요.

해당 내용에 대해 저도 동의합니다!! 실제 톰캣에서도 acceptCount는 TCP 연결까지는 맺었지만, accept 메소드를 아직 호출하지 않은 상태를 의미하는데요. MaxConnections의 정의도 살펴보면 "The maximum number of connections that the server will accept and process at any given time." 라고 나와있습니다. 저희는 요청이 들어오는 대로 accept를 하고 있기 때문에 재즈 말씀대로 메모리 낭비가 생길 수 있을 것 같네요! 톰캣의 구현과 다르기도 하구요 ^_^

유휴 스레드가 생겨서 백로그로부터 사용자 요청을 처리하는 시점에 accept()를 처리 하도록 하는게 더 나은 방안일 것 같기도한데 아직은 정확하게 근거를 못찾겠네요.

얕게 공부를 해본 결과 요청을 처리하는 스레드가 자신의 요청을 처리할 때 accept를 호출하는 것이 자연스럽다고 생각해요!
Connector에서 세마포어를 사용해서 maxThreads에 도달했을 때 accept를 호출하지 않고 블록킹 되도록 구현은 가능하겠지만, 그보다는 요청을 처리하는 쪽에서 accept를 하는 것이 더 구현이 간단하지 않을까 생각됩니다!!

어플리케이션의 스레드 풀이 OS 소켓 자원을 일방적으로 조절하는 방식이 가장 나은 대안인지도 의문이 들어요. 두 레벨간의 적절한 조화를 찾는 방법이 있을 것 같은데 지금 학습 단계에서는 아직까지는 어렵네요. 😅

저는 acceptCount 라는 정의에 맞게 구현하기 위해서는 필요한 부분이라고 생각 합니다! 그리고 소켓을 직접 다루는 LOW 레벨인 만큼 불가피 한 것 같아요..! 다만 이를 사용하는 개발자에게는 이러한 LOW 레벨을 세세히 건드릴 필요 없이 accetp-count와 max-threads 등의 설정만으로 이를 조정할 수 있다면 괜찮지 않을까라는 생각입니다 :)

고생 많으셨습니다 재즈!!
다음 미션도 화이팅이에요 ㅎㅎ

Comment on lines 8 to 9

public class AbstractController implements Controller {
public abstract class AbstractController implements Controller {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 해당 부분은 저도 리뷰하면서 놓쳤네요 ㅎㅎ

Comment on lines +19 to 23
public String getContentLength() {
return Integer.toString(responseBody.getBytes(StandardCharsets.UTF_8).length);
}

public String toMessage() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체에게 직접 물어보니 훨씬 좋네요!!

@nak-honest nak-honest merged commit d074499 into woowacourse:seokmyungham Sep 18, 2024
Comment on lines +30 to +40
public Connector() {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_CORE_POOL_SIZE);
}

public Connector(final int port, final int acceptCount, Mapper mapper) {
public Connector(final int port, final int acceptCount, final int maxThreads) {
this.serverSocket = createServerSocket(port, acceptCount);
this.threadPoolExecutor = new ThreadPoolExecutor(
DEFAULT_CORE_POOL_SIZE, maxThreads,
KEEP_ALIVE_TIME, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(BLOCKING_QUEUE_SIZE)
);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corePoolSize를 50와 maximumPoolSize 둘 다 50으로, 대기 큐 사이즈는 100으로 설정해 주신 이유가 있을까요??
그리고 corePoolSize와 maximumPoolSize 둘다 같다면, KEEP_ALIVE_TIME 은 의미가 없을텐데 위와 같이 설정하신 이유도 궁금합니닷!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants