{"componentChunkName":"component---src-templates-post-template-jsx","path":"/works/posts/2024-06-15--001","result":{"data":{"site":{"siteMetadata":{"title":"Blog by Eunyoung","subtitle":"작업 기록 블로그","copyright":"© All rights reserved.","author":{"name":"EunYoung","twitter":"#"},"disqusShortname":"","url":"https://ssongey.github.io"}},"markdownRemark":{"id":"b5390b0e-cbf7-5a81-bdcd-e4bf7f8f8665","html":"<p>현재 맡고 있는 서비스는 정부전자문서지갑 API에 대한 의존도가 높은데, 이 API는 장애가 잦은 편이다.\n장애가 발생하면 서비스 응답 속도가 느려지고, 결국 사용자 경험이 나빠진다.\n<br/>\n이런 문제를 해결하기 위해 <strong>Circuit Breaker 적용을 좀 더 세분화하여 진행</strong>했다.\n<br/>\n기존에는 큰 기능 단위로만 Client Bean을 나누었지만, <strong>API 특성별로 더 세분화하여 대응</strong>하기로 했다.</p>\n<br/>\n<h2>1. Client Bean 세분화</h2>\n<p>일반적으로 외부 API를 호출하는 Client Bean은 <strong>host 단위</strong>로 생성한다.\n하지만 장애가 잦은 API에 대해 더 정밀한 대응이 필요했기에, <strong>장애 유형별, 구간별로 Client Bean을 추가 분리</strong>했다.\n<strong>분리된 client들은 서로 중복으로 api path를 가질 수 있으며, 각 client 객체는 호출되는 시점이 다르다.</strong></p>\n<h3>✔︎ 구조 개선</h3>\n<p><strong>기존 구조 (AS-IS)</strong></p>\n<ul>\n<li>개인 전자문서 지갑 관련 api 연동 client bean</li>\n<li>수취기관 관련 api 연동 client bean</li>\n<li>증명서 신청/제출 등 api 연동 client bean</li>\n</ul>\n<p><strong>개선된 구조 (TO-BE)</strong></p>\n<ul>\n<li>\n<p>장애가 자주 발생하는 api별 client bean 생성</p>\n<ul>\n<li>증명서 신청을 위한 부가정보 조회 api 전용 client bean</li>\n<li>사용자의 전자문서지갑 상태 조회 api 전용 client bean</li>\n</ul>\n</li>\n<li>\n<p>점검 유형 정하기 위한 구간별 client bean</p>\n<ul>\n<li>전자증명서 홈 진입 시 사용되는 api 전용 client bean</li>\n<li>증명서 신청 플로우에서 사용되는 api 전용 client bean</li>\n<li>증명서 보냄/받음 플로우에서 사용되는 api 전용 client bean</li>\n<li>내 증명서 확인 플로우에서 사용되는 api 전용 client bean</li>\n</ul>\n</li>\n<li>그외 api 전용 client bean 생성</li>\n</ul>\n<br/>\n<h3>✔︎ 적용 효과</h3>\n<p>서비스 특성상 <strong>read timeout이 15초</strong>로 설정되어 있었고,\n정부전자문서지갑 서버는 <strong>Timeout 에러가 자주 발생</strong>하는 상태였다.</p>\n<p><strong>Circuit Breaker가 오픈되면서</strong></p>\n<ul>\n<li>15초 동안 기다리지 않고 <strong>빠르게 사용자에게 오류 페이지로 랜딩</strong>이 가능했다.</li>\n</ul>\n<p><strong>Client Bean을 세분화하면서</strong></p>\n<ul>\n<li><strong>어떤 플로우가 문제인지 좀 더 명확하게 파악</strong>할 수 있었다.</li>\n<li>점검 종류를 빠르게 파악이 가능하여 <strong>빠른 대응이 가능</strong>했다.</li>\n</ul>\n<br/>\n<h2>2. 불필요한 Pod 수 조정</h2>\n<p><strong>Circuit Breaker는 각 파드에서의 에러율을 기준으로 동작</strong>하기 때문에,\n트래픽 대비 Pod 수가 많으면 <strong>서킷이 제대로 동작하지 않는 문제</strong>가 있다.<br/>\n현재 트래픽에 비해 설정된 Pod 수가 많았고, <strong>적절한 Pod 개수로 조정</strong>하여 서킷이 정상적으로 동작할 수 있도록 했다.</p>\n<h3>✔︎ 적용 효과</h3>\n<ul>\n<li>트래픽이 많지 않은 시간대 &#x26; 요일에도 <strong>Circuit Breaker가 정상적으로 동작</strong>하도록 개선됨.</li>\n</ul>\n<br/>\n<h2>3. Sliding Window 타입 결정</h2>\n<p>Resilience4j의 Circuit Breaker는 아래 2가지 <strong>Sliding Window 방식</strong>을 지원한다.\n<a href=\"https://resilience4j.readme.io/docs/circuitbreaker\">참고</a></p>\n<p><strong>Count-based Sliding Window</strong></p>\n<ul>\n<li>요청 개수 단위로 데이터를 저장하고 집계하는 방식</li>\n</ul>\n<p><strong>Time-based Sliding Window</strong></p>\n<ul>\n<li>요청 시간 단위로 데이터를 저장하고 집계하는 방식</li>\n</ul>\n<br/>\n<p>처음에는 Time-based 방식을 고려했지만,\n<strong>Client Bean 세분화 및 낮은 트래픽을 가진 서비스의 특성</strong>을 고려하여 <strong>Count-based</strong>로 결정했다.</p>\n<h3>✔︎ 적용 효과</h3>\n<ul>\n<li>트래픽이 낮은 늦은 밤, 새벽 시간대에도 서킷이 동작하도록 개선 됨</li>\n</ul>\n<br/>\n<h2>4. Fallback 적용 여부</h2>\n<h3>✔︎ Fallback이란?</h3>\n<p>서비스를 차단한 경우, 예외를 발생시키는 대신 미리 준비된 동작을 실행하는 것을 의미한다.<br/>\n즉, Circuit Breaker가 Open 상태일 때 요청을 에러로 응답하지 않고, 대체 응답을 제공하는 방식이다.<br/></p>\n<p><strong>이번 작업의 목표는 빠르게 에러를 감지하고 사용자에게 안내하는 것</strong>이었기 때문에, <strong>Fallback을 적용하지 않고 즉시 에러 안내 페이지를 노출</strong>하도록 했다.</p>\n<br/>\n<h2>5. 최종 정리</h2>\n<ul>\n<li><strong>장애가 자주 발생하는 API별로 Client Bean을 세분화</strong>하여 장애 감지 속도를 높임<br/></li>\n<li><strong>Pod 개수를 조정하여 Circuit Breaker가 정상 동작하도록 개선</strong><br/></li>\n<li><strong>트래픽 특성을 고려해 Count-based Sliding Window 방식 적용</strong><br/></li>\n<li><strong>Fallback을 사용하지 않고 빠른 에러 안내 제공</strong><br/></li>\n</ul>","fields":{"tagSlugs":["/tags/circuit/","/tags/resilience-4-j/"],"slug":"/works/posts/2024-06-15--001"},"frontmatter":{"title":"Circuit 적용 고민","tags":["circuit","Resilience4j"],"date":"2024-06-15","description":""}}},"pageContext":{"slug":"/works/posts/2024-06-15--001"}},"staticQueryHashes":[]}