Skip to main content

12. 데이터 시스템의 미래

  • 앞에서는 존재하는 것에 설명했다면 마지막은 미래에는 어떻게 돼야 하는지를 설명합니다.
  • 책의 목적은 애플리케이션과 시스템을 신뢰할 수 있고 확장 가능하며 유지보수하기 쉽게 만드는 방법을 탐구하는 것입니다.

데이터 통합#

  • 책에서는 어떤 문제에 대한 해결책을 놓고 장점과 단점, 트레이드 오프에 대해 설명했습니다.
  • 가장 적절한 소프트웨어 도구를 선택하는 것은 상황에 다릅니다.
    • 선택의 폭이 넓을 경우, 소프트웨어 제품과 그 제품이 잘 어울리는 환경 사이의 대응관계를 파악하는 것입니다.
    • 대응관계를 이해해도, 데이터를 사용하는 모든 다른 상황에 적합한 소프트웨어가 있을 확률은 낮습니다. 즉, 여러 다른 소프트웨어를 함께 엮어 사용해야 합니다.

파생 데이터와 특화된 도구의 결합#

  • 예를 들어, OLTP 데이터베이스와 임의의 키워드를 대상으로 질의하는 전문 검색 색인을 통합하는 요구는 일반적입니다.
    • PostgreSQL와 같은 데이터베이스는 간단한 애플리케이션을 만들기는 충분하지만 복잡한 검색 기능을 지원하기 위해서는 전문적인 탐색도구가 필요합니다.
    • 역으로 검색 색인은 일반적으로 지속성 있는 레코드 시스템으로는 적합하지 않으므로 많은 애플리케이션은 요구사항을 만족하기 위해 두 도구를 결합합니다.
  • 데이터 통합의 필요성은 나무가 아닌 숲을 보기 위해 줌아웃해서 조직 전체 데이터플로를 고려할 때야 비로소 명확해집니다.

데이터플로에 대한 추론#

  • 다른 데이터 접근 양식을 만족하기 위해 같은 데이터의 사본을 여러 저장소 시스템에 유지해야 할 때 입력과 출력을 분명히 해야합니다.
    • 어디서 데이터를 처음으로 기록하는지, 어떤 표현형이 어떤 원본에서 파생되는지, 데이터를 모두 올바른 장소로 올바른 형식으로 어떻게 넣는지 등에 대해 충분히 고려해야 합니다.
  • 파생 데이터 시스템은 이벤트 로크를 기반으로 갱신하면 결정적이록 멱등성을 지녀 결함에서 복구하기가 상당히 쉬워집니다.

파생 데이터 대 분산 트랜잭션#

  • 파생 데이터와 분산 트랜잭션은 큰 차이점이 있습니다.
    • 트랜잭션 시스템은 일반적으로 선형성을 지원합니다. (자신이 쓴 내용 읽기 같은 유용한 기능을 보장합니다)
    • 파생 데이터 시스템은 대개 비동기로 갱신되기 때문에 기본적으로 동시간 갱신 보장을 하지 않습니다.
  • 좀 더 나은 분산 트랜잭션 방법이 있을 것이나, 훌륭한 분산 트랜잭션 프로토콜이 널리 지원되지 않는 상태에서 나는 로그 기반 파생데이터가 이종 데이터 시스템을 통합하는 장래성 있는 접근법이라 생각합니다.
  • 즉, 최종적 일관성을 어떻게 다루는 지에 고민해야 니다.

전체 순서화의 제약#

  • 작은 시스템에서 이벤트 로그의 순서 전체를 보장하는 것은 가능하나 규모가 커지면 한계가 등장합니다. 아래 모두 순서가 애매합니다.
    • 대부분 전체 순서가 정해진 로그를 구축할 때 순서를 결정하려면 모든 이벤트가 단일 리더 노드 를 통해야 합니다. 그러나 규모가 커지면 복수의 장비로 파티셔닝을 해야합니다.
    • 데이터센터 전체가 오프라인 상태가 되는 것에 대처하기 위해 서버가 지역적으로 분산된 여러 데이터센터에 걸쳐있다면 각 데이터센터에 독립적 리더를 둡니다.
    • 애플리케이션을 마이크로서비스로 배포한다고 가정할 때 흔히 선택하는 설계는 각 서비스와 서비스의 지속적인 관련 상태 정보를 독립단위로 배포하고 지속적인 상태는 서비스 간에 공유하지 않습니다.
    • 애플리케이션은 클라이언트 측 상태를 유지하고 사용자 입력이 들어올 때마다 서버의 확인 응답을 기다리지 않고 바로 갱신합니다.
  • 이벤트 전체 순서를 결정하는 것은 전체 순서 브로드캐스트 라고 합니다.
    • 브로드캐스트는 합의와 동등하지만 이러한 설게는 아직 해결되지 않은 연구 과정입니다. (2020.07 기준)

인과성 획득을 위한 이벤트 순서화#

  • 이벤트 간 인과성이 없는 경우 전체 순서가 정해지지 않아도 큰 문제가 아닙니다. 동시에 발생한 이벤트는 임의로 순서를 정할 수 있기 때문입니다.
  • 예시로 사회 연결망 서비스에서 관계를 맺은 두 사용자가 관계를 끊고, 한명이 남은 친구들에게 그 친구를 불평하는 메시지를 보냈습니다.
    • 이때 친구 상태를 저장하는 곳과 메시지를 저장하는 곳이 다른 시스템에서는 친구 끊기 이벤트와 메시지 보내기 이벤트 사이의 순서 의존성이 없습니다.
    • 인과성이을 획득하지 못하면 새 메시지에 대해 알림을 보내는 서비스가 메시지 보내기 이벤트를 친구 끊기 이벤트 전에 보내서 이전 친구에게 잘못된 알림을 보낼 가능성이 있습니다.
  • 위 경우는 조인의 타이밍 문제와 관련이 있습니다. 다만 간단히 해결할 방법은 아직 없습니다.
    • 논리적 타임스탬프를 사용하는 경우, 코디 네이션 없이 전체 순서화를 지원할 수 있기 때문에 전체 순서 브로드캐스를 쓸 수 없는 환경에서는 도움될 수도 있지만 잘못된 순서는 유지되고, 메타데이터 또한 줘야합니다.
    • 사용자가 결정을 내리기 전에 사용자가 본 시스템 상태를 기록하는 이벤트를 로깅할 수 있고 해당 이벤트에 고유 식별자를 부여할 수 있다면 이후 이벤트는 인과적 의존성을 기록하기 위한 이벤트 식별자를 참조할 수 있습니다.
    • 충동 해소 알고리즘은 예상치 못한 순서로 전송된 이벤트를 처리하는 데 도움을 줍니다.
  • 향후에는 모든 이벤트가 전체 순서 브로드캐스트의 병목을 거치지 않고서도 인과적 의존성을 효율적으로 캡처하고 파생 상태를 정확히 유지하는 애플리케이션 개발 패턴이 등장할 것입니다.

일괄 처리와 스트림 처리#

  • 데이터 통합의 목표는 데이터를 올바른 장소에 올바른 형태로 두는 것이라 생각됩니다.
  • 일괄 처리와 스트림 처리의 출력은 파생 데이터셋입니다.
  • 일괄 처리와 스트림 처리는 여러 공통 원리가 있지만, 일괄 처리와 스트림 처리의 근본적인 주요 차이점은 스트림 처리는 끝이 없는 데이터셋 상에서 운영되는 반면 일괄 처리는 유한한 크기의 입력을 사용합니다.
  • 스파크는 일괄 처리 엔진 상에서 스트림을 처리하는데 스트림을 마이크로 일괄 처리 단위로 나누어 일괄 처리합니다.
    • 반면 아파치 플링크는 스트림 처리 엔진 상에서 일괄 처리를 수행합니다.
    • 그러나 성능 특성은 다양하게 나타납니다.

파생 상태 유지#

  • 일괄 처리는 함수형 프로그래밍 언어로 코드를 사용하지 않아도 상당히 강력한 함수형 특징을 가집니다.
    • 일괄 처리는 결정적이고 출력이 입력에만 의존하며, 명시적 출력 외에는 다른 부수 효과가 없는 순수 함수를 장려합니다.
    • 스트림 처리도 유사하지만 연산자를 확장해 상태를 관리할 수 있고 내결함성을 지니게 됩니다.
  • 입력과 출력을 잘 정의한 결정적 함수의 원리는 내결함성에 도움이 될 뿐만 아니라 조직 내의 데이터플로 추론을 단순화합니다.
    • 한 가지로부터 다른 것을 파생하는 데이터 파이프라인의 관점에서 생각하는 것은 도움이 됩니다.
    • 데이터 파이프라인은 함수형 애플리케이션 코드를 통해 한 시스템의 상태 변화를 밀어 넣고 그 결과를 파생 시스템에 적용합니다.
  • 이론상으로 파생 데이터 시스템은 관계형 데이터베이스가 색인할 테이블에 기록하는 트랜잭션 내에 보조 색인을 동기식으로 갱신하는 것처럼 동기식으로 운영할 수 있습니다.
    • 비동기 방식을 사용하면 이벤트 로그 기반 시스템을 훨씬 견고하게 만듭니다.
    • 분산 트랜잭션은 참여 장비 일부가 실패하면 어보트하기 때문에 나머지 시스템으로 실패가 확산되어 실패가 증폭되는 경향이 있습니다.
  • 보조 색인을 가진 파티셔닝된 시스템이 색인을 용어 기준으로 파티셔닝했다면 복수의 파티션으로 쓰기 요청을 보내야 합니다.
    • 색인을 문서 기준으로 파티셔닝했다면 모든 파티션으로 읽기 요청을 보내야 합니다.
    • 색인을 비동기 방식으로 유지한다면 이런 파티션 간 통신에서 더욱 신뢰성 있고 확장성이 좋아집니다.

애플리케이션 발전을 위한 데이터 재처리#

  • 파생 데이터를 유지할 때 일괄 처리와 스트림 처리는 모두 유용합니다.
    • 스트림 처리를 이용하면 입력의 변화를 빠르게 파생 뷰에 반영할 수 있습니다.
    • 일괄 처리 시스템을 사용하면 누적된 상당한 양의 과거 데이터를 재처리해 기존 데이터셋을 반영한 새 파생 뷰를 만들 수 있습니다.
  • 기존 데이터를 재처리하는 것은 시스템을 유지보수하기 위한 좋은 메커니즘으로 새로운 기능 추가와 변경된 요구사항에 대응할 수 있습니다.
  • 파생 뷰를 사용하면 점진적 발전이 가능합니다.
    • 이전 스키마와 새 스키마를 함께 유지해 같은 데이터를 기반으로 두 개의 독립적인 파생 뷰를 만들 수 있으며 점진적으로 새 뷰를 접근하는 비율을 늘려 기존 뷰를 내릴 수 있습니다.
  • 점진적 이전의 장점은 처리의 모든 단계에서 뭔가 잘못됐을 때 쉽게 이전으로 되돌릴 수 있다는 점입니다.
    • 되돌릴 수 있음으로 좀 더 자신감을 가지고 있고, 시스템을 빠르게 개선할 수 있습니다.

람다 아키텍처#

  • 일괄 처리르 과거 데이터를 재처리하는 데 사용하고 스트림 처리를 최근 갱신 데이터를 처리하는 데 사용한다고 할 때 두방식을 조합해 사용하는 방법으로 람다 아키텍처(lambda architecture) 가 대표적인 제안입니다.
  • 람다 아키텍처의 핵심 아이디어는 입력 데이터를 불변 이벤트로서 증가하기만 하는 데이터셋에 추가하는 방식으로 기록해야 한다는 것으로 이벤트 소싱과 유사합니다.
    • 람다 아키텍처는 두 개의 다른 시스템을 병행해서 운용하기를 제안합니다.
  • 람다 아키텍처 접근법에서 스트림 처리자는 이벤트를 소비해 근사(approximate) 생신을 뷰에 빠르게 반영합니다. 이후에 일괄 처리자가 같은 이벤트 집합을 소비해 정확한 버전의 파생 뷰에 반영합니다.
    • 람다 아키텍처의 설계 배경은 일괄 처리는 간단해서 버그가 생길 가능성이 적은 반면 스트림 처리자는 신뢰성이 떨어지고 내결함성을 확보하기 어렵다는 것입니다.
    • 일괄 처리가 느리고 정확한 알고리즘을 사용하는 반면 스트림 처리는 빠른 근사 알고리즘을 사용할 수 있습니다.
  • 람다 아키텍처는 데이터 시스템 설계를 향상시키는 데 영향을 준 아이디어이며 특히 불변 이벤트 스트림에 대한 뷰를 파생하고 필요할 때 이벤트를 재처리하는 원리를 제공했습니다. 다만 람다 아키텍처에는 실질적인 몇 문제가 있습니다.
    • 일괄 처리와 스트림 처리 양쪽 프레임워크에서 같은 로직을 유지해야 하는 데는 상당한 노력이 필요합니다.
    • 스트림 파이프라인과 일괄 처리 파이프라인은 분리된 출력을 생산하기 때문에 사용자 요청에 대응하기 위해 출력을 병합해야 합니다.
    • 전체 과거 데이터를 재처리할 수 있다는 점은 좋으나 그 비용도 큽니다.

일괄 처리와 스트림 처리의 통합#

  • 최근에는 일괄 처리 연산과 스트림 연산을 모두 구현함으로써 람다 아키텍처의 단점을 빼고 장점만 취할 수 있게 하는 작업이 진행되었습니다.
    • 최근 이벤트 스트림을 다루는 처리 엔진에서 과거 이벤트를 재생하는 능력이 있습니다.
    • 스트림 처리자에서 사용되는 정확히 한 번 시맨틱입니다. 이 기능은 실제로 결함이 발생하더라도 결함이 없었던 상황과 동일한 출력을 내는 것을 보장합니다.
    • 처리 시간 기준이 아니라 이벤트 시간 기준으로 윈도를 처리하는 도구가 생겼습니다.

데이터베이스 언번들링#

  • 추상화 수준에서 보면 데이터베이스, 하둡, 운영체제는 모두 같은 기능을 수행합니다.
    • 이 시스템은 모두 데이터를 저장하고 처리하며 질의도 합니다.
    • 데이터베이스는 특정 데이터 모델의 레코드로 데이터를 저장합니다.
    • 운영 체제는 데이터를 파일로써 파일 시스템에 저장합니다.
  • 물론 실제로는 많은 차이가 있지만, 운영체제와 데이터베이스 사이의 유사점과 차이점은 탐구할 가치가 있습니다.
  • 유닉스와 관계형 데이터베이스는 정보 관리 문제를 각기 다른 철학으로 접근했습니다.
    • 논리적이지만 꽤 저수준인 하드웨어 추상화를 프로그래머에게 제공하는 것으로 목적을 둡니다.
    • 관계형 데이터베이스는 디스크 상의 자료 구조, 동시성, 장애 복구 등의 복잡성을 감추는 고수준 추상화를 애플리케이션 프로그래머에게 제공했습니다.
  • 무엇이 좋을 지는 무엇을 원하느냐에 따라 달라집니다.

데이터 저장소 기술 구성하기#

위에서 데이터베이스가 제공하는 다양한 기능을 설명하고, 그 기능이 어떻게 동작하는지를 설명합니다.

  • 보조 색인은 필드 값을 기반으로 레코드를 효율적으로 검색할 수 있는 기능입니다.
  • 구체화 뷰는 질의 결과를 미리 연산한 캐시의 일종입니다.
  • 복제 로그는 데이터의 복사본을 다른 노드에 최신 상태로 유진하는 기능입니다.
  • 전문 검색 색인은 텍스트에서 키워드 검색을 가능하게 하는 기능으로 일부 관계형 데이터베이스는 이 기능을 내장합니다.

데이터베이스에 내장된 기능과 일괄 처리와 스트림 처리로 구축하는 파생 데이터 시스템 사이에는 유사점이 있스빈다.

색인 생성하기#

  • 데이터베이스는 테이블의 일관된 스냅숏을 사용해 스캔하고 색인할 필드 값을 모두 골라 정렬하고 색인에 기록합니다.
    • 그 다음에 일관된 스냅숏을 사용해 스캔하고 색인한 필드 값을 모두 골라 정렬하고 색인에 기록합니다.
  • CREATE INDEX를 실행할 때마다 데이터베이스는 근본적으로 기존 데이터베이스는 근본적으로 기존 데이터셋을 재처리해서 기존 데이터를 반영하는 새로운 뷰로서 색인을 파생합니다.

모든 것의 메타데이터베이스#

  • 일종의 전체 조직의 데이터플로가 거대한 데이터베이스처럼 볼 수 있습니다.
  • 일괄 처리와 스트림 처리자는 트리거와 스토어드 프로시저 그리고 구체화 뷰 유지 루틴을 정교하게 구현한 것과 같습니다.
연합 데이터베이스: 읽기를 통합#

연합 데이터베이스 또는 폴리스토어라고 알려진 접근법은 엄청나게 많은 하단 저장소 엔진과 처리 메서드를 통합해 질의하는 인터페이스를 제공합니다.

언번들링 데이터베이스: 쓰기를 통합#

연합 데이터베이스는 다른 여러 시스템을 읽기 전용으로 질의하는 문제를 해결하지만 여러 시스템에 걸친 쓰기를 동기화하기에는 적합하지 않은 해결책입니다.

저장소 시스템들을 신뢰성 있게 결합하기 쉽게 만드는 것은 데이터베이스의 색인 유지 기능을 다른 기술에 걸친 쓰기를 도이과할 수 있는 방식으로 언번들링(unbundling) 하는 방식과 유사합니다.

언번들링 동작하게 만들기#

  • 다양한 구성 요소로부터 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 시스템을 만든다는 측면에서 연합과 언번들링은 동적의 양면과 같습니다.
  • 쓰기를 동기화하는 전통적인 접근법은 이종 저장소 시스템 간 분산 트랜잭션이 필요합니다.
    • 데이터가 다른 기술 사이의 경계를 오간다면 멱등성을 기반으로 쓰기를 수행하는 비동기 이벤트 로그를 사용하는 편이 훨씬 더 강력하고 현실적입니다.
  • 분산 트랜잭션은 특정 스트림 처리자 내에서 정확히 한 번 시맨틱을 달성하기 위해 사용할 수 있는데 상당히 잘 작동합니다.
  • 로그 기반 통합의 큰 장점은 다양한 구성 요소 간 느슨한 결합(loose coupling) 입니다.
    • 시스템 수준에서 비동기 이벤트 스트림을 사용하면 전체 사용하면 전체 시스템이 개별 구성 요소의 장애나 성능 저하가 생겨도 잘 견디게 만들 수 있습니다.
    • 인적 수준에서 데이터 시스템을 언번들링하면 소프트웨어 구성 요소와 서비스를 다른 팀에서 각자 개발하고 개선하고 독립적으로 유지보수할 수 있습니다.

언번들링 대 통합 시스템#

  • 언번들링이 실제로 미래에 사용될 방법이라고 해도 현재 형태의 데이터베이스를 대체하지는 못합니다.
    • 데이터베이스는 그 어느 때보다도 필요하며, 데이터베이스는 여전히 스트림 처리자의 상태를 유지하기 위해 필요하고 일괄 처리와 스트림 처리자의 출력에 대한 질의를 처리하기 위해서도 필요합니다.
  • 여러 다른 인프라에서 수행하는 복잡성도 문제가 될 수 있습니다.
    • 동적 부분을 가능하면 적게 배포해야 유리합니다.
  • 언번들링의 목표는 특정 작업부하에 대한 성능 측면에서 개별 데이터베이스와 경쟁하는 것이 아닙니다.
    • 몇 개의 다른 데이터베이스와 결합해 단일 소프트웨어로 가능한 것보다 더 넓은 범위의 작업 부하에 대해 좋은 성능을 달성하기 위합입니다.
  • 필요한 모든 것을 만족하는 단일 기술이 있다면 저수준 구성 요소로부터 직접 재구현하려 하지말고 그냥 해당 제품을 사용하는 것이 좋습니다.
    • 언번들링과 합성의 장점은 요구사항을 모두 만족하는 단일 소프트웨어가 없는 상황에서만 드러난다.

뭐가 빠졌지?#

  • 데이터 시스템을 구성하는 도구는 점점 좋아집니다. 그러나 유닉스 셀과 동일한 언번들링 데이터베이스가 존재하지 않습니다.
  • mysql : elasticsearch 와 같이 단순하게 선언하면 좋을 것 같습니다.
  • 마찬가지로 캐시를 사전계산하고 좀 더 쉽게 갱신할 수 있으면 매우 좋을 것입니다. 구체화 뷰는 본질적으로 사전계산된 캐시입니다.
    • 이 분야에서 예시로 미분 데이터플로(differential dataflow) 등이 있습니다.

데이터플로 주변 애플리케이션 설계#

  • 애플리케이션 코드로 특화된 저장소와 처리 시스템을 조립하는 언번들링 데이터베이스 접근법은 "데이터베이스 인사이드 아웃"이라고 합니다.
  • 현대 데이터 시스템은 내결함성과 확장성이 있어야 하고 지속성 있게 데이터를 저장해야 합니다.
    • 또한 데이터 시스템은 시간이 흐름에 따라 다른 그룹의 사람들이 개발한 이종 기술과도 통합이 가능해야 할 뿐 아니라 이미 존재하는 라이브러리와 서비스를 재사용 가능해야 합니다.

파생 함수로서의 애플리케이션 코드#

  • 데이터셋이 다른 데이터셋으로부터 파생될 때는 변환 함수 몇가지를 거칩니다.
    • 보조 색인은단순한 변환 함수를 사용하는 파생 데이터셋의 일종입니다.
    • 전문 검색 색인은 언어 감지, 단어 분리, ... 등의 다양한 자연어 처리 함수를 적용한 다음 효율적인 조회를 위한 자료 구조를 구축합니다.
  • 보조 색인용 파생 함수는 아주 일반적인 요구사항이라서 많은 데이터베이스에 핵심 기능으로 내장돼 있습니다.
  • 파생 데이터셋을 생성하는 함수가 보조 색인 생성 함수와 같은 비슷한 표준 함수가 아니라면 사용자 정의 코드를 써서 애플리케이션에 특화된 측면을 다뤄야 합니다.

애플리케이션 코드와 상태의 분리#

  • 이론상 데이터베이스가 운영체제가 같이 임의의 애플리케이션 코드를 배포하는 환경이 될 수 있으나 이는 현실성이 부족합니다.
  • 그러나 메소스, yarn, docker, k8s 등과 같은 배포와 클러스터 관리 도구는 애플리케이션 코드를 수행하는 목적으로 특별히 설계되었습니다.
    • 하나를 잘하자는 관점에 집중함으로써 이 도구들은 데이터베이스가 많은 기능 중 하나로 사용자 정의 함수의 실행을 지원하는 것보다 훨씬 잘 할 수 있습니다.
  • 시스템의 일부는 지속성 있는 데이터 저장을 전문으로 하고 다른 일부는 애플리케이션 코드 실행을 전문으로 하는 게 합리적입니다. 두 부분이 독립적이라도 여전히 상호작용이 가능합니다.
  • 오늘날 대부분의 웹 애플리케이션은 상태 비저장 서비스로 배포됩니다.
    • 상태 비저장 서비스 내에서 사용자 요청은 어떤 애플리케이션 서버로도 라우트될 수 있습니다.
    • 상태 관리(데이터베이스)와 상태 비버장 애플리케이션 로직을 분리합니다.
  • 전형적인 웹 애플리케이션 모델에서 데이터베이스는 네트워크를 통해 동기식으로 접근할 수 있는 변경 가능한 공유 변수와 같이 동작합니다.
    • 애플리케이션은 이 변수를 읽고 갱신할 수 있으며 데이터베이스는 이 변수를 지속성 있게 만3들고 동시성 제어와 내결함성을 지원합니다.
  • 관찰자 패턴(observer pattern) 이라 알려진 알림 기능을 직접 구현할 수 있지만 대부분의 언어는 이 패턴을 내장 기능으로 지원하지 않습니다.
  • 데이터베이스는 변경 가능한 데이터에 대한 이러한 수동적 접근법을 상속합니다. 데이터베이스의 내용이 변경됐는지 확인하고 싶다면 폴링, 즉 주기적으로 질의를 반복하는 게 유일한 방법입니다.

데이터플로: 상태 변경과 애플리케이션 코드 간 상호작용#

  • 데이터플로 측면에서 애플리케이션을 생각한다는 것은 애플리케이션 코드와 상태 관리 간의 관계를 재조정한다는 의미입니다.
    • 데이터베이스를 애플리케이션이 직접 조작하는 수동적 변수로 취급하는 대신 상태와 상태 변경, 그리고 상태를 처리하는 코드 간의 상호작용과 협동에 관해 좀 더 생각해 볼 수 잇습니다.
  • 데이터베이스의 변경 로그를 구독 가능한 이벤트 스트림으로 취급하는 내용을 설명했습니다.
    • 튜플 공간(tuple space) 모델에서 상태 변화를 관찰해 그 변화에 반응하는 과정의 측면으로 분산 연산을 표현하는 방법을 탐구합니다.
  • 데이터베이스에서 데이터 변경으로 트리거가 발생하거나 색인된 테이블에 변경사항을 반영하기 위해 보조 색인을 갱신할 때 비슷한 일이 발생합니다.
    • 데이터베이스를 언번들링한다는 것은 이 아이디어를 통해 원본 데이터베이스 외부에 파생 데이터셋을 생성할 때 적용한다는 의미입니다.
  • 파생 데이터를 유지하는 것은 전통적인 메시징 시스템의 설계 목적인 비동기 작업 실행과는 같지 않습니다.
    • 파생 데이터를 유지할 때 상태 변경 순서가 중요할 때가 있습니다.
    • 내결함성은 파생 데이터의 핵심입니다.
  • 안정적인 메시지 순서화와 내결함성이 있는 메시지 처리는 상당히 엄격한 요구사항이지만 분산 트랜잭션보다 훨씬 저렴하면서 탄탄한 운영을 가능하게 합니다.
    • 최신 스트림 처리자는 대규모로 순서화와 신뢰성 보장을 제공합니다. 그리고 스트림 처리자에서 애플리케이션 코드를 스트림 연산자로 실행할 수 있습니다.
  • 애플리케이션 코드로 데이터베이스에 내장된 파생 함수가 일반적으로 지원하지 않는 임의 처리가 가능합니다.
    • 파이프로 연결한 유닉스 도구와 같이 스트림 처리자를 구성해서 데이터플로를 중심으로 대형 시스템을 구축할 수 있습니다.

스트림처리자와 서비스#

  • 최근 유행하는 애프리케이션 개발 스타일은 각 기능을 REST API와 같은 동기 네트워크 요청을 통해 통신하는 서비스의 집합으로 나누는 것입니다.
    • 단일 일체식 애플리케이션에 비해 서비스 지향 아키텍처의 가장 큰 장점은 느슨한 연결을 통한 조직적 확장성입니다.
  • 스트림 연산자로 데이터플로 시스템을 구성하는 것은 마이크로서비스 접근법과 유사한 특징이 상당히 많습니다. 그러나 기반이 되는 통신 메커니즘은 매우 다릅니다.
  • 향상된 내결함성 등 "메시지 전달 데이터플로"에 나열된 장점 외에도 데이터플로 시스템은 더욱 뛰어난 성능을 낼 수 있습니다.
  • 변경 스트림 구독은 필요할 때 현재 상태를 조회하는 것보다 스프레드시트의 연산 모델에 더 가깝습니다.
    • 일부 데이터 변경이 있을 때 해당 데이터에 의존하는 파생 데이터가 신속하게 갱신됩니다.

파생 상태 관찰하기#

  • 추상적인수준에서 지난 절에서 설명한 데이터플로 시스템은 검색 색인이나 구체화 뷰 또는 예측 모델과 같은 파생 데이터셋을 생성하고 최산 상태로 유지하는 과정에 사용할 수 있으며, 이 과정을 쓰기 경로(write path) 라 부릅니다.
  • 시스템에 정보를 기록할 때마다 일괄 처리와 스트림 처리의 여러 단계를 거친 다음 결과적으로 기록된 데이터를 모든 파생 데이터셋에 통합해 갱신합니다.
  • 파생 데이터를 생성하는 이유는 질의할 가능성이 크며, 이를 읽기 경로(read path) 라고 합니다.
    • 사용자 요청을 처리할 때 먼저 파생 데이터셋을 읽고 그 결과를 어느 정도 가공한 후 사용자 응답을 만듭니다.
  • 파생 데이터셋은 쓰기 경로와 읽기 경로가 만나는 장소입니다.
    • 파생 데이터셋은 쓰기 시간에 필요한 작업의 양과 읽기 시간에 필요한 작업의 양 간에 트레이드 오프를 나타냅니다.

구체화 뷰와 캐싱#

  • 전문 검색 색인은 좋은 예제입니다.
    • 키워드에서 모든 단어를 포함(AND)하거나 어떤것이든 포함(OR)하는 등의 논리를 적용해야 합니다.
  • 색인이 존재하지 않는다면 검색 질의는 모든 문서를 스캔해야 합니다.
    • 색인이 없으면 쓰기 경로의 작업량은 줄지만 읽기 경로의 작업이 상당히 늘어납니다.
  • 모든 가능한 질의의 겸색 결과를 미리 계산해 놓는 경우, 처리하는 작업량이 줄어듭니다.
    • 그러나, 무한한 시간과 저장 공간이 필요하므로 실제로는 어렵습니다.
  • 다른 선택지로 고정된 가장 공통적인 질의 집합의 검색 결과를 미리 계산하는 방법이 있습니다.
    • 이를 통해 색인까지 가지 않고 빠르게 처리 가능합니다.
    • 일반적으로 공통 질의 캐시라고 합니다.

오프라인 대응 가능한 상태 저장 클라이언트#

  • 과거와 달리 현재는 모바일 앱이나 웹 브라우저 모두, 로컬 저장소나 모바일 장치에 저장할 수 있어 상호작용 대부분을 처리할 때 서버까지 반복할 필요가 없습니다.
  • 이 능력 덕분에 오프라인 우선(offline-first) 애플리케이션이 관심 받기 시작했습니다.
    • 동기식 네트워크 요청을 기다리지 않아도 되는 경우, 사용자에게 상당한 이점입니다.
  • 상태 저비저장 클라이언트가 항상 중앙 서버와 통신한다는 가정에서 벗어나 최종 사용자 장치에서 상태를 유지하는 쪽으로 나아가면 새로운 기회가 있는 세상이 열립니다.
    • 특회 장치 상 상태를 서버 상 상태의 캐시로 생각할 수 있습니다.

상태 변경을 클라이언트에게 푸시하기#

  • 명시적으로 변경 사항을 폴링하지 않으면 장치의 상태는 갱신되지 않은 신선도가 떨어지는 캐시입니다.
  • 많은 최신 프로토콜이 HTTP의 기본적인 요청/응답 패턴을 벗어나고 있습니다.
    • 서버 전송 이벤트(이벤트 소스, Event Source API)와 웹소켓(WebSocket) 은 웹브라우저가 서버와 TCP 접속을 유지하면서 연결이 유지되는 동안 서버가 주도적으로 메시지를 브라우저에 보내는 방식의 통신 채널을 제공합니다.
    • 이 방식을 통해 서버의 로컬에 저장된 상태가 변경되었을 때 서버에서 주도적으로 사용자에게 알려줘, 클라이언트 측 상태의 신선도가 떨어지는 것을 줄여줍니다.
  • 로그 기반 메시지 브로커를 통해도 오프라인 장치에 대한 알림을 날려줄 수 있습니다.

종단 간 이벤트 스트림#

  • React, Flux, Redux 같은 상태 저장 클라이언트와 사용자 인터페이스 개발용 최신 도구는 이미 내부적으로 사용자 입력을 표현하는 이벤트 스트림이나 서버 응답 스트림을 구독하는 방식을 사용해 클라이언트 측 상태를 관리합니다.
    • 이 방식은 구조적으로 이벤트 소싱과 비슷합니다.
  • 상태 변경은 종단 간(end-to-end) 쓰기 경로를 따라 흐를 수 있습니다.
    • 즉, 상태 변경이 트리거된 한 장치의 상호작용으로부터 이벤트 로그를 거쳐 여러 파생 데이터 시스템과 스트림 처리자를 통해 다른 장치의 상태를 보고 있는 사람의 사용자 인터페이스까지 이어집니다.
  • 다만 쓰기 경로를 최종 사용자까지 확장하려면 근본적으로 시스템을 구축하는 방식을 재고할 필요가 있습니다.
    • 요청/응답 상호작용 방식에서 벗어나 발행/구독 데이터플로 방식으로 변경해야 한다는 의미입니다.
    • 데이터 시스템을 설계한다면 현재 상태를 단지 질의하는 방식이 아니라 변경 사항을 구독하는 방식을 염두에 두어야 합니다.

읽기도 이벤트다#

  • 스트림 처리자가 파생 데이터를 저장소에 기록할 때 그리고 사용자가 저장소에 질의 요청을 할 때 해당 저장소가 읽기 경로와 쓰기 경로 사이의 경계로 작동한다고 설명합니다.
    • 저장소는 임의 접근 읽기 질의가 가능합니다.
  • 읽기는 질의 대상 데이터가 저장된 노드로 직접 보내는 일시적 네트워크 요청입니다.
    • 이 설계 외에도 읽기 요청을 이벤트 스트림으로 표현하고 읽기 이벤트와 쓰기 이벤트 모두를 스트림 처리자를 통해 보내는 방법도 가능합니다.
  • 쓰기와 읽기 모두 이벤트로 표현하고 이벤트 처리를 위해 같은 스트림 연산자로 라우팅하는 것은 사실상 일기 질의 스트림과 데이터베이스 사이의 스틤 테이블 조인 수행과 동일합니다.
  • 일회성 읽기 요청은 단지 조인 연산자를 통해 흘러가고 이후 즉시 사라집니다. 구독 요청은 조인의 다른 쪽에 있는 과거, 미래 이벤트와의 영속적인 조인입니다.
  • 읽기 이벤트 로그를 기록하면 잠재적으로 인과적 의존성과 시스템 전체의 데이터 출처를 추적할 수 있다는 장점이 있습니다.
  • 지속성 있는 저장소에 읽기 이벤트를 기록하면 인과적 의존성을 추적하기가 더 용이합니다.
    • 다만 이 방법은 추가 저장소가 필요하며 I/O 비용이 발생합니다.

다중 파티션 데이터 처리#

  • 스트림 처리자가 이미 제공하는 메시지 라우팅과 파티셔닝, 그리고 조인용 인프라르 이용하면 여러 파티션의 데이터 통합이 필요한 복잡한 질의를 분산 실행할 수 있는 가능성을 열어줍니다.
  • 스톰의 분산 RPC 기능이 이런 사용 패턴을 지원합니다.
  • 질의를 스트림으로 간주하면 기송 솔루션의 한계를 넘는 대규모 애플리케이션을 구현하는 방법이 생깁니다.

정확성을 목표로#

  • 모두가 신뢰성 있고 정확한 애플리케이션을 구축하기를 원합니다.
  • 일관성은 종종 언급되지만 잘못 정의되기도 합니다.
  • 동시성이 적고 결함이 없는 간단한 솔루션은 종종 정확하게 작동하는 것처럼 보일 때도 있지만 더 많은 요구 상황이 있는 환경에서는 미묘한 버그가 많습니다.
  • 애플리케이션이 예측하지 못한 데이터의 깨짐이나 누락을 견딜 수 있다면 매우 단순해 질 수 있습니다.
    • 그러나 강력한 정확성 보장이 필요하다면 직렬성과 원자적 커밋이 확실한 방법이나 비용이 듭니다.
    • 확장성과 내결함성 속성을 제한합니다.

데이터베이스에 관한 종단 간 논증#

  • 직렬성 트랜잭션 같은 비교적 강력한 안전성 속성을 지원하는 데이터 시스템을 사용해도 애플리케이션에 데이터 유실과 손상이 없을 것이라는 보장은 없습니다.

연산자의 정확히 한 번 실행#

  • 내결함성에서 정확히 한 번(결과적으로 한 번) 시맨틱을 설명했으며 실패한다면 포기하거나 재시도하며, 재시도는 중복의 위험성이 있습니다.
  • 정확히 한 번 연산은 동일한 결과를 최종적으로 얻기 위해 계산을 조정한다는 뜻입니다.
  • 가장 효과적인 접근법 중 하나는 연산은 멱등으로 만드는 것입니다.

중복 억제#

  • 스트림 처리 외에도 많은 곳에서 동일한 중복 제거 패턴이 발생합니다. (Ex. TCP)
  • 그러나 이러한 부분도 TCP 연결 문맥 내에서만 작동하기 때문에 데이터베이스으 트랜잭션 커밋 성공 여부는 알 수 없습니다. 2단계 커밋 프로토콜을 구현해도 마찬가지 입니다.
  • 데이터베이스 클라이언트와 서버 사이에서 중복 트랜잭션을 억제할 수 있더라도 최종 사용자 장치와 애플리케이션 서버 간 네트워크 상황도 고려할 필요가 있습니다.
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance + 11.00 WHERE account_id = 1234;
UPDATE accounts SET balance = balance - 11.00 WHERE account_id = 4321;
COMMIT;

웹 서버의 관점에서는 재시도가 별도의 요청이고 데이터베이스 관점에서 재시도는 분리된 트랜잭션입니다. 일반적으로는 중복제거 메커니즘은 도움이 되지 않습니다.

연산 식별자#

  • 네트워크 통신을 통과하는 연산을 멱등성으로 만들기 위해서는 데이터베이스가 제공하는 트랜잭션 메커니즘에 의존하는 것은 충분하지 않으며 요청의 종단 간 흐름을 생각해야 합니다.
  • 고유 ID를 사용해 중복 요청을 억제할 수 있습니다.
ALTER TABLE requests ADD UNIQUE (request_id);
BEGIN TRANSACTION;
INSERT INTO requests (request_id, from_account, to_account, amount)
VALUE('0286FDB8-D7E1-423F-B40B-792B3608036C', 4321, 1234, 11.00);
UPDATE accounts SET balance = balance + 11.00 WHERE account_id = 1234;
UPDATE accounts SET balance = balance - 11.00 WHERE account_id = 4321;
COMMIT;

종단 간 논증#

  • 중복 트랜잭션 억제 시나리오는 종단 간 논증(end-to-end argument) 이라 부르는 좀 더 일반적인 원리의 예입니다.

문제 기능은 통신 시스템의 종단점에 위치한 애플리케이션의 지식과 도움이 있어야만 완벽하고 정확하게 구현 가능합니다. 따라서 문제 기능을 통신 시스템 자체 기능으로 제공하는 것은 불가능합니다.

  • 예제에서 중복 억제 기능이 바로 문제 기능입니다.
  • 위의 예제에서 TCP, 데이터베이스 트랜잭션, 스트림 처리자 자체로만은 중복 문제를 해결할 수 없으며 이는 종단 간 해결책이 필요합니다.
    • 바로 최종 사용자 클라이언트로부터 데이터베이스에 이르는 모든 경로에 트랜잭션 식별자를 포함하는 방법입니다.
  • 종단간 논증은 데이터 무결성 검사나 암호화에 적용가능합니다.

종단 간 사고를 데이터 시스템에 적용하기#

  • 결론적으로는 애플리케이션은 중복 억제와 같은 종단 간 대책을 갖출 필요가 있습니다.
  • 그러나 내결함성 메커니즘은 구현하기 어렵습니다.
  • 트랜잭션은 오랜 기간 매우 훌륭한 추상화로 간주되었으나 비용이 많이 든다는 문제가 있스빈다.
  • 향후에는 대규모 분산 환경에서도 좋은 성능과 좋은 운영적 특성을 유지하는 내결함성 추상화를 탐구하는 것이 가치 있다고 생각합니다.

제약 조건 강제하기#

대표적인 예시로 유일성 제약 조건이 있습니다.

유일성 제약 조건은 합의가 필요하다#

  • 유일성 제약 조건을 강제하기 위해서는 합의가 필요합니다.
    • 값이 같은 요청이 동시에 여러 개 존재한다면 시스템은 어떤 방식으로든 충돌한 연산 중 하나를 수용하고 나머지를 제약 조건 위반으로 거부해야 합니다.
  • 합의를 달성하는 가장 일반적인 방법은 단일 노드를 리더로 만들고 해당 노드가 모든 결정을 하게끔 책임을 부여하는 것입니다.
  • 유일성 검사는 유일성이 필요한 값을 기준으로 파티셔닝하면 확장 가능합니다.
  • 비동기 마스터 복제는 충돌되는 쓰기를 받아들어 값이 더 이상 유일하지 않을 수 있기 때문에 쓸 수 없습니다.
    • 제약 조건을 위반하면 어떤 쓰기도 즉시 거부하기를 원한다면 동기식 코디네이션이 필요합니다.

로그 기반 메시징의 유일성#

  • 로그는 모든 소비자가 동일한 순서로 메시지를 보도록 보장합니다.
    • 공식적으로 이 보장을 전체 순서 브로드캐스트(total order broadcast) 라 부르고 이것은 합의와 동일합니다.
    • 로그 기반 메시징을 사용하는 언번들링 데이터베이스 접근법에서 유일성 제약 조건을 강제하기 위해 매우 비슷한 접근법을 사용할 수 있습니다.
  • 스트림 처리자는 단일 스레드 상에서 한 로그 파티션의 모든 메시지를 순차적으로 소비합니다.
    • 유일성이 필요한 값을 기준으로 로그를 파티셔닝하면 스트림 처리자는 충돌이 발생한 연산 중 어떤 것이 처음 들어온 연산인지 분명하면서도 결정적으로 판결할 수 있습니다.
  • 파티션 수를 늘리면 쉽게 확장할 수 있어 대규모 요청을 처리할 수 있습니다.
  • 유일성 제약 조건뿐만 아니라 다른 많은 제약 조건에도 사용할 수 있습니다.
    • 근본 원리는 충돌이 발생할 수 있는 쓰기를 모두 같은 파티션으로 라우팅하고 순서대로 처리하는 것입니다.

다중 파티션 요청 처리#

  • 원자적 커밋이 없이 파티셔닝된 로그를 사용하면 동등성 정확성을 달성할 수 있음이 밝혀졌습니다.
    • 계좌 A와 계좌 B로 송금하는 요청은 클라이언트에게 고유 요청 ID를 발급받아 요청 ID를 기준으로 특정 로그 파티션에 추가됩니다.
    • 스트림 처리자는 요청 로그를 읽습니다. 각 요청 메시지마다 보내는 사람 계좌 A의 출금 지시 메시지와 받은 사람 계좌 B의 입금 지시 메시지 두 가지를 출력 스트림으로 방출합니다. 방출된 메시지에는 원 요청 ID가 포함됩니다.
    • 후속 처리자는 출금과 입금 지시 스트림을 소비해 요청 ID로 중복을 제거한 다음 변경 내용을 계좌 잔고에 반영합니다.
  • 클라이언트가 직접 입금 지시와 출금 지시를 보낸다면 둘 다 동시에 처리하거나 동시에 처리하지 않는 것을 보장하기 위해 두 파티션 간 원자적 커밋이 필요합니다.
    • 그래서 1단계와 2단계는 반드시 필요합니다. 분산 트랜잭션을 사용하지 않으려면 먼저 요청을 메시지 형태로 로그에 지속성 있게 남겨야 합니다.
  • 2단계에서 스트림 처리자에 장개가 발생하면 이전 체크포인트에서 처리를 재개합니다.
  • 보내는 사람 계좌에서 중복 일출이 되지 않음을 보장하기 위해 추가적인 스트림 처리자를 사용할 수 있습니다.
  • 다중 파티션 트랝낵션을 서로 다른 파티셔닝된 두 단계로 나누고 종단 간 요청 ID를 사용하면 결함 존재 여부와 상관없이, 그리고 원자적 커밋 프로토콜을 쓰지 않고도 동일한 정확성 속성을 달성할 수 있습니다.

적시성과 무결성#

  • 트랜직션의 한 가지 편리한 속성은 대개 선형성이 있다는 점입니다.
    • 즉, 기록자는 트랜잭션이 커밋될 때까지 기다리고 커밋 이후부터 해당 쓰기가 모든 독자에게 보입니다.
    • 이 속성은 다중 단계로 스트림 처리자를 거쳐 연산을 언번들링하는 경우와 다릅니다.
  • 일반적으로, 일관성이라는 용어는 두 가지 요구사항이 합쳐졌다고 생각할 수 있습니다.
    • 적시성(Timeliness), 사용자가 시스템을 항상 최신 상태로 관측 가능한 의미
    • 무결성(Integrity), 손상이 없다는 의미
  • 적시성 위반은 "최종적 일관성"이고 무결성 위반은 "영구적 불일치" 입니다.
  • 적시성을 위반하면 성가시고 혼란스러울 수 있으나, 무결성을 위반하면 파국을 맞습니다.

데이터플로 시스템의 정확성#

  • ACID 트랜잭션은 대개 적시성과 무결성 양쪽 모두 보장합니다.
    • ACID 트랜잭션의 관점에서 애플리케이션 적확성을 접근한다면 적시성과 무결성을 따로 구별하는 것은 중요하지 않습니다.
  • 이번트 기반 데이터플로 시스템의 흥미로운 속성 하나가 적시성과 무결성을 분리하는 것입니다.
    • 무결성이 스트림 시스템의 핵심입니다.
  • 정확히 한 번이나 결과적으로 한 번 시맨틱은 무결성은 보존하는 메커니즘입니다.
  • 신뢰성 있는 스트림 처리 시스템은 분산 트랜잭션과 원자적 커밋 프로토콜 없이 무결성을 보존할 수 있습니다. 무결성은 아래 메커니즘의 결합을 통해 달성할 수 있습니다.
    • 쓰기 연산을 단일 메시지로 표현하기
    • 결정적 파생 함수를 사용해 해당 단일 메시지에서 모든 상태 갱신을 파생하기
    • 클라이언트가 생성한 요청 ID를 모든 처리 단계를 통해 전달하기
    • 메시지를 불변으로 만들고 필요 시 파생 데이터 재처리하기

느슨하게 해석되는 제약 조건#

  • 유일성 제약 조건을 강제하려면 합의가 필요합니다.
  • 합의는 일반적으로 모든 이벤트를 단일 노드를 통해 특정 파티션으로 보내 처리하는 방식으로 구현됩니다.
  • 많은 애플리케이션이 훨씬 완화된 유일성 개념을 사용해 이 제한을 피할 수 있습니다.
    • 두 사람이 동시에 같은 사용자명을 등록하거나 같으 좌석을 예약한다면, 두 사람 중 한 사람에게 사과 메시지를 보내 다른 이름이나 좌석을 고르게끔 부탁할 수 있습니다. 이러한 종류의 변경 방법을 보상 트랜잭션이라고 합니다.
    • 소비자가 재고보다 더 많은 상품을 주문한다면 일단 재고 주문을 더 넣고 소비자에게 배송 지연에 대해 사과하고 가격을 할인해줍니다.
    • 비슷하게 많은 항공사가 일부 승객이 비행기를 놓칠 것으로 예상하고 초과 예약을 받습니다.
    • 누군가 계좌 잔고보다 더 많은 돈을 뺀다면 은행은 그 사람에게 초과 인출 수수료를 부과하고 빚진 돈을 값으라고 요구합니다.
  • 많은 비즈니스 맥락에서 제약 조건을 일시적으로 위반하고 나중에 사과해 바로잡는 것은 실제로 수용 가능한 방법입니다.
  • 애플리케이션은 무결성을 반드시 요구합니다. 예약을 놓치거나 입금액과 출금액이 일치하지 않아 돈이 사라지는 것은 좋지 않습니다. 그러나 제약 조건을 강제하는 상황에서도 적시성은 반드시 필요한 것은 아닙니다.

코디네이션 회피 데이터 시스템#

  • 흥미로운 점은 두가지 입니다.
    • 데이터플로 시스템은 원자적 커밋과 선형성, 그리고 파티션에 걸친 동기 코디네이션 없이도 팟애 데이터에 대한 무결성 보장을 유지할 수 있습니다.
    • 엄격한 유일성 제약 조건은 적시성과 코디네이션을 요구하지만 많은 애플리케이션은 느슨한 제약 조건을 사용해도 실제로 괜찮습니다.
  • 코디네이션 회피(coordination-avoiding) 데이터 시스템은 동기식 코디네이션이 필요한 시스템보다 성능이 더 좋고 더 나은 내결함성을 지닙니다.
  • 애플리케이션의 작은 일부에서만 코디네이션이 필요하다면 모든 곳에서 코디네이션 비용을 지불할 필요는 없습니다.
  • 너무 많은 불일치나 너무 많은 가용성 문제가 없는 최적의 장소를 찾는 것이 목표입니다.

믿어라. 하지만 확인하라#

  • 정확성, 무결성, 내결함성에 대해 설명할 때 어떤 것은 잘못될 테지만 다른 것은 그렇지 않을 것이라 가정했으며 이 가정을 시스템 모델이라고 합니다.
  • 이러한 가정은 일반적으로 꽤 합리적입니다.
  • 그러나 하드웨어 문제는 거의 발생하지 않지만 신경을 써야합니다.

소프트웨어 버그가 발생해도 무결성 유지하기#

  • 하드웨어 문제 외에 소프트웨어 버그의 위험성은 항상 존재합니다.
  • 설계와 테스트, 리뷰를 신중하게 적지 않은 노력을 하더라도 버그는 여전히 생깁니다.
  • 데이터베이스는 항상 일관성 있는 상태에 있으라고 기대하지만 트랜잭션에 버그가 없을 때만 통합니다.
    • 완화된 격리 수준을 안전하지 않게 사용하면 데이터베이스 무결성은 보장할 수 있습니다.

약속을 맹목적으로 믿지 마라.#

  • 데이터 무결성을 체크하는 작업을 감사(auditing) 이라고 합니다.
  • 데이터가 여전히 거기 있다고 확인하려면 실제로 파일을 읽어서 확인해야 합니다.
  • 맹목적으로 모든 것이 잘 동작한다고 믿지않습니다.

검증하는 문화#

  • HDFS나 S3 같은 시스템은 대부분 정확하게 장독한다고 가정아며 일반적으로 합리적이지만 항상 올바르게 작동한다는 가정과 다릅니다.
    • 미래에는 스스로 무결성확인을 지속하는 자가 검증(self-validation) 이나 자가 감사(self-auditing) 시스템을 더 많이 볼 수 있기를 기대할 수 있습니다.

감사 기능 설계#

  • 이벤트 기반 시스템은 더 나은 감사 시스템을 제공합니다.
  • 데이터플로를 명시적으로 만들면 데이터의 유랙(provenance) 가 더욱 명확해져 무결성 확인이 좀 더 수월해집니다.
  • 결정적이고 잘 정의한 데이터플로를 사용하면 디버깅과 시스템에서 왜 그렇게 행동했는지 판별하기 위한 추적이 위워집니다.

다시 종단 간 논증#

  • 시스템의 모든 개별 구성 요소가 절대로 손상되지 않는다고 완전히 믿기 어렵다면 최한 데이터의 무결성만이라도 주기적으로 확인해야합니다.
  • 데이터 시스템의 무결성을 확인하는 방법은 종단 간 방식이 최선입니다.
  • 종단 간 무결성 확인을 꾸준히 함으로써 시스템이 정확하다는 확신이 높아집니다.

감사 데이터 시스템용 도구#

  • 암호화 감사 기능과 무결성 확인은 종종 머클 트리(Merkle tree)에 의존합니다. 머클 트리는 해시 트리로 특정 데이터셋 내에 나타나는 레코드를 효율적으로 증명하는 데 사용합니다.
    • 인증서 투명서(certificate transparency) 는 머클 트리를 사용해 TTS/SSL 인증 유효성을 확인하는 보안 기술 입니다.

옳은 일 하기#

  • 모든 시스템은 목적을 가지고 구축됩니다.
  • 데이터 셋은 추상적인 것이라 이야기하지만 인관과 관련된 것입니다.
  • 소프트웨어 개발에 윤리적 선택이 갈수록 중요해졌습니다.
  • 기술은 그 자체로 좋거나 나쁜 것이 아니며, 기술을 어떻게 사용하고 기술이 어떻게 사람들에게 영향을 주는가입니다.

예측 분석#

알고리즘에 의한 의사 결정이 점점 보편화되면서 사실이든 아니든 특정 알고리즘으로 위험성 있다고 딱지가 붙어진 사람은 많은 "아니오" 결정을 받습니다.

편견과 차별#

  • 알고리즘이 내린 결정이 사람이 내린 결정보다 반드시 좋거나 나쁜 것은 아닙니다.
  • 알고리즘에 투입된 입력에 시스템적 편견이 있다면 시스템은 그 편견을 학습하고 그 편견을 증폭해서 출력을 내보낼 가능성이 높습니다.
  • 예측 분석 시스템은 오직 과거로부터 추정합니다.
  • 데이터와 모델은 도구여야지 주인이 돼서는 안됩니다.

책임과 의무#

  • 의사결정 자동화는 아직 책임과 의무에 대한 문제가 해결되지 않았습니다.
  • 신용 점수는 과거의 행동을 요약하나, 예측 분석은 비슷한 사람이 과거에 어떤 행동을 했는지 기반을 두고 작동합니다.
  • 의사결정에 데이터를 최우선으로 하는 맹목적인 믿음은 망상일 뿐이며 절대적으로 위험합니다.
  • 데이터가 사람들을 해치지 않게 하고 그 대신 긍정적 잠재력을 실현하는 방법을 찾아야 합니다.

피드백 루프#

  • 예측 분석이 사람들 삶에 영향을 미칠 때 특히 자기 강화 피드백 루프 때문에 치명적인 문제가 발생합니다.
  • 피드백 루프가 언제 발생한지 항상 예측 가능한 것은 아니지만 전체 시스템을 생각하면 많은 결과를 예측할 수 있습니다.
    • 이 접근법은 시스템 사고라고 합니다.

사생활과 추적#

  • 데이터 수집 그 자체도 윤리적 문제가 존재합니다.
  • 사용자가 시스템이 특정 방식으로 데이터를 저장하고 처리하길 원하기 때문에 시스템이 사용자가 명시적으로 입력한 데이터만 저장한다면 시스템은 사용자에게 서비스를 제공하고 사용자는 고객읻 됩니다.
  • 사용자 추적은 주로 개인을 원하는 것이 아닌 서비스에 돈을 내는 광고주의 필요로 제공합니다.
    • 감시(surveillance)

감시#

  • 데이터란 단어를 감시로 바꾸면 어떤문구로 들리는지 사고 실험을 해봐야합니다.
  • 데이터가 필수적으로 감시 대상이 아니지만 이를 조사해보면 데이터 수집 업체와 사람들의 관계를 이해하는 데 도움이 됩니다.

동의와 선택의 자유#

  • 사용자는 사용자가 제공하는 데이터가 무엇이고 어떻게 유지하며 처리하는지에 대한 지식이 거의 없으며, 대부분의 개인 정보 보호 정책은 보기보다 훨씬 더 애매합니다.
  • 감시에 동의하지 않는 사람이 선택할 수 있는 실질적인 대안은 서비스를 사용하지 않는 것 뿐입니다.
    • 즉, 사실 상 서비스를 사용하도록 강제합니다.
    • 서비스가 네트워크 효과를 가지면 해당 서비스를 사용하지 않기를 선택하는 사람들이 지불해야 할 사회적 비용이 존재합니다.

사생활과 데이터 사용#

  • 그러나 사람들이 "사행활은 죽었다"라고 말하는 것은 일종의 어폐가 있습니다.
    • 사생활(privacy) 이란 동어를 오해한 것에서 기인합니다.
  • 사생활 보호가 모든 것을 비밀로 한다는 뜻이 아니며, 사생활은 누구에게 어떤 것을 보여줄 것인지, 어떤 것을 공개로 할 것인지, 어떤 것을 비밀로 할 것인지 고를 수 있는 자유를 가진다는 의미입니다.
  • 기업은 이익을 극대화하기 위해 사생활 보호 권리를 행사합니다.
  • 많은 기업은 끔직한 기업으로 인식되지 않으려는 목표가 있습니다.
  • 인터넷 서비스는 사용자가 자신의 사생활 데이터에 무슨 일이 생기는지 이해하지도 못한 채로 이런 데이터를 거대한 규모로 사용하기도 쉽게 만들었습니다.

자산과 권력으로서의 데이터#

  • 경제적 관점에서 볼 때 타게팅 광고가 서비스를 위해 지불하는 것이라면 사람들의 행동 데이터는 서비스의 핵심 자산입니다.
  • 데이터는 가치 있기 때무넹 많은 사람들이 데이터를 원하고 기업도 물론 데이터를 원합니다.
  • 기업이 축적한 데이터와 지식은 공공의 감시를 벗어나 기업에게 암암리에 시민의 삶 전반에 걸쳐 많은 권력을 부여합니다.

산업 혁명의 기억#

  • 데이터는 정보화 시대의 본질적 특징입니다.
  • 산업 혁명이 가진 어두운 면을 관리할 필요가 있는 것처럼 정보화 시대로 이전할 때 직면하는 중요한 문제들을 풀어야 합니다.

법률과 자기 규제#

  • 데이터 보호법으로 개인의 권리를 보호할 수 있습니다.
  • 사람들의 데이터를 많이 수집하는 기업은 혁신에 부담이지 장애물이란 이유로 규제를 반대합니다.
  • 각 개인은 스스로 자신의 사생활을 보호할 수 있어야 합니다. 즉, 스스로 사생활 데이터의 통제건을 가져야 하고 감시를 통해 통제권을 훔쳐서는 안 됩니다.

정리#

  • 앞에서는 일괄 처리와 이벤트 스트림을 사용해 데이터 통합 문제를 해결하는 방법을 설명했습니다.
  • 파생과 변환을 비동기식으로 만듦으로서 시스템 전체적으로 견고성과 내결함성이 증가합니다.
  • 한 데이터셋에서 다른 데이터셋으로 변환하는 것으로 데이터플로를 표현하면 애플리케이션이 발생하는 데 도움이 됩니다.
  • 데이터플로 애플리케이션의 개념을 데이터베이스의 구성 요소를 언번들링하는 것으로 재정리하고 이렇게 느슨하게 연결된 구성 요소를 구성하는 방식으로 애플리케이션을 구축합니다.
  • 비동기 이벤트 처리를 사용해 강력한 무결성 보장을 확장성 있게 구현할 수 있습니다.
  • 데이터플로로 애플리케이션을 구조화하고 제약 조건을 비동기로 확인하면 코디네이션 대부분을 피할 수 있고 무결성을 유지하지만 성능은 뛰어난 시스템을 생성할 수 있습니다.
  • 데이터 중심 애플리케이션 구축의 윤리적인 부분에 대해서도 이야기했습니다.
Last updated on