1. TCP 커넥션

전 세계 모든 HTTP 통신은 지구상의 컴퓨터와 네트워크 장비에서 널리 쓰이고 있는 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어집니다.

TCP는 HTTP에게 신뢰할 만한 통신 방식을 제공하기 때문에, 일단 커넥션이 맺어지면 클라이언트와 서버 컴퓨터 간에 주고받는 메시지들은 손실 혹은 손상되거나 충돌없이 순서가 바뀌지 않고 안전하게 전달됩니다.

 

 

위의 그림은 웹 브라우저가 TCP 커넥션을 통해서 웹서버에 요청을 보내는 과정입니다.

(1) 웹 브라우저가 URL의 호스트 명으로부터 76.76.21.61:443이라는 IP주소와 포트 정보를 얻습니다.

(2) 웹 브라우저가 76.76.21.61의 443포트에 TCP 커넥션을 생성합니다.

(3) 웹 브라우저가 서버로 HTTP 요청을 합니다.

(4) 서버가 웹 브라우저로 HTTP 응답을 합니다.

(5) 웹 브라우저가 TCP 커넥션을 끊습니다.

 

1.1 TCP 전송

HTTP가 메시지를 전송하고자 할 경우, 현재 연결되어 있는 TCP 커넥션을 통해서 메시지 데이터의 내용을 순서대로 보냅니다.

TCP 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷(혹은 IP 데이터그램)라고 불리는 봉투에 담아서 인터넷을 통해 데이터를 전달합니다.

각 TCP 세그먼트는 하나의 IP 주소에서 다른 IP 주로로 IP 패킷에 담겨 전달됩니다.

 

 

위의 그림은 IP 패킷의 구조입니다.

IP 패킷은 IP 패킷 헤더, TCP 세그먼트 헤더, TCP 데이터 스트림 덩어리로 나눌 수 있는데,

IP 패킷 헤더는 발산지와 목적 IP 주소, 크기, 기타 플래그를 가집니다.

TCP 세그먼트 헤더는 TCP 포트 번호, TCP 제어 플래그, 그리고 데이터의 순서와 무결성을 검사하기 위해 사용되는 숫자 값을 포함합니다.

 

※ IP 패킷의 구성 요소의 자세한 내용을 보고 싶으신 분은 구글에 구성  요소에 대해 검색하시면 쉽게 알 수 있습니다.

 

1.2 TCP 커넥션 유지

TCP는 포트 번호를 통해 여러 커넥션을 가질 수 있습니다.

 

TCP 커넥션은 다음과 같이 네 가지 값으로 식별합니다.

<발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트>

 

이 네 가지 값으로 유일한 커넥션을 생성합니다.

물론 유일한 커넥션이지만 다른 커넥션과 수신지 IP만 같거나 등 일부는 같을 수 있습니다.

 

1.3 TCP 소켓 프로그래밍

네트워크에서의 소켓은 데이터를 내보내거나 혹은 데이터를 받기 위한 실제적인 창구 역할을 합니다.

TCP 소켓 프로그래밍은 TCP 커넥션이 연결된 클라이언트과 서버의 소켓을 통한 상호작용을 위한 프로그래밍이라 할 수 있습니다.

 

 

위 그림은 서버와 클라이언트가 TCP 소켓 인터페이스를 사용하여 상호작용하는 방법입니다.

 

2. TCP의 성능

HTTP는 TCP 바로 위의 있는 계층이기 때문에 HTTP 트랜잭션의 성능은 그 아래 계층인 TCP 성능에 영향을 받습니다.

 

2.1 HTTP 트랜잭션 지연

트랜잭션을 처리하는 시간은 DNS를 찾고 TCP 커넥션을 설정하고 요청을 전송하고 응답 받는 시간에 비하면 상당히 짧습니다.

그렇기 때문에 대부분의 HTTP 지연은 TCP 네트워크 지연 때문에 발생합니다.

TCP 네트워크 지연은 하드웨어의 성능, 네트워크와 서버의 전송 속도, 요청과 응답 메시지의 크기, 클라이언트와 서버 간의 거리에 따라 크게 달라집니다.

물론 TCP 프로토콜의 기술적인 복잡성도 지연에 큰 영향을 줍니다.

 

2.2 TCP 커넥션 핸드셰이크 지연

핸드셰이크는 TCP의 신뢰성있는 통신 연결과 종료를 위한 통신 방법입니다.

핸드셰이크 종류에는 3-way handshake와 4-way handshake가 있습니다.

 

 

3-way handshake를 기준으로 간단히 설명드리자면,

  • 클라이언트가 커넥션 생성 요청을 서버에 보내고
  • 서버가 요청이 받아들여졌음을 클라이언트에 보내고
  • 클라이언트가 커넥션이 연결됐음을 서버에게 보내는 것입니다.
    클라이언트는 이때 데이터를 함께 보낼 수 있습니다.

어떤 데이터를 전송하든 새로운 TCP 커넥션을 열 때면, TCP 커넥션 핸드셰이크를 하게 됩니다.

그렇게 때문에 작은 크기의 데이터 전송에 커넥션이 사용된다면 HTTP 성능을 크게 저하시킬 수 있습니다.

 

2.3 TCP 느린 시작

TCP 커넥션은 시간이 지나면서 자체적으로 튜닝되어서 처음에는 커넥션의 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 속도 제한을 높여나갑니다.

이렇게 조율하는 것을 TCP 느린 시작이라고 합니다.

이는 인터넷의 급작스러운 부하와 혼잡을 방지하는데 쓰입니다.

 

2.4 TIME_WAIT

이전 커넥션과 관련된 패킷이 같은 주소와 포트 번호를 가지는 새로운 커넥션에 삽입되는 문제를 방지하기 위해 2분 정도 이내에 같은 주소와 포트 번호를 가지는 커넥션을 생성되는 것을 막아줍니다.

※ 2분은 보통 세그먼트의 최대 생명주기의 두 배 정도이며, 2MSL이라 불립니다.

 

예를 들어, 발신지 IP 주소와 포트, 수신지의 IP가 고정 되어있고 수신지의 포트만 변경할 수 있다고 하면,

수신지의 포트는 제한되어 있기 때문에 TIME_WAIT 상태에 들어가는 포트가 생기는 속도보다 트랜잭션 처리 속도가 느리다면 TIME_WAIT 포트 고갈이 발생합니다.

 

2.5 순차적인 트랜잭션 처리

브라우저가 어떤 페이지를 보여주기 위해 한 개의 HTML을 받기 위한 1개의 HTTP 트랜잭션과 세 개의 이미지를 받기 위한 3개의 HTTP 트랜잭션이 필요할 때, 이를 순차적으로 처리한다면, 각 트랜잭션이 새로운 커넥션을 맺는데 발생하는 시간과 함께 느린 시작 지연이 발생할 것입니다.

 

 

 

※ 이 외에도 네트워크 효율 관련해서 네이글 알고리즘, 확인응답 지연 알고리즘라는 것도 있습니다. 궁금하시다면 검색!

 

3. HTTP 커넥션 관리

커넥션 관리를 잘한다면 TCP 성능이 향상될 수 있습니다.

3.1 Connection 헤더

HTTP는 클라이언트와 서버 사이에 프락시 서버, 캐시 서버 등과 같은 중개 서버가 놓이는 것을 허락합니다.

HTTP 메시지는 클라이언트에서 서버까지 중개 서버들을 하나하나 거치면서 전달됩니다.

 

두 인접한 HTTP 애플리케이션이 현재 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있습니다.

이를 위해 전송자가 특정 커넥션에만 해당되는 옵션을 지정하게 해주는 것이 Connection 헤더입니다.

 

예를 들어 서버에 프락시 서버로 HTTP 메시지를 보낼 때, 헤더에 Connection: meter, close, bill-my-credit-card (Meter 헤더가 존재)가 있다고하면, meter 헤더를 다른 커넥션으로 전달하면 안되고 bill-my-credit-card 옵션을 적용할 것이며, 이 트랜잭션이 끝나면 커넥션이 끊길 것임을 의미합니다.

 

3.2 병렬 커넥션

클라이언트의 인터넷 대역폭을 한 개의 커넥션을 다 써버리는 것이 아니라면 남은 대역폭을 사용할 수 있습니다.

그렇기에 클라이언트가 여러 개의 커넥션을 한번에 맺을 수 있고, 이를 통해 여러개의 HTTP 트랜잭션을 병렬로 처리할 수 있습니다.

 

※ 병렬 커넥션에서 각 커넥션 사이에는 소프트웨어와 관련된 지연이 짧게 발생합니다.

 

병렬 커넥션이 일반적으로 더 빠르기는 하지만, 항상 그렇지는 않습니다.

예를 들어, 네트워크 대역폭이 좁을 때 각 커넥션에서 데이터를 전송받는 것은 느리기 때문에 성능상의 장점은 거의 없어집니다.

또한 다수의 커넥션은 메모리를 많이 소모하고 자체적인 성능 문제를 발생시킵니다.

예를 들어, 한 서버에 각 사용자가 많은 커넥션을 맺는다면 서버에 과부하가 걸리기 때문에 서버의 성능을 크게 저하시킵니다.

 

3.3 지속 커넥션

웹 클라이언트는 보통 같은 사이트에 여러 개의 커넥션을 맺습니다.

예를 들어 웹페이지에 첨부된 이미지들은 대부분은 같은 웹 사이트에 있고, 상당 수의 하이퍼링크도 같은 사이트를 가리킵니다.

따라서 서버에 HTTP 요청을 하기 시작한 애플리케이션은 웹페이지 내의 이미지 등을 가져오기 위해서 그 서버에 또 요청하게 될 것입니다.

이 속성을 사이트 지역성(site locality)라 합니다.

 

트랜잭션 처리 후에도 커넥션을 유지하면 이 후의 HTTP 요청에도 재사용할 수 있습니다.

이런 커넥션을 지속 커넥션이라 합니다.

 

지속 커넥션은 클라이언트나 서버가 커넥션을 끊기 전까지는 트랜잭션 간에도 커넥션을 유지합니다.

 

커넥션을 유지함으로써 커넥션을 맺고끊음으로 인한 지연과 TCP 느린 시작으로 인한 지연을 피할 수 있습니다.

 

※ 지속 커넥션은 병렬 커넥션과 함께 사용될 때에 가장 효과적이라 합니다. 그래서 많은 웹 애플리케이션이 적은 수의 병렬 커넥션만을 맺고 그것을 유지한다고 합니다. 이런 커넥션을 파이프라인 지속 커넥션이라 합니다.

 

마치며..

이번 글은 TCP 커넥션에 대한 글입니다.

 

저는 이번 공부에서

  • TCP 커넥션이 무엇인지,
  • TCP 커넥션 연결과정이 어떤지,
  • TCP 소켓 프로그래밍이 무엇인지,
  • 무엇이 TCP 성능에 영향을 끼치지는지,
  • Connection 헤더가 무엇인지,
  • 병렬 커넥션과 지속 커넥션이 무엇이고,
  • 각 커넥션이 어떤 이점이 있고, 어떠한 경우에 단점이 있는지,

를 알아갔습니다.

 

이 글에는 없지만 중간 서버로 멍청한 프락시가 있을 때 Connection 헤더의 문제점, 지속 커넥션의 제한과 규칙, 커넥션 끊기에 대해 알아갔습니다.

추후에 내용이 좀 더 이해가 된다면 추가할 예정입니다. ^-^

※ 지금 당장 그 내용들이 궁금하신 분들은 검색해주세요!

 

 

 

 

 

 

 

 

 

'채워가는 지식 > 네트워크' 카테고리의 다른 글

STOMP 웹소켓 프로그래밍  (0) 2024.02.15
웹 서버  (0) 2023.12.29
HTTP 메시지  (0) 2023.12.18
URL  (1) 2023.12.18
HTTP  (0) 2023.12.15

HTTP 메시지

HTTP 메시지는 HTTP 애플리케이션 간에 주고받은 데이터의 블록들입니다.

이 데이터의 블록들은 메시지의 내용과 의미를 설명하는 텍스트 메타 정보로 시작하고 그 다음에 선택적으로 데이터가 올 수 있습니다.

 

1. 메세지의 흐름

메시지는 클라이언트, 서버, 프락시 사이를 흐릅니다.

메시지의 흐름 방향에는 인바운드, 아웃바운드, 업스트림, 다운스트림라는 용어들이 있습니다.

 

메시지가 원 서버로 항하는 것을 인바운드라 하고, 모든 처리가 끝난 뒤에 메시지가 사용자 에이전트로 돌아오는 것을 아웃바운드라고 합니다.

 

요청 메시지인지 응답 메시지인지 상관없이 모든 메시지는 다운스트림으로 흐릅니다.

즉 메시지의 발송자는 업스트림, 수신자는 다운스트림이라 할 수 있습니다.

 

2. 메시지의 각 부분

메시지는 시작줄, 헤더, 본문으로 세 부분으로 구성되어 있습니다.

시작줄은 이것이 어떤 메시지인지를, 헤더 블록은 속성을, 본문은 데이터를 담고 있습니다.

 

2.1 메시지 문법

요청 메시지의 형식은 다음과 같습니다.

  • start line
    • 메서드(Method)
      클라이언트 측에서 서버가 리소스에 대해 수행해주길 바라는 동작입니다.
      GET, POST 메서드가 해당됩니다.
    • 요청 URL(Path)
      요청 대상이 되는 리소스를 지칭하는 완전한 URL 또는 URL의 경로 구성요소입니다.
    • 버전(Version of the protocol)
      이 메시지에서 사용 중인 HTTP 버전입니다.
  • 헤더들(Headers)
    부가적인 정보들이 들어있습니다.
    이름과 콜론(:) 다음에 오는 값(줄바꿈 없이)으로 구성되어 있는 0개 이상의 헤더들로 구성되어 있습니다.
  • 공백 줄(Blank line)
    헤더가 끝나면 한 줄 띄고 바디가 옵니다.
  • 바디(Body)
    전송하는 데이터가 들어있습니다.
    전송하는 데이터가 없으면 body가 없습니다.

응답 메시지의 형식은 다음과 같습니다.

  • status line
    • 버전(Version of the protocol)
      이 메시지에서 사용 중인 HTTP 버전입니다.
    • 상태 코드(Status code)
      요청 중에 무엇이 일어났는지 설명하는 세 자리의 숫자입니다.
      일반적으로 성공에러를 분류합니다.
    • 상태 텍스트(Status Text)
      숫자로 된 상태 코드의 의미를 사람이 이해할 수 있게 짧게 설명해주는 문구입니다.
  • 나머지는 요청 메시지와 동일합니다.

3. 메서드

클라이언트가 서버에게 어떤 요청을 보내는지 나타냅니다.

 

3.1 안전한 메서드

안전한 메서드는 HTTP 요청의 결과로 인해 서버에 아무런 일도 일어나지 않는 메서드를 말합니다.

보통 GET, HEAD 메서드가 있습니다.

 

3.2 GET

주로 서버에게 리소스를 달라고 요청하는 메서드입니다.

 

3.3 HEAD

GET처럼 행동하지만, 서버는 응답으로 바디없이 헤더만을 돌려줍니다.

 

3.4 PUT

서버가 요청의 본문을 가지고 요청 URL의 이름대로 새 문서를 만들거나, 이미 URL이 존재한다면 본문을 사용해서 교체하는 메서드입니다.

 

3.5 PATCH

리소스의 일부를 교체하기 위한 메서드입니다.

 

3.6 POST

서버에 입력 데이터를 전송하기 위한 메서드입니다.

실제로, HTML 폼을 지원하기 위해 흔히 사용됩니다.

 

3.7 TRACE

클라이언트에게 자신의 요청이 서버에 도달했을 때 어떻게 보이게 되는지 알려주는 메서드입니다.

요청 전송의 마지막 단계에 있는 서버는 자신이 받은 요청 메시지를 본문에 넣어 응답으로 되돌려줍니다.

 

※ TRACE 요청은 어떠한 바디도 보낼 수 없습니다.

 

3.8 OPTIONS

웹 서버에게 특정 리소스에 대해 어떤 메서드가 지원되는지 물어보는 메서드입니다.

 

3.9 DELETE

서버에게 요청 URL로 지정한 리소스를 삭제할 것을 요청하는 메서드입니다.

 

3.10 확장 메서드

HTTP 명세에 정의되어 있지 않은 메서드입니다.

HTTP는 필요에 따라 확장해도 문제가 없도록 설계되어 있습니다.

확장 메서드를 다룰 때는 "엄격하게 보내고 관대하게 받아들여라"라는 오랜 규칙에 따르는 것이 가장 좋다고 합니다.

 

4. 상태 코드

HTTP 상태 코드는 크게 다섯 가지로 나뉩니다.

 

4.1 100번대(1xx): 정보성 상태 코드

임시 응답으로 현재 클라이언트의 요청까지는 처리되었으나 계속 진행하라고 알리는 상태 코드입니다.

 

4.2 200번대(2xx): 성공 상태 코드

클라이언트가 보낸 요청이 성공적으로 처리되었다는 알리는 상태 코드입니다.

 

4.3 300번대(3xx): 리다이렉션 상태 코드

클라이언트가 관심있어 하는 리소스에 대해 다른 위치를 사용하라고 하거나 그 리소스의 내용 대신 다른 대안 응답을 제공하는 상태 코드입니다.

 

리다이렉션 상태 코드 중 몇몇은 리소스에 대한 애플리케이션의 로컬 복사본이 원래 서버와 비교했을 때 유효한지 확인하기 위해 사용됩니다.

예를 들어, HTTP 애플리케이션은 그의 리소스에 대한 로컬 복사본이 여전히 최신인지 혹은 원래 서버에 있는 리소스가 수정되었는지 검사할 수 있습니다.

 

4.4 400번대(4xx): 클라이언트 에러 상태 코드

클라이언트가 잘못 구성된 요청 메시지를 보냈다고 알리는 상태 코드입니다.

 

4.5 500번대(5xx): 서버 에러 상태 코드

서버 자체에서 에러가 발생했음을 알리는 상태 코드입니다.

 

5. 헤더

헤더와 메서드는 클라이언트와 서버가 무엇을 하는지 결정하기 위해 함께 사용됩니다.

헤더는 크게 다섯 가지로 분류됩니다.

 

5.1 일반 헤더

일반 헤더는 클라이언트와 서버 양쪽 모두가 사용합니다.

예를 들어, Date 헤더는 클라이언트와 서버를 가리지 않고 메시지가 만들어진 일시를 지칭하기 위해 사용됩니다.

 

일반 헤더에는 일반 캐시 헤더라는 것도 있습니다.

  • 일반 캐시 헤더
    애플리케이션에게 매번 원 서버로부터 객체를 가져오는 대신 로컬 복사본으로 캐시할 수 있도록 해줍니다.

5.2 요청 헤더

요청 메시지를 위한 헤더입니다.

서버에게 클라이언트가 받고자 하는 데이터의 타입이 무엇인지와 같은 부가 정보를 제공합니다.

예를 들어, Accept 헤더는 서버에게 클라이언트가 자신의 요청에 대응하는 어떤 미디어 타입도 받아들일 것임을 의미합니다.

 

요청 헤더에는 조건부 요청 헤더, 요청 보안 헤더, 프락시 요청 헤더라는 것도 있습니다.

  • 조건부 요청 헤더
    클라이언트는 서버가 요청에 응답하기 전에 먼저 조건이 참인지 확인하게 하는 제약을 포함시킬 수 있습니다.
  • 요청 보안 헤더
    요청하는 클라이언트가 리소스에 접근하기 전에 자신을 인증하게 함으로써 트랜잭션을 약간 더 안전하게 만듭니다.
  • 프락시 요청 헤더
    프락시의 기능을 도와줍니다.

5.3 응답 헤더

응답 메시지를 위한 헤더입니다.

클라이언트에게 정보를 제공합니다.

예를 들어, Sever 헤더는 클라이언트에게 어떤 서버의 몇 버전과 대화하고 있음을 의미합니다.

 

응답 헤더에는 협상 헤더, 응답 보안 헤더라는 것도 있습니다.

  • 협상 헤더
    서버가 협상 가능한 리소스에 대한 정보를 나타냅니다.
    예를 들어, 영어와 한국어로 번역된 HTML 문서가 있는 경우와 같이 여러가지 표현이 가능한 상황에서 서버와 클라이언트가 어떤 표현을 택할 것인가에 대한 협상을 할 수 있도록 지원합니다.
  • 응답 보안 헤더
    요청 보안 헤더와 비슷합니다.

5.4 엔터티 헤더

엔터티 본문에 대한 헤더입니다.

엔터티 본문에 들어있는 데이터에 대한 정보를 제공합니다.

예를 들어, Content-Type 헤더는 애플리케이션에게 데이터가 어떤 타입의 데이터임을 알려줍니다.

 

※ 이 글에서는 엔터티 본문과 바디는 같은 말로 사용했습니다.

 

엔터티 헤더에는 콘텐츠 헤더엔터티 캐싱 헤더라는 것도 있습니다.

  • 콘텐츠 헤더
    엔터티의 콘텐츠에 대한 구체적인 정보를 제공합니다.
    위에 예시로 들었던 Content-Type 헤더가 여기에 포함됩니다.
  • 엔터티 캐싱 헤더
    엔터티 캐싱에 대한 정보를 제공합니다.
    예를 들어, 리소스에 대해 캐시된 사본이 아직 유효한지에 대한 정보와 캐시된 리소스가 더 이상 유효하지 않게 되는 시점을 더 잘 추정하기 위한 단서를 제공합니다.

5.5 확장 헤더

애플리케이션 개발자들에 의해 만들었졋지만 아직 승인된 HTTP 명세에는 추가되지 않은 비표준 헤더입니다.

 

마치며..

이 글은 HTTP 메시지에 대한 다소 간략히 적은 글입니다.


저는 이 글에서

  • 메세지의 흐름에 무엇이 있는지,
  • 요청 메시지와 응답 메시지는 어떤 구조인지,
  • 메서드는 무엇이 있는지와 그 역할들이 무엇인지,
  • 상태 코드 몇번대는 무엇을 나타내는지,
  • 헤더의 역할과 종류는 무엇이 있는지

를 알아가셨으면 좋겠습니다.

 

개인적으로 확장 메서드와 확장 헤더는 그런게 있구나하는 정도로 넘어가시면 될 것 같습니다.

 

개인적으로 본 적이 없는 메서드, 상태 코드 혹은 헤더를 만나게 되더라도 그것이 무엇을 의미하는지는 구글링으로 쉽게 알 수 있기 때문에 상세한 내용은 알 필요 없다고 생각합니다.

 

물론 자주 쓰이는 것은 알고 있으면 좋습니다. ^-^

'채워가는 지식 > 네트워크' 카테고리의 다른 글

웹 서버  (0) 2023.12.29
커넥션  (0) 2023.12.20
URL  (1) 2023.12.18
HTTP  (0) 2023.12.15
네트워크  (0) 2023.09.11

URL

URL은 브라우저가 정보를 찾는데 필요한 리소스의 위치를 나타냅니다.

대부분의 URL은 동일한 구조로 이루어져 있습니다.

때문에 인터넷상의 모든 리소스를 가리키고 가져오기 위해, 그리고 모든 사람이 같은 방식으로 이름을 써서 리소스를 찾을 수 있도록, 단일 방식의 작명 규칙을 가집니다.

 

1. URL 구성

URL은 세부분으로 나눌 수 있습니다.

https://sports.news.naver.com/kbaseball/index

 

 

위의 주소를 예시로 들어보겠습니다.

  • 첫 번째 부분인 https://는 스킴이라 불립니다.
    스킴은 웹 클라이언트가 리소스에 어떤 프로토콜로 접근하는지 알려줍니다.
  • 두 번째 부분인 sports.news.naver.com는 서버의 위치입니다.
    위치는 웹 클라이언트에게 리소스가 어디에 호스팅 되어 있는지 알려줍니다.
  • 세 번째 부분인 /kbaseball/index는 리소스의 경로입니다.
    경로는 서버에게 웹 클라이언트가 요청한 리소스가 무엇인지 알려줍니다.

2. URL 문법

URL 문법은 스킴에 따라 달라지지만, 대부분의 URL은 일반 문법을 사용하기 때문에, 서로 다른 URL 스킴도 형태의 문법면에서 매우 유사합니다.

대부분의 URL 스킴의 문법은 일반적으로 9개 부분으로 나뉩니다.

<스킴>://<사용자 이름>:<비밀번호>@<호스트>:<포트>/<경로>;<파라미터>?<질의>#<프래그먼트>

 

이 모든 컴포턴트를 가지는 URL은 거의 없습니다.

이 중에서 가장 중요하게 생각하는 컴포넌트는 스킴, 호스트, 경로 입니다.

 

2.1 스킴

스킴은 주어진 리소스에 어떻게 접근하는지 알려주는 중요한 정보입니다.

이는 URL을 해석하는 애플리케이션이 어떤 프로토콜을 사용하여 리소스를 요청해야 하는지 알려줍니다.

 

2.2 사용자 이름과 비밀번호

많은 서버가 자신이 가지고 있는 데이터에 접근을 허용하기 전에 사용자 이름과 비밀번호를 요구합니다.

ftp://ftp.prep.ai.mit.edu/pub/gnu

 

예를들어, 위 URL는 사용자 이름과 비밀번호를 요구하는 FTP 프로토콜을 사용하고 있습니다.

위 URL처럼 사용자 이름과 비밀번호를 요구하는 URL 스킴을 사용할 때, URL에 그 값들이 들어 있지 않다면, 기본 사용자 이름과 비밀번호가 값으로 들어가게 됩니다.

 

2.3 호스트와 포트

애플리케이션이 인터넷에 있는 리소스를 찾으려면, 리소스를 호스팅하고 있는 장비와 그 장비 내에서 리소스에 접근할 수 있는 서버가 어디에 있는지 알아야 합니다.

호스트와 포트는 그 정보들을 제공합니다.

 

호스트 컴포넌트는 접근하려고 하는 리소스를 가지고 있는 인터넷상의 호스트 장비를 가리킵니다.

같은 호스트여도 호스트명과 IP 주소로 나타내는 두가지 방법이 있습니다.

 

포트 컴퍼넌트는 서버가 열어놓은 네트워크 포트를 가리킵니다.

내부적으로 TCP 프로토콜을 사용하는 HTTP는 기본 포트로 80을 사용합니다.

 

2.4 경로

경로 컴포넌트는 리소스가 서버의 어디에 있는지 알려줍니다.

HTTP URL에서는 '/' 문자를 기준으로 경로조각으로 나뉩니다.

각 경로조각은 자체만의 파라미터 컴포넌트를 가질 수 있습니다.

 

2.5 파라미터

파라미터 컴포넌트는 '키=값' 쌍의 리스트로 URL 나머지 부분들로부터 ';' 문자로 구분합니다.

이를 통하여 애플리케이션이 리소스에 접근하는데 필요한 어떤 추가 정보든 전달할 수 있습니다.

 

http://www.daco/info;type=a/index.html;graphics=true

 

위의 URL를 예시로 들면, info 경로조각에는 값이 a인 type 파라미터와 index.html 경로조각에는 값이 true인 graphics 파라미터를 가지고 있습니다.

 

2.6 질의

질의 컴포넌트는 데이터베이스 같은 서비스들이 요청받을 리소스 형식의 범위를 좁히기 위해서 사용됩니다.

URL에서 '?' 문자 뒤에 있는 값들입니다.

 

질의 컴포넌트 포맷은 사용하면 안되는 특정 문자들을 제외하면 제약사항은 없습니다.

그렇지만 편의상 많은 게이트웨이가 '&' 문자로 나뉜 '키=값' 쌍 형식을 원합니다.

 

http://www.daco/info/index.html?item=1&color=black

 

위의 예시 URL에는 item=1, color=black이라는 두 개의 질의 컴포넌트가 있습니다.

 

2.7 프래그먼트

프래그먼트 컴포넌트는 리소스의 특정 부분을 가리킬 수 있도록 해줍니다.

즉, URL은 HTML 문서에 있는 특정 이미지나 일부분을 가리킬 수 있습니다.

URL에서 '#' 문자에 이어서 옵니다.

 

일반적으로 HTTP 서버는 객체 일부가 아닌 전체만 다루기 때문에 클라이언트는 서버에 프래그먼트를 전달하지 않습니다.

 

http://www.daco/info/index.html#intro

 

위의 예시 URL는 intro라는 프래그먼트 컴포넌트가 있습니다.

브라우저는 서버로부터 전체 리소스를 내려받은 후, 프래그먼트를 사용하여 보고자 하는 리소스의 일부를 보여줍니다.

 

※ 예시로 더 설명드리자면, 웹 페이지에서 info라는 리소스가 있는 곳으로 스크롤이 이동하는 것입니다.

 

3. 단축 URL

웹 클라이언트는 몇몇 단축 URL을 인식하고 사용합니다.

상대 URL은 리소스 안에 있는 리소스를 간결하게 기술하는데 사용할 수 있습니다.

많은 브라우저가 사용자가 기억하고 있는 URL 일부를 입력하면 나머지 부분을 자동으로 입력해주는 URL 자동 확장을 지원합니다.

 

3.1 상대 URL

URL은 상대 URL과 절대 URL로 2가지로 나뉩니다.

2. URL 문법에서 다뤘던 URL은 모두 절대 URL 입니다.

절대 URL은 접근하는데 필요한 모든 정보를 가지고 있습니다.

그와 달리 상대 URL은 모든 정보를 담고 있지는 않습니다.

상대 URL로 리소스에 접근하는데 필요한 모든 정보를 얻기 위해서는 기저(base)라는 다른 URL을 사용해야 합니다.

상대 URL은 프래그먼트이거나 URL 일부입니다.
URL을 처리하는 브라우저 같은 애플리케이션은 상대 URL과 절대 URL 간에 상호 변환할 수 있어야 합니다.

 

상대 URL을 사용하면 HTML 페이지 같은 리소스 집합을 쉽게 변경할 수 있습니다.

 

3.2 URL 확장

어떤 브라우저들은 URL을 입력한 다음이나 입력하고 있는 동안에 자동으로 URL을 확장합니다.

자동으로 URL이 확장되기 때문에 사용자는 URL 전체를 타이핑하지 않아도 URL을 빠르게 입력하게 도와줍니다.

 

확장 기능은 호스트 명 확장, 히스토리 확장 두 가지로 나뉩니다.

 

3.2.1 호스트 명 확장

호스트 명 확장 기능을 지원하는 브라우저는 단순한 휴리스틱만을 사용해서 입력한 호스트명을 전체 호스트 명으로 확장할 수 있습니다.

예를 들어, 주소 입력란에 'naver'을 입력하면, 브라우저는 호스트 명에서 자동으로 'www.'와 '.com'을 붙여서 'www.naver.com'을 만들어줍니다.

 

※ 어떤 브라우저는 'naver'란 단어를 포함한 사이트를 찾지 못하면, 확장을 포기하기 전에 몇 가지의 URL을 추가로 제시합니다.

 

3.2.2 히스토리 확장

히스토리 확장은 과거에 사용자가 방문했던 URL의 기록을 저장해 놓은 것을 이용한 것입니다.

예를 들어, 이전에 방문 했던 URL의 시작 부분을 입력하면, 브라우저가 전체 URL를 보여주고 사용자가 선택 하는 것입니다.

 

4. 안전하지 않은 문자

안전한 전송이란, 정보가 유실될 위험 없이 URL을 전송할 수 있다는 것을 의미합니다.

 

전자메일에 사용되는 SMTP같은 프로토콜은 특정 문자를 제거할 수도 있는 전송 방식을 사용합니다.

 

※ 7비트 인코딩을 사용하고 있는 프로토콜에 8비트 이상으로 인코딩된 정보가 있으면 소실될 수 있습니다.


그렇기에 URL은 상대적으로 작고 일반적으로 안전한 알파벳 문자만 포함하도록 허락했습니다.

 

하지만 이후에 URL에 이진데이터나 안전한 알파벳 외의 문자도 포함하기 위해 이스케이프라는 기능을 추가하여, 안전하지 않은 문자를 안전한 문자로 인코딩할 수 있게 됐습니다.

 

4.1 URL 문자 집합

역사적으로 많은 컴퓨터 애플리케이션이 US-ASCII 문자 집합을 사용해왔습니다.

US-ASCII는 7비트를 사용하여 영문 자판에 있는 키 대부분과 몇몇 출력되지 않는 제어 문자를 표현합니다.

 

US-ASCII는 적은 수의 문자만을 포함하고 있어서 지원하지 못하는 언어들이 존재했고, 이진 데이터를 포함해야하는 경우도 있었기 때문에 이를 지원하기 위해 이스케이프 문자열이 생겼습니다.

 

이스케이프 문자열은 US-ASCII에서 사용이 금지된 문자들로, 특정 문자나 데이터를 인코딩할 수 있게 함으로써 이동성과  완성도를 높였습니다.

 

4.2 인코딩 체계

안전하지 않은 문자를 '%'로 시작해, ASCII 코드로 표현되는 두 개의 16진수 숫자로 이루어진 이스케이프 문자로 바꿉니다.

 

※ 이스케이프 문자로 바꾸기 위한 '%' 가 아닌 '%'를 그대로 보여주기 위해 사용할 땐 %25로 바꿉니다.

 

4.3 문자 제한

몇몇 문자는 URL 내에서 특별한 의미로 예약되어 있습니다.

그렇기에 URL에서 예약된 문자들을 본래의 목적이 아닌 다른 용도로 사용하려면, 그 전에 반드시 이스케이프 인코딩을 해야 합니다.

 

마치며..

이번 글에서는 URL에 대해 다루었습니다.

 

개인적으로 이글에서

  • URL 구성과 문법이 어떻게 되어있는지,
  • 상대 URL과 기저 URL과 절대 URL이 무엇인지,
  • URL 확장에는 무엇이 있는지,
  • 이스케이프 용도는 무엇인지

를 알아 가셨으면 좋겠습니다.

 

부족한 글을 읽어주셔서 감사합니다 ^-^

'채워가는 지식 > 네트워크' 카테고리의 다른 글

커넥션  (0) 2023.12.20
HTTP 메시지  (0) 2023.12.18
HTTP  (0) 2023.12.15
네트워크  (0) 2023.09.11
OSI 7계층 모델, TCP/IP 4계층 모델  (0) 2023.06.22

http를 안다고하면 다음과 같은 질문에 답할 수 있어야 한다고 생각합니다.

  • 얼마나 많은 클라이언트와 서버가 통신하는지
  • 리소스가 어디서 오는지
  • 웹 트랜잭션이 어떻게 동작하는지
  • HTTP 통신을 위해 사용하는 메시지의 형식
  • HTTP 기저의 TCP 네트워크 전송
  • 여러 종류의 HTTP 프로토콜
  • 인터넷 곳곳에 설치된 다양한 HTTP 구성요소

HTTP

HTTP는 전 세계의 웹 서버로부터 이 대량의 정보를 빠르고, 간편하고, 정확하게 사람들의 PC에 설치된 웹브라우저로 옮겨줍니다.

그리고 HTTP는 신뢰성 있는 데이터 전송 프로토콜을 사용하기 때문에, 데이터가 지구 반대편에서 오더라도 전송 중 손상되거나 꼬이지 않음을 보장합니다.

1. 웹 클라이언트와 서버

웹 콘텐츠는 웹 서버에 존재합니다.

웹 서버는 HTTP 프로토콜로 의사소통하기 때문에 HTTP 서버로도 불립니다.

이들 웹 서버는 인터넷의 데이터를 저장하고, HTTP 클라이언트가 요청한 데이터를 제공합니다.

2. 리소스

웹 서버는 웹 리소스를 관리하고 제공합니다.

리소스는 정적 파일일 수도 있고, 요청에 따라 콘텐츠를 생산하는 프로그램이 될 수도 있습니다.

요약하자면, 어떤 종류의 콘텐츠 소스도 리소스가 될 수 있습니다.

 

2.1 미디어 타입

인터넷은 수천 가지 데이터 타입을 다루기 때문에, HTTP는 웹에서 전송되는 객체 각각에 신중하게 MIME 타입이라는 데이터 포맷 라벨을 붙입니다.

그렇기에 웹 서버는 모든 HTTP 객체 데이터에 MIME 타입을 붙이고 웹 브라우저는 서버로부터 객체를 돌려받을 때, 다룰 수 있는 객체인지 MIME 타입을 통해 확인합니다.

 

MIME 타입은 /로 구분된 주 타입과 부 타입으로 이루어진 문자열 라벨입니다.

  • HTML로 작성된 문서는 text/html
  • JPEG 이미지는 image/jpeg

이 외에도 많고, 보내려는 데이터를 어떤 MIME 라벨이 붙어야 되는지는 필요할 때마다 찾아보시면 됩니다.

 

2.2 URI

URI는 인터넷의 우편물 주소 같은 것으로, 정보 리소스를 고유하게 식별하고 위치를 저장할 수 있습니다.

예를 들어 웹 서버에 있는 이미지 리소스에 대한 URI라면 다음과 같습니다.

http://www.daco.com/intro/hi.gif

 

※ URI는 URL과 URN을 포함하는 상위 개념입니다.

2.3 URL

URL은 리소스 식별자의 가장 흔한 형태입니다.

URL은 특정 서버의 한 리소스에 대한 구체적인 위치를 서술합니다.

그렇기에 리소스가 정확히 어디에 있고 어떻게 접근할 수 있는지 분형히 알려줍니다.

 

대부분의 URL은 세 부분으로 이루어진 표준 포맷을 따릅니다.

  • 첫 번째 부분은 스킴이라고 불리는데, 리소스에 접근하기 위해 사용되는 프로토콜을 서술합니다.
    ex) http://
  • 두 번째 부분은 도메인 이름 혹은 호스트 명이라고 불리는데, 서버의 인터넷 주소를 제공합니다.
    ex) www.daco.com
  • 세 번째 부분은 웹 서버의 리소스를 가리킵니다.
    ex) /intro/hi.gif

대부분 URI는 URL처럼 사용합니다.

2.4 URN

URN은 콘텐츠를 이루는 한 리소스에 대해, 그 리소스의 위치에 영향 받지 않는 유일무이한 이름 역할을 합니다.

예를 들어, 인터넷 표준 문서 RFC 2648를 나타내는 URN은 다음과 같습니다.

urn:ietf:rfc:2648

 

이해가 잘 안되신다면 URN은 잘 쓰이지 않기 때문에 이런게 있구나하고 넘어가시면 됩니다.

 

3. 트랜잭션

HTTP 트랜잭션은 요청 명령과 응답 결과로 구성되어 있습니다.

 

3.1 메서드

HTTP는 HTTP 메서드라고 불리는 여러 가지 종류의 요청 명령을 지원합니다.

 

3.2 상태 코드

모든 HTTP 응답 메시지는 상태 코드와 함께 반환됩니다.

 

4. 메세지

HTTP 메시지는 단순한 줄 단위의 문자열입니다.

HTTP 메시지에는 요청 메시지와 응답 메시지가 있습니다.

 

위의 그림 처럼 HTTP 메시지는 다음의 세 부분으로 이루어집니다.

  • 시작줄
    메시지의 첫 줄은 요청이라면 무엇을 해야하는지, 응답이라면 무슨 일이 일어났는지 나타냅니다.
  • 헤더
    시작줄 다음에는 0개 이상의 헤더 필드가 이어집니다.
    각 헤더 필드는 쉬운 구문분석을 위해 :으로 구분되어 있는 하나의 키 값으로 구성됩니다.
    헤더는 초록색 박스처럼 빈 줄로 끝납니다.
  • 본문
    빈 줄 다음에는 어떤 종류의 데이터든 들어갈 수 있는 메시지 본문이 필요에 따라 올 수 있습니다.

5. TCP 커넥션

TCP는 인터넷 전송 프로토콜 중 하나로 전송 제어 프로토콜입니다.

메시지가 TCP 커넥션을 통해서 한 곳에서 다른 곳으로 옮겨갈 수 있습니다.

 

5.1 TCP/IP

HTTP는 애플리케이션 계층 프로토콜로써, 네트워크 통신의 핵심적인 세부사항에 대해서 신경 쓰지 않습니다.

대신 대중적이고 신뢰성 있는 인터넷 전송 프로토콜인 TCP/IP에게 맡깁니다.

 

TCP는 다음과 같은 특징이 있습니다.

  • 오류없는 데이터 전송
  • 언제나 보낸 순서대로 도착
  • 언제든 어떤 크기로든 전송 가능

TCP/IP는 TCP와 IP가 층을 이루는, 패킷 교환 네트워크 프로토콜의 집합입니다.

TCP/IP는 각 네트워크와 하드웨어의 특성을 숨기고, 어떤 종류의 컴퓨터나 네트워크든 서로 신뢰성 있는 의사소통을 하게 해줍니다.

 

※ TCP는 IP 위의 계층

 

5.2 IP 주소와 포트번호

HTTP 클라이언트가 서버에 메시지를 전송할 수 있게 되기 전에, 인터넷 프로토콜(IP) 주소와 포트번호를 사용해 클라이언트와 서버 사이에 TCP/IP 커넥션을 맺어야 합니다.

http://145.32.211.22:80/index.html

 

위와 같은 URL이 있다고 하면 IP 주소는 145.32.211.22, 포트번호는 80입니다.

 

※ 글자로 된 도메인 이름 또는 호스트 명은 URL에 대한 이해하기 쉬운 형태의 별명이라 보시면 됩니다.

 

6. 프로토콜 버전

프로토콜 버전은 크게 0.9, 1.0, 1.1, 2.0, 3.0이 있습니다.

 

HTTP/0.9

간단한 HTML 객체를 받아오기 위해 만들어졌습니다.

 

HTTP/1.0

버전 번호, HTTP 헤더, 추가 메서드, 멀티미디어 객체 처리 추가

 

HTTP/1.1

기존 HTTP 설계의 구조적 결함 교정, 두드러진 성능 최적화, 잘못된 기능 제거에 집중

 

HTTP/2.0

기존 HTTP/1.x 버전의 성능 향상에 초점을 둔 프로토콜

 

HTTP/3.0

QUIC을 기반으로 나온 새로운 HTTP 메이저 버전

 

※ QUIC는 구글에서 개발한 UDP 기반의 전송 프로토콜입니다.

 

7. 웹의 구성요소

웹의 구성요소로 프락시, 캐시, 게이트웨이, 터널, 에이전트가 있습니다.

 

7.1 프락시

프락시는 클라이언트와 서버 사이에 위치한 HTTP 중개자입니다.

웹 보안, 애플리케이션 통합, 성능 최적화를 위한 중요한 구성요소입니다.

주로 보안을 위해 사용됩니다.

 

7.2 캐시

웹 캐시와 캐시 프락시는 자신을 거쳐 가는 문서들 중 자주 찾는 것의 사본을 저장해 두는, 특별한 종류의 HTTP 프락시 서버입니다.

멀리 떨어진 웹 서버보다 근처의 캐시에서 훨씬 더 빨리 문서를 받을 수 있습니다.

 

7.3 게이트웨이

게이트웨이는 다른 서버들의 중개자로 동작하는 특별한 웹 서버입니다.

주로 HTTP 트래픽을 다른 프로토콜로 변환하기 위해 사용됩니다.

7.4 터널

터널은 단순히 HTTP 통신을 전달하기만 하는 특별한 프락시입니다.

7.5 에이전트

에이전트는 사용자를 위해 자동화된 HTTP 요청을 만드는 준지능적 웹클라이언트 프로그램입니다.

자동화된 에이전트는 스파이더 또는 웹로봇라는 이름을 갖고 있습니다.

스파이더는 웹을 돌아다니며 전 세계의 웹페이지를 수집합니다.

 

마치며...

http에 대한 기본적인 내용만을 다루었기에,  이 글은 가볍게 봐주셨으면 좋겠습니다.

각 내용에 대한 좀 더 자세한 글은 책을 공부하며 추후에 쓸 예정입니다. ^-^

'채워가는 지식 > 네트워크' 카테고리의 다른 글

HTTP 메시지  (0) 2023.12.18
URL  (1) 2023.12.18
네트워크  (0) 2023.09.11
OSI 7계층 모델, TCP/IP 4계층 모델  (0) 2023.06.22
VPC  (0) 2023.03.31

멀티 모듈

Java에서 모듈이란 패키지의 한 단계 위의 집합체이며, 독립적으로 배포될 수 있는 코드의 단위를 이야기 합니다.

멀티 모듈 프로젝트는 상호 연결된 여러개의 모듈로 구성된 프로젝트를 의미합니다.

그렇기에 멀티 모듈 프로젝트의 각 모듈은 전체 서비스의 구성요소로서 동작합니다.

 

각 모듈은 독립적으로 빌드할 수 있는 것이 특징입니다.

즉, 한 프로젝트에서 특정 모듈은 자바 스프링 스택을 사용할 때, 다른 모듈은 코틀린 스프링 스택을 사용할 수도 있습니다.

또는 스프링 부트 버전을 모듈마다 다르게 사용할 수 있습니다.

우아한 기술 블로그의 멀티 모듈 구성하기

우아한 기술 블로그에 의하면

모듈 자체에 대한 특징에서는 공통적으로 어떠한 특징이 있습니다.

  • 모듈은 독립적인 의미가 갖습니다.
  • 모듈은 어떠한 추상화 정도에 대한 계층을 가지고 있습니다.
  • 계층 간 의존 관계에 대한 규칙이 있습니다.

이러한 특징들을 우리가 설계해야할 시스템에 적용한다면 아래와 같은 시스템에서 가져야할 계층 구조가 정의됩니다.

 

  • 독립 모듈 계층
  • 도메인 모듈 계층
  • 내부 모듈 계층
  • 공통 모듈 계층
  • 어플리케이션 모듈 계층

이러한 정의된 계층 구조를 갖음으로써 모듈이 어디까지 책임과 역할을 가질 수 있는지를 명확히할 수 있고, 의존 관계 또한 최소화하여 최적화된 프로젝트를 만들어낼 수 있습니다.

1. 독립 모듈 계층(independently available)

시스템과 무관하게 어디에서나 사용 가능한 라이브러리 성격의 모듈이 있는 계층입니다.

언제든 대처할 탄탄한 라이브러리가 나온다면 이 모듈은 제거 될 것이므로, 나머지 모듈 계층과 의존 관계가 없어야합니다.

 

예를 들어 시스템, 도메인의 비지니스와 전혀 별개로 자체 제작한 라이브러리 모듈이 있습니다.

2. 공통 모듈 계층(system core)

모든 모듈에서 사용될 수 있는 모듈이 있는 계층입니다.

시스템 내 모든 모듈들이 의존할 수 있을만큼 얇은 의존성을 제공해야 하기 때문에 프로젝트 내 어떠한 모듈도 의존하지 않아야 합니다.

가능하다면 사용하지 않는 것이 좋습니다.

 

예를 들어 시스템에서 정말 많이 쓰이는 Type 성격의 DTO나 기본적인 Util Class가 있습니다.

3. 도메인 모듈 계층(system domain)

시스템의 중심 도메인을 다루는 모듈이 있는 계층입니다.

내부 모듈 계층과 비슷한 성격의 계층이지만 저장소와 밀접한 중심 도메인을 다루는 계층은 더 견고하고 특별하게 격리되고 관리되어야 하기에 분리되어야 합니다.

 

이 계층은 다음과 같은 원칙이 있습니다.

  • 서비스 비지니스를 모른다.
  • 하나의 모듈은 최대 하나의 인프라스트럭처에 대한 책임만 갖는다.
  • 도메인 모듈을 조합한 더 큰 단위의 도메인 모듈이 있을 수 있다.

프로젝트 안의 어떠한 실행 가능한 어플리케이션에서도 사용 가능한 모듈이 위치해야 합니다.

그러기 위해서는 저장소 외 시스템 특성을 알지 않아야 하기 때문에 내부 모듈 계층을 의존하지 않습니다.

 

4. 내부 모듈 계층(in system available)

저장소, 도메인 외 시스템에서 필요한 모듈들이 있는 계층입니다.

시스템 전체적인 기능을 서포트하기 위한 기능 모듈이 만들어질 수 있습니다.

 

이 계층은 다음과 같은 원칙이 있습니다.

  • 어플리케이션, 도메인 비지니스를 모른다.

이 계층 역시 프로젝트 안의 어떠한 실행 가능한 어플리케이션에서도 사용 가능한 모듈이 위치해야 하므로, 도메인 계층을 의존하지 않습니다.

5. 어플리케이션 모듈 계층(application)

독립적으로 실행 가능한 어플리케이션 모듈 계층입니다.

하위 모듈들을 조립하여 서비스 비지니스를 완성시킵니다.

모든 계층을 사용성에 따라 의존성을 추가하여 사용하게 됩니다.

모듈 계층의 의존 관계 흐름

 

 

다른 글의 프로젝트 모듈 구조

1. 컨트롤러단을 위한 모듈 - Presentation Layer

2. 서비스(비즈니스 도메인)을 위한 모듈 - Business Layer

3. 레포지토리(영속성 계층)을 위한 모듈 - Persistence Layer

4. 외부 코드와 통신하기 위한 코드 모듈

 

멀티 모듈의 장점

1. 모듈화와 재사용성 강화

멀티 모듈의 기능들은 독립적이며 각자 필요한 최소 의존성을 가지고 있기 때문에 재사용에 용이합니다.

2. 팀 간 협업 및 병렬 개발

여러 개발 팀이 동시에 작업할 수 있도록 지원하고 각 팀은 프로젝트의 특정 모듈에 집중하여 병렬로 개발함으로써 개발 생산성을 향상시키고 프로젝트 일정을 단축시킬 수 있습니다.

3. 빌드 및 배포의 용이성

각 모듈은 독립적으로 빌드가능합니다.

그렇기에 특정 모듈만 업데이트하고 다시 빌드하면 전체 시스템을 갱신이 됩니다.

이는, 빠른 개발 주기와 유연한 배포가 가능케 합니다.

4. 테스트 용이성

각 모듈은 독립적으로 테스트 가능합니다.

이는, 버그를 더 쉽게 식별하고 수정 가능케 합니다.

5. 확장성

새로운 기능을 추가한다면 하나의 모듈을 추가하기만 하면 되기 때문에 쉽게 구조 변경이 가능합니다.

마치며...

아직 글로만 보는 것으로 다 이해하지 못했지만, 어느정도 길잡이 역할을 해줄 수 있는 글들을 읽어보니 프로젝트마다 나눌 수 있는 모듈들이 다를 것이라는 생각이 들었습니다.

실제로 도메인 별로 나누는 경우도 있다고합니다.

즉, 가로 계층이 아닌 세로 계층인 것이지요.

제 글은 최소한 정보만 넣었기에 참고용으로 봐주시면 좋겠습니다.

참고블로그

https://techblog.woowahan.com/2637/

 

멀티모듈 설계 이야기 with Spring, Gradle | 우아한형제들 기술블로그

{{item.name}} 멀티 모듈 설계 이야기 안녕하세요. 배달의민족 프론트 서버를 개발하고 있는 권용근입니다. 멀티 모듈의 개념을 처음알게 되었을 때부터 현재까지 겪었던 문제점들과 그것을 어떻게

techblog.woowahan.com

https://velog.io/@jonghyun3668/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%EB%8B%A8%EC%9D%BC-%EB%AA%A8%EB%93%88-%EC%BD%94%EB%93%9C%EC%97%90-%EB%A9%80%ED%8B%B0-%EB%AA%A8%EB%93%88%EC%9D%84-%EC%A0%81%EC%9A%A9%ED%95%98%EC%97%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EC%A1%B0-%EA%B0%9C%EC%84%A0%ED%95%98%EA%B8%B0

 

스프링 부트 단일 모듈 코드에 멀티 모듈을 적용하여 프로젝트 구조 개선하기

기존 단일 모듈 코드를 멀티 모듈로 적용해보고 뜯어고쳐봅시다!

velog.io

 

'채워가는 지식 > Java' 카테고리의 다른 글

Arrays.asList()와 List.of() 차이  (0) 2024.02.20
객체 지향 설계 - 프로그래밍 관점  (0) 2023.11.30
객체 지향 설계 - 이론  (0) 2023.11.30
Java에 대해..  (0) 2023.09.27

브랜치(branch)

브랜치는 개발자들이 개발하는 공간입니다.

이 브랜치를 별도로 생성하지 않고 메인 브랜치에서만 작업을 하게 되면 어떤 일이 생길까요?

혼자 개발을 한다면 큰 문제는 생기지 않을 겁니다.

하지만 개발자라는 직업은 혼자 개발하는 것은 거의 없다고 생각하고, 협업을 통해 개발을 하기 때문에 문제가 생길 것입니다.

 

오직, 메인 브랜치에서만 협업을 하게 된다면 자신이 작업 중인 파일을 누군가 건드릴 수 있게 되고, 여러 기능을 개발하면서 남긴 커밋이 뒤죽박죽 섞이게 될 것입니다.

뒤죽박죽 섞인 커밋들은 개발 중인 기능이 필요가 없어지거나, 문제가 발생한다면 원하는 시점으로 롤백하기 어렵게 만듭니다.

 

브랜치 기능을 사용하면 다른 브랜치에 영향을 받지 않는 독립적인 환경에서 기능을 개발하거나, 버그를 수정할 수 있습니다.

쉽게 말하자면, 프로젝트 폴더를 복사해서 복사한 폴더에서 따로 작업을 하는 것입니다.

그럼으로써, 여러 기능을 여러 사람이 병렬적으로 개발할 수 있게 됩니다.

 

또 다른 이점으로는 기능을 개발할 때 브랜치를 생성하고 코드를 작성하여 커밋을 남기고 이 후 기능 개발이 완료된 경우에 메인 브랜치에 머지를 하면 안전하게 기능을 개발할 수 있습니다.

또한, 기능이 필요 없게 되면 간단하게 해당 브랜치를 삭제하면 끝입니다.

그리고, 실험적인 것들을 맘편하게 시도해볼 수 있고, 잘안되면 삭제하면 그만입니다.

Git 브랜치 전략

Git 브랜치 전략에서 대표적인 Git Flow, Github Flow를 살펴보겠습니다.

1. Git Flow

 

Git Flow는 크게 Main, Develop, Supporting 브랜치로 관리합니다.

이 때, Supporting는 또 다시 Feature, Release, Hotfix 브랜치로 나뉩니다.

Main 브랜치

출시 가능한 프로덕션 코드를 모아두는 브랜치입니다.

Main 브랜치는 프로젝트 생성 시 생기며 쭉 사용하게 됩니다.

배포된 각 버전을 Tag를 이용해 표시하기도 합니다.

Develop 브랜치

다음 버전 개발을 위한 코드를 모아두는 브랜치입니다.

개발이 완료되면 Main 브랜치로 머지합니다.

Feature 브랜치

하나의 기능을 개발하기 위한 브랜치입니다.

Develop 브랜치에서 생성하며, 기능 개발이 완료되면 Develop 브랜치로 머지합니다.

주의할 점은 Develop 브랜치로 머지하기 전에 upstream 저장소를 풀하는 것입니다.

 

네이밍은 feature/기능 관련 브랜치 이름과 같은 형태로 생성합니다.

Release 브랜치

소프트웨어 배포를 준비하기 위한 브랜치입니다.

버전 이름 등의 소소한 데이터를 수정하거나 배포전 사소한 버그를 수정하기 위해 사용됩니다.

Develop 브랜치에서 생성하며,  배포 준비가 완료되면 Main과 Develop 브랜치에 머지합니다.

 

네이밍은 release/v1.1과 같은 형태로 생성합니다.

Hotfix 브랜치

이미 배포된 버전에 문제가 발생했다면, 그 문제를 해결하기 위한 브랜치입니다.

Main 브랜치에서 생성하며, 문제 해결이 완료되면 Main과 Develop 브랜치에 머지합니다.

 

네이밍은 hotfix/bug-fix과 같은 형태로 생성합니다.

2. Github Flow

 

Github Flow는 크게 Main, Feature 브랜치로 나뉩니다.

Main 브랜치

항상 Stable 상태여야 합니다.

즉, Main의 모든 커밋은 언제 배포하든 문제가 없어야하고, 언제든 브랜치를 새로 만들어도 문제가 없어야 하는 것입니다.

그러므로, Main 브랜치의 모든 커밋은 빌드가 되고 테스트를 통과해야 합니다.

이것이 Github Flow가 강제하는 유일한 사항입니다.

Feature 브랜치

하나의 기능을 개발하기 위한 브랜치입니다.

Feature 브랜치이지만 목적에 따라 버그 수정을 위한 브랜치로 사용하기도 합니다.

Main 브랜치에서 생성하며, 개발이 완료 되었다면 Main 브랜치에 머지합니다.

 

네이밍은 목적에 따라 Git Flow 브랜치 네이밍과 동일하게 사용하면 됩니다.

어느 상황에서 어떤 브랜치 전략을 사용해야 할까?

뤼튼에 의하면...

Git Flow

  • 대규모 프로젝트 또는 긴 배포 주기를 가진 프로젝트 경우
  • 안정적인 프로덕션 배포와 개발 기능의 분리가 필요한 경우
  • 기능 개발과 버그 수정을 명확하게 구분하여 관리하고자 할 경우
  • 보안 및 긴급한 버그 수정에 대한 빠른 대응이 필요한 경우

GitHub Flow

  • 작은 규모의 프로젝트나 빠른 배포 주기를 가진 프로젝트 경우
  • 간단하고 직관적인 브랜치 전략을 선호하는 경우
  • 실시간 협업과 지속적인 통합이 중요한 경우
  • 개발자들이 자유롭게 작업할 수 있는 환경을 원할 경우

프로젝트 규모, 배포 주기, 팀의 작업 스타일, 협업 요구사항 등을 고려해서 적합한 전략을 선택해야 합니다.

마치며...

둘 다 사용해보고 각각의 장단점을 느껴봐야 이 프로젝트가 어떤 브랜치 전략이 적합할지 감이 올 것 같습니다.

개인적인 생각으로는 CI가 제대로 되어있고 적합한 머지 규칙을 정한다면 Github Flow가 더 선호되지 않을까 싶습니다.

알고리즘

어떤 문제나 목적을 달성하기 위해 거쳐야 하는 여러 과정들을 의미합니다.

이 과정들은 다양하고, 상황에 따라 알고리즘은 모두 다릅니다.

따라서 상황에 맞게 성능이 좋은 알고리즘을 선택하여 사용해야 합니다.

알고리즘 성능

일반적으로 알고리즘의 성능에는 알고리즘 실행 동안 사용되는 메모리와 관련된 공간 복잡도,

알고리즘 실행 시간과 관련된 시간 복잡도가 있습니다.

하지만 메모리의 발전으로 인해 시간 복잡도에 비해 공간 복잡도의 중요성이 상대적으로 낮아졌습니다.

 

시간 복잡도

시간 복잡도는 입력 데이터 크기에 대한 실행 시간의 증가율을 나타낸 것입니다.

알고리즘 실행시간에 중요하지 않은 상수와 항을 제외하고 가장 차수가 높은 항을 고려한 점근적 표기법을 사용합니다.

 

점근적 표기법



위 예시를 보시면 알고리즘 실행 시간이 2n^2+3n+1이라면 가장 높은 차수 항인 2n^2을 고려하는 것입니다.

이 점근적 표기법에는 최선, 평균, 최악을 고려하는 표기법들이 있습니다.

 

  • 최선의 경우: Big-Ω 표기법이라 하며 알고리즘이 가장 적게 걸린 시간을 나타냅니다.
  • 평균의 경우: Big-θ 표기법이라 하며 알고리즘이 평균적으로 걸린 시간을 나타냅니다.
  • 최악의 경우: Big-O 표기법이라 하며 알고리즘이 가장 오래 걸린 시간을 나타냅니다.

시간 복잡도는 그 중 최악을 고려하는 Big-O 표기법를 자주 사용합니다.

 

Big-O 표기법

왜 최악을 고려한 Big-O 표기법을 자주 사용할까요?

Big-O가 다른 표기법에 비해 다음과 같은 이점이 있기 때문입니다.

 

  • 최악의 경우를 알면 여러 알고리즘 중 어디가 문제인지 예측하기 쉽습니다.
  • 알고리즘의 성능이 항상 이 값 이하임을 보장할 수 있습니다.
  • 최악의 경우에 대한 시간 복잡도를 비교함으로써 다양한 알고리즘을 쉽게 비교할 수 있습니다.

 



위 그림은 입력 데이터 크기에 대한 실행시간을 나타낸 그래프입니다.


그래프에 나와있는 Big-O는 O(1), O(log n), O(n), O(n log n), O(n^2), O(2^n), O(n!) 가 있습니다.
물론, 그래프에 나와있는 것 이외에도 다양한 Big-O가 있을 수 있습니다.

그래프를 보시면 O(1)O(log n)excellentgood, O(n)fair, O(n log n)bad, 나머지horrible에 있습니다.

이 그래프에서 확인할 수 있는 것은 시간 복잡도가 높을수록 입력 데이터 크기에 대한 실행시간이 엄청나게 늘어난다는 것입니다.
즉, 저희는 처리하는 데이터가 많다고 할 때, horrible한 알고리즘이 있다면 이쪽을 조금만 더 개선해도 성능면에서 큰 효과가 기대할 수 있게 됩니다.

간단하게 O(1), O(log n), O(n) 이 3가지만 살펴보겠습니다.

 

O(1)

입력 데이터의 크기에 상관없이 언제나 일정한 시간이 걸리는 알고리즘입니다.

public boolean constantTime(int[] n) {
    return n[0] == 0;


위 코드를 보시면 입력인 int 배열의 크기에 상관없이 배열의 첫번째 값이 0인지 확인하고 끝나기 때문에 O(1)입니다.

 

O(log n)

한번 돌 때마다 입력 데이터 크기가 절반이 되는 알고리즘입니다.


대표적으로 이진 탐색이 있습니다.

public int binarySearch(int key, int[] arr, int start, int end) {
    if (start > end) {
        retrun -1
    }
    int mid = (start + end) / 2;
    if (arr[mid] == key) {
        return mid;
    } else if (arr[mid] > key) {
        return binarySearch(key, arr, start, mid-1);
    } else {
        return binarySearch(key, arr, mid-1, end);
    }
}


위 예제 코드는 재귀로 구현한 이진 탐색입니다.

재귀를 한번 할때마다 mid라는 변수를 이용해 입력인 int 배열을 절반씩 줄이기 때문에 O(logn)입니다.


코드만 봐서는 이해하기 힘드실 수 도 있을거 같아서 이진 탐색과 순차 탐색을 비교할겸 gif 하나를 가져왔습니다.

 


두 알고리즘 모두 숫자 37을 찾는 알고리즘이고 위에가 이진 탐색, 밑에가 순차 탐색입니다.

이진 탐색이 순차 탐색보다 steps가 많이 적음을 확인할 수 있습니다.

 

O(n)

입력데이터의 크기에 비례하여 처리시간이 늘어나는 알고리즘입니다.

public void linearTime(int[] n) {
    for (int i = 0; i < n.length; i++) {
        System.out.println(i);
    }
}


위 코드는 일반적인 for문인데요, 입력 데이터의 크기만큼 출력해주기 때문에 O(n)입니다.

아까 보신 순차 탐색이 이에 해당합니다.

※ 그렇다면 알고리즘 속에 알고리즘이 있다면 Big-O는 어떻게 될까요?
두 Big-O를 곱하시면 됩니다!

public void nestedLoop(int[] n) {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            System.out.println("Kernel360 Let's Go!!");
        }
    }
}



예를 들어 위와 같이 같은 입력 데이터의 크기를 갖는 이중 for문이 있다고 한다면, 시간복잡도는 n과 n을 곱해서 O(n^2)이 되는 것입니다.

 

마무리

시간 복잡도에 대해 알고 알고리즘을 비교할 수 있게 된다면,

 

이 gif 파일처럼 같은 문제를 푸는 것이여도 시간 복잡도가 더 나은 알고리즘을 사용해서 더 나은 성능을 낼 수 있습니다.

 

참고 블로그

https://hanamon.kr/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-time-complexity-%EC%8B%9C%EA%B0%84-%EB%B3%B5%EC%9E%A1%EB%8F%84/

클래스

프로그래밍 관점의 표현

객체를 설계하는 도구, 생성자 메서드를 통해 객체를 Heap 메모리에 생성(모든 클래스는 기본 생성자를 가지고 있음)

자료형 측면: 새로운 자료형을 만드는 도구

객체지향 측면: 현실의 객체를 프로그래밍에서 사용하기 위해 상태와 행위를 추상화하는 도구

 

모델

소프트웨어 공학 관점의 표현, OOP에서 클래스를 역할에 따라 부르는 이름

DTO: Data Transfer Object

VO: Value Object

DAO: Data Access Object

Utility: etc..

DTO, VO의 필요성

데이터를 하나로 묶어야할 경우, 데이터를 하나로 수집하는 역할

DB에서 데이터를 가져와야 하는 경우

DAO의 필요성

DB에 데이터를 저장, 수정, 검색, 삭제하기 위해 만들어지는 모델(비즈니스 로직을 처리)

Utility의 필요성

반복적으로 사용해야 될 동작을 별도의 클래스로 만들어 놓고 필요할 때 사용

잘 설계된 VO 클래스란?

  • 모든 상태정보 은닉
  • 디폴트 생성자 생성
  • 생성자 메서드를 오버로딩하여 객체 초기화
  • setter 메서드
  • getter 메서드
  • toString 메서드

 

접근제어자

public: 모든 접근 가능

private: 멤버 메서드만 접근 가능(생성자를 private로 구현하게 되면 객체 생성을 막을 수 있음)

protected: 상속 관계의 자식만 접근 가능(같은 패키지 내에 부모 자식 클래스가 있어야함)

default: 동일 패키지 내에서만 접근 가능

 

동적 바인딩과 정적 바인딩

동적 바인딩(Dynamic Binding)

다형성을 사용하여 메소드를 호출할 때, 발생하는 현상입니다.

실행 시간(Runtime) 즉, 파일을 실행하는 시점에 변수 데이터 타입, 호출될 함수이 결정됩니다.

실제 참조하는 객체는 서브 클래스이니 서브 클래스의 메서드를 호출합니다.

정적 바인딩(Static Binding)

컴파일(Compile) 시간에 변수 데이터 타입, 호출될 함수이 결정됩니다.

변수의 타입이 슈퍼 클래스이니 슈퍼 클래스의 메서드를 호출합니다.

 

Message Polymorphism(다형성)

상위 클래스가 동일한 메세지로 하위 클래스를 다르게 동작시키는 객체 지향 이론입니다.

즉, 동일한 메세지를 전송해도 실제로 어떤 메서드가 실행될 것인지는 메세지를 수신하는 객체의 타입에 따라 달라지는 것입니다.

상속을 통해 자식 클래스는 자신의 인터페이스(행위 목록)에 부모 클래스의 인터페이스를 포함합니다.

결과적으로 부모 클래스가 수신할 수 있는 모든 메세지를 자식도 수신할 수 있습니다.

외부에서 보면 자식 클래스를 부모 클래스와 동일한 타입으로 간주 할 수 있습니다.

협력 객체가 메세지를 수신할 수만 있다면 해당 객체가 어떤 인스턴스인지는 중요하지 않습니다.

 

다형성을 보장한다는 것은 부모 클래스가 명령하면 자식 클래스가 반드시 동작하여야 한다는 뜻입니다.

즉, 재정의가 필수임을 전제로 합니다.

다형성의 전제 조건

  • 상속관계 형성
  • 메서드 재정의
  • 객체 생성시 UpCasting 활용
  • 동적 바인딩

추상클래스

다형성을 강제하기 위해 일부로 불완전하게 만든 클래스

다형성을 일부 보장하기 위해 도입된 개념

서로 비슷한 클래스의 공통부를 묶을 때 사용

스스로 객체를 생성할 수 없음

구현된 메서드를 가질 수 있음

인터페이스

객체가 이해할 수 있는 메세지의 목록을 정의

100% 다형성을 보장하기 위해 도입

추상 메서드만 멤버로 가질 수 있으며, 인터페이스를 구현하려는 클래스는 모든 추상 메서드를 재정의하도록 강제

자식 클래스의 내부 구현을 전혀 몰라도 동작 시킬 수 있음

스스로 객체를 생성할 수 없음

추상 메서드와 final static 상수만 멤버로 가질 수 있음

구현된 메서드를 가질 수 없음

다중 상속이 가능(java는 기본적으로 단일 상속 지원)

 

일반 클래스 vs 추상화 클래스vs 인터페이스

일반 클래스

재정의를 해도 되고 안해도 되므로 다형성을 보장하지 않습니다.

추상 클래스

재정의를 강제하여 다형성을 보장할 수 있지만, 구현 메서드를 멤버로 가질 수 있어서 하위 클래스가 오동작할 수 있습니다.(추상 메서드는 자식 클래스에서 재정의하지만 구현 메서드는 재정의하지 않기 때문입니다.)

인터페이스

모든 메서드가 추상 메서드이기 때문에 인터페이스를 구현하려는 하위 클래스는 다형성을 100% 보장할 수 있게 됩니다.

인터페이스를 통하면 인터페이스를 기준으로 내부와 외부의 경계가 명확해지므로, 프로그래머에게 구현의 자유를 보장할 수 있습니다.

특히, 객체의 인스턴스를 자신의 인스턴스 변수로 포함하여 사용하는 합성을 사용하여 어떤 인스턴스에 의존할 지 런타임에 스스로 결정하게 함으로써 코드의 유연성을 높힐 수 있습니다.

다만, 코드를 이해하기는 어려워지므로 적절한 균형을 찾는 것이 개발자가 할 일입니다.

 

ex) A클래스(User)는 C클래스를 통해서 B클래스를 동작 -> 이때 C클래스가 인터페이스 역할을 하며 옵저버라 합니다.

느슨한 결합(loose coupling)

두 객체가 느슨하게 결합되어 있다는 것은, 그 둘이 상호작용을 하긴 하지만 서로에 대해서 서로 잘 모른다는 것을 의미합니다.

 

추상 클래스와 인터페이스 공통점과 차이점

공통점

다형성을 보장하기 위해 등장된 개념입니다.

추상 메서드를 가질 수 있습니다.

단독으로 객체를 생성할 수 없습니다.

부모의 역할로 사용합니다.

차이점

서로 비슷한 클래스의 공통 부분을 묶을 때 추상 클래스

    - 추상 메서드와 구현 메서드를 가질 수 있습니다.

서로 다른 클래스의 공통 부분을 묶을 때 인터페이스

    - 추상 메서드와 final static 상수를 가질 수 있습니다.

 

기본 자료형

정수형에서 자주 쓰이는 것은 int,

실수형에서 자주 쓰이는 것은 double 입니다.

 

Wrapper 클래스

프로그램에 따라 기본 타입의 데이터를 객체로 취급해야 하는 경우가 있습니다.

예를 들어, 메소드의 인수로 객체 타입만이 요구되면, 기본 타입의 데이터를 그대로 사용할 수는 없습니다.

이때에는 기본 타입의 데이터를 먼저 객체로 변환한 후 작업을 수행해야 합니다.

그럴 때 사용하는 것이 Wrapper 클래스 입니다.

 

제너릭

제너릭은 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주는 기능입니다.
다시 말해 특정 타입을 미리 지정하는 것이 아니라 필요에 따라 타입을 지정할 수 있도록 하는 일반 타입이라는 것입니다.

제너릭 장점

유연성 상승

재사용성 상승

타입의 안정성 보장

 

람다식

람다 함수는 프로그래밍 언어에서 사용되는 개념으로 익명 함수의 한 종류 입니다.

 

예시 함수

public String hello() {
    return "Hello World!";
}

 

예시 함수의 람다식

() -> "Hello World!";

람다식 장점

코드 간결화

가독성 증가

생산성 증가

병렬 프로그래밍에 용이

람다식 단점

재사용 불가

디버깅 난이도 상승

남발 시 코드 난잡화

재귀에 부적합

'채워가는 지식 > Java' 카테고리의 다른 글

Arrays.asList()와 List.of() 차이  (0) 2024.02.20
멀티 모듈  (1) 2023.12.05
객체 지향 설계 - 이론  (0) 2023.11.30
Java에 대해..  (0) 2023.09.27

+ Recent posts