YoungSoo

[WebSocket] 명령과 조회를 분리하는 CQRS로 개발하기 - 4 본문

프로젝트

[WebSocket] 명령과 조회를 분리하는 CQRS로 개발하기 - 4

YoungSooSoo 2023. 7. 29. 22:49

지난 게시물에서는 WebSocket과 Stomp를 사용해서 pub/sub 방식으로 채팅 서비스를 개발했습니다.

이번 시간에는 이전 채팅 조회와 많은 고민이 있었던 읽음 처리에 대한 글을 작성하려고 합니다.

이전 채팅 조회

이전 채팅을 조회하는 기능에서 요구되는 사항은 아래와 같았습니다.

1. 채팅방

2. 안 읽은 채팅의 개수

3. 마지막 채팅 내용

 

저는 SQLD 자격증을 보유하고 있어서 세 개를 조회하는 쿼리를 작성하는 것은 어렵다고 생각하진 않았습니다.

하지만 조인과 서브쿼리를 사용해 요구하는 데이터를 조회하게 되었는데, 이 과정에서 N+1 문제와 고민이 생기게 되었습니다. N+1 문제는 하위 엔티티를 조회할 때 상위 엔티티가 같이 조회되는 상황을 말합니다.

이것을 해결하는 방법으로는 지연로딩, 패치 조인 등의 방법이 있는 것으로 알고 있습니다. 저는 이후에 조회를 변경할 목적을 가지고 있어 당장은 개발 단계이기 때문에 어떤 해결 방법이 있는지만 알고 넘어가려고 합니다.

 

또한 이렇게 조인과 서브쿼리를 통해 기능을 개발했는데, 이것을 여러 개의 작은 쿼리로 나누어 요청하게 되면 어떤 것이 장점일까가 고민이었습니다. 작은 쿼리로 나누게 된다면 여러 번 트랜잭션이 발생하는 만큼 비용이 더 발생하게 됩니다. 하지만 그만큼 더 빨라질 것으로 예상이 됩니다.

 

이후에 CQRS를 적용할 예정이기 때문에 조회를 전부 변경해줄 것이지만 이 상황뿐만 아니라 언젠가 꼭 고민해야 할 문제인 거 같았습니다. 상황에 따라 데이터베이스 성능과 응답 시간을 모니터링하고, 비용과 성능 사이의 트레이드오프를 평가하여 최적의 방법을 찾아야 할 거 같습니다. 더 좋은 방법이 있으면 댓글로 알려주시면 정말 감사하겠습니다!

 

채팅 읽음 처리

처음에 채팅 읽음 처리라고 생각했을 때는 쉽게 구현할 것이라는 생각이 들었습니다. 하지만 막상 구현을 하는 도중에 많이 막혔습니다. 채팅 읽음 처리에 대한 기능은 아래와 같았습니다.1. 처음 채팅방을 들어왔을 때2. 상대방이 웹 소켓을 연결하고 채팅방을 확인하고 있을 때위와 같이 두 개의 조건을 만족했을 때 읽음 처리가 되어야 한다고 생각했습니다.

 

(1:1 채팅방)

이를 구현하기 위해 먼저 데이터베이스에 chatMessageRead라는 Column을 만들어 해당 메시지를 조회했는 지를 체크하는 방식을 생각해 데이터 베이스를 모델링 했습니다. 읽음 처리가 되는 과정을 설명하겠습니다.

1. 사용자가 메시지를 전송하고 데이터베이스에 저장합니다.

2. 웹 소켓에 연결과 화면을 보고 있고, 메시지를 받은 구독자와 메시지를 보낸 사람이 다르다면 읽음 요청을 백엔드 서버로 전송했습니다.(Front-End: focus와 blur 그리고 window의 beforeunload 이벤트 사용)

3. 백엔드에서 읽음 처리를 하는 로직을 사용한 후 응답을 하면 프런트에서 반영하는 식으로 했습니다.

 

이와 같은 방법을 통해 읽음 처리를 해주었습니다.

 

메모리 릭 발생

메모리 릭로그램이 더 이상 필요하지 않은 메모리를 해제하지 않고 계속 보유하게 되는 상태를 말합니다. 자바에서는 GC(Garbage Collector)가 사용하지 않는 메모리를 자동으로 수거하긴 하지만 모든 메모리 누수를 감지하고 해결하는 것은 보장되지 않습니다.

 

웹 소켓을 사용하며 쓰레드 관리를 해주지 않아 메모리 릭이 발생한 것으로 보이는 문제가 발생했습니다.ㅜㅜ

다음 글은...

다음 게시물에 이를 해결하고 알림 서비스를 개발하는 게시물을 작성해 볼까 합니다!

긴 글을 읽어주셔서 감사하고 지적도 해주시면 감사하겠습니다!