[데이터 중심 애플리케이션 설계] 4장

qwer·2022년 3월 16일
1

📖 오늘 읽은 범위

4장. 부호화와 발전

만물은 변한다. 그대로 있는 것은 아무것도 없다.

  • 대부분 애플리케이션 기능을 변경하려면 저장하는 데이터도 변경 해야 함
  • 데이터 타입이나 스키마가 변경될 때 애플리케이션 코드에 대한 변경이 발생함. 하지만 대규모 애플리케이션에서 코드 변경은 보통 즉시 반영이 힘듬
  • 이것은 예전 버전의 코드와 새로운 버전의 코드, 이전의 데이터 타입과 새로운 데이터 타입이 동시에 공존할 수 있다는 뜻
  • 시스템이 원활하게 실행되려면 양방향으로 호환성 유지 필요
    • 하위 호환성: 새로운 코드는 예전 코드가 기록한 데이터를 읽을 수 있어야 한다.
    • 상위 호환성: 예전 코드는 새로운 코드가 기록한 데이터를 읽을 수 있어야 한다.
  • 하위 호환성을 일반적으로 어렵지 않지만 상위 호환성은 예전 버전의 코드가 새 버전의 코드에 의해 추가된 것을 부시할 수 있어야 하므로 어려움

데이터 부호화 형식

  • 프로그램은 보통 두 가 지 형태로 표현된 데이터를 사용
    • 메모리에 객체, 구조체, 배열, 해시 테이블 등으로 데이터를 유지
    • 데이터를 파일에 쓰거나 네트워크를 통해 전송하기 위해서는 바이트열의 형태로 부호화 필요
  • 인메모리 표현에서 바이트열로의 전환을 부호화(직렬화 또는 마샬링)라고 함

언어별 형식

  • 프로그래밍 언어에 내장된 부호화 라이브러리는 편리하지만 문제점도 많음
    • 부호화는 보통 특정 프로그래밍 언어와 묶여 있어 다른 언어에서 데이터를 읽기가 매우 어려움
    • 동일한 객체 유형의 데이터를 복원하려면 복호화 과정이 임의의 클래스를 인스턴스화 할 수 있어야 함
      • 보안문제 발생 원인
      • 공격자가 임의의 바이트열을 복호화할 수 있는 애플리케이션을 확보하게 되면 클래스를 인스턴스화 할 수 있고 공격자가 원격으로 임의 코드를 실행할 수 있게 됨
    • 데이터의 버전 관리의 어려움
    • 효율성 문제
      • 부호화나 복호화에 소요되는 CPU시간과 부호화된 구조체 크기 등이 문제가 될 수 있음
      • 자바의 내장 직렬화는 성능이 좋지 않음

JSON과 XML, 이진 변형

  • XML과 CSV는 수와 숫자로 구성된 문자열을 구분할 수 없음
  • JSON은 문자열과 수를 구분하지만 정수와 부동소수점을 구별하지 않고 정밀도를 지정하지 않음
  • 이 문제는 큰 수를 다룰 때 문제가 됨
  • JSON, XML은 유니코드 문자열을 지원하지만, 이진 문자열을 지원하지 않기 때문에 Base64를 사용해 텍스트로 부호화 가능
  • CSV는 스키마가 없으므로 칼럼의 의미를 애플리케이션에서 직접 처리해야 함

스리프트와 프로토콜 버퍼

  • 아파치 스리프트(Apache Thrift)와 프로토콜 버퍼(Protocol Buffers)는 이진 부호화 라이브러리
  • 두 라이브러리 모두 부호화할 데이터를 위한 스키마가 필요
  • 스리프트는 바이너리 프로토콜과 컴팩트 프로토콜 방식으로 이진 부호화를 진행함

아브로(Avro)

  • 2009년 하둡의 하위 프로젝트로 시작
  • 부호화할 데이터 구조를 지정하기 위해 스키마를 사용
  • 두개의 스키마 언어가 존재
    • 아브로 IDL(Avro IDL): 사람이 편집할 수 있음
    • JSON 기반 언어: 기계가 더 쉽게 읽을 수 있음
  • 이진 데이터를 파싱하려면 스키마에 나타난 순서대로 필드를 살펴보고 스키마를 이용해 각 필드의 데이터타입을 미리 파악해야 함

스키마의 장점

  • 프로토콜 버퍼, 스리프트, 아브로는 XML, JSON 스크마에 비해 훨씬 간단하고 더 자세한 유효성 검사 규칙을 지원
  • 이진 부호화에는 좋은 속석이 많음
    • 부호화된 데이터에서 필드 이름을 생략이 가능해서 이진JSON 변형보다 크기가 훨씬 작음
    • 복호화를 할 때 스키마가 필요하기 때문에 스키마가 최신 상태인지를 확인 가능
    • 스키마 데이터베이스를 유지하면 스키마 변경이 적용되기 전에 상위 호환성과 하위 호환성을 확인 가능
    • 정적 타입 프로그래밍 언어에서 컴파일 시점에 타입체크를 할 수 있기 때문에 스키마에서 코드를 생성하는 기능은 유용

데이터플로 모드

  • 하나의 프로세스에서 다른 프로세스로 데이터를 전달하는 여러가지 방법
    • 데이터베이스
    • 서비스 호출
    • 비동기 메시지 전달

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

  • 데이터를 부호화하고 데이터베이스에서 읽는 프로세스는 데이터를 복호화함
  • 대용량 데이터를 마이그레이션 하는 작업은 비싼 비용의 작업이기 때문에 대부분의 관계형 데이터베이스는 기존 데이터를 다시 기록하지 않고 null을 기본값으로 갖는 새로운 칼럼을 추가함
  • 백업 목적이나 데이터 웨어하우스 저장 목적의 데이터 덤프는 복사본을 일관되게 부호화 하는 편이 나음

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

  • 일반적인 방법으로는 서버-클라이언트 방식
  • 서버가 공개한 API를 서비스 라고 부름
  • 웹 브라우저만 클라이언트가 아니라 서버 자체가 다른 서비스의 클라이언트 일 수 있음
  • 이러한 애플리케이션 개발 방식을 마이크로서비스 설계(microservices architecture, MSA)라고 부름
    • MSA의 핵심 설계 목표는 서비스를 배포와 변경에 독립적으로 만들어 애플리케이션의 변경과 유지보수를 더욱 쉽게 만드는 것
  • REST란?
    • REST는 프로토콜이 아니라 HTTP의 원칙을 토대로 한 설계 철학
    • 간단한 데이터 타입을 강조하며 URL을 사용해 리소스를 식별하고 캐시 제어, 인증, 콘텐츠 유형 협상에 HTTP 기능을 사용
    • REST 원칙에 따라 설계된 API를 RESTful 이라고 부름

원격 프로시저 호출(RPC)

  • RPC(remote procedure call) 모델은 원격 네트워크 서비스 요청을 같은 프로세스 안에서 특정 프로그래밍 언어의 함수나 메서드를 호출하는 것과 동일하게 사용 가능
  • 편리한 것 같지만 근본적인 결함이 존재
    • 로컬 함수 호출은 결과를 반환하거나 예외를 내거나 반환하지 않을 수 있음
      • 하지만 네트워크 요청은 타임아웃으로 결과 없이 반환될 수 있음
    • 실패한 요청을 retry 할때 실제로는 처리되고 응답만 유실 될 가능성 존재
      • 이 경우 프로토콜에 멱등성을 적용하지 않으면 retry가 여러 번 수행될 수 있음
    • 네트워크 요청은 로컬 함수 호출에 비해 훨씬 느림
    • 로컬 함수 호출의 경우 포인터를 로컬 메모리 객체에 효율적으로 전달 가능한 반면 네트워크 요청은 모든 매개변수는 네트워크를 통해 전송해야 하기 때문에 바이트열로 부호화를 해야함
      • 성능 이슈 존재 가능성
    • 클라이언트와 서비스는 다른 프로그래밍 언어로 구현 가능하므로 RPC 프로임워크는 하나의 언어에서 다른 언어로 데이터타입을 변환해야 함
    • RPC 프레임워크의 주요 목적은 같은 데이터센터 내의 같은 조직이 소유한 서비스 간 요청

비동기 메시지 전달 시스템

  • 수신자가 사용 불가능하거나 과부하 상태일 경우 메시지 브로커가 버퍼처럼 동작할 수 있기 때문에 시스템 안정성이 향상
  • 장애가 발생했던 수신자에 다시 메시지를 전달함으로써 메시지 유실 방지
  • 송신자가 수신자의 IP나 포트를 몰라도 됨
    • 가상 장비를 이용하는 클라우드 시스템에서 유용)
  • 하나의 메시지를 여러 수신자로 전송 가능
  • 논리적으로 송신자와 수신자는 분리됨
    • 송신자는 메시지를 게시(publish)할 뿐이고 누가 소비(consume)하는지 상관하지 않음
  • 일반적으로 단방향이라는 점이 RPC와의 차이점
  • 메시지 브로커는 보통 특정 데이터 모델을 강요하지 않음

분산 액터 프레임워크

  • 액터 모델(actor model)은 단일 프로세스 안에서 동시성을 위한 프로그래밍 모델
  • 스레드(경쟁 조건, locking, deadlock과 연관된 문제들)를 직접 처리하는 대신 로직이 액터에 캡슐화 됨
  • 보통 각 액터는 하나의 클러이언트나 엔티티를 뜻함
  • 액터는 로컬 상태를 가질 수 있고 비동기 메시지의 송수신으로 다른 액터와 통신
  • 각 액터 프로세스는 한번에 하나의 메시지만 처리하기 때문에 thread-safe함
  • 분산 액터 프레임워크는 메시지 브로커와 액터 프로그래밍 모델을 단일 프레임워크에 통합
  • 단, 액터 기반 애플리케이션의 rolling-upgrade 를 수행하려면 메시지가 새로운 버전을 수행하는 노드에서 예전 버전을 수행하는 노드로 전송할 수 있으므로 상하위 호환성에 주의해야 함
  • 분산 액터 프레임워크의 예로는 Akka, Orleans, erlang 이 존재

0개의 댓글