-
4장. 부호화와 발전STUDY/데이터 중심 애플리케이션 설계 2025. 6. 25. 22:35
주요 내용
- 데이터 부호화를 위한 다양한 형식
- 스키마 변경 방법과 예전 버전과 새로운 버전의 데이터와 코드가 공존하는 시스템 지원 방식
- REST, RPC, 액터(actor)와 메시지 전달 시스템(메시지 큐)에서 다양한 데이터 부화화 형식이 데이터 저장과 통신에 어떻게 사용되는지
양방향 호환성
- 하위 호환성 : 새로운 코드는 에전 코드가 기록한 데이터를 읽을 수 있어야 한다.
- 상위 호환성 : 예전 코드는 새로운 코드가 기록한 데이터를 읽을 수 있어야 한다.
데이터 부호화 형식
- 프로그램은 보통 (최소한) 두 가지 형태로 표현된 데이터를 사용해 동작한다.
- 메모리에 객체, 구초제, 목록, 배열, 해시 테이블, 트리 등으로 데이터가 유지되며, 이런 데이터 구조는 CPU에서 효율적으로 접근하고 조작할 수 있게 최적화된다.
- 데이터를 파일에 쓰거나 네트워크를 통해 전송하려면 스스로를 포함한 일련의 바이트열의 형태로 부호화해야 한다.
- 부호화 : 인메모리 표현 → 바이트열 전환, 직렬화나 마샬링이라고도 함.
- 복호화 : 바이트열 → 읽어올 수 있도록 변환, 파싱, 역직렬화, 언마샬링이라고도 함.
언어별 형식
- 많은 프로그래밍 언어는 인메모리 객체를 바이트열로 부호화하는 기능을 내장한다.
- 자바 : java.io.Serializable
- 루비 : Marshal
- 파이썬 pickle
- 최소한의 추가 코드로 인메모리 객체를 저장하고 복원할 수 있어 편리하지만 심각한 문제점이 있다.
- 부호화는 보통 특정 프로그래밍 언어와 묶여 있어 다른 언어에서 데이터를 읽기 매우 어렵다.
- 동일한 객체 유형의 데이터를 복원하려면 복호화 과정이 임의의 클래스를 인스턴스화할 수 있어야 하는데, 보안 문제의 원인이 될 수 있다.
- 데이터를 빠르고 쉽게 부호화하기 위해 상위, 하위 호환성의 문제가 발생한다.
- 효율성 문제(ex. 자바의 내장 직렬화는 성능이 좋지 않고 비대해지는 부호화로 유명)
JSON과 XML, 이진 변형
- JSON, XML, CSV는 텍스트 형식이라 사람이 읽을 수 있고, 특히 데이터 교환 형식(한 조직에서 다른 조직으로 데이터를 전송)으로 사용하기 좋다.
- 단점
- 수(number)의 부호화 : XML과 CSV는 수와 숫자로 구성된 문자열을 구분할 수 없다. JSON은 구분은 가능하지만 정수와 부동소수점 수를 구별하지 않고 정밀도를 지정하지 않는다. 이런 점은 큰 수를 다룰 때 문제가 된다.
- JSON과 XML은 유니코드 문자열(사람이 읽을 수 있는 텍스트)은 지원하지만, 이진 문자열(문자 부호화가 없는 바이트열)을 지원하지 않는다.
- JSON과 XML은 모두 스키마를 지원하지만, 익히고 구현하기 상당히 난해하다.
- CSV는 스키마가 없어 각 로우와 컬럼의 의미를 정의해야 한다.
이진 부호화
- JSON과 XML은 이진 형식과 비교했을 때 많은 공간을 사용 → JSON과 XML용으로 사용 가능한 다양한 이진 부호화 개발
- 데이터타입 셋을 확장하지만(ex. 정수와 부동소수점 수의 구분이나 이진 문자열 지원 추가) JSON/XML 데이터 모델은 변경하지 않고 유지
- 특히 스키마를 지정하지 않아 부호화된 데이터 안에 모든 객체의 필드 이름을 포함
아파치 스리프트(Apache Thrift)와 프로토콜 버퍼(Protocol Buffers)
- 이진 부호화 라이브러리
- 부호화할 데이터를 위한 스키마 필요
- 스리프트
- 바이너리프로토콜 방식 : 필드 이름이 없는 대신 필드 태그 존재
- 컴팩트프로토콜 방식 : 동일한 정보를 34바이트로 줄여 부호화, 필드 타입과 태그 숫자를 단일 바이트로 줄이고 가변 길이 정수를 사용해서 부호화
- 프로토콜 버퍼
- 스리프트의 컴팩트프로토콜과 매우 비슷한데, 33바이트로 부호화
필드 태그와 스키마 발전
- 스키마 발전(schema evolution) : 스키마가 시간이 지남에 따라 변하는 것
- 필드 태그
- 부호화된 데이터를 해석하기 위해 매우 중요
- 기존의 모든 부호화된 데이터를 인식 불가능하게 만들 수 있어 변경이 불가능
- 상위 호환성 : 새로운 태그 번호를 추가 → 새로운 필드 추가 가능, 예전 코드는 해당 필드 무시
- 하위 호환성 : 예전 코드는 새로운 필드를 기록하지 않기 때문에 추가되는 필드의 경우 optional로 하거나 기본값 설정
- 필드 삭제의 경우 optional 필드만 가능하고, 같은 태그 번호는 다시 사용할 수 없음
데이터타입과 스키마 발전
- 프로토콜 버퍼 : repeated 표시자,(단일) optional 필드를 (다중) repeated 필드로 변경 가능
- 스리프트 : 전용 목록 데이터타입, 목록 엘리먼트의 데이터타입을 매개변수로 받아서 사용
아파치 아브로(avro)
- 이진 부호화 형식
- 부호화할 데이터 구조를 지정하기 위해 스키마 사용, 두 개의 스키마 언어 존재(아브로 IDL, JSON 기반 언어)
- 스키마에 태그 번호가 없음
- 이진 부호화 길이는 32바이트로 모든 부호화 중 길이가 가장 짧음
- 필드나 데이터타입을 식별하기 위한 정보가 없고, 단순히 연결된 값으로 구성
- 이진 데이터를 파싱하기 위해 스키마의 필드 순서와 데이터 타입을 미리 파악해야 함
- 읽기와 쓰기 스키마가 일치하지 않는 경우 복호화가 정확하지 않음
쓰기 스키마와 읽기 스키마
- 쓰기 스키마 : 파일이나 데이터베이스 쓰기 또는 네트워크 전송 등의 목적으로 어떤 데이터를 아브로로 부호화할 때 사용하는 스키마
- 읽기 스키마 : 파일이나 데이터베이스 또는 네트워크로 수신 등으로 읽은 어떤 데이터를 복호화할 때 사용하는 스키마
- 아브로의 핵심 아이디어는 쓰기 스키마와 읽기 스키마가 동일하지 않아도 되며 단지 호환 가능하면 되는 것이다.
- 데이터를 복호화할 때 쓰기 스키마와 읽기 스키마를 함께 살펴본 다음 쓰기 스키마에서 읽기 스키마로 데이터를 변환해 차이를 해소
- 필드 순서 상관 없음(이름으로 매핑)
- 읽기 스키마에 없고 쓰기 스키마에 있는 경우 → 필드 무시
- 쓰기 스키마에 없고 읽기 스키마에 있는 경우 → 읽기 스키마의 기본값 사용
스키마 발전 규칙
- 상위 호환성 : 새로운 버전의 쓰기 스키마와 예전 버전의 읽기 스키마를 가질 수 있음
- 하위 호환성 : 새로운 버전의 읽기 스키마와 예전 버전의 쓰기 스키마를 가질 수 있음
- 호화성 유지를 위해 기본값이 있는 필드만 추가하거나 삭제 가능
- 기본값이 없는 필드 추가 → 하위 호환성 문제, 새로운 읽기는 예전 버전 데이터 읽기 불가
- 기본값이 없는 필드 삭제 → 상위 호환성 문제, 예전 읽기는 새로운 데이터 읽기 불가
- 아브로는 널을 허용하기 위해 유니온 타입 사용
그러면 쓰기 스키마는 무엇인가?
- 많은 레코드가 있는 대용량 파일(ex 하둡) : 파일의 시작 부분에 한 번만 쓰기 스키마를 포함
- 개별적으로 기록된 레코드를 가진 데이터베이스 : 모든 부호화된 레코드의 시작 부분에 버전 번호를 포함하고 데이터베이스에는 스키마 버전 목록을 유지.
- 네트워크 연결을 통해 레코드 보내기 : 연결 설정에서 스키마 버전 합의
동적 생성 스키마
- 프로토콜 버퍼, 스리프트와 달리 스키마에 태그 번호를 포함하지 않음 → 동적 생성 스키마에 친숙
- 데이터베이스 스키마가 변경되는 경우 새로운 아브로 스키마를 생성해서 데이터를 내보냄.
- 필드가 이름으로 식별되기 때문에 갱신된 쓰기 스키마는 읽기 스키마와 매치 가능
- 스리프트나 프로토콜 버퍼의 경우 컬럼 이름과 필드 태그의 매핑을 수동으로 갱신해야 함.
코드 생성과 동적 타입 언어
- 스리프트와 프로토콜 버터는 코드 생성에 의존, 스키마를 정의한 후 선택한 프로그래밍 언어로 스키마를 구현한 코드를 생성
- 이브로는 코드 생성 없이 사용 가능(코드 생성을 선택적으로 제공)
스키마의 장점
- XML 스키마, JSON 스키마보다 간단하며, 더 자세한 유효성 검사 규칙을 지원
- 구현과 사용이 더 간단해 광범위한 프로그래밍 언어 지원
- 즉, 스키마 발전은 schemaless 또는 읽기 스키마 JSON 데이터베이스가 제동하는 것과 동일한 종유의 유연성을 제공하며 데이터나 도구 지원도 잘 보장한다.
데이터플로 모드
- 프로세스 간 데이터를 전달하는 방법
- 데이터베이스를 통해
- 서비스 호출을 통해
- 비동기 메시지 전달을 통해
데이터베이스를 통한 데이터플로
- 데이터베이스에 기록하는 프로세스는 데이터를 부호화하고 데이터베이스에서 읽는 프로세스는 데이터를 복호화한다.
- 상위 호환성과 하위 호환성 모두 필요
- 새로운 필드 추가됐는데, 예전 버전에 의해 갱신+재부화되는 경우 필드가 유실될 수 있음
- 데이터베이스 데이터를 새로운 스키마로 다시 기록하는 직업은 값비싸기 때문에, 보통 기존 데이터를 다시 기록하지 않고 널을 기본값으로 갖는 새로운 칼럼을 추가하는 간단한 스키마 변경을 허용
- 예전 로우를 읽는 경우 디스크 상의 부호화된 데이터에서 누락된 임의 컬럼은 널로 채움
- 데이터 덤프는 보통 최신 스키마를 사용해 부호화. 한 번에 기록하고 이후에는 변하지 않으므로 아브로 객체 컨테이너 파일과 같은 형식이 적합
서비스를 통한 데이터 플로: REST와 RPC
- 서버와 클라이언트가 사용하는 데이터 부호화는 서비스 API의 버전 간 호환이 가능해야 한다.
- REST와 RPC는 하나의 프로세스가 네트워크를 통해 다른 프로세스로 요청을 전송하고 가능한 빠른 응답을 기대하는 방식이다.
웹 서비스
- 서비스와 통신하기 위한 기본 프로토콜로 HTTP를 사용할 때
- 대중적인 두 가지 방식 REST와 SOAP가 존재
- REST : 프로토콜이 아닌 HTTP의 원칙을 토대로 한 설계 철학
- SOAP : 네트워크 API 요청을 위한 XML 기반 프로토콜로 HTTP상에서 가장 일반적으로 사용되지만 HTTP와 독립적이며 대부분의 HTTP 기능을 사용하지 않음
RPC
- RPC 모델은 원격 네트워크 서비스 요청을 같은 프로세스 안에서 특정 프로그래밍 언어의 함수나 메서드를 호출하는 것과 동일하게 사용 가능하게 해줌
- 하지만 예측이 어렵고, 네트워크 문제로 요청과 응답이 유실되거나 원격 장비가 느려지거나 요청에 응답하지 않는 문제가 발생할 수 있음
- 타임아웃으로 결과 없이 반환
- 실패한 네티워크 요청을 다시 시도할 때 요청이 실제로는 처리되고 응답만 유실되어 재시도 작업이 여러 번 수행될 수 있음
- 네트워크가 혼잡하거나 원격 서비스에 과부하가 걸리는 경우 처리 시간이 오래 걸림
- 모든 매개변수를 네트워크 전송이 가능하도록 바이트열로 부호화 해야함.
- 하나의 언어에서 다른 언어로 데이터타입을 변환해야 함
- RPC의 현재 방향은 같은 데이터센터 내의 같은 조직이 소유한 서비스 간 요청에 초점을 두는 것이다.
- 발전성을 위해서는 RPC 클라이언트와 서버를 독립적으로 변경하고 배포할 수 있어야 함.
메시지 전달 데이터플로
- 비동기 메시지 전달 시스템
- 클라이언트 요청(메시지)를 낮은 지연 시간으로 다른 프로세스에 전달
- 메시지를 직접 네트워크 연결로 전송하지 않고 임시로 메시지를 저장하는 메시지 브로커(message broker) 또는 메시지 큐(message queue)나 메시지 지향 미들웨어(message-oriented middleware)라는 중간 단계를 거쳐 전송
- 장점
- 수신자가 사용 불가능하거나 과부하 상태여도 메시지 브로커가 버퍼처럼 동작할 수 있기 때문에 시스템 안정성이 향상됨
- 죽었던 프로세스에 메시지를 다시 전달할 수 있어, 메시지 유실 방지 가능
- 송신자가 수신자의 IP 주소나 포트를 몰라도 됨.
- 하나의 메시지를 여러 수신자로 전송 가능
- 논리적으로 송신자는 수신자와 분리됨.
- 메시지 전달 통신은 단방향
분산 액터 프레임워크
- 액터 모델
- 단일 프로세스 안에서 동시성을 위한 프로그래밍 모델이다.
- 스레드(경쟁 조건, 잠금, 교착 상태와 관련된 문제들)를 직접 처리하는 대신 로직이 액터에 캡슐화
- 보통 각 액터는 하나의 클라이언트나 엔티티를 나타냄
- 다른 액터와 공유하지 않는 로컬 상태를 가질 수 있고 비동기 메시지의 송수신으로 다른 액터와 통신
- 메시지 전달을 보장하지 않아 에러 상황에서 유실 가능성 존재
- 각 액터 프로세스는 한 번에 하나의 메시지만 처리하기 때문에 스레드에 대해 걱정할 필요가 없고, 프레임워크와 독립적으로 실행 가능
- 분산 액터 프레임워크에서 액터 모델은 여러 노드 간의 애플리케이션 확장에 사용
- 송신자와 수신자의 노드 위치에 관계없이 동일한 메시지 전달 구조를 사용
- 서로 다른 노드에 있는 경우 바이트열로 부호화되고 네트워크를 통해 전송됨
'STUDY > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
8장. 분산 시스템의 골칫거리 (0) 2025.08.31 7장. 트랜잭션 (0) 2025.08.19 6장. 파티셔닝 (4) 2025.07.30 3장. 저장소와 검색 (0) 2025.06.18 2장. 데이터 모델과 질의 언어 (1) 2025.06.11