데이터베이스
Redis
1밀리초 미만의 응답 시간을 구현하는 인메모리 Key-Value 구조의 데이터베이스
StackOverflow 질문 수: 25706
Github Stars : ★ 66852
사용 기업
트렌비
슈퍼브에이아이
플렉스
렌딧
토스랩
큐피스트
드라마앤컴퍼니
딜리셔스
에이블리
파운트
식스샵
드림어스컴퍼니
숨고
스푼
바로고
크몽
디셈버앤컴퍼니
직방
더 보기
무신사
재고 서비스의 진화와 혁신: 지속적인 개선을 통한 안정성과 확장성 강화
안녕하세요.저는 무신사 재고 서비스의 백엔드 개발을 담당하고 있는 백승호입니다.이 포스트에서는 재고 시스템의 개선을 위한 구조적 변화와 다운타임을 최소화하기 위해서 정기적인 유지보수, 백업 시스템, 고가용성(HA) 아키텍처, 재난 복구 계획 등의 전략을 세우고 개선하는 것에 대해 소개하고자 합니다.재고 서비스의 과거와 변화재고 관리 서비스는 기업의 운영에서 핵심적인 역할을 담당하며, 특히 고객 만족도를 직접적으로 영향을 미치는 요소로 자리잡고 있습니다. 초기에는 재고 관리가 다소 소홀히 다루어져 왔으며, 운영자들은 창고에서 직접 재고를 파악하고, 수기로 어드민 시스템에 재고 입고 및 출고 정보를 입력하는 방식으로 진행했습니다. 이러한 수작업 중심의 관리 방식은 효율성이 낮고 오류 발생 가능성이 높아, 재고의 정확성 유지와 신속한 처리가 어렵다는 문제를 안고 있었습니다. 출고 바코드 관리 또한 수동으로 이루어져, 재고 관리의 중요성은 상대적으로 낮게 평가되었습니다.재고 서비스의 초기 운영초기 재고 관리 시스템은 모놀리식 PHP-MySQL 구조로 운영되었고, 재고 처리는 여러 서비스에 분산되어 있었으며, 이로 인해 유지보수가 어려운 구조를 띄었습니다. 운영자들이 수작업으로 재고를 관리하고 출고 바코드를 입력하는 방식은 오류 발생의 위험을 높였고, 빠르게 변화하는 시장 환경에 신속히 대응하기 어려웠습니다. 특히, 수동 처리로 인해 품절 취소율이 높아져 고객 서비스에도 부정적인 영향을 미쳤습니다.이러한 상황 속에서 재고 서비스의 개편 필요성이 대두되었습니다. PM인 이선화님과 서비스 운영과 개발을 하던 황두리님, 지금은 퇴사했지만 당시 함께 일하던 함지선님과 함께 이러한 변화에 대응하기 위해 재고 서비스의 전반적인 개편 작업을 시작하게 되었습니다.ERP 도입과 재고 관리의 변화ERP 시스템의 도입은 재고 관리 방식에 큰 변화를 가져왔습니다. 재고 관리의 중요성이 부각 되었고, 물류 운영, 회계, 매장 등 여러 부서에서 사용되던 재고 관리 방식이 ERP 시스템에 통합되어 재고의 정확성과 일관성을 확보할 필요성이 생겼습니다. 재고 도메인은 주문 서비스에서 분리되어 독립된 팀으로 관리 되었으며, 재고 서비스는 물류와 함께 더욱 중요한 역할을 맡게 되었습니다.재고 서비스의 개편과 주요 기술 도입재고 서비스의 구조적 변화재고 서비스의 개편은 점진적인 코드 이전과 신규 재고 서비스 도입으로 시작되었습니다. 초기에는 모든 재고 처리 로직이 다양한 서비스에 산재되어 있었기 때문에, 이 로직들을 일원화하고 단일 애플리케이션에서 여러 느슨하게 결합된 독립적인 서비스로 전환하는 작업이 필요했습니다. 이 작업은 상당한 리스크를 동반했지만, 재고 처리의 일관성을 확보하기 위해서는 반드시 필요한 과정이었습니다.ERP 시스템 도입ERP 시스템의 도입은 재고 관리 방식을 완전히 바꾸었습니다. ERP 시스템은 매입 및 오프라인 재고의 입출고를 자동화하여 실물 재고와 시스템상의 재고 간의 오차를 0.03% 이내로 줄이는 데 기여했습니다. 또한, 재고 관리 시스템은 물류 센터와
kafka
redis
지마켓
Redis Vs Mongo DB By Item View Count (이 상품 몇명이 보고 있어요)
안녕하세요 저는 VI Engineering 팀 김윤제입니다.Gmarket Mobile Web Vip(View Item Page = 상품 상세)를 담당하고 있는 Backend Engineer 입니다.이번 블로그에서는 개인적으로 상품 상세 페이지에 넣고 싶었던현재 이 상품 몇 명이 보고 있어요 기능을 혼자 공부하며 개발해보는데 있어서어떻게 설계를 해야 최적의 성능을 낼 수 있을지 고민하였고 그 과정을 설명드리려고 합니다.자세한 내용은 아래에서 살펴보도록 하겠습니다.동작 과정요구사항은 다음과 같았습니다.상품 별로 중복되지 않은 사용자가 몇 명이 보고 있는지 실시간으로 집계하여 보여준다.현재 이 상품 몇 명이 보고 있어요 기능의 동작 과정은 다음과 같습니다.사용자가 웹 또는 앱을 통하여 상품 상세 페이지에 접속한다.상품 상세 서버에서는 상품 번호와 사용자 인식 정보를 데이터베이스에 저장한다.상품 상세 서버에서는 데이터베이스에서 해당 상품번호에 몇 명의 사용자가 있는지 검색한다.데이터베이스에서 검색한 사용자 수를 현재 사용자에게 반환한다.접속 중인 사용자 (웹 또는 앱)는 주기적으로 상품 상세 서버에 현재 몇명이 이 상품을 보고 있는지 요청한다.사용자가 이탈 (상품을 벗어남)하면 데이터베이스에서 해당 상품번호에 저장된 해당 사용자 인식 정보를 제거합니다.5번에서 주기적으로 상품 상세 서버에 요청을 해야 하는데 웹 / 앱이 동일한 방법을 써야 관리하기가 쉬울 것 같다는 점에서웹소켓 / 소켓이 아닌 API 요청을 받는 게 좋다고 생각했습니다.실시간으로 쏟아지는 트래픽 속에서 집계를 해야 하는 상황이라 RDB로는 성능이 안 나올 것 같아 NoSql 데이터베이스를 선택했습니다. 이제 Nosql 데이터베이스 중 Redis와 MongoDb 사이에서 선택해야 했는데요.아래에서 각 데이터베이스 별로 장단점을 알아보도록 하겠습니다.RedisRedis란?Redis는 Remote Dictionary Server의 약자로 키(Key) - 값(Value) 쌍의 해시 맵과 같은 구조를 가진 비관계형(NoSQL) 데이터베이스 관리 시스템(DBMS)입니다.Redis는 오픈 소스 기반으로인-메모리(In-memory) 데이터 구조 저장소로 메모리에 데이터를 저장합니다.따라서 별도의 쿼리문이 필요로 하지 않고, 인-메모리에 저장되기 때문에 상당히 빠른 속도로 처리할 수 있습니다. Redis의 특징 및 장단점1. 성능모든 Redis 데이터는 메모리에 저장되어 대기 시간을 낮추고 처리량을 높입니다.평균적으로 읽기 및 쓰기의 작업 속도가 1ms로 디스크 기반 데이터베이스보다 빠릅니다.2. 유연한 데이터 구조Redis의 데이터는 String, List, Set, Hash, Sorted Set, Bitmap, JSON 등다양한 데이터 타입을 지원합니다.따라서, 애플리케이션의 요구 사항에 알맞은 다양한 데이터 타입을 활용할 수 있습니다.3. 개발 용이성Redis는 쿼리문이 필요로 하지 않으며, 단순한 명령 구조로 데이터의 저장, 조회 등이 가능합니다.또한, Java, Python, C, C
mongodb
redis
여기어때컴퍼니
[DevOps] GitLab 버전 업그레이드는 계속 된다.
안녕하세요. 여기어때컴퍼니 DevOps팀 루카스입니다. 저희 팀은 여기어때컴퍼니 Tech 조직내 개발자들의 업무 몰입을 위한 개발 환경과 체계를 만들어가는 조직으로 조직별로 상이한 개발 환경을 통합하고 운영하고 있습니다.Photo by Pankaj Patel on Unsplash이번에 다룰 주제는 팀에 합류하고 나서 첫 번째 작업이었던 GitLab 버전 업그레이드 과정입니다. GitLab은 소프트웨어 개발자에게 강력한 기능을 제공하는 형상 관리 플랫폼입니다. 하지만 최신 기능을 활용하고 보안 업데이트를 적용하기 위해서는 정기적으로 업그레이드를 해야 합니다. 우리 조직내 개발자들이 더욱 안전한 환경에서 신규 기능을 활용 할 수 있도록 저희팀은 GitLab을 업그레이드 하기로 결정하였습니다.1. 사전 준비1–1. Upgrade Path 확인GitLab의 현재 설치된 버전과 호환성을 확인합니다. 이런 경우에는 GitLab의 공식 문서에서 지원되는 업그레이드 경로를 확인하는 것이 좋습니다. https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/ 이 URL에서 현재 사용 버전, OS, 업그레이드 대상 버전 등을 선택하면 어떤 버전의 순서로 업그레이드를 해야하는지 알려 줍니다. 버전 변경에 대한 큰 변동사항에 대해서도 미리 경고해 줍니다.여기어때에서는 GitLab 15.1.6을 사용하고 있었으며, 16.9.4 버전으로 업그레이드를 진행하였습니다.15.1.6에서 16.9.4로 Upgrade Path는 다음과 같습니다.15.1.6 → 15.4.6 → 15.11.13 → 16.1.6 → 16.3.7 → 16.7.7 → 16.9.1Upgrade Path의 경고 마지막 부분에 Expiring Access Token 부분이 있었습니다. Gitlab PAT 관련 문서를 통해 추가로 확인해 보았습니다. https://docs.gitlab.com/ee/user/profile/personal_access_tokens.htmlNever Expire로 발급된 Personal Access Token은 모두 GitLab 16.0으로 업그레이드한 날짜로부터 1년 후에 만료 되도록 강제로 변경 됩니다. CI/CD Pipeline 자동화를 위해서 사용되는 토큰인 경우, 만료시 장애를 일으킬 수 있는 원인이 되기 때문에 사전 작업을 진행합니다.1) 기존 버전의 Personal Access Token의 만료일이 Never인 Token을 리스트업합니다.$ curl -s --header "PRIVATE-TOKEN: ${your_access_token}" "https://${gitlab url}/api/v4/personal_access_tokens" | jq '.[] | {id, expires_at}'결과 샘플은 다음과 같습니다.{ "id": 154, "name": "GITLAB-PAT", "expires_at": "2025-06-25"}your_access_token 은 admin 권한을 갖는 계정의 Personal Access
docker
gitlab
postgresql
redis
SK텔레콤
다양한 시각에서 바라본 Redis (2) 비교
두 번째 글에서는 다양한 친구들과 비교해 본 Redis라는 주제를 다룹니다.mysql, memcached등 redis와 자주 비교되는 친구들이죠.첫 번째 글에서 소개된 개념들이 두 번째 글에서도 중요하게 다뤄지므로, 첫 번째 글을 읽고 오시면 좋습니다.첫 번째 글에서 다룬 내용이기 때문에 링크로 대체하겠습니다.SQL DB는 두 가지 특징을 가지고 있습니다.• None 데이터는 정해진 데이터 스키마에 따라 테이블에 저장된다.• None 데이터는 관계를 통해 여러 테이블에 분산된다.No SQL에는 3가지 유형이 있습니다.키와 값으로 이루어진 데이터베이스입니다.이때 key 값은 unique한 값이어야 하고, 값에는 모든 데이터 타입을 허용합니다.Key-Value Database와 같이 Key-Value 형태로 이루어져 있습니다.하지만 Document Database는 Value에 문서를 저장합니다.데이터를 그래프 형태로 저장하고 관리하는 데이터베이스입니다.노드(Node)와 엣지(Edge)라는 개념을 기반으로 데이터를 표현합니다.이때 노드는 개체(entity)를 나타내고, 엣지는 개체들 간의 관계를 나타냅니다.• None 관계는 각 데이터를 중복없이 한 번만 저장• None 덜 유연함. 데이터 스키마를 사전에 계획하고 알려야 함. (나중에 수정하기 힘듦)• None 관계를 맺고 있어서 조인문이 많은 복잡한 쿼리가 만들어질 수 있음• None 대체로 수직적 확장만 가능함• None 스키마가 없어서 유연함. 언제든지 저장된 데이터를 조정하고 새로운 필드 추가 가능• None 데이터는 애플리케이션이 필요로 하는 형식으로 저장됨. 데이터 읽어오는 속도 빨라짐• None 수직 및 수평 확장이 가능해서 애플리케이션이 발생시키는 모든 읽기/쓰기 요청 처리 가능• None 유연성으로 인해 데이터 구조 결정을 미루게 될 수 있음• None 데이터가 여러 컬렉션에 중복되어 있기 때문에 수정 시 모든 컬렉션에서 수행해야 함 (SQL에서는 중복 데이터가 없으므로 한 번만 수행이 가능)• None• None 실행 결과가 모두 성공하거나 실패하는 성질입니다.• None• None 트랜잭션 전후에 트랜잭션 성공 여부와 상관없이 각 데이터 정합성에 문제가 없음을 의미합니다.• None• None 한 트랜잭션이 다른 트랜잭션에게 영향을 받지도 주지도 않는 성질입니다.• None• None 커밋된 데이터는 데이터베이스에 장애가 발생해도 사라지지 않는 성질입니다.MySQL은 InnoDB를 통해 ACID를 보장합니다.MySQL은 START TRANSACTION, COMMIT, ROLLBACK 명령어를 통해 원자성을 보장합니다.또한 AUTOCOMMIT을 활성화시켜 각 SQL문을 자동으로 개별 트랜잭션으로 처리되게 해 원자성을 보장할 수 있습니다.MySQL은 InnoDB의 더블라이트 버퍼와 충돌 복구를 통해 데이터를 보호해 일관성을 보장할 수 있습니다.MySQL은 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 격리 수준을 통해 격리성을 보장합니다.MySQL은 InnoDB 더블라이트 버퍼, innodb_flush_log_at_trx_commit, sync_binlog와 같은 설정 및 배터리 백업 캐시, UPS 등의 하드웨어 구성으로 이를 지원합니다.Redis는 자체 트랜잭션 명령을 통해 원자성을 보장합니다.트랜잭션 블록의 시작을 표시합니다.EXEC가 실행되기 전까지는 명령을 대기열에 추가합니다.대기열에 대기 중인 모든 명령을 실행하고 연결 상태를 정상으로 복원합니다.트랜잭션이 시작된 뒤 대기열에 쌓인 명령어가 실행되지 않고 트랜잭션을 종료합니다.먼저 WATCH를 사용하지 않은 경우를 보겠습니다.• None Telnet 환경에서 NEWJEANS라는 키를 생성한 후 VALUE에 ETA를 할당합니다.• None MULTI 명령를 통해 트랜잭션을 시작합니다.• None EXEC 명령어를 통해 대기열에 있던 명령을 실행시킵니다.• None GET을 통해 NEWJEANS라는 키에 할당된 VALUE 값을 조회합니다.Redis의 트랜잭션 중에는 다른 클라이언트의 명령을 실행시킬 수 있습니다.그래서 Redis의 트랜잭션은 격리성을 보장하지 않습니다.그 대신 Redis는 EXEC를 실행시켰을 때 큐에 있는 모든 명령이 중간에 다른 클라이언트의 명령 없이 연속적으로 실행 돼 원자성을 가지고 있습니다.클라이언트 1이 트랜잭션을 시작한 후, 클라이언트 2에서 NEWJEANS에 HYPEBOY라는 값을 할당했습니다.이때 트랜잭션이라도 다른 클라이언트가 개입을 할 수 있기 때문에 NEWJEANS의 Value가 변경된 것입니다.밑의 링크에 자세히 나와있습니다! (파이프라인 보시면 됩니다)Redis에서는 WATCH 명령을 통해 낙관적 락을 걸어줄 수 있습니다.클라이언트 1에서 WATCH 명령을 통해 NEWJEANS라는 KEY를 감시합니다.트랜잭션이 시작된 후, STACKOVERFLOW라는 Key에 58이라는 Value를 할당합니다.그리고 트랜잭션을 종료하면서 충돌이 있는지 확인을 합니다.이때 트랜잭션이 종료되기 전에 클라이언트 2에서 클라이언트 1에서 감시 중이었던 NEWJEANS라는 키에 값을 할당합니다.그러므로 충돌이 발생했습니다.충돌이 발생했으므로 트랜잭션이 실패합니다.STACKOVERFLOW라는 키를 조회했을 때 nil이 나오는 나오는 이유입니다.UNWATCH 명령을 통해 WATCH로 감시하고 있는 KEY를 해제할 수 있습니다.UNWATCH를 한 후, KEY를 다른 클라이언트에서 변경해도 트랜잭션이 정상적으로 실행됩니다.+ Redis Transaction 중 에러가 발생한다면?1. 대기열에 추가할 때 에러가 발생한 경우 (존재하지 않는 명령을 실행시킨 경우)위 코드에서는 SETSSSS ERROR E와 같은 존재하지 않은 명령을 트랜잭션 안에서 실행했습니다.그 결과 EXECABORT Transaction discarded because of previous errors.라는 문구와 함께 트랜잭션이 실행되지 않습니다.2. 명령어 실행 과정에서 에러가 발생한 경우하지만, 대기열에
memcached
mysql
redis
연관 기술 스택
Memcached