ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SSE 프로토콜을 활용하여 제작한 채팅 애플리케이션
    Projects/Toy Projects 2021. 9. 28. 11:13

    기술 스택

    • IDE
     - Visual Studio Code
     - IntelliJ IDEA
    • Language
     - HTML
     - CSS
     - JavaScript
     - Java
    • Back-end
     - Spring Boot
     - Maven
     - Lombok
    • Database
     - Mongo DB

    프로젝트 목적

    비동기 서버의 특성을 파악한다.

    SSE 프로토콜의 동작 과정을 이해한다.


    프로젝트 기능

    아이디 입력 기능

    채팅방 번호 입력 기능

    채팅 기능


    비동기 서버의 특성

    기존의 서블릿 기반의 스프링(동기 서버)

     

    ㆍ 기존의 서블릿 기반의 스프링은 Tomcat을 기반으로 동작하고, 동기방식을 사용한다. 

    ㆍ 동기 서버의 동작 방식은 위 사진과 같이 사용자의 요청이 있을 때마다 스레드가 생성된다.

    ㆍ 스레드가 많아지면 context switching이 많아지게 된다.

    context switching이 많아지게 되면 서버가 느려진다는 단점이 생긴다.

     

    Spring Boot WebFlux(비동기 서버)

     

    ㆍ Spring Boot WebFlux는 기본적으로 Netty를 기반으로 동작한다.

    ㆍ Tomcat은 요청 당 하나의 스레드가 동작하는 반면, Netty는 1개의 이벤트를 받는 스레드와 다수의 worker 스레드로 동작한다.

    ㆍ 하나의 요청이 끝나고 다음 요청을 받는 동기 서버와는 다르게 비동기 서버는 대기열에 대기 정보를 저장하고 계속해서 요청을 받는다.

    ㆍ 또한 비동기 서버는 context switching이 없기 때문에 서버가 빠르다는 장점이 있다.


    HTTP, WebSocket, SSE

    HTTP

    ㆍ HTTP는 클라이언트와 서버가 한 번 연결을 맺은 후, 클라이언트 요청에 대해 서버가 응답을 마치면 맺었던 연결을 끊어 버리는 성질을 가지고 있다.

    ㆍ HTTP는 클라이언트 쪽에서 요청을 할 때만 서버가 응답을 하는 방식으로 통신이 된다. 따라서 서버 쪽 데이터가 업데이트되더라도 클라이언트 쪽에서 화면을 Refresh 하지 않는 이상 바뀐 데이터가 업데이트되지 않는 문제가 발생한다.

    ㆍ 이러한 문제로 인해 HTTP을 사용해서 채팅 기능을 구현하기에는 적합하지 않다.

     

    WebSocket

    ㆍ WebSocket은 서버와 클라이언트 간에 socket connection을 유지하기 때문에 언제든지 양방향 통신이 가능한 기술이다.

    ㆍ 또한 WebSocket은 stateful protocol이기 때문에 클라이언트와 한 번 연결이 되면 계속 같은 라인을 사용해서 통신을 하기 때문에 HTTP 사용 시 필요 없이 발생되는 HTTP와 TCP 연결 트래픽을 피할 수 있다.

    ㆍ 이러한 성질 때문에 채팅 애플리케이션과 같은 실시간 업데이트가 아주 중요한 소프트웨어에서는 WebSocket이 아주 유용하게 사용된다.

     

    SSE

    ㆍ 양방향으로 통신하는 WebSocket과는 달리 서버에서 클라이언트 쪽으로 데이터를 보내는 단방향 통신을 의미한다.

    ㆍ 서버에서 클라이언트 쪽으로 연결된 라인을 통해 변경된 데이터를 지속적으로 전송할 수 있다.

    ㆍ 스프링에서는 WebFlux를 통해서 간단하게 구현이 가능하며, Flux 키워드를 통해 클라이언트 측으로 계속해서 변경된 데이터를 전송할 수 있다.


    서버 구현

    Chat 객체
    @Data
    @Document(collection = "chat")
    public class Chat {
        @Id
        private String id;
    
        private String msg;   // 입력받은 메시지
    
        private String sender;   // 메시지 전송자
    
        private Integer roomNum;   // 채팅방 번호
    
        private LocalDateTime createdAt;   // 메시지 입력시간
    }

    ㆍ 사용자로부터 입력받은 채팅 메시지와 매핑되는 Chat 객체에 대한 정보이다.

     

    Repository
    public interface ChatRepository extends ReactiveMongoRepository<Chat, String> {
    
        @Tailable
        @Query("{ roomNum : ?0 }")
        Flux<Chat> mFindByRoomNum(Integer roomNum);
    }

    ㆍ @Tailable은 커서를 안 닫고, 계속 유지하겠다는 의미의 애너테이션이다.

    ㆍ Flux는 흐름을 의미한다. 데이터를 한번 받고 끝내는 게 아니라 계속 받겠다는 것이며, 서버에서 클라이언트 측으로 응답을 유지하면서 계속해서 데이터를 흘려보낼 수 있다.

    클라이언트가 Controller를 통해 sender가 홍길동인 데이터를 찾는 쿼리를 실행했을 때, 다른 클라이언트에서 sender가 홍길동인 또 다른 데이터를 DB에 집어넣은 경우 @Tailable을 붙여주었다면 새로 추가된 데이터도 같이 반환된다.

    이처럼 Controller에게 DB의 데이터를 최신화해주는 것이 @Tailable이다. 또한 최신화된 데이터는 Flux로 인해서 Controller에서 클라이언트까지 계속해서 전송된다.

     

    Controller
    @RequiredArgsConstructor
    @RestController
    public class ChatController {
    
        private final ChatRepository chatRepository;
    
        @CrossOrigin
        @GetMapping(value = "/chat/roomNum/{roomNum}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
        public Flux<Chat> findByRoomNum(@PathVariable Integer roomNum) {
            return chatRepository.mFindByRoomNum(roomNum)
                    .subscribeOn(Schedulers.boundedElastic());
        }
    
        @CrossOrigin
        @PostMapping("/chat")
        public Mono<Chat> setMessage(@RequestBody Chat chat) {
            chat.setCreatedAt(LocalDateTime.now());
    
            return chatRepository.save(chat);
        }
    }

    ㆍ findByRoomNum() 메서드는 클라이언트의 채팅방 번호에 해당하는 채팅 목록을 DB에서 반환하는 역할을 한다.

    ㆍ setMessage() 메서드는 사용자로부터 입력받은 메시지를 DB에 저장하는 역할을 한다.


    결과물

    아이디 입력 페이지

     

    ㆍ 프롬프트 창을 통해 채팅방에 입장할 아이디를 입력할 수 있다.

     

    채팅방 번호 입력 페이지

     

    ㆍ 입장할 채팅방의 번호를 입력할 수 있다.

     

    채팅 페이지

     

    ㆍ 아이디와 채팅방 번호를 입력받은 후 채팅에 참여할 수 있다.


     

    GitHub - qlsdud0604/chat-app: 💬 스프링 부트를 이용하여 제작한 채팅 애플리케이션

    💬 스프링 부트를 이용하여 제작한 채팅 애플리케이션. Contribute to qlsdud0604/chat-app development by creating an account on GitHub.

    github.com

     

    728x90

    댓글

Designed by Tistory.