
데이터베이스
OracleDB
오라클 데이터베이스 제품은 고객에게 세계 최고의 컨버지드 다중 모델 데이터베이스 관리 시스템인 오라클 데이터베이스는 물론 인메모리, NoSQL 및 MySQL 데이터베이스의 비용 최적화된 고성능 버전을 제공
사용 기업

마켓컬리

카카오페이

카카오엔터테인먼트

카카오모빌리티

카카오뱅크

네이버웹툰

쏘카

11번가

엠큐닉

비바리퍼블리카

SK플래닛

엔터플

하나투어

사람인에이치알

지마켓

SK텔레콤

사미텍

오퍼스엠
더 보기
비바리퍼블리카
우리는 어떻게 해외주식 서비스 안정화를 이뤘는가
안녕하세요, 토스증권 Server Developer 김광훈입니다. 제가 근무하고 있는 해외주식 플랫폼 팀은 미국 주식을 중심으로 해외 주식 원장을 담당하고 있어요. 원장이란 증권 서비스에서 가장 주요한 영역 중 하나이며, 금융거래를 기록하는 장부를 말해요. 저희 팀에서는 고객의 주문, 자산, 권리 그리고 종목 정보 관리와 환전까지 해외주식 서비스 제공에 필요한 모든 거래와 정보들을 원장에 기록하는 개발과 운영을 하고 있어요.이번 글에서는 저희 팀이 외부 브로커와 통신하고 있는 해외 주식 서비스를 안전하게 운영하기 위해 고민했던 내용을 공유하려고 합니다.먼저, 미국 주식 매매 아키텍처를 같이 살펴볼게요. 사용자가 토스증권에서 매매 요청을 하면 현지 브로커로 요청을 보내고 브로커는 현지 미국 거래소에서 매매를 체결하고 응답을 보내는 구조입니다. 브로커라는 용어가 생소할 수 있는데요, 이름 그대로 주식 매매를 현지에서 처리를 해주는 역할을 하는 회사에요. 미국에서 직구를 할 때 중간에 상품을 현지에서 구매하고 한국으로 배송해주는 대행사와 비슷한 것이죠.브로커와 통신은 HTTP, FIX 두 가지 프로토콜을 사용하고 있어요. 메인으로는 FIX 프로토콜을 사용하고 있고, 브로커 요구사항에 따라 HTTP 를 부분적으로 사용하여 요청 보내고 있어요. 요청에 대한 응답은 최종적으로 Kafka나 SQS와 같은 큐를 사용하여 비동기로 처리하고 있어요.그럼 이제 토스증권에서 브로커와 통신하는 과정에서 어떤 문제가 왜 일어났는지 설명드릴게요. 아래 그림은 브로커 이슈로 문제가 된 상황 당시의 핀포인트 그래프입니다. 그래프를 보면 브로커 응답 시간이 조금씩 지연이 발생하였고, 지연된 주문들은 계속 대기하면서 쌓이게 되고 결국에는 5000ms 이상 응답이 걸리게 되면서 이슈가 발생한 것을 볼 수 있어요.문제의 원인은 크게 두 가지였어요.먼저 정규장 시작에 크게 뛰는 트래픽이었는데요. 아래 그래프는 주문 API 호출 건 수를 시간대별로 나타내고 있어요. 미국의 정규장 시작(22시30분)부터 호출 건 수가 급격히 증가하는 것을 볼 수 있어요. 해외주식 서비스 특성상 정규장 초반에 트래픽이 급격히 증가하고 최소 두 시간 정도는 지속돼요. TPS 를 정규장 시간과 아닌 시간을 비교해보면 20배 이상 차이가 나기에, 대부분의 운영 이슈는 정규장 오픈 초반에 발생할 수밖에 없어요.토스증권 사용자가 늘어나는 것도 문제의 원인이었어요.해외주식 주문 증가 추세를 보기 위해 주문 접수 API 요청을 월 별로 집계를 해보았어요. 아래 그래프를 보면 계속 주문 수는 증가하고 있는 추세를 볼 수 있어요. 오픈 초기 주문 요청량 대비 현재 요청량을 비교해보면 약 30배 넘게 증가한 것을 볼 수 있었습니다.서비스가 오픈하고 폭발적인 성장을 하게 되었고, 동시에 브로커도 함께 처리해야 하는 주문도 증가했어요. 그로 인하여 보이지 않았던 이슈들이 점차 수면 위로 올라왔고, 크고 작은 이슈들을 겪게 되었습니다.브로커와 통신 과정에서 이슈를 겪고 나서 팀에서는 통신 구간에 엔지니어링을 시작을 했고
grafana
kafka
mongodb
oracledb
11번가
전시 딜 내재화 프로젝트 회고: MongoDB 기반 데이터 구축과 API 개선 과정
안녕하세요, 11번가 전시서비스개발팀의 서장원입니다.전시 딜 내재화 업무를 맡아 진행했던 과정과 개선 작업이 갖는 의미에 대한 개인적인 회고를 공유해 보고자 합니다.내용 이해를 돕기위해, 기초적인 질문을 던져봅니다.• ‘딜’ 그리고 ‘내재화’ 라는게 무슨 뜻인가요?• 딜은 상품 판매를 위한 판촉행사라고 생각하면 쉽습니다. 예를 들어, 단 10일간! 사과 한 박스에 단돈 3만원!• 내재화는 외부 기술/데이터를 가져와서 우리만의 특성에 맞게 조정하고 직접 관리한다는 뜻입니다. 즉, 상품의 판촉행사 정보를 보여주는 영역에 필요한 정보는 우리 전시서비스개발팀에서 직접 구축하고 입맛에 맞게 최적화 시킨다는 뜻입니다.• 내재화하는 이유는 간단히 말해, 전시에 사용하는 딜 정보를 최적화 시켜서 더 쉽고 빠르게 유지 보수 하기 위함입니다. 아래 이미지에서처럼 이미 THOR 플랫폼 에서 전시에 사용하는 상품정보는 내재화(with MongoDB)가 완료된 상태였고 딜 정보(=행사정보)는 내재화하기 전 반정규화 테이블(with OracleDB)을 사용하고있는 상태입니다. 다시 말해, [행사 판매 중인 상품] 정보를 가져오기 위해 상품정보는 MongoDB에서, 딜정보는 Oracle에서 조회하여 조합하고 있었습니다. 이러한 조회방식은 아래와 같은 단점을 지니고 있습니다.• 매 호출마다 두 번, 서로 다른 DB에 커넥션을 받아야 하는 낭비• 개발이나 이슈 발생 시 딜정보인지 상품정보인지에 구분하여 디버깅 필요(관리 포인트 중복)• 전시서비스개발팀에서 즉각 대응/수정 가능한 상품정보와 달리, 딜정보는 OracleDB 관리 팀에 요청하는 프로세스로 개발과정 단위 테스트와 즉각적인 대응에 어려움이를 반정규화 MongoDB로 전환하면 위의 단점을 극복하고 MongoDB의 장점을 그대로 살릴 수 있습니다.• 유연한 스키마로 구조 변경에 용이하여 개발 단위 테스트 및 개발속도 향상(OracleDB 변경 요청 프로세스가 사라짐)이러한 이유로 OracleDB 반정규화 테이블은 MongoDB 반정규화 테이블로 전환하게 되었고 THOR 프로젝트의 일환으로 이번에 딜 내재화를 이어 맡아서 진행하게 되었습니다.이제 기본적인 궁금한 것도 알았고 왜 하는 건지 이해했으니 다음으로 넘어가보겠습니다.MongoDB 상품 정보 + OracleDB 딜 정보를 각각 조회하고 가공하여 전시 API로 응답하는 방식.• 기존 방식의 구체적인 문제점• DB 트래픽 낭비 문제• 한 API 응답에서 두 개의 DB Pool Connection 을 맺는 추가 리소스• 대량 트래픽 발생시, 오라클 커넥션 풀이 부족한 경우가 발생했고 이는 지연 발생의 원인이 될 수 있음• 유지 보수 한계 (이슈 발생시 딜 정보 추적이 어려움)• 직접 관리하는 테이블이 아니다 보니, Oracle Serving 테이블의 생성 로직과 엮여있는 배치의 프로세스와 주기, 관계 파악 쉽지 않음• 이슈의 원인을 파악하기 위해 Oracle SP의 생성 로직과 갱신 주기 등을 매번 다른 팀에 문의하거나, MongoDB(상품 정보)와 OracleDB(딜 정보)를 모두 확인해야 합니다.→ Oracle Serving 테이블 참조를 제거하고 자체 구축한 MongoDB 컬렉션을 참조하도록 변경필요 지금부터는 좀 더 깊게 생각해봅니다기존에 딜 정보를 사용하는 API를 전수조사를 해보니 약 60개, 각 API 마다 사용처는 그보다 훨씬 많았습니다.다행히, 이미 잘 짜여진 구조와 적용된 패턴 덕분에, 일일이 60여개의 API의 코드를 모두 확인해봐야 할 필요는 적었습니다. 대부분의 API에서는 facade의 메서드(findProductsBy)만을 호출하여 필요한 정보를 조회하도록 캡슐화되어 있었고, factory에서 반환하는 하위 객체 별 조회 동작 구현부만 수정하면 되었기 때문입니다. 하지만 앞서 말했듯이, API자체가 많았고 이를 이용하는 사용처가 많다보니 로직상 숨겨진 의도와 데이터변환 조건등을 잘 챙겨야만 했습니다. API별 실제 사용되는 필드가 다르고 재변환로직이 조금씩 달랐기 때문에 필드 하나하나 신중한 접근이 필요해 보였습니다. 그래서 이를 정확히 검증하기 위해, 최종 작업에서 as-is VS to-be API 간 응답 값을 확인할 수 있는 validation 기능을 가진 프로세스를 추가하여 검증하는 것이 필요했습니다. 각 제품마다 딜은 [신청-승인-확정-진행-종료] 형태의 라이프사이클이 존재합니다. 그리고 라이프사이클이 진행되는 동안 딜 데이터는 계속 변하며, 이를 추적하고 빠르게 갱신 해주어야 합니다.하지만 AS-IS 모델의 Serving 데이터와 TO-BE 모델의 새로 구축한 Serving 데이터가 갱신되는 시점이 서로 다르다보니, AS-IS와 TO-BE 간에 데이터의 정합성을 비교할 때, 비교하는 시점에 따라 일시적인 다름인지, 잘못된 데이터인지 판단할 수 있어야 합니다. 특정 시점, 예를 들어 15:00:00에 판매 수량 데이터를 확인했을 때, A 상품은 15건, B 상품은 10건으로 표시되는 상황이라면, 세 가지 가능성을 염두하고 판단할 수 있습니다.• A 상품의 판매 수량 15건은 최신 갱신된 결과이지만, B 상품의 10건은 아직 갱신 이전의 값 일 수 있습니다. 이 경우, B 상품의 판매 수량이 다음 갱신을 통해 15건으로 변경된다면 TO-BE로의 전환이 잘 되었고 일시적인 다름이었음을 판단 할 수 있습니다.• 반대로, 만약 B 상품의 판매 수량 10건이 갱신 이후의 값이었다면, B상품의 판매 수량 결과값이 잘못된 것으로 판단할 수 있습니다.• 추가로, B의 10건이 정확한 값이었고, 오히려 A값이 잘못 계산되어왔던 것인지 추가로 확인해 볼 수도 있습니다. 예시 이외에도, 각 필드마다 갱신 조건이 있고 어떤 시점에 어떻게 변경될 수 있는지 알아야 검증 과정에서 정상적인 데이터인지 아닌지 판단 할 수 있습니다.또한, 딜의 라이프사이클뿐 아니라 상품의 라이프사이클도 영향을 미치기 때문에 딜 한정 수량이 품절되어도 상품 수량이 남아있는지 구분하여 전시 노출 해야하는 부분, 전시종료 여부는 딜의 기간종료인지 품절종료인지, 품절은 상품품절인지 딜품절인지를 구분하여 전시
mongodb
oracledb
CJ올리브영
신규 재고 시스템 구축을 위한 개발 여정
안녕하세요~ 올리브영에서 백엔드 개발을 담당하고 있는 인벤토리 스쿼드 올여우입니다. 오늘은 인벤토리 스쿼드에서 진행 중인 신규 재고 시스템 구축과 그 개발 여정을 소개하겠습니다.현재 올리브영의 시스템은 하루가 다르게 발전하고 있습니다. 기존 레거시 시스템들의 문제들을 파악해서 신규 아키텍처로 전환하는 작업들이 지속적으로 진행 중입니다.신규 재고 시스템 구축 역시 개선 작업의 일환으로 시작했습니다.현재 올리브영의 주요 데이터는 Oracle DB에 저장되고 있습니다. 하지만 수많은 시스템의 커넥션이 발생하면서 Oracle DB의 부하는 종종 문제가 되곤 합니다.그래서 Oracle에 집중된 DB 트래픽 분산과 MSA 전환을 목적으로 신규 재고 프로젝트가 시작됩니다. 더 나아가 복잡한 레거시의 프로세스를 개선하고 안정적인 재고 시스템 구축으로 유연한 비즈니스 확장을 목표로 합니다.'개편의 시작은 철저한 레거시 분석부터'라는 말이 있습니다. 프로젝트 방향을 정하기 위해 레거시 재고 프로세스 분석을 먼저 진행했습니다.재고는 매장을 비롯해서 온라인몰, 물류 등 다양한 영역의 데이터를 가지고 있습니다. 저희는 먼저 1차 구축 목표를 오프라인 매장 재고로 정했습니다.올리브영의 오늘드림 서비스가 매장 재고를 기반으로 하기 때문입니다.오늘드림은 온라인몰에서 고객이 상품을 구매하면, 오프라인 매장에서 배달대행을 통해 빠르게 배송해 주는 올리브영의 대표적인 O2O 서비스입니다. 아직 오늘드림을 사용해 보지 않으셨다면, 꼭 빠른 배송의 새로운 세계를 경험해 보시기 바랍니다.오늘드림 서비스를 위해서는 온라인몰에서 오프라인 매장 재고 조회가 필수입니다. 하지만 대규모 트래픽이 발생하는 온라인몰에서 매장 재고를 실시간으로 조회하면서 트래픽 이슈가 빈번히 발생했습니다.특히 트래픽이 높은 일부 서비스에서는 Cache, Batch 등 보조 수단으로 성능 이슈를 해소해 왔습니다. 저희의 목표는 분명합니다.신규 시스템을 구축하면 수 많은 기술 고민에 맞닥뜨리게 됩니다. 그리고 당면한 문제를 효율적으로 해결하기 위해서는 심도 깊은 노력과 선택이 필요합니다.아래는 프로젝트를 진행하면서 고민했던 몇 가지 기술입니다.매장 재고는 전국의 매장 POS, 물류 시스템, 관리자 등 여러 클라이언트에서 동시에 호출이 발생합니다. 따라서 데이터 동시성 제어는 필수입니다.먼저 Redis 라이브러리는 Redisson을 선택했습니다. 아래 기능 외에도 다양한 장점을 가지고 있습니다.• Java의 표준 컬렉션 인터페이스 구현으로 간단하게 데이터 연동 가능• 분산 락과 동기화 지원으로 분산 환경에서 자원 접근 조정 (데이터 일관성과 동시성 관리)• 비동기 및 반응형 프로그래밍 모델을 지원해서 고성능 애플리케이션 구축 가능동시성 제어를 위해 Redisson의 분산 락 인터페이스인 RLock을 활용했습니다. Pub/Sub 기반의 분산 락 메커니즘을 제공합니다.아래는 분산 락 구현을 위한 간단한 Kotlin 예제입니다.RedissonClient 객체는 Factory Pattern으로 정의했고, AOP로 분산
oracledb
연관 기술 스택

AWS AuroraDB

AWS MariaDB

MySQL

PostgreSQL