웹 소켓???

Mini_me·2023년 7월 22일
0

공부 [Spring]

목록 보기
24/27
post-thumbnail

본 글은 CRAFT 로 먼저 작성 한 후, VELOG에 옮긴 글이기때문에 가독성이 안좋을 수 있습니다.

가독성이 좋은 , 정리된 원본 글을 보고싶은 분들은 아래 링크를 클릭하세요.

완성된 정리본 : https://www.craft.me/s/DtXX6CV4kjYesk

🤔 왜 웹소켓을 사용하게되었나요??

웹소켓은 클라이언트와 서버 간의 실시간 양방향 통신이 가능한 기술이며, 이 때문에 인스타그램과 같은 플랫폼의 DM 기능이나 채팅 기능을 구현하는데 적합합니다.

기본적으로 HTTP 통신에서 클라이언트는 서버에 요청하고 서버가 그에 대한 응답을 제공합니다.

하지만 실시간 채팅 기능이 필요한 경우, 서버가 클라이언트의 요청 없이도 데이터를 전달할 수 있어야 합니다. 즉 모든 사용자가 "양방향" 통신을 해야한다.

이러한 패러다임의 변화를 위해 웹 소켓이 사용됩니다.

image.png

사람 1 채팅 화면 : "HI"

사람 2 채팅 화면 : (사람1에게 받은 메세지) HI

사람2 채팅 화면 : "Oh hi"

사람1 채팅화면 : (사람2 에게 받은 메세지) Oh hi

위 그림처럼 웹 소켓을 TCP 연결을 통해서, 양방향 통신 채널을 제공하는 기술이며, 간단한 채팅 서비스는 웹 소켓으로 어렵지 않게 만들 수 있습니다.

아! 웹 소켓은 HTTP 통신과는 다르다는 건 알겠어

근데 구체적으로 어떻게 작동하는걸까?

Image.png

💡 웹소켓 동작 원리

  1. 웹소켓은 클라이언트와 서버 간의 통신이기 때문에, 먼저 클라이언트와 서버가 핸드쉐이크 과정을 거쳐 웹소켓 연결을 생성합니다.
  2. 이후 서버와 클라이언트는 웹소켓 연결을 통해 실시간 데이터 전달(패러다임 전환)이 가능해집니다.

웹소켓 연결이 끊어졌을 때 재연결을 처리하는 방법은 어떻게 될까요?

웹소켓 연결이 끊어진 경우, 여러 가지 방법을 사용하여 재연결할 수 있습니다. 일반적으로는 자동 재연결, 연결 재시도 제한, 백오프(Backoff) 기법, 지수적 재연결 딜레이, 사용자 확인 및 재연결 유예 등을 사용합니다. 이를 통해 연결이 끊어진 경우 일정 주기로 연결을 재시도하거나, 일정 횟수 이상 재시도 실패 시 연결시도를 중단하거나 다른 조치를 취할 수 있습니다.

Image.png

🔗 웹소켓과 HTTP 통신 차이점

  • HTTP: 단방향 통신만 가능 (서버 -> 클라이언트의 요청 불가능)
  • 웹소켓: 클라이언트와 서버간의 접속 유지, 양방향 데이터 주고받기 가능

🔎 웹소켓과 STOMP

웹소켓은 실시간 양방향 통신에 적합한 프로토콜이지만, 메시지의 내용과 포맷에 대해서는 정의하지 않습니다. 이때 STOMP 프로토콜이 웹소켓 위에서 동작하며, 클라이언트와 서버가 전송할 메시지의 유형, 형식, 내용을 정의하는 매커니즘이 필요합니다.

이때 STOMP 프로토콜이 필요한 역할을 합니다. 웹소켓과 STOMP를 함께 사용하면 효율적인 메시지 전송이 가능하고 규격을 갖춘 메시지를 보낼 수 있습니다.

📨 STOMP

Stomp는 클라이언트와 브로커 간의 텍스트 기반 메시지 프로토콜이다.

이프로토콜은 다양한 메세지 브로커에 적용하여 신뢰성 잇는 연결을 제공하며, 구성 요소간 통신을 처리하고 메세지를 전송하는데 사용된다.

이를 통해 클라이언트가 서버에서 주고받는 메세지를 관리할수 있으며,

이경우 pub/sub과 함께 사용되어 메세지를 발신자와 수신자 사이에 전달할수 있다.

STOMP의 기본 동작 원리

STOMP에서 클라이언트는 서버에 STOMP 명령을 보내고, 서버는 명령에 따른 응답을 제공한다.

STOMP는 메시지 발행-구독(Pub/Sub)과 지점간(Point-to-Point) 메시징 패턴을 모두 지원한다.

stomp의 메세지 전송 방식과 패턴에 대해

(Pub/Sub) 패턴에서,

발행자는 특정 주제(topic)를 지정하고,

해당 주제에 관심 있는 구독자(subscriber)는 해당 주제에 대한 구독 요청을 보냄으로써 발생한 메시지를 수신한다.

(Point-to-Point) 패턴에서는,

메시지를 전송하는 발신자(sender)와 메시지를 수신하는 수신자(receiver) 사이에서 직접 메시지가 전송된다.

📨 Pub/Sub에 대한 설명

Pub/Sub 구조에서 발행자(Publisher)는 메시지를 특정 주제(Topic)에 전송하고,

구독자(Subscriber)는 해당 주제를 구독하고 메시지를 수신합니다.

구독자는 여러 명이 될 수 있습니다.

채팅방과 비교하면,

주제(Topic) 생성은 채팅방 생성이고 주제 구독은 채팅방 입장입니다.

주제로 메시지를 발행 및 구독하는 과정이 채팅방에서 메시지 송수신입니다.

🌐 Pub/Sub 구조와 채팅 기능 구현 예시

Pub/Sub 구조를 사용하여 채팅 기능을 구현할 경우 다음 과정을 따릅니다.

image.png

  1. 두명 이상의 사용자가 웹 소켓으로 서버에 연결합니다.
  2. 사용자들은 서버의 메시지 브로커나 웹소켓 서버를 구독하고 채팅방(예: 22번 방)에 들어가 서로 메시지를 주고받습니다.
  3. 서버는 발행된 메시지를 확인하고 동일한 채팅방을 구독한 모든 사용자에게 메시지를 전달합니다.

채팅의 경우에는 사용자가 메세지 발행 및 구독이 가능합니다.

image.png

🔄 외부 메시지 브로커가 필요한 이유

예를 들어, 웹 사이트에 수십만 명 이상의 사용자가 있는 경우 한 대의 서버나 웹 소켓 인스턴스로는 처리와 관리가 어려울 수 있습니다.

대규모 서비스에서는 보통 여러 대의 서버를 사용해 웹 소켓 접속을 처리하고 사용자와의 통신을 관리합니다.

이렇게 함으로써 네트워크 연결과 작업 부하를 분산시켜 전체 시스템의 성능과 안정성을 높입니다. 이러한 구조에서 외부 메시지 브로커가 필요합니다.

예를 들어, 사용자 1,2,3 모두 같은 ROOMID를 구독하고 있다.

그런데 사용자 1,2만 서버1에 있고, 사용자3는 서버2에있는 경우, 발행자가 메세지를 보내게 되면 서버1에 구독중인 사용자 1,2만 메세지를 전달받게 된다.

그래서 이런 상황에서 외부 메시지 브로커가 필요하다.

발행자는 ROOMID = 22를 구독중인 구독자에게 메세지를 보내고 싶다

발행자가 사용자1,2가 속한 서버1에 메세지를보냈을 때, 서버1에서는 메세지 브로커의 EXCHANGE에 메세지를 전달한다.

EXCHANGE에 바인딩되어있는 사용자 1,2,3의 큐에 메세지를 전달하게 되어 서버 2에연결되어있는 사용자 3도 메세지를 받을 수 있다.

만약 참여자 중 누군가가 인터넷 연결이 끊어진 시점에도, 외부 메시지 브로커가 큐를 관리하고 있기 때문에 나중에 연결이 복구되면 큐에 저장된 메시지를 확인할 수 있다.

예시처럼, 외부 메시지 브로커는 이러한 구조에서 메시지 전달을 안정적으로 처리하기 위해 사용됩니다.

사용자가 서로 다른 서버에 접속해있어도 외부 메시지 브로커를 사용하면 동일한 채팅방의 사용자에게 메시지가 전달됩니다.

지금 진행하는 프로젝트는 단일서버로만 진행 중인데 왜 외부 메세지 브로커를 쓸까요??

외부메세지 브로커는 스케일 업 했을 때에도 장점이 있지만, 이외에도 다양한 장점들이 존재합니다.

📅 일정 타임스탬프 이후 데이터 복구:

⏰ RabbitMQ는 메시지에 타임스탬프를 부여하여 각 메시지가 생성된 시간을 기록합니다.

이를 활용하여 일정 시간 이후의 메시지는 별도의 백업 저장소에 유지하고 있는 경우에도 데이터를 복구할 수 있습니다.

따라서, 예기치 않은 문제로 인해 메시지가 유실되더라도 해당 시점 이후의 데이터를 복구할 수 있습니다.

🔐 유실 가능성에 대한 대비:

🚀 RabbitMQ는 안정적인 메시지 전달을 위해 다양한 방법을 제공합니다. 메시지 전송 중에 네트워크 장애가 발생하거나, 컨슈머가 일시적으로 다운되는 등의 상황에서도 메시지의 유실을 최소화하기 위해 다음과 같은 방법들을 사용할 수 있습니다:

  1. 메시지 지속성(Durability): RabbitMQ는 지속성 기능을 제공하여 메시지를 디스크에 저장하고 유실 가능성을 줄입니다. 메시지를 지속성을 가지도록 설정하면 RabbitMQ가 재시작하거나 중단된 상황에서도 메시지를 보존할 수 있습니다.
  2. 메시지 복제(Replication): RabbitMQ는 복제 기능을 통해 메시지를 여러 대의 노드에 복사하여 내구성과 가용성을 향상시킵니다. 이는 하나의 노드에 장애가 발생하더라도 다른 복제된 노드에서 메시지를 처리할 수 있도록 보장합니다.
  3. 트랜잭션(Transaction): RabbitMQ는 트랜잭션 지원을 제공하여 메시지 전송 과정에서의 일관성과 안정성을 보장합니다. 메시지 전송을 트랜잭션으로 묶음으로써, 트랜잭션 내의 모든 작업을 성공적으로 완료할 때만 메시지를 전송합니다.

🌟 STOMP와 외부 메시지 브로커의 역할

STOMP 프로토콜은 발행/구독(Pub/Sub) 구조에 기반하며, 메시지 전송을 효율적으로 처리하기 위해 사용됩니다.

외부 메시지 브로커는 여러 개의 서버 인스턴스를 사용하는 구조에서 메시지 전달을 안정적으로 수행하는 역할을 합니다.

두 기술을 함께 사용함으로써 대규모 실시간 채팅 시스템에서 메시지 전달을 신뢰성 있게 처리할 수 있습니다.

🐇 RabbitMQ

✨ RabbitMQ의 핵심 기능

1️⃣ 메시지 전달 패턴 (📢)

RabbitMQ는 PUB-SUB, REQUEST-RESPONSE 등 다양한 메시징 패턴을 지원합니다. 애플리케이션 간에 유연한 메시지 전달을 가능하게 해주죠.

2️⃣ 메시지 라우팅 (📬)

Exchange (🌐) 기능을 통해 메시지 라우팅을 제공합니다.

Exchange는 메시지를 특정 큐로 전달하는 역할을 합니다.

따라서 송신자가 특정 큐로 메시지를 전송하면, 해당 큐에 구독 중인 수신자에게 메시지가 전송됩니다.

3️⃣ 메시지 큐 (📦)

예를 들어, 사용자 A가 채팅 메시지를 입력하면 해당 메시지는 RabbitMQ의 큐에 저장됩니다.

그리고 채팅 방에 참여한 다른 사용자인 B와 C에게 해당 메시지가 전달됩니다.

B와 C는 자신들의 큐에서 메시지를 확인하고 화면에 표시하여 실시간으로 메시지를 주고받을 수 있게 됩니다.

RabbitMQ의 큐는 메시지의 안전한 보관과 처리를 담당합니다.

메시지는 큐에 저장되어 순차적으로 처리되며, 소비자가 처리 가능할 때에만 전달됩니다. 이를 통해 채팅 애플리케이션은 안정적이고 확장 가능한 메시징 시스템으로 구현될 수 있습니다.

4️⃣ 고성능과 확장성 (🚀)

RabbitMQ는 고성능 및 확장성을 갖추고 있어 대규모 시스템에서도 효율적으로 동작할 수 있습니다.

📚 RabbitMQ의 프로토콜

RabbitMQ는 다양한 프로토콜을 지원합니다:

1️⃣ AMQP (Advanced Message Queuing Protocol):

RabbitMQ의 주요 프로토콜입니다. 신뢰성 있고 메시지 지향적인 통신을 위한 표준 프로토콜이죠.

AMQPAdvanced Message Queue Protocol의 약자로 메시지 지향 미들웨어(MOM)를 위한 개방형 표준 응용 계층 프로토콜입니다.

Image.png

AMQP의 구조

AMQP메세지 큐 구조에 Exchange라는 라우터 역할이 존재합니다. ExchangePublisher에게 메시지를 수신 받으면 그것을 Queue에게 분배해주는 역할을 합니다. 한개의 Queue만 있다면 일반적인 메세지 큐와 다를 것 없지만 여러 개의 ConsumerQueue가 존재할 때 높은 효율을 보여줍니다.

2️⃣ MQTT (MQ Telemetry Transport):

경량 프로토콜로, 작은 장치에서 효율적인 메시지 전달에 사용됩니다. RabbitMQ도 MQTT 프로토콜을 지원합니다.

MQTTMessage Queue Telemetry Transport의 약자로 Publish-Subscribe 구조의 메시지 송수신 프로토콜입니다. HTTP 프로토콜에 비해 제한된 통신 환경과 낮은 전력으로 사용할수 있기에 주로 IoT 부야와 메신져 분야에서 사용합니다.

MQTT의 구조

MQTTBroker Publisher Subscriber 구조를 가지고 있습니다. PublisherTopic을 생성하면 Subsucriber는 생성된 Topic을 구독합니다. 이들 사이에는 Broker가 존재해서 두 역할들을 중계해줍니다.

하나의 Topic에는 여러개의 Subscriber가 붙을 수 있기 때문에 1:N 관계의 통신 구축에 사용됩니다.

Image.png

RabbitMQ의 구성 :

교환기 (Exchange), 큐 (Queue), 바인딩 (Binding) 등의 구성 요소로 이루어져 있습니다.

Exchange

큐 (Queue) 📦

바인딩 (Binding) 🔗

  • 채팅 애플리케이션에서 바인딩은 Exchange와 큐를 연결하여 메시지의 라우팅 규칙을 설정하는 역할을 합니다.
  • 예를 들어, "일반 채팅 메시지"와 "중요 알림 메시지"를 구분하여 라우팅하고 싶다고 가정해봅시다. 이 때, Direct Exchange를 사용하여 메시지를 라우팅할 수 있습니다.
  • Exchange와 Queue를 Binding하여 메시지의 라우팅 키에 따라 해당 큐로 전달될 수 있도록 설정합니다.

이와 같이 Direct Exchange를 사용하여 메시지 라우팅을 구현하면, 채팅 애플리케이션에서 일반 채팅 메시지와 중요 알림 메시지를 구분하여 다른 Queue로 전송할 수 있습니다. Direct Exchange는 메시지의 라우팅 키와 Binding 키를 일치시켜 메시지를 전송하는 방식으로 동작하며, 이를 통해 메시지를 원하는 Queue로 정확하게 라우팅할 수 있습니다.

RabbitMQ는 다른 메시지 큐 시스템과 비교하여 안정성, 유연한 라우팅 설정, 다양한 클라이언트 라이브러리, 확장성 등의 강점을 가지고 있습니다

📈 채팅 시스템 구축

image.png

위는 현재 구현한 프로젝트의 채팅 기능 요구사항이다.

현재 구현한 코드를 바탕으로 한 시퀀스 다이어그램이다.

채팅 구현 관련한 포스팅은 시간이 나는대로 이글에다가 업데이트할예정이다.

0개의 댓글