오늘은 V3 고도화 작업에서 사용할 기술들에 대한 자료 조사를 진행했다!
우리 팀은 고도화 작업에서 소셜 로그인 및 이메일 인증, AWS와 CI/CD, 위치 기반 목록 조회(반경 5km 내 모임 조회), 실시간 알림, 채팅을 진행하기로 하였다.
그리고 만약 시간이 남을 때 검색 기능을 고도화하기 위해 Elastic Search를 사용하기로 하였다.
나는 이 중에 위치 기반 목록 조회와 실시간 알림을 맡았는데, 오늘은 이 기능들을 어떻게 구현할지, 무슨 기술을 사용해야 할지를 정리하는 시간을 가졌다.
먼저, 위치 기반 목록 조회에서는 모임 전체 목록 조회 시, 사용자가 지정한 위치에서 5km 이내의 모임만 조회 가능해야 한다.
추가로 우리는 검색 기능에 지도 API를 사용하려고 하는데, 이때 사용자가 지도를 확대하고, 축소함에 따라 모임의 목록이 다르게 보이도록 구현하려고 하고, GPS를 통해 사용자의 실시간 위치를 받아서 주변의 모임 조회도 가능하도록 하려고 한다.
이에 대한 구현 방법은 크게 3가지가 있었는데,
첫 번째는 하버사인 공식(Haversine Formula)을 이용해 사용자의 위치를 중심으로 5km를 계산하고, 그 이내에 위치한 모임들을 DB에서 직접 조회하는 것이다.
이렇게 구현하게 되면 데이터의 정합성이 보장되고, DB에서 직접 조회하기 때문에 모집 상태와 날짜, 카테고리 등 다양한 조건과 조합할 수 있게 된다.
하지만, 거리 계산에는 비용이 발생하기 때문에 데이터가 많아질수록 DB 부하가 증가하게 되고, 지도가 이동하거나 줌이 되면 호출이 많아지기 때문에, 이때 성능이 저하된다는 단점이 있다.
두 번째는 프론트에서 입력받은 지도의 Viewport를 통해 조회하는 것인데, 앞선 방법에서의 거리 계산을 프론트에서 진행하여 넘겨주는 것이다.
이런 경우에는 백엔드에서는 범위 조건으로만 조회하면 되기 때문에 성능이 매우 좋아진다.
하지만, 이 방법은 프론트에 대한 의존도가 너무 높고, 검색 시에는 사용할 수 있지만, 단순 5km 이내 모임 조회에는 활용하기가 어려워진다.
마지막으로 세 번째는 Redis의 Geospatioal을 활용하는 것인데, Redis Geospatial은 Redis에서 sorted set 자료 구조를 통해 위치 정보를 저장해주는 것이다.
여기에 위치 정보를 저장하면, 매우 간단하고 빠르게 원하는 범위 내에 위치하는 내용들을 조회할 수 있게 된다.
하지만, 캐시로 관리하는 만큼 데이터의 정합성 관리가 필요하고, 이 자체로는 복합 조건을 처리할 수 없게 된다.
추가로 Redis라는 외부 서버가 필요한만큼 장애 시의 대응도 필요하다.
일단 나의 판단으로는 위 3가지 방식을 모두 사용하기로 하였다.
일단 1차적으로는 Redis Geospatial을 통해 거리 내 모임을 1차로 필터링할 것이다.
이때 Redis에는 모인 상태가 OPEN인 모임에 대해서만 등록을 하고, 모임 상태가 CLOSED 되었거나 COMPLETED 된 내용에 대해서는 캐시에서 삭제할 것이다.
Redis를 통해서는 모임의 id 값만 받을 수 있기 때문에, 여기에서 받은 id 값을 기반으로 실제 모임 객체들을 조회한 뒤, 이에 대해 추가 조건을 걸어 조회하려고 한다.
Redis가 무너졌을 때는 하버사인 공식을 통해 거리를 측정하여 조회하고, 프론트에서 지도 API를 사용할 때는 Viewport를 전달받아 조회하려고 한다.
아직 팀원들과 구체적으로 소통해보지도 않았고, 더 자세한 조사를 진행해보지 않았기 때문에 이후에 구현 방법이 바뀔 수도 있다.
하지만, 지금 생각하기로는 3가지 방법 중 하나를 선택하기보다는 상황에 맞게 필요한 방법을 모두 사용하는 것이 적합하다고 판단된다.
두 번째로는 실시간 알림을 구현하는 방법에 대해 조사해보았다.
여기에도 세 가지의 방법이 있었는데,
첫 번째는 롱 풀링으로, 클라이언트가 서버에 요청을 보내면, 서버는 연결을 유지한 상태로 대기하다가 이벤트가 발생하면 그때 클라이언트에게 응답하는 것이다.
이 방법은 구현 난이도가 가장 낮지만, 빈번하게 발생하는 이벤트에 사용하기에는 오버헤드가 크다는 단점이 있다.
두 번째는 웹소켓을 사용하는 것인데, 클라이언트와 서버가 최초로 한 번 연결되면 이 연결을 통해 양방향 통신을 지속적으로 진행할 수 있게 된다.
이는 지연 속도가 굉장히 낮아서 빠르게 데이터를 전송할 수 있지만, 설정이 복잡하다는 단점이 있다.
그래서 웹소켓은 게임 플랫폼이나 채팅과 같이 양방향 소통이 꼭 필요하지만, 대기 시간이 짧고, 지속적으로 데이터를 업데이트해야 하는 어플리케이션에 더 적합하다고 한다.
마지막은 SSE, Server Sent Events인데, 이는 클라이언트와 서버간 SSE 통신이 연결되면, 서버에서 클라이언트로 단방향 통신이 지속되는 것이다.
이 방법은 설정이 단순하고, 클라이언트에서 자동 재연결을 요청하기에 간편하다는 장점이 있지만, 클라이언트에서 서버로는 데이터 전송이 불가능하고, 연결 수에 제한이 있을 수 있다는 단점이 있다.
이 3가지 방식을 모두 고려해봤을 때, 알림 서비스는 서버에서 클라이언트로의 알림 전달이 핵심이기 때문에, 단방향 통신만 지원하는 SSE가 더 적합하다고 판단된다.
이때 SSE가 스프링의 커넥션 풀을 모두 차지하지 않을 수 있도록 고려해서 구현을 진행해보려고 한다.
여기까지의 구현이 제한 시간 안에 모두 마무리되면, 이후에는 Elastic Search를 통해 검색 기능을 고도화해보려고 하는데, Elastic Search를 사용하면 검색 속도가 향상될 뿐만 아니라, 우리 서비스의 여러 조건들을 더 단순하게 처리할 수 있게 된다고 한다.
아직 이와 관련된 자료 조사가 부족해서 이와 관련해서는 조금 더 조사를 해보려고 한다.
이제는 기존에 배웠던 내용들이 아니라 새로운 기능에 새로운 기술을 적용해야 하기 때문에, 자료 조사가 중요해졌다.
난생 처음 들어보는 기술들이라 어떤 내용들인지 이해하느라 시간이 오래 걸렸지만, 실제로 구현하는 작업에 들어가면 더 재미있어질 것 같다.