올바른 데이터 저장소를 선택하고 운영하는 것은 애플리케이션의 성능과 확장성, 가용성과 신뢰성 등 여러 문제와 직접적인 연관을 갖는다.
전체 애플리케션을 하나의 통합된 패키지로 개발, 배포하는 방식.
소규모 프로젝트 같은 경우에는 모놀리틱 구조가 운영하기 쉽지만, 서비스의 규모가 확장되면 유지보수의 복잡도도 증가된다는 단점이 존재.
모듈간 의존성이 높다.
하나의 파트에서 리소스가 모자라서 그 부분만 확장을 시키고 싶어도 전체를 확장시켜야 한다.
출처: https://www.f5.com/company/blog/nginx/introduction-to-microservices
MSA는 독립된 각각의 모듈을 조립해 하나의 서비스를 만드는 아키텍처이다.
기능별로 작게 나뉘어진 서비스가 독립적으로 동작하는 서비스를 의미한다.
모듈간 의존성이 낮다. -> 운영 안정성이 향상된다.
하지만, 개발 및 운영에 있어 인원이 충분하지 않는 소규모 팀에서는 서비스 분리로 인한 관리 복잡도와 운영 부담이 증가되는 단점이 존재한다.
RDBMS 같은 경우에는 고정된 스키마를 가지고 있고, 테이블 간의 관계를 정확하게 규정하고 있다.
서비스의 규모가 커질수록 데이터를 추출하기 위한 쿼리가 복잡해진다.
관계 간의 복잡성 문제로 쿼리 성능에 이슈가 발생하며, 쿼리 성능을 향상 시키기 위해 쿼리, 인덱스, 테이블 구조를 자주 최적화 해야한다.
RDMS를 통해 데이터의 집약화를 이뤄 서비스를 구축하는 경우에는 RDBMS의 주기적인 최적화가 서비스 성능에 큰 영향을 미쳤다.
RDMS의 특성: ACID
- 원자성(Atomicity): 트랜잭션이 완벽하게 실행되거나 아예 실행되지 않음을 보장한다.
- 일관성(Consistency): 트랜잭션은 실행 전후로도 제약 조건을 만족시킴을 보장한다.
- 독립성(Isolation): 트랜잭션 실행 시 다른 트랜잭션의 개입이 없음을 보장한다.
- 지속성(Durability): 성공적으로 수행된 트랜잭션은 영원히 반영돼야 함을 보장한다.
하지만, 다차원 적이고 깊은 계층 구조를 가지는 비정형 데이터는 RDBMS의 정형화된 테이블에서는 관리가 힘들다.
실시간 로그 데이터와 같은 시계열 데이터들은 RDBMS에 저장하는 것이 쉽지 않다.
RDBMS를 사용하는 경우에는 테이블 구조 변경을 위해 DA가 승인하고, DBA가 작업을 진행하기에 개발 속도가 저하될 수 있다.
NoSQL 사용 시 개발 팀이 바로 데이터 구조를 바꿀 수 있어 더 빠른 개발이 가능하다.
비즈니스의 특성과 데이터의 형태를 고려하여 NoSQL과 RDBMS를 적절히 선택해 운영해야 한다.
MSA에서 가장 중요한 것은 서비스는 스스로의 상태를 유지하고, 이를 위해 독립된 데이터 저장소가 필요하다.
Not Only SQL을 의미한다.
관계형 데이터베이스에서 테이블의 데이터를 쿼리하기 위한 SQL(Standard Query Language)을 사용하지 않는 데이터 저장소임을 의미한다.
데이터 저장소에서 데이터를 가져올 때 발생할 수 있는 지연은 0 ~ 1ms 이내여야 한다.
MSA에서 개별 서비스가 빠르게 동작하지 않을 때, 서비스 자체가 병목 현상을 유발할 수 있다.
NoSQL은 분산 시스템 기반으로 데이터를 여러 노드에 복제하고 샤딩하여, 일부 노드가 장애를 겪어도 서비스가 중단되지 않도록 고가용성을 보장한다.
자동 장애 복구와 무중단 유지보수를 지원해 안정적인 데이터 접근이 가능하다.
NoSQL은 분산 아키텍처와 스키마리스 구조로 클라우드의 수평적 확장성과 자원 유연성에 최적화되어 있다.
자동 복구와 데이터 복제를 통해 클라우드 환경에서 고가용성과 확장성을 쉽게 구현할 수 있다
개발자와 운영자가 데이터 저장소를 간단하게 사용할 수 있다.
NoSQL이 스키마리스 구조를 제공해 데이터 모델 변경이 자유롭고, 복잡한 설정 없이 자동 복제와 확장이 가능하기 때문이다.
출처: https://www.linkedin.com/pulse/nosql-databases-empowering-modern-data-management-jagarlapoodi/
엔티티 간의 관계를 효율적으로 저장하도록 설계됐다.
노드(Node), 엣지(Edges), 속성(properties)으로 데이터를 나타내고, 데이터의 엔티티는 노드로 표현하며, 데이터 사이의 관계를 엣지로 나타낸다.
데이터 간 관계를 저장하고 표현할 때 유용하며 저장되는 속성의 크가 크거나 매우 많은 경우에는 적합하지 않다.
친구 관계를 이용한 추천 서비스에서 유용하게 사용될 수 있다.
데이터를 행(Row)이 아닌 열(Column)을 기준으로 저장한다.
칼럼 유형은 칼럼 지향적(column-oriented) 또는 와이드 칼럼(wide column) 유형으로도 불린다.
대량의 데이터에 대한 집계 쿼리를 다른 유형보다 훨씬 빠르게 처리할 수 있다.
출처: https://lennilobel.wordpress.com/2015/06/01/relational-databases-vs-nosql-document-databases/
JSON 형태로 데이터가 저장돼, 개발자들이 편하게 사용할 수 있다.
스키마가 따로 정해져 있지 않아, 애플리케이션에 맞게 데이터를 그대로 저장할 수 있어 유연성이 크다.
데이터를 저장하거나 검색하는 데 효과적이며 MongoDB, CouchDB, AWS DocumentDB 등이 존재한다.
출처: https://www.researchgate.net/figure/Key-value-NoSQL-Database_fig1_332188615
가장 단순하여 빠른 데이터 액세스와 처리 속도를 보장한다.
데이터의 저장이 간단하기 때문에 다른 유형보다 수평적 확장이 쉽다.
게임, IoT와 같은 로그를 남기는 작업이나 대규모 세션을 실시간으로 관리하는 상황에서 유용하다.
AWS Elasticache, AWS DynamoDB, Oracle NoSQL Database, Memcached 등이 존재한다.
Remote dictionary server(Redis)의 약자이다.
고성능 키-값 유형의 인메모리(in-memory) NoSQL 데이터베이스로, 오픈 소스 기반의 데이터 저장소이다.
인메모리(In-Memory)는 데이터를 디스크가 아닌 RAM에 저장하여 빠르게 읽고 쓰는 방식을 의미한다.
이 방식은 지연 시간(Latency)을 최소화하고, 실시간 데이터 처리나 캐싱, 세션 관리 등에 유리하다.
실시간 응답(빠른 성능)
단순성
키에 매핑되는 값에는 문자열, 해시(hash), 셋(set) 등 복잡하고 다양한 데이터 구조를 저장할 수 있다.
내장된 다양한 자료 구조를 통해 임피던스 불일치를 해소하고 개발을 편리하게 할 수 있다.
다양한 오픈 소스 클라이언트를 사용할 수 있으며, 다양한 개발 언어를 지원한다.
레디스는 싱글 스레드로 동작한다.
출처: https://blog.devgenius.io/lets-dance-on-the-redis-floor-d93e02828bef
메인 스레드 1개와 별도의 스레드 3개 총 4개의 스레드로 동작한다.
하지만 클라이언트의 커맨드를 처리하는 부분은 이벤트 루프를 이용한 싱글 스레드로 동작한다.
고가용성
레디스는 자체적으로 HA(High Availability) 기능을 제공한다.
복제를 통해 여러 서버에 데이터 분산이 가능하다.
센티널(sentinel)은 장애 상황을 탐지해 자동으로 페일오버(failover)를 시켜준다.
애플리케이션 - 센티넬 - 레디스 구조에서는 마스터에 장애가 발생해도 레디스 엔드포인트를 변경하지 않아도 페일오버가 자동으로 이루어져 정상화된 마스터 노드를 사용할 수 있다.
확장성
출처: https://www.aeraki.net/docs/v1.x/tutorials/redis/cluster/
클러스터 모드를 이용해 쉽게 수평적 확장을 할 수 있다.
데이터는 레디스 클러스터 내에서 자동으로 샤딩된 후 저장된다.
클러스터 구조에서 모든 레디스 인스턴스는 클러스터 버스라는 프로토콜을 이용해 서로 감시를 하여 마스터 노드에 장애가 발생할 시 자동으로 페일오버를 시켜준다.
클라우드 네이티브
클라우드 네이티브는 클라우드 환경에 특화된 애플리케이션의 개발 및 운영 방식을 의미한다.
레디스는 멀티 클라우드 환경에서 일관된 성능과 기능을 제공하여 서비스의 연속성과 데이터의 일관성을 보장한다.
각 서비스별 개별 저장소로 사용하기에 간편하다.
고가용성을 위해 로드 밸런서나 프록시 등 추가적인 서비스를 설치할 필요가 없다.
데이터의 영속성을 위해 AOF(Append Only File)와 RDB(Redis DataBase)형식으로 디스크에 주기적으로 저장할 수 있다.
장애가 발생해 데이터가 유실되도 백업 파일을 이용하면 쉽게 복구가 가능하다.
MSA에서는 서비스들 간 지속적 통신을 위해 메시징 큐 혹은 steam과 같은 메시지 브로커를 이용해 서비스들 간에 비동기 통신 채널을 구현하는 것이 좋다.
Redis pub/sub 기능을 통해 메시징 기능을 구현할 수 있다.
1개의 채널에 데이터를 던지면 해당 채널을 듣고 있는 모든 소비자는 데이터를 빠르게 가져올 수 있다.
하지만 모든 데이터는 전달된 뒤 삭제되므로 fire-and-forgot 패턴이 필요한 간단한 알림 서비스에서 유용하다.
list 자료 구조를 이용하여 메시징 큐로 사용하고, 블로킹 기능도 사용할 수 있다.
- 킹 기능
redis 블로킹 기능은 특정 명령어를 실행할 때, 조건이 충족될 때까지 클라이언트를 대기 상태로 유지하는 기능이다. 이 기능은 주로 리스트(List) 자료구조에서 사용되며, 데이터를 기다리는 상황에서 유용하다.
stream 자료 구조를 이용하여 스트림 플랫폼으로 사용할 수 있다.
stream 자료 구조는 테이터는 계속해서 추가되는 방식으로 저장된다.
카프카처럼 저장되는 데이터를 읽을 수 있는 소비자와 소비자 그룹이 존재해 데이터의 분산 처리가 가능하고 시간대별로 검색도 가능하다.