빠르게 메시지를 전파하고 싶어
배경
NATS는 정말 아름다워
NATS는 Go 언어로 작성된 메시지큐입니다. 그리고 제가 개인적으로 좋아하는 오픈소스 프로젝트이기도 합니다. 한때 NATS에서 서브스크립션이 메시지를 받는 방식이 단순 채널이 아닌 독특한 자료구조가 따로 있는 걸 봤었던 적이 있습니다. 이 자료구조는 연결리스트를 통해 특정 서브스크립션에 전달될 메시지를 저장합니다. 그리고 sync.Cond
를 이용하여 별도의 대기 중인 서브스크립션을 위한 고루틴에게 알려줍니다.
- 서브스크립션은 생성될 때, 별도 고루틴에서
sync.Cond
의Wait()
메서드를 통해 메시지가 추가되길 대기합니다. - 커넥션은 외부 연결을 통해 서브스크립션에 대한 메시지를 받아옵니다.
- 커넥션은 해당 서브스크립션의 연결리스트에 메시지를 추가하고,
sync.Cond
의Signal()
메서드로 해당 고루틴을 깨웁니다. - 서브스크립션은 연결리스트를 순회해서 메시지를 읽어 처리합니다.
쓰는 사람 따로, 읽는 사람 따로
이 구조는 쓰는 주체가 가지는 상태와 읽는 주체가 가지는 상태가 별도로 존재한다는 것에 의의를 느꼈습니다. 물론 channel
도 버퍼를 주게 되면 상태를 따로 가질 수 있습니다만, 기본적으로 내부에서 락을 가지는 구조이며 반쯤 동기식으로 동작하도록 코드가 작성됩니다. 그리고 무엇보다 채널은 팬아웃(fan out)에 적합한 구조가 아닙니다.