본문 바로가기

CS 잡지식

@Tailable(feat.SSE Protocol...)

@Data
@Document(collection = "chat") // 채팅이 오고 갈때마다, 이 [컬렉션]에 데이터들을 밀어 넣을 거다.
public class Chat {

    @Id
    private String id;
    private String msg;
    private String sender; // 송신자
    private String receiver; // 수신자

    private LocalDateTime createdAt;

}

MongoDB에 "chat"이라는 [컬렉션]이 있다고 하자!

db.chat.insert({sender:'ssar',receiver:'cos',msg:'안녕'}); // 송신자 : ssar, 수신자 : cos

db.chat.insert({sender:'cos',receiver:'ssar',msg:'응 반가워'}); // 송신자 : cos , 수신자 : ssar(ssar에 대한 cos의 답장)

라는 JSON Object를 삽입을 했다고 하자. 

db.chat.find({sender:'cos',receiver:'ssar'}).pretty(); // char 컬렉션 중, sender가 cos이고, 수신자가 ssar인 JSON Object임.
[
  {
    _id: ObjectId("6498a0d6e264048efbafafc3"),
    sender: 'cos',
    receiver: 'ssar',
    msg: '응 반가워'
  }
]

public interface ChatRepository extends ReactiveMongoRepository<Chat,String> {


    @Tailable // 커서를 안 닫고 계속 유지하게 한다.(티스토리 참조)
    @Query("{sender:?0, receiver:?1}") // db.chat.find({sender:'cos',receiver:'ssar'})와 같은 형태의 MongoDB의 SELECT 기능이다.
    Flux<Chat> mFindBySender(String sender,String receiver); // Flux(흐름) : 연결을 유지하면서 데이터를 계속 흘려 보낼 수가 있다.
}

 

위 코드에서 @Tailable이 하는 역할을 생각해야 한다. 

클라이언트 ssar이 만약 mFindBySender(sender,receiver)로 요청을 보내게 되면, 

몽고DB에서 해당 JSON Object를 찾아서 반환한 뒤, [DB]를 닫는 것이 아니라, [DB]를 열어둔 상태에서

char Collection에 (String sender, String receiver) 관련된 Json Object가 insert될 때마다 Flux(흐름)에 의해서

계속해서 자동적으로 ssar에 mFindBySender(sender,receiver)의 결과가 지속적으로 ssar에 전달이 된다. 

그러나 기존의 HTTP Protocol에 의해서는 위 기능을 구현하는 데에는 한계가 있다. 

HTTP Protocol은 하나의 요청이 들어오고, 그에 대한 응답이 보내지면 connection을 닫아 버린다. 

만약 sender:ssar, receiver:cos와 관련된 JSON Object가 100개 였다면, 100번의 TCP/IP 연결 비용이 들며

엄청나게 느리게 된다. 

@Tailable 기능을 스무즈하게 구현하기 위해서는 SSE Protocol을 사용해야 한다. 

SSE Protocol

ssar 클라이언트가 요청을 하고, 그에 대한 응답을 받고 나면

요청 connection은 끊고, 응답에 대한 connection은 그대로 유지를 하여, (sender : ssar, receiver : cos)와 관련된

JSON Object가 DB에 INSERT될 때마다 응답 Channel을 통해서 계속해서 흘려(Flux) 보내준다.