배달의민족 Flutter 도입과 아키텍처 설계 교훈

배달의민족은 주문접수 채널에서 Flutter를 도입하여 멀티 플랫폼 대응력을 높이고, Clean Architecture를 통해 효율적인 코드 관리를 실현했습니다. 이 글에서는 Flutter 도입과 아키텍처 설계의 과정에서 얻은 교훈을 바탕으로, 변화하는 비즈니스 요구에 맞추기 위한 혁신적인 접근을 소개합니다. 또한, 이러한 경험이 다른 기업이나 개발자에게도 유용한 전략이 될 수 있도록 공유하고자 합니다. Flutter 도입으로 인한 혁신적인 변화 배달의민족은 Flutter 도입을 통해 플랫폼 전환과 유지보수 측면에서 큰 혁신을 이루었습니다. 기존의 Windows, Android, iOS 플랫폼에 추가하여 macOS와 다양한 Android 디바이스로까지 확장할 필요성을 느꼈습니다. Flutter의 도움으로 단일 코드베이스에 의해 멀티 플랫폼을 동시에 지원할 수 있게 되었고, 이를 통해 개발자 수를 줄이고 생산성을 향상시킬 수 있었습니다. 개발자들은 각 플랫폼에 대해 반복적으로 구현할 필요가 없어졌고, 버그 수정이나 기능 변경 시에도 이전에 비해 적은 시간에 모든 플랫폼에 적용할 수 있게 되었습니다. Flutter의 도입은 크로스 플랫폼 반응형 UI 구현을 가능하게 하여, 사용자 경험의 일관성을 높였습니다. 이제 파트너들은 다양한 OS 환경에서 동일한 경험을 하게 되므로, 학습 비용도 줄어들고, 혼란이 줄어드는 장점을 경험하고 있습니다. 이러한 변화는 단순히 기술적인 접근방식이 아닌, 사업의 방향성을 전환하는 계기로 작용했습니다. 파트너사들이 원하는 효율적인 주문 관리 시스템을 제공하기 위해, 기존의 네이티브 아키텍처에서 벗어나 새로운 기술 스택으로 과감히 옮겨갔습니다. Firebase와 같은 클라우드 서비스를 활용하여 실시간 데이터 업데이트와 동기화가 가능하게 되었고, Flutter의 강점을 극대화하여 사용자 친화적인 UI/UX도 구현됐습니다. 이로 인해 즉각적인 피드백을 수렴할 수 있는 구조가 마련됐습니다. 결국 Flutter의 도입은 배달의...

Redis 신규 연결 증가 원인 분석 및 해결방법




1. Redis 신규 연결 생성 원인 분석

Redis 신규 연결이 지속적으로 증가한 이유는 여러 요인에 기인했습니다. 먼저, Lettuce 기반의 파이프라이닝(Pipelining) 기능이 핵심 원인이었습니다. RedisTemplate의 executePipelined() 메서드는 여러 명령을 병렬로 처리하기 위해 별도의 커넥션을 생성합니다. 이 과정에서 기본 커넥션 풀이 존재하더라도, 파이프라이닝의 특성상 별도의 연결이 새로 열리게 됩니다.

특히 사용자 요청이 집중되는 자정 무렵에도 신규 커넥션 수가 급증한 이유는, 해당 파이프라이닝이 트래픽 피크 시간대에 반복적으로 실행되었기 때문입니다. 즉, 명령어를 일괄 처리하는 과정에서 기존 연결 재사용이 아닌 새로운 커넥션 생성이 계속 이어진 것입니다.

두 번째 요인은 커넥션 풀의 LIFO(Last In First Out) 전략이었습니다. LIFO는 최근 사용된 커넥션부터 재사용하기 때문에, 사용되지 않는 커넥션은 IDLE 상태로 남게 됩니다. 트래픽이 몰릴 경우 이 IDLE 커넥션은 제거되거나 새로운 커넥션 생성으로 이어질 수 있습니다.

AWS ElastiCache 환경에서는 기본적으로 100초 이상 IDLE 상태의 커넥션을 자동으로 제거합니다. 따라서, IDLE 커넥션이 폐기되고 새로운 연결이 반복적으로 생성되는 구조적 문제가 발생했습니다. 결과적으로 커넥션 끊김 및 재연결 현상이 지속되며, 신규 연결 수가 급격히 늘어나는 현상이 나타났습니다.

이 과정을 통해 Redis 관련 메트릭을 지속적으로 모니터링하고, 트래픽 특성에 맞는 커넥션 설정을 정교하게 조정해야 함을 인식하게 되었습니다.

2. Redis 신규 연결 문제 해결 방법

신규 연결 증가 문제를 해결하기 위해 두 가지 접근 방식을 적용했습니다.

첫 번째는 커넥션 풀 전략 변경입니다. 기본 LIFO 방식을 FIFO(First In First Out)로 전환하여, 이전에 반납된 커넥션을 우선 재사용하도록 구성했습니다. FIFO 방식은 오래된 커넥션부터 순차적으로 재사용하기 때문에, IDLE 상태로 장시간 남아 있는 연결이 최소화됩니다.

예를 들어, commons-pool2를 사용하는 경우 poolConfig.setLifo(false) 설정을 통해 FIFO 전략으로 동작하게 할 수 있습니다. 이 변경을 통해 커넥션이 자주 폐기되지 않고, 장기간 안정적으로 재사용되며, Redis 서버의 연결 요청 부하를 줄이는 효과가 확인되었습니다.

두 번째는 IDLE 커넥션 관리 설정입니다. 불필요하게 오래 유지되는 커넥션을 주기적으로 정리하기 위해, minEvictableIdleDurationtimeBetweenEvictionRuns 값을 조정했습니다. 예를 들어 두 값을 각각 30초로 설정하면, 30초 이상 사용되지 않은 커넥션은 자동으로 제거되어 풀의 효율성이 유지됩니다.

이 설정은 커넥션 풀 내부에 쌓이는 불필요한 IDLE 연결을 줄이고, Redis 서버 자원의 낭비를 방지하는 효과를 가져왔습니다. 또한, 애플리케이션에서 커넥션 재활용이 효율적으로 이루어져 클러스터의 응답 속도가 안정적으로 유지되었습니다.

요약하자면, LIFO → FIFO 전략 변경과 IDLE 커넥션 정리 설정을 병행하여 Redis 신규 연결 폭증 문제를 실질적으로 완화했습니다.

3. Redis 신규 연결 문제 해결의 성과

설정 변경 이후, 신규 커넥션 지표가 뚜렷하게 안정화되었습니다. 특히 트래픽 피크 시간대 이후에도 신규 연결이 급증하는 현상이 사라졌습니다. 서버 리소스 사용률이 개선되었고, 전체적인 커넥션 유지 비용이 크게 감소했습니다.

Redis 클러스터 모니터링 결과, 연결 수와 처리 지연이 이전 대비 약 30% 이상 감소했으며, 클라이언트 측 재연결 이벤트도 크게 줄어든 것으로 확인되었습니다.

또한, 본 문제 해결 과정을 통해 Spring Data RedisElastiCache 간의 세부 동작 차이를 깊이 이해할 수 있었습니다. Lettuce 커넥션의 특성과 AWS의 세션 유지 정책을 함께 고려해야 한다는 점이 명확해졌습니다.

앞으로는 Redis의 연결 관리와 자원 최적화를 위해 정기적인 모니터링과 세부 설정 검토를 지속할 예정입니다. 이번 경험은 동일한 문제를 겪는 개발자들에게 실질적인 참고 자료가 될 것입니다.

결론: 안정적 Redis 운영을 위한 교훈

Redis 신규 연결 증가는 단순한 설정 문제가 아닌, 커넥션 관리 전략의 구조적 이슈였습니다. FIFO 기반 풀 전략과 IDLE 관리 정책을 적용함으로써 시스템 안정성과 성능 모두를 개선할 수 있었습니다.

결국 Redis 성능 최적화는 ‘지속적인 관찰과 점진적 조정’에서 비롯됩니다. 각 환경의 트래픽 패턴을 분석하고, 적절한 풀 전략을 도입해 안정적 운영을 실현하는 것이 중요합니다.


이 블로그의 인기 게시물

우아한형제들의 실시간 알림 혁신: SSE(Server-Sent Events)로 이룬 효율성과 안정성

우아한 디버깅 툴 개선으로 QA 업무 효율화

물어보새의 진화와 지식 공유 확장