
이전 에는 구독이 끊겼을 경우에 대해서 해결책을 알아봤다
(https://velog.io/@wellbeing-dough/Redis-pubsub%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%B1%84%ED%8C%85-%EB%8B%A4%EC%8B%9C-%EB%8F%8C%EC%95%84%EB%B3%B4%EA%B8%B0)
이번엔 구독이 안끊겼는데, 중간 메시지가 유실되는 case에 대해서 해결책을 알아보자
근데 왜 이걸 이제서야 해결할까? 채팅 시스템 구축은 3개월 전에 끝냈는데? 이유는 이렇다
어느정도 정신없이 여러 프로젝트를 끝내고 기술 부채를 해결할 수 있는 시간이 생겼다.
또한 중간 메시지 유실이 얼마나 발생하는지 확실하게 트래킹 해볼 수 있다.
이제 해결해보자
구독이 끊기지 않았는데, 중간에 메시지가 하나가 유실됨.

이게 정상적인 흐름이라고 가정해 보자

하지만 "산본역에서" 라는 메시지가 유실된 것이다
구독이 끊기지 않았기 때문에 6, 7번 메시지가 나간 상황이다.

출처: https://www.cspsprotocol.com/tcp-sequence-number/
TCP는 데이터 전송 시 시퀀스 넘버(Sequence Number)를 사용한다.
보내는 데이터 바이트마다 번호를 붙이고, 수신 측에서는 이 번호가 순차적으로 잘 도착했는지 확인한다.
만약 중간에 누락되거나 순서가 꼬이면?
ACK를 멈추거나
재전송 요청하거나
타임아웃 후 자동 재전송이 일어난다
즉, "데이터 유실 → 감지 → 보완" 흐름을 아주 단단하게 갖춘 프로토콜이다.
여기서 해결책을 얻었다.
그림으로 보면

이게 정상적인 상황인데 만약에 "산본역에서" 가 누락됬다고 쳐보자

그렇다.
유저 두명이 정말 동시에 메시지를 보내면 숫자가 1씩 증가하지 않고 같은 시퀀스 숫자가 두번 나올 수 있다.
어플리케이션 코드 내에서 AtomicInteger로 하나씩 늘릴 수 있지만 스케일 아웃이 되는 순간 그 또한 보장할 수 없다

출처: https://redis.io/docs/latest/commands/incr/
해당 redis 명령어로 원자성을 보장할 수 있다. 왜? redis는 싱글 스레드니까. 그리고 심지어 시간복잡도도 1이고 ACL categories에 무서운 단어도 없다.
하지만 이미, redis에 너무 많은 의존을 하는 채팅 시스템이다.... 물론 redis에 시간 복잡도가 log n 이상인 명령어를 쓰지 않아서 cpu bound는 없지만, 메모리적인 측면에서 좀 생각을 해봐야 한다.
우리가 redis 에서 메모리로 올라가 있는게
1. 채널 목록 + 구독 목록
2. 채팅방 세션
3. 채팅 시퀀스 번호
여기에 저장된 데이터을 최대한 간결하게 하고
아직 간단하게 추론하여 보수적으로 계산 해 보았을 때, 천명정도가 수용 된다.
물론 redis memory 80퍼 찼을 때, 알림도 있지만 어쨌든 redis에 대한 의존도가 너무 높다
