대부분의 웹 서버는 여러 개의 요청을 동시에 수행할 수 있고, 이는 작성한 코드가 동시에 수행될 수 있다.
프로그래밍을 하다 보면 이러한 동시성 처리가 필요한 경우가 있다.
하지만 동시성과 병렬성이 혼돈되어 사용되는 경우가 있어 한 번 정리해볼까한다.
동시성 vs 병렬성
동시성(Concurrency)
병렬성(Parallelism)
동시에 실행되는 것 같이 보이는 것
실제로 동시에 여러 작업이 처리되는 것
싱글 코어에서 멀티 스레드를 동작시키는 방식
멀티 코어에서 멀티 스레드를 동작시키는 방식
한 번에 많은 것을 처리
한 번에 많은 일을 처리
논리적인 개념
물리적인 개념
그림은 싱글 코어와 멀티 코어에서 동작하는 모습을 비교하는 그림이다.
싱글 코어에서는 2개의 작업을 동시에 실행되는 것처럼 보이기 위해 번갈아 가면서 작업을 수행한다.
이때, 다른 작업으로 바꾸어 실행할 때 내부적으로 Context switch가 일어난다
자세한 문맥교환은 다른 페이지에서 다루도록 하겠다.
그렇다면 우리가 동시성 이슈를 해결해야하는 이유는 무엇일까 ?
진행했던 프로젝트가 실제 적용될 수 있는 사례와 유사하니 이로 예시를 들어보겠다.
수량이 마지막 1개가 남아있는 시점에서 동시에 두 명의 유저가 요청을 하게 되었을 때 동시성 이슈가 해결되지 않을 경우, 둘 모두 성공하여 수량은 1개인데, 가져야 하는 사람이 2명인 난감한 상황이 펼쳐지게 된다. 이와 같은 상황에서 둘 모두 성공하는 것이 아니라 한 명만이 성공해야 하기때문에 동시성 이슈를 해결해야 한다.
위와 같은 상황을 경쟁 조건(race condition)이라고 한다.
경쟁 조건
여러 프로세스 및 스레드가 동시에 동일한 데이터(공유 데이터)를 조작할 때 타이밍이나 접근 순서에 따라 예상했던 결과가 달라질 수 있는 상황을 의미한다.
동시성 이슈의 문제점
공유 데이터에 대해 예상 결과가 다르지만 오류가 발생하지 않는다.
코드를 작성할 때는 로컬에서 개발하기때문에 파악하기 힘들다.
비정형적으로 발생하기때문에 디버깅이 힘들 수 있다.
동시성 이슈를 해결하면서 주의사항
뮤텍스, 세마포어, Lock 과 같은 경우 상호 배제만 해결해주기때문에 교착상태와 기아상태를 발생할 수 있다.
기아상태 (Starvation)
특정 프로세스의 우선 순위가 낮아서 원하는 자원을 계속 할당 받지 못하는 상태를 말한다.
교착상태
교착상태(Dead Lock)은 둘 이상의 프로세스들이 자원을 점유한 상태에서 서로 다른 프로세스가 점유하고 있는 자원을 요구하며 무한정 기다리는 현상을 의미한다.
기아상태와 교착상태의 차이
교착상태는 프로세스가 자원을 얻지 못해 다음 처리를 하지 못하는 상태를 말하고,
기아상태는 프로세스가 원하는 자원을 계속 할당 받지 못하는 상태이다.
즉, 교착 상태는 여러 프로세스가 동일한 자원 점유를 원할 때 발생하고,
기아 상태는 여러 프로세스가 자원을 점유하기 위해 경쟁할 때 특정 프로세스는 영원히 자원 할당을 받지 못하는 것이다.
교착 상태 발생 조건
주로 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황에서 발생한다.
교착상태가 발생하기 위해서는 다음의 4가지 조건이 충족되어야 하는데, 이 네가지 조건 중 하나라도 충족되지 않으면 교착상태가 발생하지 않는다.
상호 배제(Mutual Exclusion)
자원은 한 번에 한 프로세스만이 사용할 수 있어야 한다.
상호 배제 기법에는 뮤텍스, 세마포어 등이 있다.
이 방법들은 상호 배제만 해결해주기 때문에 데드락과 기아상태가 발생할 수 있다.
뮤텍스
Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 (스레드, 프로세스) 만이 공유자원에 접근할 수 있다.
임계영역을 가진 스레드들의 실행 시간이 서로 겹치지 않고 각각 단독으로 실행되도록 하는 기술
뮤텍스 객체는 제어되는 섹션에 하나의 스레드만 허용하기때문에 해당 섹션에 접근하려는 다른 스레드들을 강제적으로 막음으로써 첫 번째 스레드가 해당 섹션을 빠져나올 때까지 기다리도록 한다
세마포어
멀티 프로그래밍 환경에서 공유된 자원에 대한 접근을 제한하는 방법
현재 공유자원에 접근할 수 있는 스레드, 프로세스의 수를 나타내는 값을 기반으로 한다
세마포어는 공유 리소스에 접근할 수 있는 최대 허용치만큼 동시에 사용자 접근을 할 수 있게 한다.
스레드들은 리소스 접근을 요청할 수 있고, 세마포어에서는 카운트가 하나씩 줄어들게 되며 리소스 사용을 마쳤다는 신호를 보내면, 세마포어 카운트가 하나 늘어나게 된다.
이때 세마포어에서 발생할 수 있는 단점은 DeadLock 교착상태이다
모니터
뮤텍스와 세마포어의 차이
세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.
세마포어는 소유할 수 없으며, 뮤텍스는 소유할 수 있고, 소유주가 그에 대한 책임을 가진다.
세마포어는 동기화 대상이 여러 개일때 사용하고, 뮤텍스는 동기화 대상이 오로지 하나일 때 사용된다.
점유와 대기(Hold and Wait)
최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.
비선점(Non-preemption)
다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 빼앗을 수 없어야 한다.
환형 대기(Circular Wait)
서로 다른 공유자원을 사용하기 위해 대기하는 프로세스들이 원형으로 구성되어 있어 자신에게 할당된 자원을 점유하면서 앞이나 뒤에 있는 프로세스의 자원을 요구한다.
교착 상태 해결 방안
예방(Prevention)
교착상태가 발생하지 않도록 사전에 시스템을 제어하는 방법으로, 교착상태 발생의 4가지 조건 중에서 어느 하나를 제거한다. 즉, 자원 낭비가 가장 심한 해결 방법이다.
상호 배제 부정 : 한 번에 여러 개의 프로세스가 공유 자원을 사용할 수 있도록 한다.
점유 및 대기 부정 : 프로세스가 실행되기 전 필요한 모든 자원을 할당하여 프로세스 대기를 없애거나 자원이 점유되지 않은 상태에서만 자원을 요구한다.
비선점 부정 : 자원을 점유하고 있는 프로세스가 다른 자원을 요구할 때 점유하고 있는 자원을 반납하고, 요구한 자원을 사용하기 위해 기다린다.
환형대기 부정 : 자원을 선형 순서로 분류하여 고유 번호를 할당하고, 각 프로세스는 현재 점유한 자원의 고유 번호보다 앞이나 뒤 어느 한쪽 방향으로만 자원을 요구하도록 한다.
회피(Avoidance)
교착상태가 발생할 가능성을 배제하지 않고 교착상태가 발생하면 적절히 피해나가는 방법으로, 주로 은행원 알고리즘(Banker’s Algorithm)이 사용된다.
은행원 알고리즘
은행원 알고리즘은 다익스트라가 제안한 기법으로, 은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래한 기법이다.
각 프로세스에게 자원을 할당하여 교착상태가 발생하지 않으면 모든 프로세스가 완료될 수 있는 상태를 안전상태, 교착상태가 발생할 수 있는 상태를 불안전 상태라고 한다.
은행은 자원을 할당한 후에도 안정 상태로 남아있는지 검사하여 안정 상태에 있으면 자원을 할당하고 그렇지 않으면 다른 프로세스들이 자원을 해제할 때까지 대기한다.
은행원 알고리즘을 적용하기 위해서는 자원의 양과 사용자(프로세스) 수가 일정해야 한다.
은행원 알고리즘은 프로세스의 모든 요구를 유햔한 시간안에 할당하는 것을 보장한다.
탐지(Detection)
시스템에 교착상태가 발생했는지 점검하여 교착상태에 있는 프로세스와 자원을 발견한다.
교착 상태 발견 알고리즘과 자원 할당 그래프등을 사용할 수 있다.
복구(Recovery)
교착상태를 일으킨 프로세스를 종료하거나 교착상태의 프로세스에 할당된 자원을 선점하여 프로세스나 자원을 회복한다.
프로세스 종료
교착상태에 있는 프로세스를 종료
교착상태에 있는 프로세스들을 하나씩 종료
자원 선점
교착상태의 프로세스가 점유하고 있는 자원을 선점하여 다른 프로세스에게 할당하며, 해당 프로세스를 일시 정지시키는 방법이다. 우선순위가 낮은 프로세스, 수행된 정도가 적은 프로세스, 사용되는 자원이 적은 프로세스등을 위주로 해당 프로세스의 자원을 선점한다.
마이크로서비스란 작고, 독립적으로 배포 가능한 각각의 기능을 수행하는 서비스로 구성된 프레임워크라고 할 수 있다. 마이크로서비스는 완전히 독립적으로 배포가 가능하고, 다른 기술 스택(개발 언어, 데이터베이스등)이 사용 가능한 단일 사업 영역에 초점을 둔다
등장배경
Monolithic Architecture
소프트웨어의 모든 구성요소가 한 프로젝트에 통합되어 있는 형태이다.
웹 개발을 예로 들면 웹 프로그램을 개발하기 위해 모듈별로 개발하고, 개발이 완료된 웹 어플리케이션을 하나의 결과물로 패키징하여 배포된 형태를 말한다.
웹의 경우 WAR파일로 빌드되어 WAS에 배포하는 형태를 말하며, 주로 소규모 프로젝트에 사용된다.
하지만 일정 규모 이상의 서비스, 혹은 수백명 이상의 개발자가 투입되는 프로젝트에서 Monolithic Architecture는 한계를 보인다
Monolithic Architecture 한계
부분 장애가 전체 서비스의 장애로 확대될 수 있다.
개발자의 잘못된 코드 배포 또는 갑작스러운 트래픽 증가로 인해 성능에 문제가 생겼을 때, 서비스 전체의 장애로 확대될 수 있다.
부분적인 Scale-out이 어렵다
Monolithic Architecture에서는 사용되지 않는 다른 모든 서비스가 Scale-out되어야 하기때문에 부분 Scale-out이 어렵다
Scale-out : 여러 server로 나누어 일을 처리하는 방식
서비스의 변경이 어렵고, 수정시 장애의 영향도 파악이 힘들다
여러 컴포넌트가 하나의 서비스에 강하게 결합되어 있기때문에 수정에 대한 영향도 파악이 힘들다
배포 시간이 오래 걸린다
최근 어플리케이션 개발 방법은 CI/CD를 통한 개발부터 배포까지 빠르게 반영하는 추세이다.
그러나 규모가 커짐에 따라 작은 변경에도 높은 수준의 테스트 비용이 발생하기도 하며, 많은 사람이 하나의 시스템을 개발하여 배포하기때문에 영향을 줄 수 밖에 없다
한 Framework와 언어에 종속적이다
Spring Framework를 사용할 경우, 블록체인 연동 모듈을 추가할 때 node.js를 사용하는 것이 일반적이며 강세이다. 그러나 선정했던 Framework가 Spring이기때문에 Java를 이용하여 해당 모듈을 작성할 수 박에 없다.이러한 Monolithic Architecture의 한계를 보완하기 위해 MSA가 등장하게 되었다. 기존의 특정한 물리적인 서버에 서비스를 올리던 on-promise 서버 기반 Monolithic Architecture에서 이제는 클라우드 환경을 이용하여 서버를 구성하는 MicroService Architecture로 많은 서비스들이 전환되고 있다.
특징
MSA는 API를 통해서만 상호작용할 수 있다.
즉, 마이크로서비스는 서비스의 end-point(접근점)을 API 형태로 외부에 노출하고, 실질적인 세부사항은 모두 추상화한다. 내부의 구현 로직, 아키텍처와 프로그래밍 언어, 데이터베이스, 품질 유지 체계와 같은 기술적인 사항들은 서비스 API에 의해 철저하게 가려진다
따라서 SOA(Service Oriented Architecture)의 특징을 다수 공통으로 가진다
제대로 설계된 마이크로서비스는 하나의 비즈니스 범위에 맞춰 만들어지므로 하나의 기능만 수행한다
즉, 어플리케이션 출시처럼 하나의 목표를 향해 일하지만, 자기가 개발하는 서비스만 책임진다 또한, 여러 어플리케이션에서 재사용할 수 있어야 한다
어플리케이션은 항상 기술 중립적 프로토콜을 사용해 통신하므로 서비스 구현 기술과는 무관하다
따라서, 마이크로서비스 기반의 어플리케이션을 다양한 언어와 기술로 구축할 수 있다는 것을 의미한다
마이크로서비스는 SOA에서 사용되는 집중화된 관리체계를 사용하지 않는다.
마이크로서비스 구현체의 공통적인 특징 중 하나는 ESB(Enterprise Service Bus)와 같은 무거운 제품에 의존하지 않는다는 점이다. REST 등 가벼운 통신 아키텍처, 또는 Kafka등을 이용한 message stream을 주로 사용한다
장점
각각 개별의 서비스 개발을 빠르게 하며, 유지보수도 쉽게할 수 있도록 한다
각각의 서비스가 모듈화되어 있으며, 이러한 모듈끼리는 RPC 또는 message-driven API등을 이용하여 통신한다
팀 단위로 적절한 수준에서 기술 스택을 다르게 가져갈 수 있다
서비스별로 독립적 배포가 가능하다
따라서 지속적인 배포 CD도 모놀리식에 비해서 가볍게 할 수 있다
각각 서비스의 부하에 따라 개별적으로 scale-out이 가능하다
메모리, CPU적으로 상당부분 이득이 된다
단점
모놀리식에 비해 상대적으로 많이 복잡하다
서비스가 모두 분산되어 있기대문에 개발자는 내부 시스템의 통신을 어떻게 가져가야 할지 정해야 한다
또한, 통신의 장애와 서버의 부하등이 있을 경우 어떻게 트랜잭션을 유지할지 결정하고 구현해야 한다
트랜잭션 유지가 어렵다
모놀리식에서는 단일 트랜잭션을 유지하면 됐지만 MSA에서는 비즈니스에 대한 DB를 가지고 있는 서비스도 각기 다르고, 서비스의 연결을 위해서는 통신이 포함되기때문에 트랜잭션을 유지하는게 어렵다
통합 테스트가 어렵다
개발 환경과 실제 운영 환경을 동일하게 가져가는 것이 쉽지 않다
실제 운영 환경에 대해서 배포하는 것이 쉽지 않다
마이크로서비스의 경우 서비스 1개를 재배포한다고 하면 다른 서비스들과의 연계가 정상적으로 이루어지고 있는지도 확인해야 한다
MemberDAO 클래스를 통해 find(id)를 실행하면, JPA는 SELECT SQL을 생성한다
JDBC API를 사용하여 생성된 SELECT SQLD을 보낸다
DB에서 반한된 정보를 ResultSet 매핑을 통해 객체로 변환해준다
이 과정에서도 패러다임 불일치 문제를 해결해준다
JPA를 사용하는 이유
생산성
JPA는 쿼리문을 별도로 작성할 필요가 없다
데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 애플리케이션 개발이 가능하다
유지보수
JPA에서는 쿼리를 직접 작성하지 않기 때문에 필드가 변경되더라도 매핑 정보만 잘 연결하면 SQL문은 자동으로 작성된다
개발자가 작성해야 할 SQL과 JDBC API 코드를 JPA가 대신 처리해줌으로 유지보수해야 하는 코드 수가 줄어든다
패러다임 불일치 문제 해결
상속, 연관관계, 객체, 그래프 탐색, 비교등을 설계 차이로 인해 발생하는 패러다임 불일치 문제를 해결한다
객체는 상속 구조를 만들 수 있으며, 다형성 구현이 가능하지만, 관계형 데이터베이스의 테이블은 상속이라는 개념이 존재하지 않는다
객체는 참조를 통해 관계를 표현하며 방향을 가지고 있으나, 관계형 데이터베이스는 외래 키를 통해 관계를 표현하며, 방향이 존재하지 않는다. 또한 다대다 관계 문제를 해결하기 위해 조인을 사용한다
이외에도 다양한 패러다임 불일치 문제가 존재한다
데이터 접근 추상화와 벤더 독립성
데이터베이스 기술에 종속되지 않도록 한다
데이터베이스를 변경하면 JPA에게 다른 데이터베이스를 사용한다고 알려주기만 된다
JPA의 단점
복잡한 쿼리 처리
복잡한 쿼리를 사용할 경우는 SQL문을 사용하는게 나을 수도 있다. JPA에서는 Native SQL을 통해 기존의 SQL문을 사용할 수 있지만 그러면 특정 데이터베이스에 종속된다는 단점이 생긴다. 이를 보완하기 위해서는 SQL과 유사한 기술인 JPQL을 지원한다
성능 저하 위험
객체 간의 매핑 설계를 잘못했을 때 성능 저하가 발생할 수 있으며, 자동으로 생성되는 쿼리가 많기때문에 개발자가 의도하지 않는 쿼리로 인해 성능이 저하되기도 한다
학습
JPA를 사용하기 위해선 학습해야 할 것들이 많다
JPA를 사용해도 SQL을 알아야 Hibernate가 수행한 쿼리 확인 및 성능 모니터링이 가능하다
JDBC API
자바 프로그래밍 언어와 다양한 데이터베이스 SQL 또는 테이블 형태의 데이터 사이에 독립적인 연결을 지원하는 표준
즉, 다양한 형태의 관계형 데이터베이스에 접속하여 자바 프로그래밍 언어와 데이터베이스 사이에 데이터를 주고 받을 수 있도록 지원하는 표준 자바 응용 프로그래밍 인터페이스이다.
JDBC API 역할
JDBC API는 표준 응용 프로그래밍의 인터페이스만을 제공해주는 것이고,
실질적인 인터페이스의 메소드 기능들에 대한 실제 구현은 DBMS 제조사들이 자신들의 데이터베이스에 맞게 구현하여 제공하며, 이를 JDBC 드라이버라고 한다
JDBC 드라이버
DBMS 회사들이 자신들의 데이터베이스 시스템에 접근할 수 있도록 표준 JDBC 인터페이스에 명시된 메소드들을 구현한 것
따라서 JDBC API를 사용할 경우, 하나의 자바 응용 프로그램만으로 JDBC 드라이버를 제공하는 어떤 종류의 관계형 DBMS에도 접근이 가능할 것이며, 사용자들은 특정 회사의 데이터베이스의 정확한 사용 방법을 몰라도 JDBC API만 배우면 데이터베이스 응용 프로그램을 구현할 수 있는 것이다.
입출력에 다소 시간이 걸리는 단점이 존재한다. 이러한 여러가지 부분에 있어서 인증 토큰에 대해서는 Redis를 사용한다.
Redis
Remote Dictionary Server 약자로
Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSQL)
특징
Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템 (NoSql)
데이터베이스, 캐시, 메세지 브로커로 사용된다
In-Memory 기반의 데이터 처리 및 저장을 제공하여 속도가 빠르지만 서버가 꺼지면 모든 데이터가 사라지기 때문에 보조 데이터베이스로 사용된다.
데이터를 디스크에 쓰는 구조가 아니라 메모리에서 데이터를 처리하기때문에 속도가 빠르다
String, Lists,Sets,Sorted Sets, Hashes 자료 구조를 지원한다
String : 가장 일반적인 key-value 구조의 형태
Sets : String의 집합, 여러 개의 값을 하나의 value에 넣을 수 있다
Sorted Sets : 중복된 데이터를 담지 않는 Set 구조에 정렬 Sort를 적용한 구조로 사용할 수 있다
Lists : Array 형식의 데이터 구조, List를 사용하면 처음과 끝에 데이터를 넣고 빼는 건 빠르지만 중간에 데이터를 삽입하거나 삭제하는 것은 어렵다
Single Threaded
한 번에 하나의 명렁만 처리할 수 있다 그렇기 때문에 중간에 처리 시간이 긴 명령어가 들어오면 그 뒤에 명령어들은 모두 앞에 있는 명령어가 처리될 때까지 대기가 필요하다 (하지만 get, set 명령어의 경우 초당 10만 개 이상 처리할 수 있을 만큼 빠르다)
SOCK 프로젝트에선 Redis의 특징 중 Single Threaded를 활용하여 레시피 인기도 상승에 대한 로직을 구현하였다
구현 방식에 대한 자세한 내용은 다음 포스팅에 작성하도록 하겠다
데이터 베이스가 있는데도 Redis라는 인메모리 데이터 구조 저장소를 사용하는 이유가 무엇일까
데이터베이스는 데이터를 물리 디스크에 직접 쓰기때문에 서버에 문제가 발생하여 다운되더라도 데이터가 손실되지 않는다. 하지만 매번 디스크에 접근해야 하기때문에 사용자가 많아질수록 부하가 많아져서 느려질 수 있다
일반적으로 서비스 운영 초반이거나 규모가 작은, 사용자가 많지 않은 서비스의 경우에는 WEB -WAS -DB 의 구조로도 데이터베이스에 무리가 가지 않는다.
하지만 사용자가 늘어난다면 데이터베이스가 과부하될 수 있기때문에 이때 캐시 서버를 도입하여 사용한다
그리고 이 캐시 서버로 이용할 수 있는 것이 바로 Redis이다
캐시는 한번 읽어온 데이터를 임의의 공간에 저장하여 다음에 읽을 때는 빠르게 결괏값을 받을 수 있도록 도와주는 공간이다
같은 요청이 여러번 들어오는 경우 매번 데이터 베이스를 거치는 것이 아니라 캐시 서버에서 첫 번째 요청 이후 저장된 결괏값을 바로 내려주기때문에 DB의 부하를 줄이고 서비스의 속도도 느려지지 않는 장점이다
캐시 서버는 Look aside cashe 패턴과 Write Back 패턴이 존재한다
Look aside cache
클라이언트가 데이터 요청
웹 서버는 데이터가 존재하는지 Cache 서버 먼저 확인
Cache 서버에 데이터가 존재하면, DB에 데이터를 조회하지 않고 Cache 서버에 있는 결괏값을 클라이언트에게 반환 (Cache Hit)
Cache 서버에 데이터가 존재하지 않다면, DB에 데이터를 조회하여 Cache 서버에 저장하고 결괏값을 클라이언트에게 반환 (Cache Miss)
Write Back
웹 서버는 모든 데이터를 Cache 서버에 저장
Cache 서버에 특정 시간 동안 데이터가 저장됨
Cache 서버에 있는 데이터를 DB에 저장
DB에 저장된 Cache 서버의 데이터를 삭제
insert 쿼리를 한 번씩 500번 날리는 것보다 insert 쿼리 500개를 붙여서 한 번에 날리는 것이 더 효율적이다는 원리이다
이 방식은 들어오는 데이터들이 저장되기 전에 메모리 공간에 머무르는데 이때 서버에 장애가 발생하여 다운된다면 데이터가 손실될 수 있다는 단점이 있다
Redis 사용에 주의할 점
서버에 장애가 발생했을 경우 그에 대한 운영 플랜이 꼭 필요하다
: 인메모리 데이터 저장소의 특성상, 서버에 장애가 발생했을 경우 데이터 유실이 발생할 수 있다
메모리 관리가 중요하다
싱글 스레드의 특성상, 한 번에 하나의 명령만 처리할 수 있다. 처리하는데 시간이 오래 걸리는 요청, 명령은 피해야 한다
이 외에도 Master-Slave 형식의 데이터 이중화 구조에 대한 Redis Replication, 분산 처리를 위한 Redis cluster, 장애 복구 시스템 Redis Sentinel, Redis Topology, Redis Sharding, Redis Failover 등의 Redis를 더 효율적으로 사용하기 위한 개념들이 존재한다