마이데이터 전체 연동 장애 해결 및 성능 개선
저희 회사는 마이데이터 기반 보험플랫폼을 운영중입니다.
마이데이터 연동만 하면 한번에 내가 가입한 보험을 모두 볼수 있는 기능이 있습니다.
이 기능은 우리 회사 뿐만 아니라 마이데이터 사업자라면 적합성 검증만 받으면 모두 할 수 있는 기능이지만, 이 데이터를 기반으로 어떻게 활용 할 것인지에 따라 많은 것이 달라집니다.
저희 회사는 이런 고객 데이터를 분석하여 고객 핏에 맞는 보험상담 서비스를 운영중입니다.
문제 부분
오늘 이야기 할 부분은 이런 고객 데이터를 분석하기 이전에 마이데이터 연동이 원활하게 되고 있지 않았던 부분에 대해 해결했던 경험을 하려합니다.
서비스를 위한 가장 기본이 되는 부분이자 마이데이터의 핵심인 부분입니다.
(참고로 저희 회사는 Java + Spring을 사용 중입니다.)
연동이 안되네. 날씨가 흐린가?
마이데이터 연동이 안된다는 CS가 많이 들어온 날은 항상 날씨가 흐렸습니다. 어느 순간부터날씨가 흐린날 = 연동이 안되는 날이라는 생각이 들 정도로 명확하게 연동이 더 잘 안 됐었습니다.
비가 오거나 하면 네트워크가 불안정하니 어느정도 일리는 있지만 그럼에도 말도 안되는 현상이죠.
나만 10번중 8번이 실패해?
다른 분들은 그래도 날씨가 좋은날은 연동이 되던데 이상하게 제 폰으로 연동을 하면 10번중 8번이 실패했었습니다. 비가 오는날에는 100% 실패라는 경이로운 기록도 했었습니다.
이게 저만의 문제라면 다행이지만, 저만의 문제일리가 없다고 생각했고 우리 서비스의 가장 중요한 부분이라는 것을 깨달아 본격적으로 파고 들었습니다.
마이데이터 연동 큰 구조
- 보맵 앱에서 마이데이터 연동 요청 시도
- 보맵 서버는 게이트웨이를 통해 네이버 인증을 요청 (통합인증)
- 네이버 통합인증을 받음
- 다시 보맵 서버는 각 보험사 총 38개로 각각 고객의 토큰 발급을 요청 (병렬처리)
- 게이트웨이는 각 38개의 보험사에 요청을 보냄
마이데이터 연동을 하면 인증 이후 보험 목록을 조회할 때 38개의 보험사에 각각 요청을 하는데 대부분의 타임아웃이 이 때 발생하고 있었습니다. (이 부분이 주요 문제)
(물론 토큰을 발급 받은 보험사 한정 요청을 하기 때문에 실질적으로는 평균 10개 이내의 보험사에 요청을 합니다.)
타임아웃의 발생 위치가 어디인가?
- 앱 <-> 서버
- 서버 <-> 게이트웨이
- 게이트웨이 <-> 보험사
이 중 어디에서 타임아웃이 발생하고 있는 것인지 전혀 트래킹을 할 수 없는 상황이였습니다.
그래서 우선 게이트웨이에 요청과 응답에 대한 로깅을 하여 분석을 했었습니다만 게이트웨이는 문제가 없어 보였습니다.
그러던 중 갑자기 연동이 실패할 때 몇 초나 걸리지? 싶은 생각이 들어 한 번 초를 세어 보았더니 정확히 30초가 걸리는 것을 알 수 있었습니다.
아! 앱 <-> 서버간 타임아웃이구나
게이트웨이가 문제가 됐던 어쨌건 서버는 각 요청에 대해 타임아웃 처리를 한 후 클라이언트로 30초내에 응답을 내려줬어야 합니다.(이 생각을 왜 이렇게 늦게 했을까..)
그런데 서버 자체가 이런 역할을 못하고 있으니 타임아웃이 발생한 것이구나 라는 생각이 들어 네트워크 요청에 걸리는 시간을 로깅하여 지켜봤습니다.
대부분 빠르게 왔지만 특정 보험사는 90초까지 걸리는 이상한 현상을 발견했습니다.
90초가 걸린것도 이상하지만, 90초 동안 응답을 대기하고 있는 상황이 이상했습니다.
Feign Client에 타임아웃 설정이 되어 있는데?
저희 회사는 서버 to 서버 요청에 Feign Client 라이브러리를 사용중입니다.
Feign Client는 각 요청에 대해 특정 시간동안 응답이 없으면 타임아웃으로 처리할 수 있도록 설정할 수 있습니다.
이런 설정이 30초로 걸려 있음에도 90초가 걸리는 게 이상했습니다.
보험 목록 조회는 각 보험사 별로 한 번만 하면 될텐데?
90초가 걸렸다는 것은 하나의 보험사가 30초를 꽉 채우는 타임아웃을 내뱉었고 이런 요청을 총 3번을 했다는 의미가 됩니다.
그래서 로직을 살펴 본 결과 보험 목록 조회 외에도 이제는 사용하지 않고 있는 두 가지 요청을 더 하고 있었습니다.
아! 나만 연동이 유난히 실패했던 이유가 이거였구나
다른 사람들에 비해 저만 유난히 연동이 더 안됐었는데, 그 이유가 제가 연동하고자 하는 보험사가 타임아웃이 더 자주 발생하는 보험사였기 때문이였습니다.
하나의 보험사가 타임아웃을 뱉으면 사실상 전체실패인 상황속에 제가 가입된 보험사가 유난히 타임아웃을 자주 뱉어 그랬던 것입니다.
그래서 저와 같은 보험사를 가입했던 고객들은 저와 비슷한 현상이였을 것으로 추정됩니다.
토큰 인증은 병렬로, 보험 목록 조회는 동기로?
로직을 분석하던 중 이상한 부분을 하나 더 발견했습니다.
그건 바로 토큰 인증은 병렬적으로 수행하고 있으나, 보험 목록 조회는 동기적으로 처리하고 있다는 점이였습니다.
토큰 인증을 병렬 처리하고 있었기 때문에 당연하게도 보험 목록 조회도 병렬적으로 수행할 것이라 생각한 것이 큰 오산이였습니다.
이런 구조가 된 이유는 이전에 작업했었던 분들이 다 퇴사하였기에 알 수 없습니다.
지금까지 내용을 요약 해보자
- 38개의 보험사에 병렬로 토큰 발급 요청 (30초 이내에 끝나야 됨)
- 토큰 발급 받은 보험사 한정 보험 목록 조회
- 최대 38개의 보험사이니 최악의 경우 38 * 3 = 114번의 요청 (이게 30초 이내에 끝나야 됨)
요약해보면 사실상 연동이 되고 있던것이 기적이라고 볼 수 있습니다.
로직 개선
모든 문제는 파악했으니 이제 수정을 해야합니다.
불필요한 네트워크 요청 제거
현재는 사용하지 않는 요청은 모두 제거 하였습니다. 이로인해 각 보험사 별보험 목록 조회 API를 한 번씩만 호출 하게 되었습니다.
보험 목록 조회 병렬 처리
보험사 별로 요청을 보내는 부분을 Spring의 @Async와 CompletableFuture를 이용하여 병렬 처리 되도록 수정하였습니다.
토큰 조회 병렬 스트림 개선
토큰 조회 시, 병렬 스트림을 사용하여 병렬 처리를 하고 있었습니다. 이 부분 또한 포크/조인 공용 풀을 사용하기 때문에 병목 지점이 될 수 있다고 판단하여 @Async와 CompletableFuture를 이용하여 병렬 처리 되도록 수정하였습니다.
CompletableFuture사용 시, 따로 커스텀 풀을 지정해주지 않으면 기본적으로포크/조인 공용 풀을 사용하지만@Async안에서 사용 시, 설정한ThreadPoolTaskExecutor을 사용합니다.
Feign Client 타임아웃 시간 조정
현재 30초로 설정되어 있기 때문에 어느 보험사 하나만 실패해도 전체 실패가 될 것입니다.
그래서 Feign Client 타임아웃 시간을 10초로 줄였습니다. 네트워크간 통신이 10초나 걸린다면 어차피 문제가 생긴것이라 생각하였습니다.
스레드를 20개로 조정하여 20개 모두 타임아웃이 나는 최악의 상황에도 2번이니 20초면 끝이 나도록 하여 어떻게든 클라이언트가 응답을 받도록 하였습니다.
이런 상황은 거의 존재하지 않으며 현재까지는 38개가 거의 동시에 병렬처리 되어 10초내에 대부분 완료되고 있습니다.
개선 결과
고객 입장에서 보면 이전에는 인증 30초 + 보험 목록 조회 30초로 최대 60초를 기다리다가 전체 연동 실패로 인해 아무런 결과를 못봤다면,
개선 이후 인증 10초 + 보험 목록 조회 10초로 최대 20초를 기다리다가 실패 건에 대한 보험사 제외하고 결과를 볼 수 있게 되었습니다.
물론 스레드가 20개이기 때문에 이론상 정말 최악의 경우 40초(인증 20초 + 보험 목록 조회 20초)가 걸릴 수도 있지만 아직까진 평균 20초 이내에 끝났습니다.
보험사 중 한 곳만 타임아웃을 뱉어도 인증 10초 + 보험 목록 조회 10초로 20초는 걸리게 됩니다.(꼭 한 곳은 타임아웃을 뱉더라구요.)
요약해보자면 아래와 같습니다.
개선 이전 상황
- 고객입장: 대기시간 최대 60초 (인증 + 보험 목록 조회) + 전체 실패로 결과 없음
- 서버입장: 각 보험사별 최대 90초 대기(최악 38 * 90초) + 앱은 이미 커넥션이 끊겼음에도 서버는 의미 없는 데이터 처리 중
- 전체 연동 실패
개선 이후 상황
- 고객 입장: 대기시간 최대 20초 (인증 + 보험 목록 조회) + 실패한 보험사를 제외한 결과 리턴
- 서버입장: 각 보험사별 최대 10초 대기 + 병렬로 처리되기 때문에 평균 10초 내에 처리 완료 (스레드 상황에 따라 조금의 변동성은 있지만 평균 10초 내에 완료)
- 전체 연동 실패 건이 현재까지는 존재하지 않음
수정 이후 현재까지는 마이데이터 연동 실패 건에 대한 이슈는 없습니다.
이제는 날씨가 흐려도 연동이 잘됩니다.

