04부호화와 발전
RDBMS 는 일반적으로 하나의 스키마를 따름
반면 schemaless DB는 스키마를 강요하지 않음
-> 유연성이 높은 편
스키마가 변경될 때 애플리케이션 코드 수정이 자주필요
-> 대규모 애플리케이션에서 즉시 코드 변경은 어려움
-> 서버는 순회식 업그레이드(rolling upgrade)(단계적 롤아웃(staged rollout))을 통해 무중단이 가능하나 클라이언트는 이전버전과 새버전이 공존하게됨
= 양방향 호환성 유지가 필수적
하위 호환성
: 새로운 코드가 이전 데이터를 읽을 수 있어야 함
상위 호환성
: 이전 코드가 새 버전 데이터를 무시하고 읽을 수 있어야 함
1. 데이터부호화형식
데이터는 메모리에 효율적인 형태(객체, 배열, 트리 등)로 존재
-> 파일이나 네트워크 전송을 위해 바이트열(JSON, XML 등)로 변환 필요
- 부호화(직렬화/마샬링): 인메모리 표현에서 바이트열로의 전환
- 복호화(역직렬화/언마샬링): 바이트열 표현에서 인메모리로 전환
1)언어별형식
대게 프로그래밍 언어는 인메모리 객체를 바이트열로 부호화하는 기능을 내장
but..
언어의 종속성, 보안, 버전관리, 성능 등의 문제로 일시적인 목적 외에 언어에 내장된 부호화를 사용하는 방식은 일반적으로 좋지 않음
2)JSON과 XML, 이진 변형 텍스트 형식의 부호화 : JSON, XML, CSV
- 사람이 읽을 수 있음
- 숫자 처리에 애매함이 있는 편
- JSON과 XML은 이진 문자열을 지원하지 않아 Base64로 우회 처리가 필요함(데이터 크기가 33%증가)
- JSON과 XML을 정의하는 스키마 언어는 강력하지만 익히고 구현하기가 상당히 난해 함
- CSV는 스키마가 없음
-> 이진 형식에 비교해 너무 많은 공간을 차지함😵
= 이진 부호화가 등장했으나..
JSON/XML 데이터 모델은 변경하지 않고 유지
-> 크게 공간 효율을 높이지는 못함
= 절약되는 용량과 속도 향상 정도가 가독성의 손실을 감수할 만큼 큰지 상황에 따라 평가필요
4)스리프트와 프로토콜 버퍼 스키마 기반 이진 부호화 방식
a. 스트리퍼
struct Person {
1: required string userName,
2: optional i64 favoriteNumber,
3: optional list interests
}
- 바이너리 프로토콜(BinaryProtocol)
:필드 이름이 없고, 부호화 된 데이터는 숫자 같은 필드 태그 포함
- 컴팩트 프로토콜(CompactProtocol)
:필드 타입과 태그 숫자를 단일 바이트로 줄이고 가변 길이 정수(variable-length integer)를 사용해서 부호화
b. 프로토콜 버퍼
message Person {
required string user_name = 1;
optional int64 favorite_number = 2;
repeated string interests = 3;
}
컴팩트 프로토콜과 비슷하게 필드 태그를 사용
필드의 required, optional 지정
equired는 필드 누락 여부를 실행 시점에 확인하는 기능(버그 방지용으로 유용)
5)아브로 스리프트와 프로토콜 버퍼와 경쟁하는 이진 부호화 방식
record Person {
string userName;
union { null, long } favoriteNumber = null;
array interests;
}
아브로의 스키마 정의 방식
아브로 IDL (Avro IDL): 사람이 쉽게 읽고 편집할 수 있는 형식
JSON 기반 스키마: 기계가 쉽게 처리할 수 있는 형식
- 필드 태그나 타입 정보가 데이터 내에 존재하지 않음.
- 즉, 문자열임을 알려 주는 정보가 없음
- 정수는 가변 길이 부호화를 사용해서 부호화
-> 읽기 스키마와 쓰기 스키마가 정확히 동일해야 정확한 복호화가 가능함.
?아브로의 스키마 해석(schema resolution) 방식
필드를 이름으로 매칭
-> 필드 순서가 달라도 괜찮음.
- 읽기 스키마에 없고 쓰기 스키마에만 있는 필드는 읽을 때 무시함.
- 읽기 스키마에만 있는 필드는 기본값으로 채워짐.
용도에 따른 아브로 사용
부호화된 데이터에 항상 전체 스키마를 포함시키는 것은 비효율적이므로 용도에 맞게 사용이 필요
a.많은 레코드가 있는 대용량 파일
- 파일의 처음에 한 번만 쓰기 스키마를 기록하는 방식(object container file)
b.개별적으로 기록된 레코드를 가진 데이터베이스
- 각 레코드에 스키마 버전 번호를 포함.
- 버전 번호를 이용해 DB에서 쓰기 스키마를 조회하여 복호화.
c.네트워크 연결을 통해 레코드 보내기- 연결 초기 설정 시 스키마 합의 후 사용.
2. 데이터플로모드
1)데이터베이스를 통한 데이터플로
프로세스는 데이터베이스에 데이터를 쓰거나 읽음
데이터베이스에 데이터를 기록한 프로세스는 미래의 자신이 데이터를 다시 읽고 복호화할 수 있어야 함.
= 하위 호환성(새로운 코드가 이전 데이터를 읽을 수 있는 것)이 필요
서로 다른 버전의 프로세스(서비스 또는 애플리케이션)가 데이터베이스에 동시에 접근하는 상황이 많음.
-> 이전 버전의 코드가 새로운 버전의 코드가 기록한 데이터를 읽어야 하는 경우가 발생
= 상위 호환성(이전 코드가 새로운 데이터를 읽을 수 있는 것)이 중요
이전 코드가 새로운 필드를 모르는 상태에서 데이터를 읽고 다시 쓰는 경우가 발생할 수 있음.
-> 많은 부호화 형식(아브로, 프로토콜 버퍼 등)은 이러한 알지 못하는 (unknown)필드 보존을 지원
-> 나중에 이 모델 객체를 다시 재부호화 시 알지 못하는 필드가 유실될 가능성이 있음
2)서비스를 통한 데이터플로
a.REST(Representational State Transfer)
HTTP를 적극 활용한 간단한 설계 철학
URL로 리소스를 명확히 식별하고 JSON 같은 간단한 데이터 형식 사용
코드 생성이나 도구 없이 간단히 테스트 가능
마이크로서비스에 주로 사용
b.RPC (Remote Procedure Call)
원격 서비스 호출을 로컬 함수처럼 다루는 개념 (위치 투명성)
편리하지만 네트워크 오류, 지연, 중복 호출 등 복잡성 존재
-> 이를 고려한 개선된 RPC 프레임워크 등장
- gRPC (프로토콜 버퍼 사용, 스트림 지원)
- 스리프트(Thrift), 아브로(Avro) 내장 RPC 지원
- 피네글(Finagle), Rest.li (퓨처, 프라미스 활용)