안녕하세요. 올리브영 선물/기프트카드 스쿼드에서 백엔드 개발을 담당하고 있는 기프트데이입니다.
여러분은 선물에 대해 어떻게 생각하시나요?
선물은 마음을 전하고, 기쁨을 나누며, 순간을 특별하게 만드는 좋은 방법입니다.
요즘에는 편리한 선물하기 기능 덕분에 언제 어디서든 따뜻한 마음을 전할 수 있게 되었습니다.
올리브영에서는 소중한 분들께 감사와 따뜻한 마음을 전할 수 있도록 선물하기관을 운영하고 있습니다.
선물하기관은 고객이 선물하기에 적합한 상품을 쉽게 찾을 수 있도록 설계된 특별한 공간입니다.
다양한 상품 목록과 맞춤형 큐레이션을 제공하여, 모바일 올리브영 홈에서 선물하기 아이콘을 클릭하면 선물하기관을 만나볼 수 있습니다.
저희 스쿼드는 선물하기관을 더욱 편리하고 빠르게 이용할 수 있도록 개편을 진행했습니다.
이제 올리브영의 선물하기관 개편에 대해 자세히 소개해 드리겠습니다.
왜 선물하기관을 개편하려고 했나요?
기존 선물하기관은 성능 문제로 인해 고객들이 불편을 겪는 경우가 잦았습니다.
앱에 접속했을 때 빈 화면이 오래 보이면, 서비스에 문제가 있다고 느끼지 않으신가요?
특히 이벤트 기간에는 화면이 빈 상태로 노출되는 '백화 현상' 이 자주 발생하여,
저희 스쿼드에서는 성능 문제 해결을 최우선 과제로 삼고 원인 분석을 시작했습니다.
주요 문제를 정리하면 다음과 같았습니다.
- DB 자원 과다 사용으로 인한 성능 저하: 페이지 렌더링 시 DB 호출에 크게 의존해, 사용자 수가 몰리는 시간대에는 DB 리소스 부족과 속도 저하 문제가 발생했었습니다. 일부 페이지에는 Redis 캐시를 적용해 개선했지만, 대부분의 페이지는 여전히 실시간 DB 호출에 의존하고 있었습니다. 이로 인해 트래픽이 급증하는 이벤트나 프로모션 기간 동안 사용자 경험에 불편을 주었습니다.
- 일 단위 배치 작업으로 인한 정보 업데이트 지연: 기존 선물하기관 데이터는 일 단위 배치 작업을 통해 업데이트 되고 있었습니다. 이로 인해 상품 가격 변동이나 품절 상태가 실시간으로 반영되지 않아, 고객이 상품 상세 페이지로 이동해야 최신 정보를 확인할 수 있는 불편이 있었습니다.
- 배치 작업의 복구 절차 미흡: 앞서 언급한 일 단위 배치 작업에서는 오류 발생 시 자동화된 복구 절차가 마련되어 있지 않았습니다. 이는 오류 발생 시 자동 복구 절차가 마련되어 있지 않아 담당자가 수동으로 데이터를 재 처리해야 했고, 이로 인해 고객에게 오류 데이터가 노출되거나 휴먼 에러 발생 가능성도 존재했습니다.
이러한 이슈들은 서비스 신뢰도에 부정적인 영향을 줄 수 있다고 판단했습니다.
선물하기관은 어떻게 개편되었나요?
올리브영의 전시 전략과 선물하기 기능이 따로 운영되면서, 사용자 경험을 개선하고 서비스의 일관성을 유지하기 위해 두 기능을 통합할 필요가 있었습니다. 통합이 필요했던 사유는 위와 같습니다.
- 일관된 사용자 경험 제공: 전시 전략과의 통합을 통해, 선물하기관 이용 시 올리브영의 다른 서비스와 일관된 경험을 제공할 수 있어야 했습니다.
- 효율적인 자원 관리: 서비스가 동일한 전시 전략을 따르도록 해, 전체 트래픽 증가 상황에서도 안정적인 성능을 유지할 수 있게 해야 했습니다.
- 데이터 동기화: 전시 전략과 통합하여 선물하기관과 다른 전시 페이지 간의 데이터 동기화를 원활히 함으로써 최신 정보 제공과 실시간 반영이 가능해야 했습니다.
- 유지보수 효율성 강화: 동일한 전략을 기반으로 개발하여 신규 기능 개발 및 유지보수의 효율성을 높이고 오류 발생 시 신속하게 대응할 수 있도록 만들어야 했습니다.
올리브영 전시 전략을 바탕으로, 선물하기는 리플렉션 기법을 사용하여 새로운 기능 추가나 서비스 방향에 따라 신속하게 개발하고 적용할 수 있도록 했습니다.
아래의 불편한 점을 개선하기 위해 해당 기법을 적용하기로 하였습니다.
- @CircuitBreaker 애너테이션과 @Cacheable 애너테이션을 선언하고 연관된 값을 일일히 설정해야 했습니다.
- 스프링에서 관리하는 캐시 매니저를 사용하여 레디스 캐시명과 TTL 등의 설정이 서로 다른 위치로 분리되어 파편화되어 있었습니다.
- 키값이나 fallback을 지정할 때 "문자열"을 사용하여 IDE에서 문제를 검출하기 어려웠고 변경 시 실수 확률이 높아졌습니다.
해당 불편한 점을 개선하고, 리플렉션을 사용하여 위와 같은 이점을 얻을 수 있었습니다.
- Cache Stampede 방지를 위한 로직 등을 단일 포인트에서 공통로직으로 제어하여, 쉽게 개선할 수 있도록 하였습니다.
- 파라미터 처리에 AOP를 활용하여, 개발자가 비즈니스 로직에 집중할 수 있도록 이점 제공
해당 코드와 같이 커스텀 어노테이션을 바탕으로 전시 전략 바탕 아래 선물하기 서비스에 맞춘 전시 전략을 세울 수 있었습니다.
@CircuitBreaker(
name = "giftCircuitBreaker",
fallbackMethod = "fallbackGiftVersion"
)
@Cacheable(
cacheManager = "giftManager",
value = "gift:Page",
key = "{#giftPageNumber}",
unless = "#result == null or #result.isEmpty()"
)
override fun fetchGiftVersion(
giftPageNumber: Long
): GiftReturnDto {
// 로직 실행
}
@GiftCaching
과 @GiftCachingKey
어노테이션은 스프링 AOP와 Kotlin 리플렉션을 활용하여 캐싱 기능을 구현한 커스텀 어노테이션이며, 설계 과정과 발생했던 이슈를 해결해나간 자세한 이야기들은 2부에서 다룰 예정입니다.
@GiftCaching(
gnbRedisCacheInfo = GIFT_PAGE_KEY,
dateTimeKeySuffix = LOCAL_DATE
)
override fun fetchGiftVersion(
@GiftCachingKey giftPageNumber: Long
): GiftReturnDto {
// 로직 실행
}
선물하기 개편에 적용된 올리브영의 전시 전략은 아래 기술 블로그 글들을 참고해 주세요.
개편을 통해 무엇이 달라졌나요?
이번 개편은 선물하기관의 성능 및 신뢰성을 개선하는 데 중점을 두었습니다. DB 리소스 점유 문제와 실시간 정보 반영, 오류 데이터 문제를 해결함으로써 고객분들이 보다 빠르고 정확하게 상품 정보를 확인하고 선물하기 기능을 이용할 수 있게 되었습니다.
마치며
이번 개편을 통해 선물하기관은 더 빠르고 정확한 정보를 제공하는 서비스로 개편되었습니다.
1부에서는 기존 선물하기관의 문제점과 개편의 필요성, 개선된 상태를 소개해 드렸습니다.
2부에서는 개편 과정의 세부 기술과 구현 과정을 더 자세히 다룰 예정입니다.
많은 관심과 기대 부탁드립니다!
감사합니다.