FCM을 사용하면서 발생한 문제들

4 분 소요

FCM을 사용하면서 겪은 문제와 문제를 해결했던 방법.

FCM 을 사용하면서 겪은 문제와 해당 문제들을 어떻게 해결하였고, 앞으로 어떤 방식으로 사용을 해야할 지에 대해 고민했던 것들에 대한 글이다.

어디까지나 필자 개인의 경험을 기반으로 한 글이다.

1. FCM Push TOPIC_RATE_EXCEEDED error

하나의 토픽에 많은 양의 데이터를 빠르게 전송하면, 해당 에러가 발생하며, 푸시를 더이상 할 수 없게 된다.

해당 에러의 발생 사유는 아래와 같다.
특정 주제의 구독자에게 전달되는 메시지 비율이 너무 높습니다. 이 주제로 보내는 메시지 수를 줄이세요. 바로 다시 보내도록 시도해서는 안 됩니다

단위토픽에 대해 전송되는 메세지의 개수를 줄여야 한다라는 문제가 생겼다.
해당 문제를 해결한 방법은 아래와 같다.

해결당시 사용언어는 Erlang이며, Erlang의 특징은 분산처리 및 경량프로세스이며, 분산처리를 언어자체에서 지원을 해준다는 장점이 있다.
따라서, 서버를 여러대 올려놨을때, 조금만 처리를 하게되면, 각 노드간 통신을 하게끔 하는 것은 매우매우 쉬운 일이다.
Erlang에 보면 gen_server를 실행시킬 때, global로 등록할 것인지, local에 등록할 것인지 옵션을 통해 지정해 줄 수 있다.
global로 실행시킨 다면, 통신하고 있는 노드들 중에서 동일한 이름의 gen_server는 오직 하나의 프로세스만 실행이 가능하다.
해당 특성을 이용하여, push해야하는 topic 이름으로 gen_server를 실행시켜, 푸시 요청이 올 경우, 0.25초 마다 한번씩만 보내도록 하였다.
해당 개수는 문서 상에서 FCM의 클라이언트 수신 가능한 최대 개수가 분당 240개. 시간당 5000개까지 제한하고 있다는 점에서 가져온 것이고, 실제로 토픽에 0.25초당 한번씩 보내게 되는 경우는 없을거라고 생각한다.

기존에 작업했던 서버의 경우 주된 푸시 방법이 FCM이다. 또한, 데이터를 동기화하는데 이용하였다.
하지만, 지금 생각해 보면, 메인 푸시를 FCM을 사용하는 것이 당시에는 최선의 방법이었을 수 있지만(필자가 1년도 안되었을 때, 다른분들이 결정하셨었다.), 지금은 아니라 생각한다. 주된 데이터를 동기화하는 방법으로는 맞지 않다고 생각한다.
애초에 토픽에 0.25초당 하나씩 보내는 상황 자체를 만들지 않도록 구성하는 것이 옳은 방향이라 생각한다.
따라서, 추후 FCM을 사용한다면, 어디까지나, 알람 용도로 사용해야 하지, 많은 데이터를 전송하는 용도로 사용하는 것은 경험상 좋진 않다고 생각한다. 데이터 전송이 많다면, 백그라운드는 굳이 돌리지 말고, 앱이 포그라운드일때, MQTT같은 것을 사용해서 데이터를 푸시받는게 옳은 방향이라 생각된다.

만약, 이후 데이터를 FCM으로 받게 되는 일이 있다면, 도저히 시간이 나지 않는 상황이나, 데이터 전송이 자주 일어나지 않게 되는 경우에만 사용하게 될 것 같다.

참고 링크
단일 기기에 대한 최대 메시지 속도
FCM 에러 목록

2. 동시에 여러명의 유저들에 대해 선별하여 알람보내기

이전에 개발헀던 서비스의 서버에 보면, 여러명의 유저가 하나의 토픽을 함께 구독하고 있는 상황이 많고, 해당 토픽에 대해 공통적으로 알람을 보내야하는 경우가 있다.
하지만, 유저에 따라, 알람을 켜놓거나 꺼놓을 수 있으므로, 해당 토픽으로 한번에 알람을 푸시하게 되면, 원하지 않는 유저가 알람을 받게 된다.
따라서, 해당 부분에 대해서는 2가지 방법을 생각했었다.

  1. 유저의 토큰을 서버에 저장하여, 알람을 끄지 않은 유저들에 대해서만 알람 전송
  2. 데이터 푸시토픽과 알람토픽의 분리

당시 선택한 방법은 1번이었다.
알람을 끄지 않은 유저에 대해서 선별은 데이터베이스에 해당 유저의 알람 onoff 여부를 조회하여 확인하였다.
그리고 푸시는 multicast 방법을 사용하면, 동시에 최대 1000개 토큰에 대해서 동시에 보낼 수 있어서, 해당 방법을 사용하였다.
해당 방법을 사용함으로써, 알람정보를 가지고 있는 DB에 대해 의존성이 생겼지만, 그부분은 어쩔 수 없는 부분이라 생각된다.

만약, 2번째 방법을 사용한다고 했을 때, 구독할 수 있는 토픽의 개수가 최악의 경우, 절반 정도 밖에 안되게 된다. (FCM 최대 구독가능 개수가 약 2000개 였던것으로 기억한다.)
따라서, 당시에 떠올렸었어도, 1번 방법으로 진행했을거라 생각한다.

3. Topic은 구독중인데, 해당 유저에게 FCM을 전송할 경우, 데이터가 누락되는 문제

아직 해결하지 못한 문제입니다.

어느날, 특정 토픽에 대해 알람 및 데이터 푸시를 받지 못하는 현상이 발생하였다.
혹시, 해당 토픽을 FCM단에서 구독해제 되었거나, FCM TOKEN이 만료되었을 수 있겠다는 가능성을 열어두고, 테스트를 진행하였다.
첫번째로 해당 토큰이 만료되었는지, 혹시 정상적으로 작동하지 않는지에 대해 테스트하였다.
데이터, 데이터/알람, 알람 순으로 해당 토큰으로 메세지를 전송해보았는데, 클라이언트에서 모두 정상적으로 수신에 성공하였다.
그 뒤, 대상 토픽에 대해 정상적으로 구독하고 있는지 확인하였고, 해당 토픽은 정상적으로 구독이 되어있는 상태였다.
이후, 다시 데이터, 데이터/알람, 알람 순으로 해당 토픽으로 메세지를 전송해봤는데, 클라이언트에서 정상적으로 수신하지 못하였다.
일단, 당시 클라이언트는 AOS였고, AOS에서는 알람을 백그라운드에서 직접 생성을 한다. 알람이 생성되어야 할 동작이 이루어졌음에도 불구하고, 알람을 노출하지 않았고, 앱을 껏다 켰을 때 동기화 API에 의해 데이터를 가져오고 있었다.
그리고 만약, FCM단에서 알람을 전송한다면, 그 어떤 처리도 없기 떄문에 알람이 고스란히 노출된다. 하지만, 알람은 도착하지를 않았다.
따라서, 해당 토픽에 대해 다른 클라이언트를 구독하였고, 다시 테스트 해본 결과 다른 클라이언트는 정상적으로 데이터 및 알람을 모두 받는데, 해당 클라이언트만 여전히 못받고 있었다.
따라서, 서버단에서 재구독 하였더니, 정상적으로 수신되기 시작하였다.

이후에, 데이터만 포함된 FCM 메세지를 받지 못하는 버그도 발생하였었다.
해당 문제 또한 재구독으로 해결하였다.

위 문제에 대해 고민을 해보았고, 해당 문제에 대한 해결법은 해당 토큰으로 직접 보내는 방법이라고 생각을 하고 있다.
토픽에 대해서는 이유없이 데이터 수신이 되질 않으니, 해당 상황이 발생하였을 때 정상동작하였던 토큰을 통한 발송이 당장 떠오르는 방법이다.

4. HTTP > HTTPv1 API로 이전하지 않은 이유

해당 방법으로의 이전을 고민하던 당시에, 개발하던 서버에서는 AOS/IOS를 각각 따로 FCM PUSH를 하였다.
즉, 개선된 버전에서는 1번만 보내도 될 것을 기존 버전에서는 2번보내고 있으므로, 해당 횟수를 줄일 수 있다면, 줄이는 것이 맞는 방법이라 생각하였다.
따라서, HTTP API > HTTP v1 API 로 이전을 시도해보았다.

기존 버전의 경우, FCM ServerKey를 이용하여 고정된 키값을 Header에 넣어서 전송요청하는 방법을 사용하였는데, v1의 경우, Access Token을 발급하여, 메세지를 전송한다.
그리고, IOS/AOS/WEB 등에 대해 한번에 푸시할 수 있도록 개선되었다.

하지만, 복병은 의외의 곳에서 나타났다.
AOS에서 데이터를 FCM 푸시를 수신하지 못하는 것이다.
뭔가 이상함을 느끼고 여러가지 테스트를 진행해 보았고, FCM Data Push가 도착할 때마다 토스트 메세지를 띄워주도록 변경한 클라이언트를 AOS/IOS에 요청하여 받아 테스트해봤는데, AOS에서는 메세지가 도착하질 않았다.
기존 버전으로 테스트 할 때는 잘 되던 것이 v1에서는 되질 않아서, 내가 잘못보냈나 하면서 바꿔가면서 테스트해봐도, 여전히 수신을 못하고 있었다. ( Firebase 서버에서 못보내는건지, Android에서 못받는건지 모르겠다. )

위의 이유 때문에 이전은 하지 않게 되었다.
만약, 됐었어도 HTTP > HTTPv1 으로 변경하지 않은 추가적인 이유는 아래와 같다.
multicast 방법을 지원하지 않는다. 만약, Google에서 인증 서버에 문제가 생겨서 AccessToken을 재발급받지 못하면, 장애가 난 시간만큼 클라이언트에 푸시가 전송되지 않게 된다.

5. HTTP API에서 AOS/IOS 푸시는 함께 ? 따로 ?

과거에는 서비스의 서버에서 AOS/IOS에 대해 푸시를 따로 전송하였다.
그렇게 전송하는 이유는 이미 서비스 서버를 본격적으로 개발하기 시작했을 때는 이미 그런 상황이라 잘 모른다.
하지만, 위 4번에 해당하는 작업을 못하게 되면서, 그냥 IOS/AOS에 대해 같은데이터를 넣고 한번에 푸시를 보내니, 둘 모두 데이터를 정상적으로 수신하였다.
물론, 각각(AOS/IOS)의 동일한 키값에 대해 서로 다르게 받고 있는 데이터를 사용하고 있다면, 따로 전송하는 것이 맞겠지만, 개발하던 서비스에서는 그렇지 않기 때문에, 문제가 없다 판단되었다.
만약, 동일한 키값에 대해 서로 다르게 받아야 한다고 하면, 그때가서 개선하면 될 문제라고 생각한다.

태그:

카테고리:

업데이트: