The Last Mind

Captain's Log

Category Archives for: Software Development

CAP Twelve Years Later: How the “Rules” Have Changed

25 December 2012 by Joseph Jang

지난 2012년 2월, IEEE Computer에 CAP Theorem에 대한 특집이 실렸습니다. 특집의 첫번째 아티클을 쓴 저자는 지난 2000년 PODC (Symposium on Principles of Distributed Computing)에서 CAP Theorem을 conjecture의 형태로 발표했던 바로 Eric Brewer입니다.

CAP Twelve Years Later: How the “Rules” Have Changed by Eric Brewer

1. CAP Theorem

소위 NoSQL 운동에 대해서 조금이나마 관심이 있었던 분들은 CAP Theorem에 대해 들은 바가 있을 것입니다.

CAP Theorem은 네트워크를 통해 데이터를 공유하는 시스템은 아래의 3가지 특성 중 2개만을 가질 수 있다고 얘기하고 있습니다.

  • Consistency (C)
  • High Availability (A)
  • Tolerance to Network Partitions (P)

네트워크로 연결된 2개의 노드로 구성된 시스템이 있다고 가정해봅시다. 그리고 네트워크 파티션에 의해 2개의 노드는 통신할 수 없는 상황이 벌어졌다고 생각해봅시다.

Availability를 위해 하나 이상의 노드가 상태를 업데이트할 수 있도록 한다면 2개의 노드가 가지고 있는 데이터는 inconsistent해지므로 Consistency를 포기하는 것이 됩니다. Consistency를 보존하려고 한다면, 2개의 노드 중 한 쪽은 unavailable한 것처럼 행동해야 하므로, Availability를 포기하는 것이 됩니다. 노드들이 서로 통신할 때만, Consistency와 Availability를 동시에 보존할 수 있으므로 이는 Partition Tolerance를 포기하는 것이 됩니다.

2. Why 2 of 3 is misleading

“Partition Tolerence를 포기할 수 없으므로, Consistency와 Availability 중 하나를 선택해야 하고, Availability를 희생할 수 없으므로, Consistency를 희생해야한다” 정도가 NoSQL 운동의 초기에 등장했던 AP 시스템들의 공통된 주장이었습니다.

그러나, Eric Brewer는 이런 식으로 3개의 특성 중 2개만을 선택해야 한다는 관점이 많은 오해를 불러왔다고 얘기하고 있습니다.

그 이유는 다음과 같이 설명하고 있습니다.

  • 파티션은 흔히 일어나지 않으므로, 파티션이 일어난 상황이 아닐 때에도 Consistency나 Availability를 포기할 타당성은 적다.
  • Consistency-Availability 사이의 선택은 하나의 시스템에서 단 한번 이루어지는 것이 아니라, 세부적인 단위로에서 여러번 일어날 수 있다.
  • 3개의 특성들은 연속적이다. Availability는 0% – 100%, 여러 레벨의 Consistency, Partition에 대한 시스템 내의 Disagreement 등이 이를 나타낸다.

3. Cap-Latency connection

또한 Eric Brewer는, 전통적인 관점에서 네트워크의 파티션은 커뮤니케이션의 단절을 의미하는 것이지만, 제한된 시간 내에 커뮤니케이션을 하지 못하는 것을 네트워크 파티션으로 보는 관점을 제시하고 있습니다. 즉, 어떤 오퍼레이션의 타임아웃이 발생한 시점에 시스템이 해당 오퍼레이션의 재시도를 시도한다면 Consistency를 선택하는 것이고, 그렇지 않는다면 Availability를 위해서 파티션을 허용하는 것입니다.

이러한 관점에서 시스템의 설계자가 목표로 하는 response time에 따라 타임아웃을 설정하면, 타임아웃이 발생하는 것을 파티션으로 감지하고, 파티션 모드로 진입할 수 있게 됩니다.

한편, 지연 (Latency)을 피하기 위해 강한 Consistency를 포기하는 시스템의 예로 Yahoo의 PNUTS를 들고 있고, 업데이트와 업데이트 이후 일정 시간동안의 읽기에 대해서는 지연을 허용하는 Facebook의 시스템을 그 반대의 사례로 들고 있습니다.

4. Managing partitions

Eric Brewer는 파티션을 다루는 전략을 다음과 같이 제안하고 있습니다.

우선 파티션은 흔하지 않기 때문에, CAP은 대부분의 시간 동안 완벽한 C와 A를 허용해야합니다. 하지만, 파티션이 발생했을 경우에는, 파티션을 매우 명시적으로 관리해야한다고 언급하고 있습니다. 이를 아래의 3단계와 그림으로 표현하고 있습니다.

  1. 파티션의 시작을 감지
  2. 특정 오퍼레이션을 제한할 수 있는 명시적인 파티션 모드에 진입
  3. 커뮤니케이션이 회복된 후, Consistency를 복구하고 파티션 모드 동안의 실수를 만회하기 위한 파티션 복구 프로세스를 시작

Managing Partition

4.1. Which operations should proceed?

기본적으로 어떤 오퍼레이션을 제한할지는 시스템이 유지해야하는 불변조건 (invariants)에 달려있습니다. 파티션 동안 유지되지 않아도 되고, 파티션 복구 시 쉽게 복구할 수 있는 경우 (예를 들어, 중복된 키들의 병합)에는 오퍼레이션을 허용할 수 있고, 파티션 동안 유지되어야만 하는 불변조건에 해당하는 경우에는 오퍼레이션을 금지하거나 지연하거나 수정해야 한다고 얘기하고 있습니다.

실제로 오퍼레이션에 대해 어떤 조치를 취할지는 시스템에 대한 모든 원자적인 (atomic) 오퍼레이션과 불변조건들의 테이블을 만들고 각각의 항목별로 오퍼레이션이 불변조건을 위반할 수 있는지 여부를 검토해야 합니다.

중요한 것은 실제로 시스템을 사용하는 사용자에게는 이러한 조치가 보이지 않는 것입니다. 신용카드 결제의 경우 통신이 불가능한 상황에서 의도를 기록한 후 나중에 실행하는 것이나, Bayou의 캘린더 애플리케이션에서 잠재적으로 inconsistent한 항목들을 다른 색상으로 표시하는 등 흔히 오프라인 모드라고 불리는 사용자 인터페이스에서의 처리를 언급하고 있습니다. 본질적으로 이러한 오프라인 모드는 장시간 동안의 파티션과 다름없다는 것입니다.

파티션이 끝난 후 복구를 위해 파티션의 양단에서 일어난 오퍼레이션의 이력을 추적하는 가장 좋은 방법으로 오퍼레이션들 사이의 인과적인 의존성을 보존하는 버전 벡터 (version vector)를 사용하는 것이라고 얘기하고 있고, 이러한 시스템의 좋은 예로 Dynamo를 들고 있습니다.

4.2. Partition recovery

파티션 복구 동안, 파티션 양단의 상태를 일관되게 (consistent) 만들고, 잘못된 응답이나 시스템 외부로의 영향 등 파티션 모드 동안에 이루어진 실수를 만회하는 두가지 문제를 해결해야 합니다.

우선 일관성의 문제는 파티션 상태로부터 시작해서 양단의 오퍼레이션들을 재실행 (roll-forward) 하면서 계속 일관된 상태를 유지하는 방식을 가장 쉬운 방식으로 언급하고 있습니다.

한편, 양단의 오퍼레이션을 병합할 때 발생하는 충돌에 대해서는, 일반적인 충돌 해결의 문제는 해결 불가능하지만, 현실적으로는 설계자는 파티션 동안의 오퍼레이션 제한을 통해 복구 동안의 자동 병합에서 문제가 생기지 않도록 합니다. (예를 들어, Google Docs는 텍스트의 추가, 삭제, 스타일의 적용으로 오퍼레이션을 제한)

상태의 자동적인 수렴을 위한 일반적인 프레임워크 중 하나는 상호적인 (commutative) 오퍼레이션입니다. 하지만, 실제로는 상호적인 오퍼레이션만 사용하는 것은 매우 어렵기 때문에, CRDT (Commutative Replicated Data Type)이란 개념을 소개하고 있습니다. CRDT는

  • 파티션 동안 모든 오퍼레이션들은 상호적임을 보장하거나,
  • 상태를 기록한 후, 파티션 동안에 일어나는 모든 오퍼레이션은 그 상태에 대해 단조적임을 보장합니다.

예를 들어, 집합에 대한 추가와 삭제 오퍼레이션에 대한 CRDT 구현은, 추가된 항목들과 삭제된 항목들에 대한 집합을 각각 유지하는 것입니다. 파티션 복구 시점에서 시스템은 양단의 집합으로부터 정리 작업을 수행할 수 있습니다. 정리 작업은 파티션 동안에는 불가능하기 때문에 파티션 이후로 지연시켜야 하는 오퍼레이션이지만, 인지되는 가용성을 제약하지 않습니다. 따라서, CRDT를 통해 상태를 구현할 수 있다면, 설계자는 Availability를 선택하더라도 파티션 이후에 자동적으로 상태가 수렴될 수 있도록 보장할 수 있습니다.

4.3. Compensating for mistakes

시스템 외부에 가해진 실수를 복구하는 것은 시스템 외부로의 영향에 대한 이력을 필요로 합니다. 어떤 사람이 전날 밤 술에 취해 전화를 걸었다면, 그 전화들은 외부로의 영향에 해당하고, 그 사람이 다음 날 아침 정상 상태가 되었을 때, 잘못 건 전화들에 대해 만회를 하기 위해서는 어젯밤 걸었던 전화들에 대한 기록을 필요로 합니다.

다른 예로, 파티션 동안에 시스템이 동일한 주문을 두 번 수행했다고 가정해봅시다. 시스템이 주문의 이력으로부터 중복된 주문을 식별할 수 있다면, 중복된 주문 중 하나를 취소하고 고객에게 적절하게 사과하는 메일을 보낼 수 있지만, 그러한 이력이 없다면, 그러한 실수를 파악하는 것은 고객의 부담이 됩니다.

Brewer는 여기서 보상 트랜잭션 (Compensating Transaction)의 개념을 소개하고 있습니다. 예를 들어, 하나의 트랜잭션으로 모든 직원들의 레코드들을 업데이트 하려고 한다면 모든 레코드를 lock하게 됩니다. 보상 트랜잭션은 커다란 트랜잭션을 다수의 작은 트랜잭션으로 쪼개어 각각 따로 commit하는 방식을 취합니다. 따라서, 원래의 커다란 트랜잭션을 취소하려고 할 때 이미 commit된 작은 트랜잭션의 영향을 수정하는 새로운 트랜잭션 -보상 트랜잭션을 실시합니다. 보상 트랜잭션의 접근은 전통적인 데이터베이스의 접근과 같이 직렬성 (Serializability)이나 격리성 (Isolation)에 의존하기 보다는 트랜잭션의 전체적인 영향에 의존합니다. 그리고 외부에 미친 영향까지도 고려가 되어야 합니다. 예를 들어, 중복된 지불을 환불하는 것은 애초에 고객에게 청구하지 않는 것과 같다고는 할 수 없지만, 거의 동등하다는 것이고, 이러한 생각 – 실수를 인정하고 보상을 통해 동등한 결과를 얻는 방식이 파티션 복구에서도 성립한다고 얘기하고 있습니다.

5. Closing

Eric Brewer가 마지막에서 강조하고 있는 것은 시스템 설계자는 파티션이 존재할 때, 무턱대고 consistency나 availability를 희생하려고 해서는 안되고, 이 글에서 언급하고 있는 방식을 통해 양쪽 모두를 최적화하려고 해야한다는 것입니다. 이를 위한 버전 벡터 (version vector)나 CRDT 등의 기술들이 프레임워크화되고 좀 더 보편화될 것이라고 얘기하고 있습니다.

제가 이 글을 읽고 느낀 점들은 아래와 같습니다.

  • CAP Theorem에 대해서 이 글을 읽기 전까지만 해도 단순화된 관점 – 2 of 3을 가지고 있었으나, 이 글을 읽고나서 CAP Theorem에 대한 이해도가 좀 더 높아졌고, 단순한 AP 또는 CP 시스템 이외의 시스템 설계의 많은 가능성에 대해서 생각해보게 되었습니다.
  • 상태의 수렴을 위한 데이터와 오퍼레이션의 재설계가 필요하다는 것은 깨닫고 있었지만, CRDT와 같은 좋은 사고 도구가 될 수 있는 정식화 (formalization)가 있는지는 몰랐습니다.
  • 결국 현재로서는 분산 저장 시스템은 매우 복잡한 설계가 필요할 뿐만 아니라, 전통적인 DB와는 다르게 보편화된 프레임워크가 있기 보다는 개별 시스템 별로 따로 설계를 해야하는 수준이기 때문에, 아직 더 많은 연구와 개발이 필요한 분야인 반면, 그만큼 비용이 많이 들어가는 부문인 것 같습니다.
  • CAP Theorem 특집의 글들을 읽고 있습니다만, 이를 요약할 수 있을 정도로 완벽하게 이해하고 정리하는 것은 매우 시간이 걸리는 일이네요. 여력이 된다면 다섯개의 글 모두 정리해보고 싶습니다.

 

 

Comments Off | Categories: Software Development | Tags: , ,

Timelines @ Twitter

03 October 2012 by Joseph Jang

Qcon London 2012에서 Arya Asemanfar의 발표입니다.

Timelines @ Twitter by Arya Asemanfa

Timeline Delivery

Twitter 의 사용자별 Timeline은 사용자가 자신이 following하는 사용자들의 tweet 목록을 볼 수 있는 화면으로 Twitter 서비스의 중심을 구성하는 UI 입니다.

Twitter의 Timeline 서비스는 기본적으로 새로운 Tweet이 발생할 때, 이를 구독하는 사용자들의 Timeline에 해당하는 목록에 Tweet ID를 추가해주고, 각 사용자들이 자신의 Timeline을 읽을 때는 이 목록을 가져가서 빠르게 Timeline을 표시할 수 있도록 하는 구조입니다.

Timeline에 대한 poll-based query는 200K qps 정도가 발생하고 response time은 1ms (median) 정도로, throughput과 response time 모두에서 높은 수준을 요하는 서비스입니다. 이는 Twitter가 전세계적으로 성공한 서비스임을 감안할 때 그리 높지 않은 수치들인 것 같은데, 어쩌면 모바일 사용자가 증가하면서 이제는 Timeline에 대한 조회가 poll-based가 아니라 push 위주이기 때문일지도 모르겠습니다.

새로운 Tweet이 쓰여지는 속도는 피크 시간대에 5k/sec 정도로 역시 생각보다는 그리 많지 않은 양이지만, follower로 인한 fan-out이 높은 서비스 특성 상, timeline에 대한 delivery는 300k/sec 정도라고 합니다. 100만명의 follower에게 delivery하는데에도 불과 3.5초 밖에 걸리지 않는다고 합니다.

Architecture

아래의 그림은 발표자료로부터 가져온 Search는 제외한 Timeline 관련 Architecture 그림입니다.

특이할만한 사항들을 간략하게 정리하면 다음과 같습니다.

  • HTTP Proxy에서 어떤 API를 호출할지 결정이 됩니다.
  • API layer와 Service layer가 잘 분리되어있습니다. 필요하다면 API가 다수의 Service를 사용할 수 있습니다.
  • Tweet API의 경우 queue를 가지고 있어서 asynchronous하게 처리될 뿐만 아니라, 여러 시스템 (예를 들어, tweet 기록을 위한 tweet daemon과 검색 인덱싱을 위한 search blender)으로 이 request를 전송할 수 있는 것 같습니다.
  • 다수의 follower에 대한 Timeline delivery를 위해서 수천명의 follower에 대한  delivery로 쪼개어 동시에 보낼 수 있습니다.
  • Timeline cache는 Redis에 대한  partitioning layer로서 동작합니다.
  • 사용자별 Timeline은 Redis의 list로 표현되며, list의 element에는 Tweet ID (8 bytes), User ID (8 bytes), bitfield (4 bytes), optional하게 Retweet ID가 들어갑니다.
  • 특정 사용자에 대한 Timeline에 대한 query가 몰린다면 이를 탐지하여 Timeline service에서 해당 쿼리에 대해 in-process cache를 활성화합니다.

Finagle

이러한 여러 컴포넌트가 논리적, 물리적으로 분산되어 있는 Service-oriented Architecture를 위해서 Twitter에서는 JVM 기반의 RPC Library인 Finagle을 모든 컴포넌트에서 사용하고 있다고 합니다.

Finagle은 connection pooling, connection 수 제약 등의 기본적인 connection 관리는 물론 여러 프로토콜을 플러그인 방식으로 사용할 수 있어서 그야말로 모든 컴포넌트에서 사용할 수 있습니다. HTTP Proxy에서 필요로 하는 HTTP 프로토콜, API layer와 Service 컴포넌트가 통신하는데 사용하는 Thirft, Redis 까지도 모두 Finagle로 처리가 되고 있는 것 같습니다.

Finagle은 ZooKeeper 기반의  service discovery (혹은 location service)를 지원하기 때문에, RPC 호출을 위한 endpoint를 지정할 때는 호스트 이름이 아닌 클러스터의 이름을 사용할 수 있습니다.

Q&A

  • HTTP Proxy는 JVM 기반으로 만들어져있고, Finagle을 기반으로 하고 있고 Routing, SPDY 지원등이 주요한 기능이라고 합니다. 초기에는 GC 문제로 고생했지만, 튜닝을 거쳐 CMS를 사용하고 나서 어느 정도 안정화 되었다고 합니다.
  • HTTP Proxy, Timeline Service 등은 Scala로 만들어져 있고, Search에 관련된 시스템은 Java로 만들어져 있다고 합니다. Timeline 팀과 Search 팀이 나뉘어져 있어서 그런 모양입니다. 참고로 Finagle은 Scala로 만들어진 라이브러리입니다.
  • Timeline은 디스크에 저장되지 않고 메모리에만 저장된다고 합니다.
  • Durable Store - 아마도 MySQL 또는 Cassandra에 저장되는 데이터는 Tweets, Tweets에 대한 index 등 이라고 합니다. Twitter에서의 Durable Store에 관해서는 QCon 2011에서의 발표를 참고하라고 합니다.
  • Partitioning을 위해서는 역시 github에 공개되어 있는 gizzard를 사용하고 있는 것 같습니다. (그런데 발표자는 snowflake라고 대답했군요.)

Closing

Timelines 아키텍쳐를 보고 가장 크게 느낀 점은  매우 높은 수준의 response time 요구사항을 가지고 있음에도 불구하고, 물리적으로 분리되어 있는 컴포넌트 사이의 RPC를 다수 포함하고 있는 아키텍쳐를 가지고 있다는 것입니다. 현재 고민하고 있는 시스템에서는 단 하나의 layer를 물리적으로 나누는 것에도 매우 망설이고 있는데, Twitter의 경우에는 tweets API만 하더라도 몇 단계의 RPC 통신을 필요로 하고 있습니다. 이것은 queue를 이용한 asynchronous한 API 처리 때문에 가능한 것 같습니다. 그 이외에도 물리적으로는 나누어져 있다고 하더라도 로컬 머신 내의 다른 daemon으로 리퀘스트를 먼저 보낸다든가 하는 최적화가 되어있을지도 모르겠습니다. 이론적으로는, 논리적인 분리만 이루어져있다면 성능 제약이 있지 않는 한 컴포넌트의 물리적인 분리는 불필요하지만, 실제로는 논리적인 분리의 강화, 성능 분석의 용이성 등의 여러가지 감추어진 이점이 있다고 생각합니다. 어쩌면 저는 물리적인 분리가 두려워서 가능한 해결책을 생각해보지도 않고 두려워하는 것일지도 모르겠습니다.

두번째는, Finagle과 같은 훌륭한 기반이 있기 때문에, 이러한 서비스 기반 아키텍쳐가 만들어질 수 있었다는 것입니다. Twitter의 경우에도 처음에는 단일한 서비스로 이루어져 있었을지도 모르겠지만, 분리의 필요성이 생겼을 때 Finagle과 같은 라이브러리 또는 Finagle이 이용하는 시스템이 기반이 되어준다면, 분리의 비용이 훨씬 낮기 때문에, 훨씬 쉽게 분리할 수 있을 것입니다.

세번째는 관찰가능성 (observability)입니다. 발표자가 Finagle에 대해서 설명할 때 살짝 얘기하고 지나갔지만, Finagle을 통한 RPC call에 관련한 여러가지 statistics들은 물론, 여러 컴포넌트들을 따라 일어난 RPC call의 trace도 역시 별도의 시스템으로 보내진다고 합니다. Twitter와 같은 여러 컴포넌트가 연동되어 있는 시스템에서는 한 컴포넌트의 실패가 다른 컴포넌트들의 연속적인 실패로 이어질 수 있으며 (Cascading Failure) 엄청난 재난이 될 수 있습니다. Twitter의 경우 (Finagle을 통해) 이러한 문제에 대한 대비가 모든 컴포넌트 사이에서 되어있고, 컴포넌트의 실패 또는 연속적인 실패 등을 쉽게 발견할 수 있도록 준비되어 있는 것 같습니다.

전반적으로 구조는 매우 단순해보이지만, 그러한 단순함을 얻기 위해, 수많은 경험을 바탕으로 쌓아올린 노력이 엿보이는 아키텍쳐인 것 같습니다.

Comments Off | Categories: Software Development | Tags: ,

Data Infrastructure @ LinkedIn

02 June 2012 by Joseph Jang

QCon London 2012에서의 Siddharth Anand의 강연입니다.

Data Infrastructure @ LinkedIn by Siddharth Anand

Siddharth Anand는 작년 7월에 열린 QCon London 2011에서 NoSQL @ Netflix라는 제목의 강연을 한 적이 있었는데, 1년 새 Netflix로부터 LinkedIn으로 옮긴 모양이군요.

강연의 제목대로 이 강연은 LinkedIn의 데이터 기술에 대해서 다루고 있습니다만, 특히 데이터베이스와 데이터의 복제 기술에 대해서 다루고 있습니다.

Read Scalability & Write Scalability

LinkedIn은 현재 Oracle을 주 데이터베이스로 사용하고 있으며, 사용자가 LinkedIn에 제공한 데이터 – 사용자의 프로필, 관계들은 모두 이 곳에 저장된다고 합니다. 이 데이터를 가공하여 생성된 2차 데이터들은 목적에 따라 여러 종류의 스토리지를 활용하고 있는 것으로 보입니다.

서비스의 규모가 커지면 물론 Oracle 성능의 Scalability가 문제가 되는데, 이를 Read Scalability와 Write Scalability의 문제로 나누어서 설명하고 있습니다.

Read Scalability는 Oracle Slaves나 Memcached, Voldemort 등의 복제나 캐시 스토리지를 활용하고 있고, Write Scalability는 Oracle이 동작하는 하드웨어를 업그레이드하거나 다른 기술 (예를 들어, Cassandra)을 사용하는 방법 밖에는 없다고 얘기합니다.

Oracle Slaves

Oracle Slaves의 경우, 문제는 결국 Master에 쓰여진 데이터와의 consistency가 문제가 되는데, LinkedIn에서는 writer에게는 그 다음에 따르는 read를 보장하고, 다른 reader들에게는 eventual consistency를 허용하고 있습니다. 이를 위해서 사용하는 메커니즘은 다음과 같습니다.

데이터 도메인별로 데이터에는 변경시점을 나타내는 timestamp를 가지고 있는데, 클라이언트로부터의 write는 항상 master에 대해 발생하며, 이 때 timestamp를 변경하면서 이 timestamp를 자신의 context에 보유하고 있습니다. 클라이언트가 read를 할 때는 먼저 slave에 대해 read 액세스를 하되, 읽어 들인 timestamp와 자신이 보유하고 있는 timestamp를 비교하여, 만약 자신이 보유하고 있는 timestamp가 더 작다면 master의 데이터를 읽습니다.

이러한 메커니즘이 Oracle에서 직접 지원되는 기능인지 inhouse에서 만든 클라이언트 라이브러리와 별도의 필드를 이용해 구성한 메커니즘인지는 정확히 모르겠습니다만, 비교적 간단한 방식으로 replication 방식의 gap 문제를 극복하고 있군요. 하지만, consistency가 항상 중요한 데이터라면 이러한 방식은 사용할 수 없기 때문에, 결국 consistency 요구사항에 대한 정확한 파악이 필요하다고 할 수 있습니다.

Voldemort

Voldemort는 Dynamo paper에 기반해 만들어진 분산 스토리지로, NoSQL이라는 키워드의 역사로 따지자면 선조격에 해당한다고 볼 수도 있겠네요. 이 글에서는 Dynamo에 관한 얘기는 생략하도록 하겠습니다. 이 후에 만들어진 Dynamo 계열의 스토리지인 Riak, Cassandra 등을 선택하지 않은 이유는 단지 Riak이나 Cassandra는 스토리지 기술을 선택할 당시 (2008년)에 존재하지 않았다고 하는군요.

다른 Dynamo 계열 스토리지에 대비해 Voldemort의 특징은 Layered Pluggable Architecture라고 하는데요. Conflict Resolution, Serialization, Repair Mechanism, Failure Detector, Routing 등의 Layer들을 필요에 따라 클라이언트 또는 서버 측으로 배치할 수 있다고 합니다. 현재 LinkedIn에서는 대부분의 기능을 클라이언트에서 수행하도록 구성 (fat client 방식)하고 있지만, 이들을 서버쪽으로 옮겨놓고자 (fat server 방식) 한다고 합니다.

Storage Engine도 필요에 따라 선택해서 사용할 수 있는데, Read-Write 저장소에는 BDB JE 스토리지 엔진을 사용하고 있고, Read-Only 저장소에는 커스터마이즈된 스토리지 엔진을 사용하는데, key는 원래의 key나 key의 MD5, value는 파일의 형태이되, 메모리 맵 인덱스 (offset의 index)를 통해서 필드를 액세스할 수 있도록 한다고 합니다.

LinkedIn에서는 Voldemort를 fault tolerant한 분산 memcached와 같이 생각한다고 합니다. Read-Only 저장소에 저장되는 데이터는 Hadoop을 통해서 생성된 데이터를 Voldemorts가 로드하는 배치를 통해 생성된다고 합니다.

DataBus: Timeline-Consistent Change Data Capture

DataBus는 LinkedIn에서 데이터를 복제하거나 2차 데이터를 생성하기 위한 주요 인프라라고 할 수 있습니다. Oracle master로의 write는 DataBus가 모두 복제하고 이를 검색 인덱스, 그래프 인덱스, replica, Standardization 서비스 등으로 보낸다고 합니다.

DataBus Architecture

DataBus는 Relay 서비스와 Bootstrap 서비스의 2가지로 이루어져 있는데, Relay는 Shard를 통해 분산되어 있고 Oracle로부터 받은 트랜잭션 – 트랜잭션을 통해 변경된 레코드 데이터 전체를 메모리 상에서 버퍼링하며, Avro로 인코딩해서 Bootstrap을 포함한  다른 스토리지로 전달하는 역할을 합니다. Bootstrap은 이러한 트랜잭션들을 저장해서 임의의 시점으로부터의 변경사항 (Consolidated Delta) 또는 특정 시점의 스냅샷 (Consistent Snapshot)을 제공할 수 있습니다. “arbitrary long lookback”이라고 부르는 기능인데요. DataBus의 Relay를 통해 트랜잭션을 수신하는 클라이언트가 재시작이나 실패 등으로 수신을 하지 못하는 상황이 벌어졌을 때, 새로운 클라이언트가 데이터를 얻어야 할 때 필요한 기능들이 아닐까 싶습니다. Bootstrap은 Log Storage와 Snapshot Storage로 구성되어 있고, Log Writer가 Log Storage에 write하고 Log Applier가 Snapshot Storage에 log를 적용하는 방식입니다.

SCN을 통해서 커밋 순서에 따른 전송 (in-commit-order delivery)을 보장한다거나 ‘arbitrary long lookback’과 같은 기능을 제공하는 것은 꽤 강력한 기능들인 것 같습니다. 반면에 Bootstrap의 데이터는 복제가 없기 때문에 데이터의 지속성 (durability)에 대해 취약한 면은 있는 것 같습니다.

Kafka: High-Volume Low-Latency Messaging System

Kafka는 기본적으로 일반적인 메시지큐라고 할 수 있는데, DataBus의 application-level 데이터 스트림, 사용자들의 행동 추적, 네트워크나 시스템의 메트릭 전송 등에 사용하고 있다고 합니다.

메시지큐의 topic (큐라고 생각하면 됩니다)은 sequential write로 쓰여지는 로그 방식의 파일이고, consumer는 이를 pulling 방식으로 가져갑니다. 그리고 topic들은 partition되어 있는데, 이들의 관리는 ZooKeeper가 담당합니다. sendfile을 이용한 zero copy와 같은 tuning들이 되어 있고, 자체적인 cache 없이 OS page cache에 의존한다고 합니다. 메시지의 전송 여부에 대한 기록은 없으며 단순히 일정 시간이 지나면 파기하는 방식이라고 합니다.

Secondary Index

NoSQL은 간단한 동작 방식 (semantic)을 통해 기존의 관계형 데이터베이스들에 비해서 가용성이나 성능을 높이는 것에 초점을 맞추고 있는데, Siddharth Anand는 secondary index를 NoSQL에 접목시키는 순간 복잡한 시스템이 되어버리고 애초의 장점을 잃는다고 얘기합니다. 따라서, DataBus와 같은 것을 이용해 비동기적으로 secondary index를 유지하는 방식을 선호한다고 얘기합니다. 클라이언트가 2군데 이상의 스토리지에 write를 하는 동기적인 방식에 대해서도 비판적으로 얘기합니다. 데이터의 불일치 문제 등에 대해서는 Netflix에서도 이를 해결하기 위한 reconcilation job이 존재했었고, 지인에게 듣기로는 Google에서도 비슷한 작업이 많이 있다고 합니다.

Closing

이 강연에서 가장 인상적인 것은 DataBus 였습니다.

  • 변경 사항을 실시간으로 제공하면서 변경 사항의 이력과 스냅샷을 제공하는 시스템
  • 어떤 이벤트에 대해서 수행해야할 여러가지 작업을 효과적으로 분산하는 메시지 전송 시스템

Oracle의 트랜잭션을 복제하는 것은 아주 오래전부터 캐싱을 위해서 활용하는 방법이기 때문에 새롭다고 하기는 힘들지만, 이력과 스냅샷을 제공하는 시스템으로 만든 것 하나만으로 유용성이 굉장히 높아지는 것 같습니다. 그리고, 이러한 방식 자체는 스토리지의 복제 뿐만 아니라 변화의 추적과 동시에 전체 데이터의 동기화를 필요로 하는 여러가지 장소에 활용될 수 있는 것 같습니다. 예를 들어,

  • 스마트 클라이언트의 동기화를 위한 서버 시스템: 스마트폰과 같이 로컬 스토리지를 가지고 있는 디바이스는 서버의 변경사항을 지속적으로 수신하면서도 서버의 데이터 전체를 받아야하거나 서버와의 동기화를 필요로하는 시점도 필요합니다. 이 때 서버에서는 이에 적합한 저장 방식을 보유하고 있어야 합니다.
  • 이종 스토리지 사이의 복제: Redis의 복제는 Redis의 특성상 lookback이 존재하지 않습니다. 즉, Redis slave로부터 master로의 접속이 한순간이라도 끊기면 모든 데이터를 다시 받아야 합니다. Redis-Redis 사이에서는 크게 문제가 안될지 모르지만, Redis-MySQL이나 Redis-HBase가 필요하다면 단순히 replication 프로토콜을 구현하는 것만으로는 해결되지 않습니다. 이런 경우에 유용하게 사용할 수 있습니다. MySQL을 예를 들면, 위의 Redis와 같은 문제를 해결하기 위해 binlog를 master쪽의 디스크에 저장하고 있습니다만, 당연히 master의 트랜잭션에 방해가 되거나 디스크의 용량을 크게 차지하기 때문에 이를 외부로 돌릴 수 있다면 메모리 상의 트랜잭션 로그나, 최소한의 binlog를 유지할 수 있게 되어 유용할지도 모르겠습니다.

반복되지만 스토리지 아키텍쳐의 구성에 대해서도 역시 계속 곱씹을 여지를 주는 것 같습니다.

  • 서비스에서 가장 핵심이 되는 데이터는 그 자체로는 Scalability에 한계가 있더라도 Oracle과 같은 신뢰성이 높은 스토리지를 이용한다.
  • 신뢰성이 높은 스토리지가 존재하고 이로부터의 트랜잭션을 순서대로 제공할 수 있는 기능만 있다면 비교적 단순한 구조 하에서 Eventual Consistency를 성취하는 것은 그리 어렵지 않을지도 모른다.
  • 사용자 입장에서 Loose한 Consistency를 제공하더라도 문제가 없는 데이터를 식별한다.
  • 데이터의 불일치에 대해서 수정하는 작업이 필요하다.

데이터 복제의 문제만 하더라도 일반적인 노드 사이의 복제, 클라이언트로부터의 quorum write, Proxy 등 여러가지 방법을 고민하고 있는데, 정말 쉬운 문제는 아니로군요.

한편, 강연에서 현재 LinkedIn에서 개발하고 있고 몇개월 내에 완성될 예정인 Espresso라는 key-value 스토리지에 대한 언급이 나오는데, 어떠한 목적을 가지고 만드는 것인지 궁금하네요. 어서 볼 수 있었으면 합니다.

Comments Off | Categories: Software Development | Tags: , ,

Building Highly Available Systems in Erlang by Joe Armstrong

25 May 2012 by Joseph Jang

QCon London 2012에서의 Joe Armstrong의 강연입니다.

Building Highly Available Systems in Erlang by Joe Armstrong

Joe Armstrong은 에릭슨에서 일하던 1986년에 Erlang의 초기 버전을 개발했으며, Erlang OTP 프로젝트의 Chief Architect였습니다. Erlang은 1998년 open source로 나오기 전에는 에릭슨의 proprietary 언어로 개발 되었기 때문에 Erlang의 창시자라고 불러도 될지는 조금 애매하기는 하지만, 소위 Programming XXX라는 책 - Programming Erlang (2007)의 저자로서 그렇게 불러도 큰 문제는 없지 않을까 싶습니다. 2003년 PhD thesis로 Making reliable distributed systems in the presence of software errors이라는 논문을 내놓았는데 이 역시 Erlang에 관한 내용이고, 현재도 Erlang에 관련한 활동을 활발히 하고 있는 것 같습니다. Erlang의 역사에 대해서 좀 더 알아보기는 해야겠지만, 이런 것들만 보아도 꽤나 재미있는 이력이라고 생각합니다.

6 Rules

먼저 Redundancy, Consistent Hashing과 Chord의 Quorum System에 대해 간략하게 설명하고, Reliable Data Storage의 문제는 알고리즘 차원에서는 이미 풀렸다라고 선언합니다. 100% 납득이 가는 것은 아니지만, 그렇다고 인정하고 넘어간다면 그 다음엔 이 개념들을 어떻게 구현 – 코딩할 수 있을 것인가에 대해서, 6가지의 룰을 설명합니다. 결국 이러한 6가지 룰을 – 프레임워크나 라이브러리가 아니라 – 프로그래밍 언어 차원에서 구현한 언어가 바로 Erlang이라고 얘기하는 흐름이라서 조금 힘이 빠지는 느낌이 드는 것은 사실입니다.

1. Isolation

모든 것이 격리되어있다면, 더 많은 컴퓨터가 투입될 수록 시스템의 실패 확률은 점점 낮아질 수 있다는 얘기입니다. 이를 통해 10 nines도 실현 가능하다고 얘기합니다. Joe Armstrong은 Erlang 프로세스들이 공유하고 있는 문맥이 없다는 점으로 설명합니다. Erlang 프로세스들은 VM위에서 동작하는 가벼운 프로세스 (light-weight process)들로 일반적인 프로세스들처럼 메모리를 공유하고 있지 않습니다.

2. Concurrency

세상의 대부분의 문제들은 생각보다 병렬적(parallel)이고, 2대 이상의 컴퓨터를 제공함으로써 병행성(concurrent)을 확보할 뿐만 아니라 분산(distributed)된다고 얘기합니다. Erlang의 프로세스 얘기로 다시 돌아가면, 이론적으로 모든 Erlang 프로세스들은 병렬적으로 동작하고, 여러 core로 퍼져서 실행된다고 합니다.

3. Fault Detection

실패의 탐지를 위해서는 3대의 컴퓨터가 필요하다고 얘기합니다. 별도의 설명이 없지만 leader election의 이야기겠죠? Erlang 프로세스들은 실패를 탐지할 수 있도록 되어있고, 원격의 프로세스들을 연결해서 이들의 실패를 탐지해서 대신 문제를 해결하는 것도 가능하다고 합니다.

4. Fault Identification

실패한 원인을 아는 것도 중요하다고 얘기합니다. 이를 위해서는 4대의 컴퓨터가 필요하다고 얘기하는데 역시 consensus의 이야기일까요? 슬라이드에서는 코드를 함께 보여주지만, Erlang에서 에러를 알려줄 때, 마치 Exception 객체를 catch할 때 cause가 들어있는 것처럼 에러의 원인에 해당하는 코드도 함께 알려줍니다.

5. Live Code Upgrade

Erlang에 대해 간략한 설명을 들을 때 나름 감명깊었던 기능인데, Erlang에서는 애플리케이션이 실행되는 도중에 코드를 수정 – 업그레이드할 수 있습니다.

6. Stable Storage

Erlang에는 기본으로 제공되는 mnesia라는 storage가 있는데, 데이터를 disk와 RAM 둘다에 저장할지, RAM에 저장하되 복제할지 등등을 모두 customize할 수 있다고 합니다. 그 외에도 riak, couchdb 등의 꽤 잘 알려진 NoSQL storage들이 erlang에 기반하고 있습니다.

Messaging

발표의 중간 정도에서 Joe Armstrong은 몇가지 인용구를 보여주는데 아래와 같습니다.

the process achives fault containment by sharing no state with other processes; its only contact with other processes is via messages carries by a kernel messge system
–Jim Gray, Why do computers stop and what can be done about it?, 1985

실패를 격리하기 위해서는 프로세스 사이에 상태를 공유하지 않고, 하부의 메시지 시스템에 의해서 제공되는 메시지를 통해서만 다른 프로세스와 접촉해야한다라는 이야기네요. 1985년의 글이므로 아마 이 글이 Erlang의 설계에 커다란 영향을 미쳤을지도 모르겠습니다. Shared nothing 아키텍쳐라는 단어는 아마 다들 익숙하시리라 생각합니다. 현대의 웹 서비스 아키텍쳐에서는 이미 널리 쓰이고 있죠. 공유하는 상태를 분리하는 것은 매우 중요합니다만, 오히려 공기처럼 우리 주위에 있기 때문에 그 중요성이 간과되고 있는 것이 아닐까 생각이 들 정도입니다.

The big idea is “messaging” — that is what the kernel of Smalltalk/
Squeak is all about (and it’s something that was never quite completed
in our Xerox PARC phase)….

–Alan Kay

한편, 메시징의 가장 큰 성공은 넓은 의미에서는 클라이언트-서버 아키텍쳐에 있다고 생각하지만, 좁은 의미에서는 우리에게 익숙한 것은 아니라고 생각합니다. 비동기적인 메시징과 메시지 디스패쳐 스타일의 애플리케이션은 아직은 자주 볼 수 있는 것은 아님에도 불구하고, 커다란 규모의 시스템에서는 오래전부터 요구되어 왔던 것이고, 인터넷 서비스의 규모가 점점 커지면서 점점 자주 보게되지 않을까 싶습니다.

Fail Fast and Early

Halt on failure: in the event of an error a processor should halt instead of performing a possibly erroneous operation.

Failure status property: when a processor fails, other processors in the system must be informed. The reason for failure must be communicated.

Stable Storage Property: The storage of a processor should be partitioned into stable storage (which survives a processor crash) and volatile storage which is lost if a processor crashes.

– Schneider, ACM Computing Surveys 22(4):229-319, 1990

6 Rules에서도 어느 정도 언급이 되어있지만 기본적으로는 failure를 detection할 수 있어야 하고 failure가 발생한 프로세스는 정지시키고, 안정적인 스토리지에 저장된 상태를 이용해 다른 프로세스가 failure를 복구하는 개념입니다. 높은 수준의 가용성을 요구하는 하드웨어에서 2개의 circuit을 준비하고 언제든지 하나의 circuit에서 failure가 발견되면 다른 circuit으로 대체하는 것과 같은 이야기 같습니다. 특히, 여러 인용을 사용하여 fail-fast와 fail-early를 강조하고 있는데, 이러한 scheme에서 fault 상태의 지속을 최소화하기 위해서는 당연한 이야기 같습니다.

Closing

이 발표를 들은 것은 애초에 Erlang 자체보다는 HA 시스템을 만들기 위한 방법에 대한 Erlang의 관점을 알고 싶었던 것이고, Shared nothing + Messaging 아키텍쳐,  fail-fast, fail-early 등의 개념들의 중요성을 다시금 깨닫는 계기가 되었습니다.

Erlang을 사용해보지도 않은 상태에서 섣부른 생각일 수도 있겠지만, 이 발표를 통해 느낀 Erlang의 가장 큰 장점은 Shared nothing + Messaging 아키텍쳐의 애플리케이션을 개발할 때 필요한 거의 모든 것들을 공짜 로 또는 바로 (off-the-shelf) 제공한다는 것 같습니다. 현대의 웹 서비스들은 비교적 failure에 안전한 언어와 플랫폼 (Java), 실패를 탐지하고 복구하기 위한 메커니즘 (L4), 메시징에 기반한 프로토콜과 그 구현 (HTTP와 이를 concurrent하게 처리할 수 있는 웹 서버 구현), 안정적인 스토리지 (DB)로 만들어져 있기 때문에 역시 이 비용을 크게 느끼지 않는 것 뿐이지, 이러한 것들에 의존하지 않는 새로운 애플리케이션을 만들어야 한다면, 무시할 수 없는 비용을 치뤄야만 합니다. 예를 들어, 언제든지 segmentation fault를 맞이하더라도 이상하지 않는 C로 애플리케이션을 개발해야하고, 실패 탐지와 복구를 Linux HA를 사용하되, 애플리케이션의 요구사항에 따라 실패 탐지의 방법과 복구 방법을 개발해야하며, 메시징을 위해 RPC 프레임워크나 ESB를 개발하는거나 적절한 대안을 탐색하는 것, 새로운 애플리케이션의 특성에 적절한 분산 스토리지를 개발하거나 탐색하는 것 모두가 비용에 해당하는 것입니다. Erlang이 이에 게재되는 모든 문제를 해결하는 것이라고 생각하지는 않지만, 일부는 해결해주고 있다고 생각합니다.

한편으로는, Shared-nothing 아키텍쳐의 애플리케이션, 즉 상태를 공유하지 않아도 되는 애플리케이션은 개발하기도 쉽고, Scalability도 쉽게 보장되기 때문에, 비용은 애플리케이션 환경이나 요구사항에 따라서 다르겠지만, 상대적으로 쉬운 문제입니다. 정말 어려운 문제는 상태 즉, 안정적인 스토리지에 있습니다. 물론, 안정적인 스토리지의 구현에도 Erlang은 위에서 언급한 면에 커다란 도움을 줄 수 있다고 생각합니다만,  단지 구현상의 문제라고 보기에는 현실과 거리가 있다고 생각합니다. 안정적인 스토리지의 문제 전체 영역은 Erlang이 해결하는 영역에 비해서 훨씬 크다고 생각합니다.

Comments Off | Categories: Software Development | Tags: , ,

Pallet – DevOps for the JVM by Antoni Batchelli

22 May 2012 by Joseph Jang

Closure/West 2012에서의 Antoni Batchelli의 강연입니다.

Pallet – DevOps for the JVM by Antoni Batchelli

제목을 보고 JVM 기반 애플리케이션들 대한 모니터링이나 관리에 대한 얘기인 줄 알았는데, JVM 기반 언어로 만든 Configuration Management Tool이네요. 한마디로 말하자면 Closure로 만든 Cloud용 Chef나 Puppet 정도 되는 것 같습니다.

설명보다는 직접 코드를 보는 편이 훨씬 와닿으리라고 생각합니다. (InfoQ 페이지에서 Slides를 받을 수 있습니다.)

 

느낀 점은 두가지 정도네요.

1. Ruby나 Closure 같은 언어들이 유행하면서 라이브러리 수준의 DSL만으로 descriptive language 처럼 쉽게 기술할 수 있게 된 것은 오래되었지만, 점점 보편화하고 있군요. 특히, 주로 행동이 아닌 상태를 기술해야하는 Configuration Management Tool에서는 이러한 방식이 더욱 이해하기 쉽고, 유용하며 따라서 모듈화에도 유리한 듯. Provisioning은 적절하게 개념을 세우고 분류를 해서 DB로 만들기만 해도 어느 정도 잘 동작하지만, 대규모 Configuration Management가 필요할 때에도 어느 정도 모듈화되고 버전 관리되는 shell scripts 이상은 직접 본 적이 없고, 그 한계도 잘 알고 있는데, 이제는 Chef나 Puppet 계열을 시도해 봐야 할지도 모르겠군요.

2. 슬라이드들을 자세히 보셨는지 모르겠지만, 만족해야하는 하드웨어 요건과 설치해야하는 소프트웨어들, 노드들의 수를 기술하면, AWS  또는 VM Infra로부터 자동으로 적절한 타입의 instance를 생성해서 요구한대로 설정해주는 시나리오입니다. cloud 환경이나 VM infra 환경 하에서는 당연하게도 이런 마법 같은 일이 가능하다는 것, 가능하다는 것은 알고 있지만, 구체적인 시나리오를 보니 느낌이 새롭네요. 전통적인 인프라 환경에서는 직접 구현하려고 해도 절대 쉽지 않은 일인데요. 저런 꿈 같은 일이 보편화 하는 날이 오게 될지 매우 기대됩니다.

Comments Off | Categories: Software Development

How To Design A Good API and Why it Matters by Joshua Bloch

18 May 2012 by Joseph Jang

2007년 1월 24일 Google TechTalks에서의 Joshua Bloch의 강연입니다.

How To Design A Good API and Why it Matters (Slides)

InfoQ에서 공개되어 있는 Javapolis에서의 2005년 강연도 있습니다만, 내용은 같아 보입니다. Slides로 충분하다고 생각하지만 OOPSLA 2006에 제출하기 위해 만든 요약도 참고하세요.

Joshua Bloch에 대해서는 Effective Java에 관한 글에서 소개한 적이 있지만, 굳이 여기서 다시 언급할 필요도 없다고 생각합니다. Java의 주요 클래스 라이브러리들의 설계를 주도하여, Java의 API 설계 품질의 기준을 한층 끌어올린 그는, API 설계에 관해 전문가라고 해도 충분하다고 생각합니다.

이 강연의 주제는 제목 그대로 좋은 API를 설계하는 방법과 그 중요성에 대한 강연이고, 제가 아는 한 API 설계에 관한 대부분의 중요한 생각들을 담고 있다고 생각합니다. 그 생각들을 전달하는 면에 있어서도 매우 훌륭한 강연이기에 만약 아직 이 강연을 보신 적이 없으신 분들은 시간을 들여 직접 보실 가치가 있으리라고 생각합니다. 이 글에서는 주로 API의 설계 과정에 대한 내용에 대해 제가 현재 시점에서 인상적인 부분들에 대한 의견을 적어봅니다.

If you program, you are an API designer

예전에는 프로그래머들을 API 설계 경험이 있는 프로그래머와 그렇지 않은 프로그래머로 분류할 수 있다고 생각했습니다. API 설계를 하기 전에는 다른 프로그래머가 어떤 도메인에 대해서 어떤 생각을 가지고 있을지, 주어진 API를 사용할 때 얼마나 실수할 수 있을지, 주어진 API가 얼마나 이해하기 쉬울지에 대해서 고민해보지 않았으니까요. 그리고, 그러한 고민들을 통해서 문제들을 해결하는 방법을 깨닫는 과정이 중요하다고 생각했습니다. API 설계를 경험하고나서 제가 느낀 것은 학부 시절에 Automata 수업을 들었을 때의 느낌이었죠.

그런데, Joshua Bloch은 모든 프로그래머는 API 디자이너라고 얘기합니다. 이 말을 듣고 다시 생각해보니, 실제로는 모든 프로그래머는 자신이 만든 코드를 사용할 모든 사용자 – 즉, 최종 사용자 (end-user)이거나 다른 프로그래머들을 고려하지 않으면 안된다는 것을 깨달았습니다. 어쩌면 그만큼 프로그래머에 대한 잣대가 올라갔다는 생각도 듭니다.

Start with Short Spec–1 Page is Ideal

API 설계의 시작 단계에서는 기민성(agility)이 완전성( completeness)보다 중요하다는 이야기입니다. API 설계의 시작 단계에서는 실제로 그 API를 들고 사용자에게 부딪혀보지 않으면 그 API가 요구사항에 적합한지 알 수 없는데, 이해하기도 힘든 복잡한 API 스펙을 가지고는 사용자들이 이해하기도 힘들고, 변경하기도 힘들다는 것입니다. 일반적인 소프트웨어 개발은 기민성을 중요시하면서도 API 설계에 있어서는 기민성과 완전성 사이에서 저울질 하기가 어려운 면이 있었는데, 한 페이지라는 기준은 매우 훌륭한 기준인 것 같습니다. 그리고, 이 한 페이지를 들고 사용자와 부딪혀보는 과정들 (이를테면, Hallway testing) 도 매우 중요하게 여겨집니다.

When in doubt leave it out

API의 어떤 요소 (메서드, 파라미터, …)가 들어가야 할지 말기 고민된다면, 빼버리라는 것입니다. 이미 다른 사람들이 사용하는 API는 없애기 힘들지만, 추가하기는 쉬운 API의 특성에 기인하는 매우 중요한 특성입니다. 요구사항을 다른 부서 등과 조율하는 과정에서 애매모호한 기능 요구사항들이 항상 나타나는데 이에 대한 명확한 결정을 내리는 것이 가장 좋긴 하겠지만, 그렇지 못하는 경우도 흔히 벌어지는 일인 것 같습니다. 이 때, API의 이러한 특성은 요구사항의 결정에서도 중요한 근거가 될 수 있지 않을까 하는 생각이 드네요.

Write to Your API Early and Often

API 설계에서 가장 흔하게 겪고, 또 가장 중요한 문제점으로 드러나는 것은, API를 이용한 구현하는 도중에 특정 기능을 충족할 수 없음을 발견하는 것일겁니다. 기민한 개발 과정으로 볼 수도 있겠지만, API 사용자 입장에서는 부족한 API 설계 상의 문제를 파악하거나 API가 동작하지 않는 문제를 발견하는 것, 그리고 변경된 API를 적용하는 과정들은 매우 힘들고 비용이 많이 들 뿐만 아니라 괴로운 과정입니다. 이러한 문제들의 대부분은 결국 API를 이용해서 구체적인 프로그램을 만들어보는 것 밖에는 방법이 없고, 기본적으로 이 역할을 API 설계자에게 있어야 합니다. TDD를 한번이라도 해보신 분들은 아시겠지만, API를 사용하는 코드를 먼저 써보는 것은 API 설계에 커다란 도움이 됩니다. 그리고 이러한 과정에서 만들어진 API 예제를 사용자에게 제공하는 것은 API를 사용하는 방법을 쉽게 익힐 수 있도록 도와줄 뿐만 아니라 API 사용자들이 잘못된 사용 방법에 빠지지 않도록 도와줍니다. Joshua는 API 설계 시의 API 예제가 API를 사용하는 모든 코드 중에 가장 중요한 코드라고 얘기합니다. 이는 절대 과장이 아니라고 생각합니다. API 예제가 제공되지 않는 API를 직접 개발하거나 사용해본 입장에서 이 부분이 뼈저리게 느껴지는군요.

Document Religiously

API라고 한다면 가장 좋은 문서화가 요구되어야 하는 것은 당연한 것 같습니다. 하지만, 문서가 없는 API를 종종 봅니다. 저도 잘못된 내용의 문서화가 된 API를 쓰거나, 모든 측면의 문서화를 하지 않은 등의 실수들이 떠오릅니다. 문서화에는 정말 ‘Religiously’라는 단어 – 우리말로 굳이 옮긴다면 ‘열광적으로’ 라고 해야할까요 – 를 써야할 정도로 개발자가 그만큼 공을 들이지 않으면 안되는 것 같습니다.

Closing

이 강연은 비록 5년 전의 내용이지만, API의 설계 과정 뿐만 아니라, 일반적인 API 설계 원리, 클래스, 메서드, 익셉션의 설계에 관한 내용들을 담고 있으므로, 현재는 물론 앞으로도 계속 곱씹을 수 있는 내용이라고 생각합니다. 다시금 말씀드리지만, 한번씩은 보시기를 권해드립니다. 가능하다면, 누군가가 자막 번역을 해준다면 좋겠다는 생각이 드는군요.

제게는 API 설계에 대해서 예전에 했던 생각들을 더올리게 되면서 현재 직면하고 있는 문제들에 대해서도 새롭게 많은 고민들을 할 수 있게 해주는 강연이었습니다. 좋은 강연에 대해서 Joshua Bloch에게 감사드립니다.

Comments Off | Categories: Software Development

Google 20% Time

12 October 2011 by Joseph Jang

Google의 20% Time 제도는 Google의 직원이라면 누구나 업무 시간의 20%, 즉 매주 하루 정도의 시간을 자신이 원하는 일에 투입할 수 있다는 제도. 이 제도는 Gmail 과 같은 성공적인 프로젝트의 요람이 된 것으로 매우 잘 알려져 있고, Google이라는 회사에서 ‘혁신’이라는 가치를 소중하게 여긴다는 사실을 대변하고 있다.

그렇다면 어떤 소프트웨어 회사든 Google의 20% Time 제도를 도입한다면 ‘혁신’에 성공할 수 있을까? 현실을 냉철하게 바라보는 사람이라면 Google에서 조차도 20% Time 제도가 ‘혁신’에 있어서 성공적인가라는 질문에 의문을 품는 것이 당연하다고 본다.

예를 들어, 당신은 어떤 소프트웨어 회사의 상위 관리자이고, ‘혁신’의 추진력을 높이기 위해 (그다지 현명한 이유는 아닐지라도) 유명한 Google의 20% Time의 도입을 검토하고 있다고 생각해보자.

이러한 관점에서 20% Time에 대한 Quora의 답변 내용을 간략하게 정리해본다. 여러 사람들이 기술한 사항들이기 때문에 주관적이기도 하고 시간이 흐르면서 변화한 사항들도 있을 테니, 이 글에 있는 모든 사항들이 정확하다고 보기에는 힘들다는 점을 유념해서 읽어주었으면 한다. Google의 employee가 아닌 입장에서 이 글을 쓰는 한 대체로 부정확하고 상상력에 기초한 우스운 글이 되기 쉽다는 것을 잘 알고 있지만, 동기 부여라는 주제에 관한 스스로의 고민의 과정을 정리해놓는 의미로 생각한다. 이 글에서 언급된 현실을 반영하지 않는 잘못된 사실이나 미묘한 의미가 있다면 지적해준다면 그러한 과정에 매우 도움이 될 것이다.

평가: 20% Time은 어떻게 평가되어야 하는가?

20% Time을 도입한다고 할 때, 가장 먼저 부하 직원들이 묻는 것이 바로 이 부분일 것이다. 20% Time은 강제로 사용하는 것인가? 선택적으로 사용하는 것인가? 어느 쪽이든 평가에 불이익이 있는 것이 아닌가?

In Google

20% Time을 모든 사람이 반드시 활용해야 하는 것은 아니다. 한편, 20% Time을 활용하고자 하는 사람이 20% Time을 사용하는 것을 직접적으로 가로막는 것은 없다. 하지만, 관리자나, 함께 main project의 일정을 고려해야 하는 동료들의 동의를 얻는 것이 바람직하다. 관리자의 승인 하에 20% Time을 모아서 한 주 동안 Full Time으로 일할 수도 있다.

또한 기본적으로 20% Time은 평가 (performance review)에서 제외되며, 포함된다고 하더라도 평가 (performance review)에 인지되기 힘들다. 동료 평가(peer review)에서 인지되는 것이 바람직하겠지만, 현실적으로 100%의 시간을 주요 프로젝트에 사용한 동료가 더욱 좋은 평가를 얻을 확률이 높고 승진도 빠를 수 있다. 정당한 평가를 위해서는 실제로 자신이 기여한 프로젝트의 PM에 대해 정당한 동료 평가를 요구하여야 한다.

이러한 현실적인 어려움 때문에, 대부분의 Google 직원들은 이를 활용하고 있지 않다.

Opinion

보통, 관리자의 입장에서 20% Time을 위한 리소스를 할당하는 것은 절대 쉬운 일은 아니라고 본다. 하지만, 이는 리소스에 대해 단기적인 시각에서 바라보았을 때의 결과라고 생각한다. 만약 20% Time이, 혁신을 유도하거나 생산성을 높이거나 적어도 Turn-over 비율을 감소시킴으로써, 투입한 비용 이상의 성과를 산출할 수 있다면, 처음에 이를 선택하는 것은 조금 과감할 필요가 있겠지만, 곧 익숙해진다면 별로 문제가 되지 않을 거라고 생각한다.

20% Time을 평가에 포함시킬 것인가, 포함시키지 않을 것인가는 매우 어려운 문제다. 평가에 포함시킨다면, 평가를 어떻게 할 것인가라는 문제를 차치하더라도, 평가 자체가 20% Time에 참여하는 사람들의 의도를 왜곡하여 20% Time의 본래 의미를 잃어버리기가 쉽다. 평가에 포함시키지 않는다면, Google의 사례와 같이 20% Time을 사용하기 위한 커다란 incentive가 사라지게 된다. 양쪽 모두가 각각의 문제를 지니고 있기 때문에, 결국은 제도 자체의 겉모습에 치중할 것이 아니라, 제도를 통해서 획득하려는 가치를 기준으로 판단해야 한다고 생각한다.

20% Time이 조직에 혁신을 위한 문화를 조성하고 실제로 혁신을 이끌어내기 위한 것이라면, Google과 같이 평가에 포함시키지 않는 쪽이 더 바람직해 보인다. 그 이유는 다음과 같다.

  • 모든 사람이 혁신을 위한 아이디어를 가지고 있고, 이 아이디어를 실제로 실행할 의지를 가지고 있으며, 또 그를 성공시키기 위한 역량을 가지고 있으며, 상황적인 조건이 부합하는 것은 아니다. 아마도 이는 소수에 불과할 것이다.
  • 정말로 가치 있는 일이라면 적어도 20% 정도의 보상 기회를 희생할 정도의 가치가 있어야 할지도 모른다.
  • 불확실한 미래의 보상을 기대한다고 하더라도, 현재의 확실한 희생을 수용한 사람이라면, 그만큼 보람 있고 열정적으로 일 할 것이다.

물론, 실제 실행 시에는 보다 많은 미묘한 문제들이 발생할 거라고 추측되지만, 이러한 허들을 뛰어넘을 수 있는가의 여부는 실제로 실행해보지 않고서는 미리 예측하기 힘들다.

시간: 20% Time은 너무 길거나 반대로 너무 짧은 것은 아닌가?

In Google

Google에서 실제로 하나의 서비스를 launch하기 위해서는 개발 비용을 넘어서는 커다란 오버헤드를 필요로 한다. 예를 들어, 조그마한 서비스라고 하더라도 launch를 위한 기술 및 제품 승인을 얻기 위해서는 많은 노력을 필요로 한다. 자신의 프로젝트에 참여하기 위한 사람들을 찾는 것도 매우 어려운 과정 중의 하나라고 한다. 막상 서비스를 launch하더라도 수시로 발생하는 outage나 운영 상의 변화에 대응하기 위한 유지보수에 다시 20% Time을 들여야 한다. 따라서, 제대로 뭔가를 하려면 20% Time 만으로는 부족하고 야근과 주말근무를 불사해야 한다. 의견이 엇갈리기는 하지만, 20% Time은 workholic을 위한 제도라고 얘기할 정도. 20% Time은 서비스를 launch하는 수단으로서는 그다지 좋지 않다는 의견도 존재한다.

활용: 20% Time을 어떻게 활용하는가?

In Google

다음과 같은 다양한 활용이 가능하다.

  • 기존 및 현재의 프로젝트에서 다른 사람들을 설득하지 못하지는 못했지만, 스스로는 가치가 있다고 생각하는 문제를 개선할 수 있다. 현재의 개발팀이 우선순위 때문에 관심을 기울이지 못하는 어떤 기능을 개선할 수 있다.
  • 새로운 서비스나 새로운 소프트웨어를 개발한다.
  • 이미 존재하는 전사 프로세스나 도구를 개선한다.
  • 외부의 오픈 소스 프로젝트에 기여할 수도 있고, Journal에 기고하거나, 새로운 프로그래밍 언어나 UI 디자인에 대해 공부하는 등, Job Skill을 확장하기 위한 뭐든지 할 수 있다.

가치: 20% Time이 Google에게 가져다 주는 것은 무엇인가?

이에 대해서는 일단 Dion Almaer의 글을 인용해보자.

The key was the following effect:

  • In order for 20% time to work, anyone must be able to see what is out there
  • In fact, if you want to get some people working “for free” you need to both advertise your project, and write it in such a way that it is easy to get ramped up and productive (end result: better code)

The end result is the culture HAS to be kept very open. The ability to see the projects that are worked on, check out the code, see presentations and design docs, is a key reason why Google does so well at engineering in my opinion.

난 위의 Quora의 답변 내용에서 나왔던 사실들로부터 20% Time의 효과에 대해 원래 가지고 있었던 의심을 약간은 확인했다고 생각했는데, 이 글을 읽고 내가 지인들로부터 들었던 이야기들이 떠오르면서 그러한 생각이 완전히 바뀌게 되었다.

20% Time은 어떻게 동작하는가?

다음 사항들은 지인들로부터 들었던 이야기들이라 더욱 부정확할 수 있겠지만, 일단 정리해보자.

  1. Google에서는 20% Time 프로젝트에 참여할 다른 엔지니어를 모집하기 위해 전사 메일을 보낼 수 있다. 그리고, 20% Time 프로젝트에 리소스를 승인 받거나 공개 서비스로 내놓기 위해 승인 받는 과정이 정의되어 있다.
    • 자신의 좋은 아이디어를 전사 메일로 보낼 수 있고, 참여를 호소할 수 있으며, 이것이 제도적으로 뒷받침되는 소프트웨어 회사는 과연 얼마나 될까?
    • 관리자들은 자신에게 이야기를 하면 되는데 이야기를 하지 않아서 그렇다고 생각할 지 모르겠지만, 공식적인 제도가 있는 것과 이야기를 하면 된다라는 것은 조직원 입장에서는 천지차이다.
  2. Google에서는 자신이 만들어 낸 코드, 문서, 발표 자료 등을 누구든지 볼 수 있다.
    • 자신의 프로젝트에 참여하고자 하는 사람 또는 관심이 가는 프로젝트를 주도하는 사람이 얼마나 뛰어난가를 확인하는 가장 정확한 방법은 그 사람이 실제로 해놓은 것을 보면 된다. 다시 말해, 엔지니어가 다른 엔지니어의 산출물에 대해 가장 잘 평가할 수 있다.
    • 대부분의 회사에서도 어떤 방식으로 산출물이 관리되고 있긴 하겠지만, 실제로 어떤 사람의 산출물을 공개적으로 접근하는 것은 매우 어렵다.그래서, 직급이라든가, 함께 일했던 시절의 주고 받은 대화나 메일, 과거 동료들의 단평 정도를 간접적으로 이용하는 것에 불과하다.
  3. Google에서는 코드 리뷰가 필수적으로 행해지고 있으며, 코드에 대한 평가를 수치화한 Readability Score라는 척도가 공개적으로 조회 가능하고, 이러한 수치가 다른 프로젝트에 대한 Commit의 허용 여부에 영향을 미친다.
    • 단순히 모든 산출물이 공개되어 있을 뿐만 아니라, 이를 정량화하고 실제로 이러한 척도가 어느 정도의 신뢰성을 가지고 동작한다는 것이 매우 놀랍다.
    • Readability Score는 평가(Performance Review)와는 무관하다.
    • Google의 코드 리뷰 제도에 관해서는 역시 Quora의 답변들을 읽어보면 참고가 될 것이다.

제도, 시스템과 문화를 통한 혁신

혁신에 관한 이야기를 꺼낸다면 아마도 대부분의 상위 관리자들은 다음과 같은 이야기를 할 것이다.

혁신에서는 시간이 있는가, 없는가가 중요한 것이 아니라, 얼마나 열정적으로 문제를 해결하려고 하는 가가 중요하다. 또한, 혁신은 아이디어가 아니라 실행이다.

나는 이런 이야기들에 거의 찬성한다. 나조차도 이런 얘기를 한 적이 분명 여러 번 있을 것이다. 조직의 구성원들의 열정은 혁신에 있어서 필수불가결한 요소이고, 시간의 부족만을 그 원인으로 진단하는 것에 대해서는 반성이 필요한 경우가 많은 것이 사실이라고 본다.

그럼에도 불구하고 혁신과 열정의 원동력이 오직 조직 구성원 내부에만 있다고 보는 관점도 온전히 옳다고만 할 수는 없다고 본다. 단지 조직원 사이에서 혁신과 열정이 저절로 꽃피어나기를 기다리는 것보다는 구성원이 혁신적인 아이디어에 대해 열정적으로 일할 수 있도록 동기를 부여하거나 지원하는, 좀 더 적극적이고 체계적인 행동이 조직에는 필요하다고 생각한다. 이 때, 적극적이고 체계적인 행동이라는 것의 의미는 관리자 개인의 능력이나 성향, 선의에 의한 동기 부여 행동과 대비되는 것을 의미한다.

제도나 시스템이 아닌 관리자 개인에 의존할 경우 다음과 같은 문제들이 존재할 수 있다.

  • 관리자 개인에 따라 개인의 능력이나 성향, 선의에 따라서 동기 부여의 수준은 극단적으로 낮을 수 있다. 이러한 경우에 대한 대책이 없거나 있더라도 제대로 동작하지 않을 가능성이 있다.
    • 일반적인 hierarchical 조직에서, 관리자 개인이 조직원의 동기 부여를 크게 해친다고 하더라도 관리자 자신은 이러한 상황을 인지하지 못하거나, 인지하더라도 변화하기가 힘들며, 조직원은 변화를 위한 적절한 권한이나 역량이 없으며, 상위 조직장은 이를 인지하지 못하는 경우가 많다.
    • 조직이 보통 요구하는 것은 조직의 단기 성과를 높일 수 있는 충분한 역량을 가진 조직장이며, 물론, 동기 부여의 능력 또한 조직이 요구하고 바람직한 능력이나, 성과와 동기 부여가 충돌할 경우, 조직은 전자를 선택하는 경향이 있는 것 같다. 팀의 morale을 와해한 조직장이 승승장구하는 (적어도 살아남는) 스토리는 이러한 이유에 기인한다고 생각한다.
  • 조직의 상황에 따라 동기 부여의 수단이 쉽게 희생될 수 있다.
    • 일반적인 상황에서 조직 및 이를 대변하는 관리자는 생산성의 저하 요소를 제거하기 위해서 동기 부여에 노력을 기울일 수 있다. 하지만, 조직원의 동기 부여와 우선순위와 R&R 같은 좀 더 전통적인 조직 가치가 충돌할 경우 후자를 우선시하는 경향이 있는 것으로 보인다. 이러한 선택은 조직의 구조나 목적 상 물론 불가피한 측면이 있는 것이 사실이다.
    • 문제는 이러한 조정이 개인에 의한 것일 경우, 극단적인 희생이 이루어질 가능성이 높다는 것이다. 예를 들어, 일반적인 상황에서 동기 부여를 위한 노력이 50%의 비중이었다면, 문제의 상황에서는 0%가 되어버릴 수 있다는 것이다.

단편적인 예를 들어, ‘내가 원하기만 한다면 내가 원하는 일을 언제든지 할 수 있어’와 ‘내가 원하더라도 조직장에게 얘기를 해야할까? 얘기를 한다면 불이익을 받지 않을까? 소속 조직을 옮겨야 할까? 소속 조직을 옮기기 위해 회사의 제도를 활용할 수 있을까? 또는 누구와 얘기해야할까? 그냥 이직을 해야할까?’는 조직원 입장에서 엄청난 차이일 수 밖에 없다.

Google의 20% Time에서 가장 중요한 측면 중 하나는 Google은 조직원의 동기 부여에 대한 강조가, 관리자 개인에만 의존하지 않고, 전사적인 제도와 이를 뒷받침하는 시스템, 그리고 문화를 통해 항상 일정 수준으로 이루어진다는 것이다.

수평적인 평가와 비물질적인 보상을 통한 혁신의 동기 부여

평가와 보상이란 조직에 있어서 가장 중요한 요소 중의 하나이다. 평가의 본질적인 목적은 보상을 어떻게 공평하게 분배할 것이냐가 아니라, 조직원의 potential을 최대한 발휘하게 하여 조직 전체의 성과를 증가시키는 것에 있다.

하지만, 일반적으로 평가는 어려울 뿐만 아니라, 예측과 정량화의 어려움으로 인한 Software 개발의 본질 상 Software 개발 조직에서의 평가는 매우 어려운 것이 보편적으로 받아들여지고 있다.

<To Be Written>

Closing

Google이 20% Time을 통해서 단지 제도와 시스템 뿐만 아니라 혁신의 문화를 배양하는 것은 실제로 동작하는 사례로서 매우 높은 성취라고 생각한다. 하지만, 혁신을 위한 조직 문화를 만들기 위한 수단이 비단 Google의 20% Time만이 있는 것은 아닐 거라고 추측해본다. 보다 많은 조직에서 이에 대해 고민하고 또 실험하면서 그들만의 혁신 문화를 창조해나갔으면 좋겠다.

좀 더 읽어볼 글들:

Comments Off | Categories: Software Development

Jolt Awards 2011

25 September 2011 by Joseph Jang

Excellence Award는 Continuous Delivery, Productivity Award는 Seven Languages in Seven Weeks와 Mining the Social Web이 수상했다. 이들 Top 3 이외에 당장 관심이 가는 책은 Martin Fowler의 DSL 책, Scalability Rules 정도.

The Best Books

http://drdobbs.com/joltawards/231500080

  • Domain-Specific Languages, by Martin Fowler
  • The Art of Computer Programming, Volume 4A: Combinatorial Algorithms, Part 1, by Donald E. Knuth
  • The Joy of Clojure: Thinking the Clojure Way, by Michael Fogus and Chris Houser
  • Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages, by Bruce A. Tate
  • Mining the Social Web: Analyzing Data from Facebook, Twitter, LinkedIn, and Other Social Media Sites, by Matthew A. Russell
  • Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation, by Jez Humble and David Farley

The Rest of the Best

http://drdobbs.com/joltawards/231600815

  • Arduino Cookbook
  • CLR via C#, 3rd Edition
  • Data Analysis with Open Source Tools
  • Eloquent Ruby
  • High Performance JavaScript
  • Scalability Rules: 50 Principles for Scaling Web Sites
  • The Software IP Detective’s Handbook: Measurement, Comparison, and Infringement Detection
  • The Rails 3 Way
  • The RSpec Book: Behavior Driven Development with Rspec, Cucumber, and Friends

Comments Off | Categories: Book, Software Development | Tags:

NoSQL @ Netflix

06 September 2011 by Joseph Jang

http://www.infoq.com/presentations/NoSQL-Netflix

지난 7월 QCon 발표. 이 발표자는 굉장히 여러 군데서 동일한 내용으로 발표한 모양인데도 불구하고, 실은 썩 마음에 드는 발표는 아니었지만, 실제 엔지니어링 경험이 뼈저리게 느껴져서 인상 깊게 보았던 발표다.

Netflix’s Cloud Transition

2008년 말, Netflix는 하나의 데이터센터를 가지고 있었고, SPOF와 cooling, power, space, traffic capacity 문제에 봉착하고 있었다. (문맥상 그야말로 데이터센터를 ‘보유’하고 있었던 것으로 보이는데, 미국의 경우 이러한 방식이 일반적인 방식인 것인지, 그리고, SPOF가 중요한 문제가 될 만큼 데이터센터의 신뢰성이 문제가 되는 수준인지 궁금하다.) 그리고, 놀랍게도 outsourcing을 통해,  당시 IaaS 플랫폼으로서는 leader 격이었던 AWS를 통해 해결하기로 결정한다.

Netflix의 cloud migration에서 중요한 점 중 하나는 가장 중요한 사용자 개인 정보 (PII), 결제 정보 (PCI DSS)는 그들의 데이터센터에 남겨놓고, 나머지 – 비디오의 메타데이터, 리뷰, 사용자의 비디오 큐, 시청 기록, 평점, 로그 등 만을 cloud로 이동했다는 점이다.

AWS로 가면서 자연스럽게 선택하게 된 storage는 바로 Simple DB와 S3인데, Simple DB는 RDBMS의 대체, S3는 Simple DB의 item 크기 제약을 넘어서고, single key로만 액세스하는 데이터를 저장하는데 사용한다. 그러다 Simple DB의 데이터 모델 제약이라든지, Scalability concern등의 문제들을 넘어서기 위해서 Cassandra도 사용하게 되었다고 한다. 이 발표에는 등장하지 않았지만 M-R과의 조합이 필요한 곳에는 Bigtable도 사용하는 것으로 보인다.

이 발표에서는 Simple DB와 Cassandra를 간략하게 소개하고, Simple DB를 실제로 적용할 때 겪었던 문제들을 정리하고, Cassandra 에서 이러한 문제들이 많이 해결되었다고 얘기하고 있다.

Problems in transition from RDBMS to Key-Value Data Store

당연하지만, RDMS에 있을 때 편하게 썼던 기능들이 필요해지면 application layer에서 알아서 구현해야 한다.

  • partial or no sql support
    • joins이나 group by가 없기 때문에 application layer에서 구현
  • no relations between domains
    • application layer에서 구현.
  • no transaction
    • simple db에서는 conditional put/delete op이 존재하기 때문에 이를 이용해 optimistic locking
    • cassandra에서는 batch mutate op 이용
  • no schema
    • attribute 이름 등에서 misspelling이 발생할 경우 silent하게 실패.
    • 공통 data access layer에서 validation
  • no sequences
    • primary key를 위해서는 자연스럽게 발생하는 unique key나 그러한 경우가 아닐 때는 UUID 사용
    • ordering을 위해서는 distributed sequence generator (using zookeeper)나 client timestamps 사용
  • no constraints (uniqueness, foreign key, referential , integrity)
    • application layer에서 구현

Workaround Issues in SimpleDB

SimpleDB의 설계나 구현이 아직 충분히 성숙되지 않았음을 엿볼 수 있기도 하고, 어떤 측면에서는 다른 DBMS에서도 충분히 겪을 수 있는 문제이나, 충분한 사용 경험이 없기 때문에 해결에 많은 시간을 들여야 할 가능성이 높다고 생각한다. 발표를 들으면서 발표자인 Siddharth Anand가 얼마나 고생했을지 감정이입이 될 정도.

  • no backup and recovery
  • no native support for types
    • 모든 데이터는 UTF-8 character string이고 sorting은 lexicographical만 지원하기 때문에, 숫자 sorting을 하기위해서 데이터에 zero-padding을 해야 한다는 어처구니 없는 일이 발생한다.
  • null attributes are not indexed
    • null 은 indexing이 안되어있기 때문에 where clause에 is null을 쓰면 full domain scan.
      • null인지 여부를 나타내는 필드를 추가해야 하기 때문에, 결국 sparse table의 장점을 잃어버림.
    • 역시 비슷한 문제로 null일 수 있는 attribute에 대해 order by 하면 null attribute의 record는 아예 나오지 않음.
  • data set partitioning

    • domain에 10GB limit와 1B attributes limit가 존재하기 때문에 domain을 application level에서 sharding 해야 함.
    • write throughput을 늘리기 위해서는 sharding 해야 함.

  • attribute name이 case-sensitive하므로 miscased나 misspelled attribute names을 체크해야 함.
  • limit N clause가 없으면 100개의 row만 return 되므로 실수하지 않았는지 체크해야 함.
  • 하나의 statement 내에서 하나의 attribute를 업데이트하고 다른 attribute는 null out할 수 없음.

Thoughts

흔히 NoSQL로 분류되는 storage들은 RDBMS가 아니라는 것 외에는 별로 공통적이라고 할만한 것이 없다. 그래서 NoSQL이라는 말을 쓰는 것을 매우 싫어하는 편이다. 이 발표를 들으면서 이러한 생각에 좀 더 확신이 들었다고 할 수 있을 것 같다.

NoSQL이라고 하는 storage들을 실제로 자세히 들여다보면 각각마다 데이터모델, 오퍼레이션 특성, 성능 특성, 성숙도는 천차만별이다.  결국 하나의 storage를 채용하기 위해서 서로 다른 특성들을 이해하고, 유효한 방법으로 평가는 일만 하더라도 결코 쉬운 일이 아닐뿐더러, 채용하기로 결정한 storage의 데이터모델에 적합하게 데이터를 구성한다든가, 위의 사례에서 보았듯이 각 storage별 세부 특성이나 결함 등을 처리하는 일까지 더한다면 하나의 storage solution을 도입하는 일은 보통 일이 아니다. 그래서, “NoSQL이란 거 좋다면서?”라고 말을 꺼내는 사람이 있으면 “그냥 RDBMS 쓰세요”라고 얘기해주는 것이 정답이라고 본다. NoSQL이라는 bandwagon에 타려고 발걸음을 서두르기 전에, 남들이 하는 이야기들을 반복하기 전에, 왜 RDBMS를 쓰면 안되는 지부터 자신의 도메인에서 고민해보았으면 한다.

주변 사람들에게는 몇 번 얘기했었지만, 이 발표를 들으면서 한가지 매우 인상 깊었던 얘기는 consistency가 깨질 수 있는 것을 인정하고 배치의 형태로 항상 백그라운드에서 동작하고 있는 data fixer를 개발하고 있다는 내용이었다. 별 것 아니라고 생각할 수도 있지만, 이러한 패러다임은 RDBMS를 사용하던 시절에는 inconsistency를 유발하는 원인이 있다면 이를 제거해야 하는 것으로 보는 것 (아니면 아예 무시하거나)과는 완전히 다른 패러다임이다. 현재로서는 weak consistency의 NoSQL storage를 사용하면서도 아직 기존의 패러다임에 젖어 있는 것이 사실인 듯 하다. 지금은 transaction 없이 application layer에서 index를 만들고 나중에 consistency가 깨어지지 않기를 기도하겠지만, 앞으로는 application layer에서도 anomaly를 탐지하고 자연스럽게 해결할 수 있도록 해야할 뿐만 아니라, 지속적인 validation & flx 작업이 필요할 것이다. RDBMS도 경쟁하고 있는 환경에서 weak consistency 모델이 얼마나 유행할지는 잘 모르겠지만, weak consistency 모델의 이러한 데이터 운영 패러다임을 간략한 개념과 구현으로 정리할 수 있다면 바람직할 것 같다.

Comments Off | Categories: Software Development

Development at the Speed and Scale of Google

15 December 2010 by Joseph Jang

어제 송년회가 피곤했던지 일찍 잠들었다 새벽에 깨는 바람에, QCon SF 2010에서 Google의 Engineering Manager인 Ashish Kumar가 발표한 Development at the Speed and Scale of Google이라는 Presentation을 보게 되었다.

이 발표의 내용은 Google의 Infrastructure 중 하나인 빌드 시스템에 관한 내용으로 아주 재미있는 발표는 아니었지만, 몇 가지 흥미로운 점이 있었다.

Monolithic Code Tree

Google은 어느 정도 알려진 바와 같이, 하나의 코드 저장소에 모든 코드를 관리하고 있으며, 누구든지 필요한 소스코드를 체크아웃해서 사용할 수 있다.

Reducing Checkout Costs

모든 것을 소스로부터 빌드하기 때문에, 의존성을 가진 코드들을 체크아웃하는 비용을 무시할 수가 없는데, 사실 변경하려는 코드가 아닌 코드에 대한 로컬 복사본은 필요 없으므로, FUSE 기반 파일 시스템을 이용한 전체 code tree의 읽기 전용 복사본을 이용한다고 한다.

Reducing Code Review Costs

Google의 개발 프로세스를 보면 commit 이전의 코드 리뷰가 필수적으로 들어가있는 것으로 보이며, 코드 리뷰의 비용을 줄이기 위한 시도로서, 웹 상에서 graphical diffs를 조회하고 이에 대한 comment를 남길 수 있는 code review 도구와 lint error, code coverage, code analysis, test results 등이 제공된다.

IDE 기반의 도구에 대비해, 웹 기반 도구를 사용하고 있는 것이 흥미로운 점인데, C/C++ 계열에는 적절한 IDE가 부족한 점도 있겠지만, 아무래도 웹 기반 도구는 그 기본적인 특성 덕분에 하나의 정보를 여러 사람들에게 공유하기가 매우 쉽다는 점이 커다란 장점으로 작용하는 듯 하다. 다시 말해, 웹 만큼 훌륭한 shared workspace는 흔치 않다.

Reducing Build Costs

개발 과정에서의 커다란 비용 중의 하나로 지적하고 있는 것이 바로 build를 하는 도중 기다리는 비용인데, 이를 줄이기 위해서 object 파일들의 캐슁, 빌드 결과물에 대한 lazy한 액세스, incremental link (old binary + modified object files) 등을 지원하는 분산 빌드 시스템을 채용하고 있는 것 같다.

Continuous Integration

지속적인 통합 (Continuous Integration)이 실패했을 때 발송되는 메일에는 빠르게 원인을 파악할 수 있도록, 실패한 테스트의 목록, 실패를 유발한 Difff를 포함하고 있으며, 테스트 결과, 변경사항, 빌드 결과에 해당하는 웹 도구들에 대한 직접적인 링크를 포함하고 있다.

흔히 이러한 종류의 메일 보고서의 내용은 소홀한 경우가 많은데, 문제에 대한 진단이라는 것이 최종적인 목표라는 점을 생각한다면, 이러한 메일 보고서의 내용을 잘 갈고 닦을 필요가 있다.

Infrastructure

Google의 빌드 시스템은 외부에서도 사용할 수 있는 형태로 공개되어 있지는 않지만, 원래는 존재하지 않던 도구들을 Google이 사용하고 있는 것은 아니다. 가장 중요한 것은 아무래도 모든 도구들과 시스템이 통합된 형태로, 아무런 비용을 지불하지 않아도 전사적으로 제공되며, 실제 개발 과정에서 가능한 한 보이지 않는 형태로 제공되는 것으로 보인다.

여러 가지 종류의 도구들 (예를 들어, 여러 회사의 도구)을 혼합해서 사용하는 경우, 절대로 기능적인 면은 통합된 도구에 비해서 부족하지 않겠지만, 실제로는 접근성 등에 있어서 균질적이지 않아서, 어떤 도구는 사용하지만, 어떤 도구는 상대적으로 소외되어서 결과적으로 효율 차이가 발생하는 것으로 보인다.

Measurement

빌드 시스템 자체와는 별개로 흥미로웠던 것은 빌드 시스템의 각 요소에 대한 필요성을 실제 데이터로 증명하고, 빌드나 빌드 시스템의 개선을 위해서도 측정의 중요성을 지속적으로 강조하고 있다는 점이다. 즉,  ‘Cannot improve what we don’t measure’라는 모토인데, 엔지니어로서는 더 이상 공감하기 어려운 이야기라고 생각한다. 단기간의 개선은 직관이나 추측이 잘 먹힐지는 몰라도, 장기간에 걸친 개선에 있어서 측정은 필수적이다.

현실에서는 time-to-market 요구사항이나 엔지니어 개인의 취향, 심리적 상태와 같은 요소 때문에 측정이 희생되는 모습을 자주 보게 된다. 다소 공격적으로 얘기해서, 합리적인 trade-off를 통해 희생하거나, 다른 요소에 의해 제약 받지 않은 상태임에도 불구하고, 측정을 소홀히 하는 엔지니어는 엔지니어로서의 기본적인 소양이 부족한 것이 아닌가 생각을 해본다.

Comments Off | Categories: Software Development

← Older posts

Newer posts →