이번 포스트에서는 제가 실제로 겪었던 Node.js 버전 차이로 인한 장애 사례와 이를 어떻게 대응하고 개선했는지를 정리해보려 합니다.
누군가에게는 비슷한 문제를 사전에 예방하는 데 도움이 되었으면 좋겠습니다.
장애 발생 배경
프로젝트에서 OneSignal 태그 API를 연동하는 작업을 진행하던 중, 개발 환경에서는 아무 문제없이 잘 작동하던 API가 운영 환경에서 주기적으로 서버가 죽는 현상이 발생했습니다.
초기에는 로직 오류나 외부 API 문제를 의심했지만, 로그를 살펴보며 원인을 좁혀나간 끝에 문제의 핵심은 Node.js의 버전 차이였습니다.
원인 분석
문제는 코드 내에서 사용한 fetch API였습니다.
- 개발 환경(Node 18): fetch가 기본 내장되어 있어 문제없이 작동.
- 운영 환경(Node 16): fetch가 내장되어 있지 않음 → 런타임에서 ReferenceError: fetch is not defined 발생 → 서버 크래시.
즉, 코드 자체는 문제 없었지만 운영 서버의 Node.js 버전에서는 fetch를 지원하지 않아 장애가 발생했던 것이죠,, 😭 😭
1차 대응: httpService로 긴급 대체
장애가 발생한 당시, 가장 빠르게 문제를 해결하기 위해 코드를 롤백해서 OneSignal API 호출하는 부분을 모두 제거했습니다.
그리고 fetch를 사용하는 부분을 NestJS에서 제공하는 HttpService로 빠르게 전환 후 hotfix로 수정했습니다.
// 기존
await fetch('https://api.onesignal.com');
// 수정
await this.httpService.axiosRef.post('https://api.onesignal.com', {});
이렇게 수정 후에는 더 이상 서버가 죽지 않았고, 장애는 일단락되었습니다.
2차 대응: Node.js 버전 업그레이드
정말 부끄럽고 기본이 부족한 이유이지만 이번 장애의 궁극적인 원인은 개발 서버 Node 버전과 운영 서버의 Node 버전의 싱크를 맞추지 않고 운영한 것에서 발생한 문제라고 생각하여서 장기적으로는 fetch뿐 아니라 다른 최신 기능도 사용할 수 있도록 운영 서버의 Node.js 버전을 18로 업그레이드해서 개발 서버 버전과 통일시켰습니다.
업그레이드 이후에는 fetch도 다시 사용할 수 있게 되었고, 개발 서버에서 발생하지 않는 문제가 운영 서버 전파되지 않도록 구성하였습니다.
3차 대응: ECS 배포 파이프라인 테스트 단계 추가
이번 장애를 계기로 배포 전 테스트 코드의 중요성을 다시 한번 느꼈습니다. 그래서 후속 조치로 ECS 배포 파이프라인에 테스트 코드 검증 단계를 추가했습니다.
배포 전에 코드가 현재 운영 Node.js 환경에서 문제없이 동작하는지 체크하도록 설정하여, 환경 차이로 인한 문제를 사전에 발견할 수 있도록 개선했습니다.
마무리하며
이번 장애는 기본중에 기본인,, 개발과 운영 환경을 일치 시키지 않는 말도 안 되는 문제에서 시작되었지만, 덕분에 시스템 안정성과 배포 프로세스를 더욱 견고하게 만드는 계기가 되었습니다.
환경 차이에 대한 고려, 빠른 롤백/우회 처리, 지속적인 테스트 자동화는 앞으로도 계속 챙겨야 할 중요한 부분이라는 것을 다시 느꼈습니다.
혹시 비슷한 환경에서 개발하고 계신 분이라면, 운영 환경의 Node.js 버전도 꼭 체크해 보세요 🥲
추가적으로 fetch 사용하려고 했던 이유는
- fetch 사용:
- fetch는 HTTP 응답 자체 (Response 객체)만 반환합니다.
const response = await fetch(url, options);
const { recipients, success } = await response.json(); // 바로 구조 분해 가능
- HttpService 사용:
- Axios는 AxiosResponse 형태로 응답
const response = await this.httpService.axiosRef.get(url, { });
const { recipients, success } = response.data;
{
data: {...}, // 실질적인 응답 JSON
status: 200,
statusText: 'OK',
headers: {...},
config: {...},
request: {...}
}
응답 데이터 구조가 더 단순하게 다가오기 때문에 사용하려고 했는데 이 여파가 장애로 이어지다니,,,
'아키텍처 고민' 카테고리의 다른 글
랜덤 문제 풀이 이거 간단하거 아니었네? (0) | 2025.03.27 |
---|---|
Android In-App Purchase RTDN(Real-time Developer Notifications) 개발기 (0) | 2025.03.14 |
iOS In-App Purchase와 Apple Server Notification(ASN) 개발기 (0) | 2025.03.14 |