부호화와 발전

애플리케이션 기능을 변경하려면 저장하는 데이터도 변경해야 한다. 새로운 필드나 레코드 유형을 저장해야 하거나 기존 데이터를 새로운 방법으로 제공해야 할지 모른다.

시스템이 계속 원활하게 실행되게 하려면 양방향으로 호환성을 유지해야 한다.

하위 호환성 : 새로운 코드는 예전 코드가 기록한 데이터를 읽을 수 있어야 한다. 상위 호환성 : 예전 코드는 새로운 코드가 기록한 데이터를 읽을 수 있어야 한다.

하위 호환성은 쉬우나 상위 호환성은 어렵다.

데이터 부호화 형식

메모리에 객체, 구조체, 목록, 배역, 테이블, 트리 등으로 데이터를 유지하고 최적화하는데 파일에 쓰거나 네트워크를 통해 전송하려면 스스로를 포함한 일련의 바이트열의 형태로 부호화해야 한다. 인메모리 표현에서 바이트열로의 전환을 부호화(직렬화, 마샬링)라고 하며, 그 반대를 복호화(파싱, 역직렬화)라고 한다.

각 언어의 라이브러리에는 직렬화, 파싱 기능이 있는데 특정 프로그래밍 언어와 묶여 있어 다른 언어에서 데이터를 읽기 힘들다. 효율성도 떨어지고 보안상의 문제가 있다.

JSON과 XML, 이진 변형

XML, CSV의 경우 수 랑 숫자를 구분을 못한다. JSON은 큰 수를 다룰 때 문제가 된다.

유니코드를 지원하지만 이진 문자열을 지원하지 않는다. 그래서 Base64를 사용하지만 데이터 크기가 33% 증가한다.

CSV는 스키마가 없으므로 각 로우와 칼럼의 의미를 정의하는 작업은 애플리케이션이 해야 한다.

스키마의 장점

프로토콜 버퍼와 스리프트, 아브로는 스키마를 사용해 이진 부호화 형식을 기술한다. XML, JSON 스키마보다 훨씬 간단하며 자세한 유효성 검사 규칙을 지원한다.

스키마 데이터베이스를 유지하면 스키마 변경이 적용되기 전에 상위, 하위 호환성을 확인할 수 있다.

정적 타입 프로그래밍 언어는 컴파일 시점에 타입 체크를 할 수 있어서 스키마로부터 코드를 생성하는 기능은 유용하다.

데이터베이스를 통한 데이터 플로우

DB에 기록하는 프로세스가 데이터를 부호화하고 DB에서 읽는 프로세스가 데이터를 복호화 한다.

새로운 버전의 애플리케이션이 기록한 데이터를 예전 버전의 애플리케이션이 갱신하는 경우 주의하지 않으면 데이터가 유실될 수 있으므로.

데이터는 코드보다 더 오래 산다. 데이터를 새로운 스키마로 마이그레이션 하는 작업은 가능하지만 대용량 데이터셋 대상으로는 값비싼 작업이기 때문에 대부분의 DB에서 가능하면 피한다. 스키마 변경을 할 때도 그냥 빈칸을 NULL을 허용하는 방식.

백업목적이나 DW로 적재하기 위해 DB의 스냅샷을 수시로 만든다고 가정하면 이 경우 데이터는 보통 최신 스키마를 사용해 이전방식으로 부호화 한다. 데이터를 복사하기 때문에 복사본을 일관되게 부호화 하는 편이 낫다.

서비스를 통한 데이터 플로우 : REST, RPC

네트워크를 통해 통신해야 하는 프로세스가 있을 때 클라이언트와 서버의 두 역할로 배치한다. 서버는 API를 공개하고 클라이언트는 이 API로 요청을 만들어 서버에 연결할 수 있다. 마이크로서비스, 서비스 지향 설계는 서버가 클라이언트가 되어 다른 서버로 요청을 보낼 수 있다. 따라서 서버와 클라이언트가 사용하는 데이터 부호화는 서비스 API의 버전 간 호환이 가능해야 한다.

웹서비스(API):

REST와 SOAP가 있다.

REST는 프로토콜이 아니라 HTTP의 원칙을 토대로 한 설계 철학.

SOAP는 네트워크 API요청을 위한 XML기반 프로토콜. 대부분의 HTTP 기능을 사용하지 않은 대신 다양한 기능을 추가한 광범위하고 복잡한 여러가지 표준을 제공한다. SOAP웹서비스는 SWDL이라고 부르는 XML기반 언어를 사용해 기술한다. 사람이 읽을 수 있게 설계하지 않았고, SOAP메시지를수동으로 구성하기에는 너무 복잡하다. 따라서 상호운용성은 종종 문제를 일으킨다.

원격 프로시저 호출(RPC):

로컬함수호출은 예측이 가능해서 제어가능한 매개변수에 따라 성공하거나 실패한다. 네트워크 요청은 예측이 어렵다. 요청과 응답이 유실되거나 원격 장비가 느려지거나 요청에 응답하지 않을 수 있고, 이런 문제는 전혀 제어할 수 없다.

Timeout, 중복제거기법, 지연시간, 포인트->바이트열로 부호화 등의 문제가 있다.

RPC의 현재 방향:

이래도 RPC는 사라지지 않는다. REST는 공개 API의 주요한 방식, RPC 프레임워크의 주요 초점은 보통 같은 데이터 센터 내의 같은 조직이 소유한 서비스 간 요청에 있다.

메시지 전달 데이터플로우

메시지 브로커를 사용하는 방식은 직접 RPC를 사용하는 방식과 비교했을 때 여러 장점이 있다. 메시지 전달 통신은 일반적으로 단방향이라는 점이 RPC와 다르다. 즉 송신 프로세스는 대게 메시지에 대한 응답을 기대하지 않는다. 이런 통신 패턴이 비동기다. 송신 프로세스는 메시지가 전달될 때까지 기다리지 않고 보낸 다음 잊는다.

메시지 브로커:

래빗MQ, 액티브MQ, 아파치 카프카 같은 오픈소스 구현이 대중화

프로세스 하나가 메시지를 이름이 지정된 큐나 토픽으로 전송하고 브로커는 해당 큐나 토픽 하나 이상의 소비자, 구독자에게 메시지를 전달한다. 동일한 토픽에 여러 생산자, 소비자가 있을 수 있다. 단방향 데이터플로우만 제공한다. 보통 특정 데이터 모델을 강요하지 않는다. 일부 메타데이터를 가진 바이트 열이므로 모든 부호화 형식을 사용할 수 있다.

분산 액터 프레임워크:

액터모델은 단일 프로세스 안에서 동시성을 위한 프로그래밍 모델이다. 스레드를 직접 처리하는 대신 로직이 액터에 캡슐화 된다. 보통 각 액터는 하나의 클라이언트나 엔티티를 나타낸다. 액터는 로컬 상태를 가질 수 있고 비동기 메시지의 송수신으로 다른 액터와 통신한다.

분산 액터 프레임워크는 송신자와 수신자가 같은 노드에 있는지 다른 노드에 있는지 관계없이 동일한 메시지 전달 구조를 사용한다. 다른 노드에 있는 경우 메시지는 명백하게 바이트열로 부호화되고 네트워크를 통해 전송되며 다른 쪽에서 복호화한다. 액터모델을 사용한 경우 로컬과 원격 통신 간 근본적인 불일치가 적다. 위치 투명성은 RPC보다 액터 모델에서 더 잘 동작한다.

정리

많은 서비스가 새로운 버전의 서비스를 동시에 모든 노드에 배포하는 방식보다 한 번에 일부 노드에만 서서히 배포하는 순회식 업그레이드가 필요하다. 정지 시간 없이 새로운 버전의 서비스를 출시 가능하게 하고 배포를 덜 위험하게 만든다. 이런 속성은 애플리케이션 변경을 쉽게 할 수 있는 발전성에 도움이 많이 된다. 따라서 모든 데이터는 하위 호환성(새로운 코드가 예전 데이터를 읽을 수 있음)과 상위 호환성(에전 코드가 새로운 데이터를 읽을 수 있음)을 제공하는 방식으로 부호화해야 한다.

1. JSON, XML, CSV같은 텍스트 형식은 널리 사용된다. 이 형식들은 데이터 타입에 대해 다소 모호한 점이 있기 때문에 숫자나 이진 문자열과 같은 항목은 주의해야 한다.

2. 스리프트, 프로토콜 버퍼, 아브로 같은 이진 스키마 기반 형식은 짧은 길이로 부호화되며 명확하게 정의된 상위 호환성과 하위호환성의 맥락에서 효율적인 부호화를 지원한다. 문서와 코드 생성에 유용하지만 사람이 읽기 위해서는 복호화해야 한다는 단점이 있다.

1. DB에는 기록, 읽기만 하고 부호화, 복호화는 프로세스가 하는게 바람직하다.

2. 클라이언트가 요청을 부호화하고, 서버는 요청을 복호화하고, 응답을 부호화하고, 최종적으로 클라이언트가 응답을 복호화하는 RPC, REST API

3. 송신자가 부호화하고 수신자가 복호화 하는 비동기 메시지 전달.

상하위 호환성과 순회식 업그레이드가 가능하다.

Last updated