SIU
article thumbnail
Published 2024. 2. 4. 21:24
외부 조회 API 연동 장애 대응책 CS

 

현재 다니고 있는 회사는 SaaS형 웹 사이트를 고객사에 제공하고 있습니다. 외부 API를 연동하는 부분이 많아, 장애 대응 방법을 고민하고 있었습니다. 대외 고객사가 많아, 에러가 나면 리스크가 크고 보고와 대응 방법 체계가 중요했습니다.

특히, 요즘 모니터링 툴을 살펴보면 쓰레드 임계치를 넘을 때가 많아, 외부 API 장애 대응 레퍼런스를 정리하였습니다.

아래 사례는 저희 회사의 직접적인 사례는 아니지만, 유사한 점이 있어 많은 도움이 되었습니다.

 

 

 

 

앱이 API 요청을 하면 일부는 DB에서 처리하고 일부는 뒤쪽 외부 API를 호출하는 형태인데, 이 구조에서 에러가 발생했다.

 

 

 

최근, 순간적인 DB 커넥션 풀 부족 장애 방생

 

  • 약 10분 정도 2차례, API 서버에서 응답 시간 지연과 에러 발생
    • 커넥션 풀에서 커넥션을 가져오지 못하면서 에러 발생
    • 급하게 대응
      • 잽싸게 서버 재시작 + 커넥션 풀 개수 증가 (DB 최대 커넥션 수 증가)
      • 누적된 요청을 전부 에러 처리

 

 

 

커넥션 풀 부족 원인

  • DB 트랜잭션 범위에서 외부 API 호출하는 구조
  • 특정 외부 API에 트래픽이 순간 몰림(푸리 발송) : 외부 서버에서 문제가 발생하면서 그 문제가 연쇄적으로 전파가 됨 
    • 외부 API의 응답 시간 증가 : 외부 API 성능이 그렇게 좋지 않아, 응답 시간 증가
    • (외부 API 응답을 기다리느라) 커넥션이 커넥션 풀에 반환되지 않음
    • 커넥션 풀에 커넥션 부족
    • (다른 클라이언트가 요청을 했을 떄) 커넥션을 구하는 다른 쓰레드 대기
    • 대기 시간 초과하면서 구하기 실패 에러

 

  • 4번 외부 API 연동이 느리면서, 응답 시간도 같이 느려졌습니다.

 

 

 

대응방법

(가능한 기능이면) 트랜잭션 범위에서 외부 연동 분리 : 적용

  • 많이 불리는  API에 적용
  • 트랜잭션 범위에 있는 외부 연동 API을 트랜잭션 범위에서 빼는 것(분리)을 고민
  • 외부 연동 응답 지원이 발생해도 (커넥션을 물고있어 풀에 돌려주지 않는 문제를 해소) 커넥션 풀에 주는 영향 감소

 

 


controller에서 주문 요청 request가 들어오면 service를 호출을 합니다.@Transactional 을 걸어둔 서비스에서 
재고감소() 
PG승인처리() <-- 외부 API 
주문완료처리()

위와 같은 단계를 순차 처리하게되면 db connection을 물고 외부 api를 호출하게 됩니다.그러면 외부 api 응답이 늦어질수록 db pool에 connection이 금방 마르게 됩니다.그래서 간단하게 Controller에서 위 3개의 메소드를 별도로 호출하는데 재고감소(), 주문완료처리() 메소드는 Transaction을 걸어서 처리하고,

PG승인처리 메소드는 Transaction 없이 외부 API를 호출하도록 처리합니다. 이때 PG승인이 타임아웃이나 오류인 경우는 재고를 롤백하도록 예외를 잡아 Transaction 걸고 롤백시키도록 하고요.

위의 사례처럼 트랜잭션을 물고 외부 기관이 장애 혹은 지연이 발생하면 의도치 않게 내가 서비스하는 DB의 connection이 부족하게 됩니다.

외부 API 호출은 빠른 응답을 보장할 수 없다고 무조건 가정하여 db 트랜잭션 없이 처리하도록 합니다.

동시에 수많은 주문 요청이 들어오면 재고 관리가 중요합니다.결제 이전에 재고를 먼저 차감해서 재고가 부족하면 결제까지 가지 않도록 처리해야 고객 사용성에 도움이 됩니다.재고도 없는데 결제를 던지고 성공하면 재고없다고 결제 취소를 하는 케이스는 고객이 원하지 않을거라서요.단 재고 차감 혹은 쿠폰 발급/사용같은 처리는 동시성 이슈를 생각해야 합니다.DB 락 혹은 Redis를 이용한 분산락 같은 매커니즘을 이용하시는게 좋아요.

 

 

https://helloworld.kurly.com/blog/distributed-redisson-lock/

 

풀필먼트 입고 서비스팀에서 분산락을 사용하는 방법 - Spring Redisson

어노테이션 기반으로 분산락을 사용하는 방법에 대해 소개합니다.

helloworld.kurly.com

 

 

외부 API 별로 동시 실행 가능한 쓰레드 개수 제한하기 : 미적용

  • 특정 외부 API가 쓰레드 풀을 다 점유하는 것을 막기 위함 (+ 커넥션을 먹고 있는 문제 해결)
  • 외부 API 마다 성능이 빠른 애가 있고 느린 애가 있는데, 성능이 느린 API에 갑자기 많은 쓰레드를 몰아주면 응답시간이 느려져 API 서버에도 전파되어 영향을 줌
  • 외부 API에 따라 다른 개수 할당 (외부 API별로 동시에 호출할 수 있는 쓰레드 개수를 제한)
  • 허용 개수만큼(혹은 초과) 동시 요청 발생시 빠르게 에러 응답 처리 -> 응답 시간은 느려질 수 있어도, 응답을 기다리거나 커넥션을 못 구해서 대기하고 있어 에러를 내는 부분이 줄어든다)
  • API 서버 입장에서는 DB 커넥션이 부족해지는 문제가 발생할 확률이 확 줄어든다.

 

 

 

 

푸시를 천천히 보내기 (이미 일부 외부 대상에 적용) : 가장 빠르면서 효율적임(가성비)

  • 문제가 발생한 근본적인 원인 :  푸시를 발송한 것 -> 푸시가 나가니, 푸시를 보고 사용자가 누름 -> 트래픽이 오름
  • 푸시 발송 규모가 늘어난 외부 API 대상으로 천천히 보내기
  • 좀 천천히 가도 되는 푸시임
  • 실제로 일부 외붐 API에 적용이 되어 있었다. 다만, 푸시 발송 규모가 늘어난 외부 API가 있어 이번에 영향을 주었다.

 

 

기타 후보

  • 외부 API에 서킷 브레이커 적용 : 아직 미적용
    • 응답 시간이 에러 날 만큼 늘어난 것은 아니어서 효과가 있을 지 고민 됨
    • 에러가 일정 비율이나 개수만큼 발생하면, 차단해서 에러가 발생하지 않게 하는 효과
    • 해당 원인이 외부 API가 엄청난 장애가 아니라, 평소에 0.5초 였던 응답시간이 5~6초로 응답 시간이 길어지면서 커넥션 풀을 안 놔줘서 ( 커넥션이 커넥션 풀로 돌아가지 못함) 생김
  • 조회 API 결과를 캐시에 보관 : 적용 중
    • 다수 조회 API는 실시간 특징을 보임 (예, 결제 후 상태 변경되는 것을 보여줘야 함)
    • 데이터 변화가 거의 없는 조회 API에 적용함 (예. 자주 불리는 HOME API)
  • 비동기처리
    • 데이터 동기화 목저으로 조회하는 API

 

 

INSIGHT

 

외부의 조회 API가 응답 시간이 느려지면서, 발생한 Connection Pool 포화  + 그로인해 촉발된 장애에 대해 정리하였습니다. 작년 말에 들은 카카오 미트에서도 로그인과 카카오톡 관련해서, 해당 장애 해결 방법과 겹치는 부분이 많았습니다. 

 

https://maystar8956.tistory.com/211

 

Kakao Tech Meet 참여 후기_카카오가 소통하는 방법

Kakao Tech Meet은 카카오의 공개 기술 세미나로, 최신 기술 트렌드와 경험 및 노하우를 자주, 지속적으로 공유하며 개발자와 함께 성장을 도모하고 긴밀한 네트워크를 형성하는 노력을 하고 있습니

maystar8956.tistory.com

 

[비슷한 레퍼런스]

  • thread제어를 두지 않아서 과도한 메모리를 사용하는 업무
  • pg사 승인api 호출이 트랜잭션 내에서 처리되어 pg사 장애시 말씀하신 장애를 똑같이 경험하여, 승인api 호출전 재고감소 같은 사전처리 트랜잭션 끝내고 api 호출 후 정상 혹은 api 에러 발생 시 롤백 트랜잭션을 새로 시작해서 api는 트랜잭션 물지않고 처리함

 

회사에서도 Lock이 걸리거나, 로그인 관련해서 트래픽이 몰려 임계치를 넣을 때가 있어, 어떤 해결 방법으로 완화하면 좋을지 고민하게 되었습니다. 외부 API는 이젠 필수라, 에러 핸들링과 대비책, 장애 프로세스를 미리 구축하는 것이 필요하다고 느꼈습니다.

profile

SIU

@웹 개발자 SIU

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!