데이터 중심 애플리케이션 설계- 04장. 부호화와 발전

부호화 (직렬화)와 발전

  • 7장 트랜잭션의 맥락에서도 사용되서 단어 중복 선택을 피하고자 부호화라는 단어를 사용
  • 데이터 부호화를 위한 다양한 형식들
    • JSON, XML, 프로토콜 버퍼, 스리프트(Thrift), 아브로(avro) 등..
  • REST (Representational State Transfer, REST), RPC(remote procedure call) 와 같은 메시지 전달 시스템에서 부호화 형식이 데이터 저장과 통신에 어떻게 이용되는지?

데이터 부호화 형식

  • 데이터를 파일에 쓰거나 네트워크를 통해 전송하려면 일련의 바이트열 (ex. JSON) 의 형태로 부호화 해야 한다.
    • 메모리에서 사용하는 데이터 구조와는 상당히 다르기 때문
    • 인메모리 표현 → 바이트열 전환을 ‘부호화’ 라고 하고 바이트열 → 인메모리 표현 과정을 복호화 (파싱, 역직렬화, 언마샬링) 이라고 한다.
      • 마샬링이 직렬화보다 좀 더 포괄적인 개념, 마샬링이라는 단어는 ‘변환하는 일련의 과정’ 을 뜻한다.

언어별 형식

  • 많은 프로그래밍 언어는 인메모리 객체를 바이트열로 부호화 하는 기능을 내장하고 있음
    • JAVA = java.io.Serializable
    • ruby = Marshal
    • python = pickle
    • 하지만 이러한 내장된 부호화 라이브러리는 문제점 또한 많다.
      • 보통 특정 프로그래밍 언어와 묶여있어 다른 언어에서 데이터 읽기가 어려운 점, 다른 시스템과 통합하는데 방해가 될 수 있다.
      • 상위,하위 호환성의 문제가 등한시 되곤 함
      • 자바의 내장 직렬화는 성능이 좋지않고 비대해지는 부호화로 유명함

JSON 과 XML

  • 많은 프로그래밍 언어에서 읽고 쓸 수 있는 표준화된 부호화
    • JSON
    • XML
    • CSV
  • 텍스트 형식이라 어느정도 사람이 읽을 수 있는 장점도 있다.
  • 파싱적인 문법 문제 외 일부의 미묘한 문제가 있긴한데, 그럼에도 JSON ,XML ,CSV 는 다양한 용도로 사용하기 충분하다!
    • 특히 데이터 교환 형식 (한 조직에서 다른 조직으로의 데이터 전송)으로 사용하기에 매우 좋음

이진 부호화

  • 조직 내에서만 사용하는 데이터라면?

    • 좀 더 간편하고 파싱이 빠른 형식을 선택할 수 있다.
  • JSON과 XML 모두 이진 형식과 비교하면 둘 다 훨씬 많은 공간을 사용한다.

    • 이런 관찰이 다양한 이진 부호화의 개발로 이어짐
      • JSON( 메시지팩, BSON ,BJSON, UBJSON, 등)
      • XML( WBXML, 패스트 인포셋)
  • ex) 메시지 팩

    {
       "username":"Martin",
       "favoriteNumber": 1337,
       "interests":["daydreaming","hacking"]
    }
    
    • 위 JSON 을 메시지 팩으로 부호화 할 경우 텍스트 JSON 을 부호화할 때보다 어느정도 절약되는지 확인
      • 텍스트 JSON 부호화 시 Byte 수 (81바이트)
      • 메시지 팩으로 부호화 시 Byte 수 (66바이트)
    • 별로 안나는데?
      • 어쨋든 전보단 압축이 되긴한다.. 테라바이트 정도가 되면 이점이 있을거 같긴함..
  • 스리프트와 프로토콜 버퍼

    • 이번엔 위 예제를 가지고 아파치 스리프트 (Apache Thrift) 와 프로토콜 버퍼 (Protocol buffers, protobuf) 로 부호화 해보자
    • 스리프트나 프로토콜 버퍼로 부호화하려면 IDL(인터페이스 정의 언어, Interface definition language) 스키마로 기술 해야 한다.
      [스리프트 IDL로 기술한 스키마]
      struct Person {
      		1: required string   userName,
      		2: optional i64      favoriteNumber,
      		3: optional list<string> interests
      }
      
      [프로토콜 버퍼 IDL로 기술한 스키마]
      message Person {
      		required string user_name = 1;
      		optional int64 favorite_number = 2;
      		repeated string interests = 3;
      }
    • 스리프트와 프로토콜 버퍼는 위 처럼 기술된 스키마 정의를 사용해 다양한 프로그래밍 언어로 스키마를 구현할 클래스를 생성 한다.
      • 이렇게 생성된 코드를 사용해 스키마의 레코드를 부호화하고 복호화 할 수 있다.
    • 부호화된 데이터는 어떤 모습일까?
      • 바이너리프로토콜과 컴팩트 프로토콜 이라는 다른 이진 부호화 형식이 있다.
        • 스리프트 바이너리프로토콜
            - 메시지팩과의 가장 큰 차이점은 필드 이름이 없다는 것이다.
                - 대신 부호화된 데이터는 **필드 태그**를 포함한다.
                    - 필드태그 : 스키마 정의에 나타난 숫자
            
        - 스리프트 컴팩트프로토콜
            
            - 의미상 바이너리프로토콜과 같으나 동일한  정보를 34바이트로 줄여 부호화 함
                - 필드 타입과 태그숫자를 단일 바이트로 줄이고 가변 길이 정수를 사용함
                
        - 프로토콜 버퍼
            
            
            - 컴팩트프로토콜과 매우 비슷함.
    
    - 앞서 봤던 스키마에는 각 필드에 requried 나 optional 표시가 있었지만, 부호화 하는 방법에는 차이가 없다.

필드 태그와 스키마 발전

  • 스리프트와 프로토콜 버퍼는 하위 호환성과 상위 호환성을 유지하면서 어떻게 스키마를 변경할까?
    • 부호화된 레코드는 부호화된 필드의 연결일 뿐이다.
    • 부호화된 데이터는 필드 이름을 전혀 참조하지 않기 때문에 필드이름은 변경할 수 있다.
    • 하지만, 필드 태그의 경우 기존의 모든 부호화된 데이터를 인식 불가능하게 할 수 있어서 변경할 수 없다.
    • 상위 호환성 유지
      • 필드에 새로운 태그 번호를 부여하는 방식으로 스키마에 새로운 필드 추가 가능
        • 예전 코드에서 새로운 코드로 기록된 데이터를 읽으려는 경우에는 해당 필드를 간단히 무시할 수 있다.
    • 하위 호환성 유지
      • 새로 추가한 필드를 required 로 하지 않고 optional로 하거나 기본 값을 가지게 하면 된다.

데이터타입과 스키마 발전

  • 필드의 데이터 타입을 변경하는 건 어떤가?
    • 값이 정확하지 않거나 잘릴 위험이 존재함

아브로

  • 스리프트가 하둡의 사용 사례에 적합하지 않아 2009년 하둡의 하위 프로젝트로 시작함
  • 아브로는 2가지 스키마 언어를 지원 한다.
    • 아브로IDL
    • JSON
record Person {
		string               userName;
		union { unll, long}  favoriteNumber = null;
		array<string>        interests;

}

{
	"type" : "recode",
	"name" : "Person",
	"fields" : [
		{"name" : "userName" , "type" : "string"},
		{"name" : "favoriteNumber", "type" : ["null","long"], "default" : null},
		{"name" : "interests", "type" : {"type" : "array", "items": "string"}}
	]
}
  • 스리프트와 프로토콜버퍼와 다르게 스키마에 태그 번호가 없다.
  • 아브로 부호화 모습
    • 위 그림을 보면 필드나 데이터타입을 식별하기 위한 정보가 없다.
    • 부호화는 단순히 연결된 값으로 구성된다.
    • 아브로를 이용해 이진 데이터를 파싱하려면 스키마에 나타낸 순서대로 필드를 살펴보고 스키마를 이용해 각 필드의 데이터타입을 “미리” 파악해야 한다.
      • 데이터를 읽는 코드가 데이터를 기록한 코드와 정확히 같은 스키마일 경우에만 올바르게 복호화 할 수 있음을 뜻한다.

쓰기 스키마와 읽기 스키마

  • 어떤 데이터를 아브로로 부호화하길 원한다면 알고 있는 스키마 버전을 사용해 데이터를 부호화 하면 되는데, 이를 쓰기 스키마라고 한다.
  • 파일, DB or 네트워크 수신 등으로 읽은 데이터를 복호화하길 원한다면 데이터가 특정 스키마로복호화하길 기대하는데 이 스키마를 읽기 스키마 라고 한다.
  • 아브로의 핵심 아이디어는 이 쓰기 스키마와 읽기 스키마는 동일하지 않아도 되고, 단지 호환 가능하면 된다는 것

스키마 발전 규칙

  • 아브로에서 상위 호환성
    • 새로운 버전의 쓰기 스키마와 예전 버전의 읽기 스키마
  • 아브로에서 하위 호환성
    • 새로운 버전의 읽기 스키마와 예전 버전의 쓰기 스키마

동적 생성 스키마

  • 스리프트와 프로토콜 버퍼와 다르게 아브로 방식은 동적 생성 스키마에 좀 더 친숙하다.
  • 즉, 아브로는 동적 생성 스키마를 고려해 설계되어 있다.
  • 스리프트나 프로토콜 버퍼의 경우 데이터베이스 스키마 변경 시 필드 태그를 수동으로 할당 해야만 한다.
    • 스키마 변경 때 마다 컬럼 이름과 필드 태그의 매핑을 수동 갱신 해줘야 함..

코드 생성과 동적 타입 언어

  • 스리프트와 프로토콜 버퍼는 코드 생성에 의존한다.
    • 자바, C++ ,C# 같은 정적 타입 언어에서 유용함
  • 아브로의 경우 코드 생성 을 선택적으로 제공하나, 코드 생성 없이도 사용할 수 있다
    • 즉, 자바스크립트, 루비, 파이썬 같은 동적 타입 프로그래밍 언어에서도 사용하기 유용하다.

중간 요약

  • JSON , XML , CSV 같은 텍스트 데이터 타입이 널리 사용되지만, 스키마를 기반으로 한 이진부호화 또한 선택 할 수 있다!

데이터플로 모드

  • 데이터플로는 매우 추상적인 개념이며, 하나의 프로세스에서 다른 프로세스로 데이터를 전달하는 방법은 아주 많다!
  • 가장 보편적인 방법
    • 데이터베이스
    • 서비스 호출
    • 비동기 메시지 전달

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

  • 데이터베이스에 기록하는 프로세스는 데이터를 부호화 하고, 데이터를 읽는 프로세스는 데이터를 복호화한다.

서비스를 통한 데이터플로 (REST , RPC)

  • REST (REpresentational State Transfer)

    • 간단한 데이터 타입을 강조하며, URL 을 사용해 리소스 식별 및 캐시 제어, 인증, 콘텐츠 유형 협상에 HTTP 기능을 사용한다.
    • REST 원칙에 따라 설계된 API 를 Restful API 라 한다.
    • 참고영상 : https://www.youtube.com/watch?v=RP_f5dMoHFc
  • RPC (Remote Procedure Call)

    • 원격 네트워크 서비스 요청을 같은 프로세스 안에서 특정 프로그래밍 언어의 함수나 메서드를 호출하는 것과 동일하게 사용 가능케 해준다. (이런 추상화를 “위치 투명성" 이라 한다.)
    • 장점
      • 다양한 언어를 가진 환경에서 쉽게 확장 가능
      • 비즈니스 로직에 집중 (하위 네트워크 프로토콜 관련해서 신경쓰지 않아도 됨)
    • 근본적인 문제
      • 네트워크 요청은 로컬 함수 호출과는 매우 다르다는 점
      • 로컬 함수는 예측 가능하다, 하지만 네트워크 요청의 경우 예측이 어렵다.
      • 예를들어 faill 한 요청에 대해 retry 하는 등의 대첵을 미리 세워야 한다.
    • RPC 프레임워크들
      • 스리프트와 아브로는 RPC 지원 기능을 내장 하고 있음
      • gRPC는 프로토콜 버퍼를 이용한 RPC 의 구현체
  • REST vs RPC ?

    • 굳이 비교를 해보자면, REST 상에서 JSON 과 같은 부류의 프로토콜보다 이진 부호화 형식을 사용자 정의 RPC 프로토콜이 우수한 성능을 제공할지도 모른다.
    • 하지만 REST 의 경우 실험과 디버깅에 적합하며, 모든 주요 프로그래밍 언어와 플랫폼을 지원하며 다양한 도구 생태계가 있다. (범용성이 더 좋음)

메시지 전달 데이터플로

  • 메시지 브로커
    • 클라이언트 요청을 낮은 latency 로 다른 프로세스에 전달하는 점에서는 RPC 와 비슷하다.
    • 메시지를 직접 네트워크 연결로 전송하지 않고 임시로 메시지를 저장하는 메시지 브로커 라는 중간 단계를 거쳐 전송하는 점은 데이터베이스와 유사하다.
    • 메시지 브로커를 사용하는 방식이 직접 RPC 를 사용하는 방식 보다 좋은점
      • 수신자가 사용 불가능이거나 과부하 상태면 메시지 브로커가 버퍼처럼 동작하기에 시스템 안정성 향상
      • 메시지 유실 방지
      • 송신자가 수신자의 IP 주소나 포트를 알 필요가 없음
      • 브로드캐스팅 가능
    • 메시지 전달 통신은 일반적으로 단방향임
      • 송신 프로세스는 대개 메시지에 대한 응답을 기대하지 않음
      • 송신 프로세스는 메시지가 전달될 때까지 기다리지 않고 단순한 메시지를 보낸 뒤 잊어버림
    • 메시지 브로커를 구현한 오픈소스
      • ActiveMQ , RabbitMQ , Kafka ... 등
  • 분산 액터 프레임워크
    • 액터 모델
      • 단일 프로세스 안에서 동시성을 위한 프로그래밍 모델
        • 스레드를 직접 핸들링 하는 대신 로직이 액터에 캡슐화 된다.
    • 분산 액터 프레임워크는 여러 노드 간 애플리케이션 확장에 사용된다.
    • 종류
      • Akka , Orleans , erlang ...

좋은 웹페이지 즐겨찾기