-
Notifications
You must be signed in to change notification settings - Fork 0
김수현 3주차 학습일지
- 요청 파라미터(Request Parameters) : 클라이언트가 서버로 HTTP 요청을 보낼 때 함께 전송하는 데이터
- GET 요청의 query string : query parameter
- POST 요청의 request aprameter: html 폼을 통해 제출된 데이터
- Path parameter: 요청 파라미터이긴 하지만 경로의 일부로 간주됨. 일반적으로 서블릿이 아닌 프레임워크에서 처리됨
-
ServletRequest
의getParameterNames()
메서드는 쿼리 스트링과 요청 파라미터의 이름만 반환. path parameter x
- 스트림을 Reader로 읽는 것과 byte로 읽은 후 문자열로 변환하는 것의 차이: reader는 내부에 버퍼를 포함해서 성능이 좋고, 문자 인코딩 문제를 자동으로 처리한다. 인코딩을 명시적으로 지정하지 않으면 jvm의 기본 문자 인코딩을 사용함.
- InputStream을 버퍼로 감싼 후 매 라인을 string으로 변환하는 것과 Reader를 사용하는 것의 성능 차이는 크지 않다.
- Socket의
InputStream
으로 수신하는 데이터가 항상 문자열이 아닐 수 있다. 따라BufferedInputStream
을 사용하여 바이트 단위로 데이터를 읽는 것이 더 적절하다.BufferedInputStream
은 효율적인 버퍼링을 제공하므로, 데이터 읽기 성능을 향상시킬 수 있습니다.
-
HTTP/1.1에서 도입된 데이터 전송 방식. 데이터의 전체 크기 없이 청크 단위로 전송받을 수 있도록. ex) 스트리밍 데이터 전송, 실시간 생성된 데이터 전송에서 사용
-
ChatGPT와 같은 대화형 AI 시스템이 응답을 전송할 때도 Chunked Transfer Encoding을 사용할 수 있습니다.
-
서버가 데이터를 청크 단위로 보내기 때문에, 큰 데이터를 메모리에 모두 로드할 필요가 없음. 데이터가 준비되는대로 전송, → 메모리 사용을 줄이고 효율성을 높임.
-
Content-Length 헤더는 포함하지 않고, Content-Type은 포함.
HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked
-
하나의 응답을 여러개의 청크로 나누어 전송한다는 것. 하나의 요청에 대해 여러 개의 응답이 전송되는 것이 아니라, 하나의 HTTP 응답이 여러 청크로 나뉘어 전송.
-
Connection: Keep-Alive가 필수가 아님. chuncked encoding은 실제로는 하나의 요청, 하나의 응답으로 이루어지기 때문에.
-
데이터 형식: 응답 본문은 여러개의 청크로 나뉨. 각 청크는 청크 크기인 16진수 숫자로 시작. 0CRLFCRLF는 응답본문의 끝을 나타냄
-
Chunked Transfer Encoding을 사용하는 동안 타임아웃이 발생하면, 데이터 전송이 중단되고 연결이 종료됩니다. incomplete chunk encoding , 클라이언트는 전체 응답을 받지 못하게 됩니다.
- 유틸리티 클래스 :
static
메소드만 가지고 있는 클래스. 생성자를 Private으로 선언해 인스턴스를 만들지 못하게 한다. 상태를 가지지 않고 여러 클래스에서 정적 참조로 사용할 수 있도록 제공 - 일반적으로
final
로 선언하는 것이 좋다.-
의도 명확화:
- 클래스가 상속되지 않도록 의도를 명확히 합니다.
final
로 선언하면 다른 개발자에게 이 클래스는 상속을 위해 설계되지 않았음을 분명히 전달할 수 있습니다.
- 클래스가 상속되지 않도록 의도를 명확히 합니다.
-
불필요한 상속 방지:
- 클래스가 상속되지 않도록 강제하여 설계 의도를 보호합니다. 이는 코드 유지보수성과 안정성을 높일 수 있습니다.
-
성능 최적화:
- JIT 컴파일러는
final
클래스를 더 효율적으로 최적화할 수 있습니다. 이는 성능 향상에 기여할 수 있습니다.
- JIT 컴파일러는
-
인스턴스화 방지:
- 유틸리티 클래스는 일반적으로 인스턴스화되지 않아야 합니다.
final
로 선언함으로써 해당 클래스가 상속되어 인스턴스화되는 것을 방지할 수 있습니다.
- 유틸리티 클래스는 일반적으로 인스턴스화되지 않아야 합니다.
-
의도 명확화:
- org.apache.catalina : tomcat의 서블릿 컨테이너. 기능을 담당.서블릿과 jsp를 처리하는 주요 기능을 제공
- 서블릿 및 Jsp 파일의 로딩, 실행, 및 생명주기 관리
- 웹 어플리케이션 컨텍스트와 관련된 설정 및 리소스 관리
- 세션 관리
- 웹 어플리케이션 보안 : 인증 및 권한 부여와 관련된 보안 기능 관리
- 주요 클래스: Session, Servlet, Filter등
- org. apache.coyote: connector컴포넌트, http요청을 처리하고 응답을 생성하는 역할.
- http프로토콜을 처리
- 소켓 통신 관리
- 요청 파싱 및 응답 생성
- 주요 클래스: Http11NioProtocol, Request, Response
- org.apache.tomcat: 주요 유틸리티 클래스와 지원
- Tomcat에서는 기본적으로 모든 요청에 대해 세션을 만들지 않습니다. 세션은 명시적으로 애플리케이션에서 세션을 요청할 때만 생성됩니다. HttpServletRequest객체의 getSession() 메서드가 호출될때
- SessionManager의 역할 : Tomcat에서 세션 관리를 담당하는 핵심 컴포넌트는
-
세션 생성 및 삭제:
- 새로운 세션을 생성하고, 만료되거나 무효화된 세션을 삭제합니다.
-
세션 저장 및 로드:
- 세션 객체를 메모리에 저장하고, 필요한 경우 디스크나 다른 스토리지 매체에서 세션을 로드합니다.
-
세션 만료 처리:
- 세션 타임아웃 설정에 따라 세션을 만료시키고, 만료된 세션을 적절히 정리합니다.
-
클러스터링 지원:
- 클러스터 환경에서 세션 복제를 지원하여, 여러 노드 간에 세션 정보를 동기화합니다.
-
세션 생성 및 삭제:
- getSession()의 동작방식
- 클라이언트의 HTTP 요청이 Tomcat에 도달하면, Tomcat은 요청을 처리하기 전에 세션 ID 쿠키(
JSESSIONID
)를 검사합니다. - 요청에 세션 ID가 포함되어 있다면,
SessionManager
는 해당 세션 ID에 대한 세션 객체를 찾습니다. - 요청에 세션 ID가 없거나 유효하지 않은 경우, session manager는 새로운 세션을 생성한다.
- 클라이언트의 HTTP 요청이 Tomcat에 도달하면, Tomcat은 요청을 처리하기 전에 세션 ID 쿠키(
- 특징
- Spring Boot는
HttpSession
을 활용하여 세션을 관리하지만, 추가적인 기능을 제공합니다. - Spring Session 프로젝트를 통해 Redis, JDBC, Hazelcast 등을 사용한 세션 저장소를 지원합니다.
- Spring Security와의 통합을 통해 보다 세밀한 세션 제어와 보안 기능을 제공합니다.
- Spring Boot는
- Spring Session Redis를 사용하면 Spring Session이 세션 관리를 담당하게 되어 Tomcat의 세션 관리 기능을 대체하거나 우회하게 됩니다.
- SessionRepositoryFilter가 모든 요청을 가로채고 세션 관리를 담당한다.
- 요청 객체와, 응답 객체를 SessionrepositoryReqeustWrapper, SessionRepositoryResponseWrapper를 래핑하여 톰캣 세션이 아닌 SpringSession이 관리하는 세션을 사용하도록 한다.
- HttpServletRequest.getSession() 메서드를 오버라이드한다.
- 다른 사람들은 로그인 후에 인증 결과를 ThreadLocal에 저장했는데 나는 Request객체의 Session 내에 저장함. spring security에서 인증 결과인 Authentication객체를 SecurityContextHolder에 thraedlocal로 저장하기 때문에. 스레드마다 안전하게 인증 결과를 저장할 수 있고, static으로 모든 클래스에서 쉽게 접근 가능하게 해도 안전함.
- 인증된 상태는 요청을 넘어서 세션 스코프에서 존재해야하므로 ThreadLocal에만 저장하는 것은 불가능.
- ThreadLocal에 저장한다는 것도 세션에 저장되어있는 것을 미리 세션에서 로드해서 ThreadLocal에 저장해둔다는 것이므로 조회 편의성 혹은 속도를 위한 것임.
- 로그아웃시: 전체 세션 무효화 vs 현재 세션의 principal 정보만 무효화
- 데이터 보존이 중요한 경우: 로그인 정보 외에 다른 중요한 데이터가 세션에 저장되어 있고, 이 데이터를 유지해야 하는 경우에는 로그인 관련 데이터만 선택적으로 제거할 수 있습니다.
- 보안이 중요한 경우: 로그아웃시에 세션에 저장된 모든 데이터를 무효화
- 톰캣의 HttpRequest객체는 login(), logout(), authenticate()를 제공. login()은 요청 파라미터의 username, password를 사용해서 인증후 인증된 사용자 정보를 세션에 저장.
- JAVA EE 표준 사양에 정의된 메서드, http 요청에서 인증 정보를 추출하고, 인증 컨테이너의 보안 매커니즘(기본 인증, 폼 기반 인증) 을 사용하여 사용자를 인증. 보안과 관련된 기능을 표준화
- tomcat login()을 사용하는 장점: was가 제공하는 인증 방식을 사용하면 표준화된 보안 매커니즘을 사용해서 보안상의 취약점을 줄이고, 보안 관리 작업을 단순화
- tomcat login()을 사용하는 단점: 어플리케이션만의 인증 방식을 사용하기 어렵다. 고급 보안 요구사항을 충족하지 어렵다.
-
세션을 언제 만료될까?
- 만료기간이 되었을때
- 더 이상 클라이언트가 사용하지 않는 세션. ex) 브라우저가 종료되서 클라이언트에서 세션 키 쿠키가 삭제되었을때
-
언제 만료된 세션을 세션 저장소에서 삭제할까?
- 백그라운드에서 주기적으로 전체 세션을 검사한다: 스케줄러나 백그라운드 스레드로 구현. 특정 요청시점에 시스템 부하가 급증하지 않음, 세션 정리 작업이 요청 처리 스레드와 독립적으로 실행. 검사 작업 자체가 상당한 리소스를 소비할 수 있음.
- request가 올때마다 전체 세션을 검사한다: 요청 처리 로직에 통합하여 쉽게 구현하고, 세션 관리가 실시간으로 이루어짐. 빈번한 요청시, 불필요한 검사 작업이 과도하게 이루어질 수 있음.
⇒ 두가지 방식을 혼용: 백그라운드 작업을 통해 주기적으로 전체 세션을 정리하고, 요청시 만료된 세션을 즉시 정리.
-
세션은 만료된 후에도 삭제되지 않을 가능성이 있기 때문에, 최대한 적은 정보를 저장해서 가볍게 유지하는게 좋다.
- 클라이언트에게 이벤트를 서빙하는 방법
- polling : 어떤 상태인지 클라이언트가 주기적으로 서버에게 물어본다. → 일정시간마다 요청이 만들어져서 서버 자원이 많이 필요하다. 어떤 주기로? 이벤트가 발생했지만 서빙되지 않는 사이에 간격이 생김. 실시간성이 떨어짐.
- long polling : 어떤 상태인지 확인하고, 일정시간동안 커넥션을 유지하고 커넥션을 유지하는 동안 이벤트가 발생하면 서버가 응답을 보내고 커넥션을 종료하고 커넥션이 종료되면 클라이언트가 다시 요청 → 실시간성은 있지만 폴링만을 위해서 socket이 많이 사용됨.
- server sent events : 클라이언트가 서버를 구독(커넥션을 수립), 커넥션을 유지한 채 서버에서 이벤트가 발생하면 클라에게 전송. accept : text/event-stream. transfter-encoding: chuncked. scaleout이 어려워짐(서버가 Stateful해짐)
- 메모리는 폴링이 좋고, CPU는 SSE가 좋다. 폴링 방식은 주기적으로 요청을 계속 보내기 때문에 요청 처리에 CPU 사용량이 높아질 수 있음. SSE는 연결을 유지해야하므로, 연결을 관리하기 위한 메모리 사용이 필요하다.
- Spring Emitter를 사용해서 쉽게 구현 가능
- SSE content-type: text/event-stream 사용
- db와의 연결은 트랜잭션 종료(롤백, 커밋)시 connection pool에 반환됨. 트랜잭션 바깥에서 lazy loading시에 예외 발생함.
- 서버는 클라이언트의 각 TCP 연결에 대해 소켓을 유지합니다. 각 소켓은 고유한 연결을 나타냅니다.
- 클라이언트의 IP 주소와 포트 번호를 기반으로 소켓을 식별합니다. 서버는 연결이 유지되는 동안 동일한 클라이언트로부터 오는 요청을 동일한 소켓을 통해 처리합니다.
- 서버는 네트워크 스택을 통해 이러한 정보를 관리하고, 이를 통해 클라이언트의 소켓을 식별합니다.
- TCP 3-way handshake를 통해 TCP 연결을 설정하는 과정에서 클라이언트와 서버 간에 IP 주소와 포트 번호가 교환됩니다. 서버는 클라이언트의 IP 주소와 포트 번호를 기반으로 각 소켓을 고유하게 식별합니다.
- 언제 connection pool이 반환되지?
- 사이즈자체보다 timeout설정이 더 중요하다. timeout설정에 따라서 크키가 달라지게된다.
- timeout 설정
- 스레드 풀 QueueTimeout: 모든 스레드가 사용중일때 대기열에 추가된 작업이 일정시간 내에 처리되지 않을때
- 네트워크 connection timeout
- db 연결시 timeout
- 이슈 : 로컬에서 build한 jar 파일을 ec2에서 실행시 file을 로드하지 못하는 현상
- 원인 : jar파일 내(클래스패스 내)이 리소스를 파일시스템을 사용해서 읽기 때문
- 해결: 1) File객체를 사용하지 않고 InputStream으로 읽는다. 2) fat jar를 만들어서 파일을 jar파일 내에 포함시켜서 File객체로 읽을 수 있도록 한다.
- java -jar 명령어로 단독 실행할 수 있도록 의존하는 모든 라이브러리를 jar 안에 포함시키는 것
- fat -jar가 아니라면 java -jar -cp로 라이브러리가 있는 경로를 classpath로 포함해주어야함
- springboot는 기본적으로 build를 할때 자동으로 참조되는 라이브러리를 넣어 fat jar파일로 만들어준다. gradle기본은 build 시에 fat-jar를 만들지 않는다.
jar {
...
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
// 중복된 파일은 제외한다. 중복된 라이브러리를 추가시 충돌 오류가 난다.
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
} // jar안에 실행시에 필요한 모든 라이브러리의 경로를 포함시킨다.
// 폴더라면 그대로, 파일인 경우에는 압축해서 포함시킨다.
...
}
- 클래스패스 리소스 vs 파일 시스템 리소스
-
클래스패스 리소스:
getResourceAsStream
메서드는 클래스패스 내의 리소스를 읽는다. 이는 JAR 파일 안에 포함된 리소스나, 애플리케이션의 클래스패스 내에 포함된 파일을 읽을 수 있습니다. -
파일 시스템 리소스:
File
객체는 파일 시스템 경로를 통해 파일을 읽습니다. 이는 클래스패스와 무관하게 파일 시스템에 직접 접근합니다. jar로 패키징시 클래스패스 내의 리소스는 jar파일 안에 있어 파일 시스템 경로로 접근할 수 없음.
-
클래스패스 리소스: