이 글은 Martin Kleppmann의 데이터 중심 애플리케이션 설계를 읽고 기억하고자 적는 게시글입니다.
4. 부호화와 발전
이번에 알아 볼 내용은 “그래서 실제 서비스에서 부호화가 왜 중요한데?”라는 질문에 대답하기 위한 데이터플로에 대해서 알아보겠습니다.
이전 페이지에서는 메모리를 공유하지 않는 다른 프로세스에게 데이터를 보내고 싶을 때 어떻게 데이터를 부호화해야 하는지 알아봤습니다.
가장 먼저 새로운 데이터를 복호화 하는 읽기 스키마는 이전에 저장 된 데이터도 복호화 할 수 있어야 한다 는 “하위 호환성”과 새로운 데이터를 이전의 읽기 스키마로 읽을 수 있어야 한다.는 “상위 호환성”에 대해서 알아보았습니다.
그리고 가장 자주 사용하는 문자열 그대로 저장하는 XML과 JSON 혹은 CSV 파일 저장에 대해서 알아보고, 다른 프로세스에 바이트 형태로 전달하기 위해 JSON 형태의 스키마를 이용해서 데이터를 표현하는 Compact, Avro 등에 대해서 알아보았습니다.
그러면 우리는 이러한 부호화와 복호화를 어떻게 사용 할 수 있을까요?
데이터 플로
큰 주제로 데이터 플로라는 단어를 사용했지만, 사용하는 애플리케이션에 따라 데이터를 전달하는 방식이 달라집니다.
데이터베이스를 통한 데이터 플로
데이터베이스의 프로세스에서 데이터는 어떻게 부호화 되고 또 복호화 되어야 하는지에 대해서 알아보겠습니다.
데이터베이스에서 데이터를 기록하는 프로세스는 부호화를 수행하고, 데이터를 읽는 프로세스는 복호화한다고 말 할 수 있습니다.
그러면 데이터베이스에서 데이터를 기록 할 때 우리는 미래에 읽기 위해서 임을 알고 있습니다. 즉 하위 호환성이 필수적으로 필요합니다. 왜냐하면 미래의 스키마와 데이터를 기록하는 순간의 버전은 다를 수 있고, 복호화를 해야하니까요.
또 주의깊게 생각하는 점은 코드는 예전 코드 일 수 있다는점입니다. 이 경우에는 예전 버전의 입장에서도 최근의 데이터를 읽을 수 있어야 한다는 것이고, 즉 상위 호환성 또한 필요합니다.
다양한 시점에 기록된 다양한 값
애플리케이션의 새로운 버전을 배포 할 때 예전의 데이터베이스 내용은 그대로 남아있습니다. 즉 5년 전의 데이터는 그 당시의 스키마에 따라 부호화 되어 그대로 저장되어 있습니다.
이 경우에는 새로운 스키마로 마이그레이션을 할 수 있습니다. 하지만 대규모 데이터셋은 이러한 작업이 어렵기 때문에 다른 방안을 찾는게 좋습니다.
RDB는 새로운 컬럼을 추가하는 간단한 스키마 변경을 하면서 이전의 값은 NULL로 처리하는 방법을 사용하고, 문서형 데이터베이스와 같은 것은 Avro를 이용해서 버전 별 읽기 스키마를 사용해서 문제를 해결 할 수 있습니다.
보관 저장소
백업 목적이나 데이터 웨어하우스에 적재하기 위해 데이터베이스의 스냅샷을 수시로 만든다고 가정 할 때, 데이터를 덤프하는 과정에서 가장 최근의 스키마를 사용하는게 좋습니다.
서비스를 통한 데이터 플로 : REST와 RPC
네트워크 통신을 이용한 데이터 전송은 크게 REST와 RPC가 있습니다.
요즘 애플리케이션을 설계 할 때 마이크로서비스 설계(MSA)를 장려하고 있는데, MSA는 해당하는 팀이 다른 팀과 조정없이 서비스의 새로운 서비스를 출시 할 수 있는, 말 그대로 서비스에 독립적인 환경이라고 할 수 있습니다.
이러한 서비스를 개발 할 때는 예전 버전과 새로운 버전의 서버와 클라이언트가 동시에 실행되어야 하기 때문에 연관 된 모든 서비스 API의 버전 간에 호환이 되어야 합니다.
REST 특징
RPC 특징
메시지 전달 데이터플로
메시지 전달 데이터플로는 RPC와 데이터베이스 간 비동기 메시지 전달 시스템입니다. 이 시스템은 클라이언트 요청을 낮은 지연 시간으로 다른 프로세스에 전달하기 위하는 점에서 RPC와 비슷합니다. 그리고 메시지를 직접 네트워크 연결로 전달하지 않고 메시지 브로커(큐)나 메시지 지향 미들웨어와 같은 중간 단계를 거친다는 점은 데이터베이스와 유사합니다.
메시지 브로커를 사용하는 방식은 직접 RPC를 사용하는 방식과 비교했을 때 이런 장점이 있습니다.
- 수신자가 사용 불가능하거나 과부화 상태라면 메시지 브로커가 버퍼처럼 동작 할 수 있다.
- 죽었던 프로세스에 다시 메시지를 보낼 수 있어서 유실을 방지 할 수 있다.
- 송신자가 수신자의 IP 주소나 포트 번호를 알 필요 없다.
- 하나의 메시지를 여러 수신자로 전송 할 수 있다.
- 논리적으로 송신자는 수신자와 분리된다.
메시지 전달은 RPC와는 달리 단방향입니다. 또한 송신 프로세스는 수신자의 응답을 기대하지 않고 또한 비동기 방식으로 동작하기 때문에 전달 완료를 기다리지 않습니다.
메시지 브로커의 동작
메시지 브로커가 동작하는 방법은 다음과 같습니다.
- 가장 먼저 프로세스가 메시지를 이름이 지정된 큐나 토픽으로 전송합니다.
- 브로커는 해당 큐나 토픽을 하나 이상의 소비자나 구독자에게 메시지를 전송합니다.
그리고 한 토픽에 여러 생산자와 소비자가 있을 수 있고 토픽은 단방향 데이터플로만 제공합니다. 하지만 방향이 단방향일 뿐 소비자 자체가 송신자가 되어 다른 토픽으로 게시하거나 할 수 있습니다.
메시지 브로커는 특정 데이터 모델을 강요하지 않고 모든 부호화 형식을 사용 할 수 있습니다.
분산 액터 프레임워크
액터 모델은 단일 프로세스 안에서 동시성을 위한 프로그래밍 모델입니다. 액터 모델의 특징은 다음과 같습니다.
- 스레드( 경쟁, 잠금, 교착) 대신에 독립적인 상태를 가지고 실행 할 수 있도록 캡슐화 되어 있습니다.
- 하나의 클라이언트와 엔티티를 나타냅니다.
- 로컬 상태를 가질 수 있습니다.
- 비동기 메시지의 송수신으로 다른 액터와 통신합니다.
- 메시지의 전달을 보장하지 않습니다.
- 액터 프로세스는 한 번에 하나의 메시지만 처리하기 때문에 스레드에 걱정 할 필요 없습니다.
- 각 액터는 프레임워크와 독립적으로 실행 할 수 있습니다.