하둡(Hadoop) 관련 기술 - 피그, 주키퍼, HBase에 대한 간략한 정리!

|



하둡과 관련해 HDFS(하둡 파일 시스템), MapReduce(맵리듀스)를 기본적으로 알아야 합니다. 

그러나 때로는 하둡 에코 시스템으로 제공하는 도구들을 이해하면 좀 더 빠르고 쉽게 하둡 프로그래밍을 할 수 있습니다. 

이번에는 하둡과 관련된 많은 프로젝트들 중에서 피그(pig), HBase, 주키퍼(Zookeeper)에 대해서 간략하게 개념을 정리하려고 합니다. 

해당 개념들을 살펴보고 추후 필요할 때 활용하면 좋겠네요. 


피그(Pig)

피그는 대용량 데이터셋을 좀 더 고차원적으로 처리할 수 있도록 합니다. 

맵리듀스에서 처리할 수 없는 부분들을 지원한다고 하는데요. 대표적으로 조인(Join)과 같은 연산이 가능합니다. 

피그는 다중 값과 중첩된 형태를 보이는 좀 더 다양한 데이터 구조를 지원하고, 데이터에 적용할 수 있는 변환 종류도 훨신 더 많다고 합니다. 


피그는 피그 라틴과 실행환경의 두가지로 이루어져 있습니다.

  • 데이터 흐름을 표현하기 위해 사용하는 피그 라틴이는 언어
  • 피그 라틴 프로그램을 수행하는 실행 환경. 현재 단일 JVM에서의 로컬 실행 환경과 하둡 클러스터 상의 분산 실행 환경 두 종류가 있음. 


다시 말해, 피그는 대용량 데이터셋을 다루기 위한 스크립트 언어입니다.  

내부적으로 연속된 맵리듀스 작업으로 변경하지만, 대부분 개발자는 이것을 눈치채지 못하므로 데이터 자체에 집중할 수 있다고 합니다. 

즉, 개발이 복잡하고 시간이 오래 걸리는 맵리듀스의 단점을 보완하기 위한 것입니다. 


또한 피그는 확장이 용이하도록 설계되었습니다. 

로딩, 저장, 필터링, 그룹핑, 정렬, 조인등 모든 부분이 사용자 정의 함수를 통해 원하는대로 변경할 수 있습니다. 


하지만 피그도 맵리듀스와 마찬가지로 데이터의 배치 처리를 위해 설계되어 있으므로 모든 데이터 처리 업무에 적합한 것은 아닙니다. 

그리고 내부적으로 맵리듀스로 변환해서 실행해야 하므로 맵리듀스로 작성된 프로그램만큼 좋은 성능을 내지 못합니다. 

기존 맵리듀스보다는 과부하가 불가피하게 발생하는 것이죠. 


피그 프로그램을 실행하는 방법에는 다음과 같은 세가지가 있습니다. 

  • 스크립트(Script): 피그는 피그 명령어가 포함된 스크립트 파일을 실행할 수 있습니다. 
  • 그런트(Grunt): 그런트는 피그 명령어를 실행하는 대화형 쉘입니다. 
  • 내장형(Embeded): JDBC를 사용해서 Java에서 SQL 프로그램을 실행하는 것처럼 Java에서 피그 프로그램을 실행할 수 있습니다. 


마지막으로 피그 라틴 언어를 위한 편집기가 "PigPen"이라는 이름의 이클립스 플러그인으로 있습니다. 


HBase

HBase 프로젝트는 2006년 말 Chang et al에 의해 일반에게 논문으로 공개된 

구글의 "빅테이블: A Distributed Storage System for Structured Data"을 모델로 해서 채드 왈터스(Chad Walters)와 짐 캘러맨(Jim Kellerman)에 의해 시작되었습니다. 


HBase는 HDFS에 구현한 분산 컬럼 기반 데이터베이스로서 대규모 데이터셋에 실시간으로 랜덤 엑세스가 필요할 때 

사용할 수 있는 하둡 응용프로그램입니다. 

HBase는 확정성을 위해 단지 노드만 추가하면 선형적으로 확장할 수 있으며, 

관계형 데이터베이가 아니고 SQL도 지원하지 않지만 기존 RDMS에서 부족한 기능들을 대체할 수 있습니다. 


예를 들면, 수집된 웹 페이지와 웹 페이지 URL을 Key로하는 웹 테이블과 같은 것들을 HBase에서 쉽게 처리할 수 있습니다. 

기존 데이터베이스에서 가용성, 확장성, 응답속도에 따른 문제점을 고민하고 있다면, 

HBase와 같은 NoSQL로 이동하는 것을 고려해 볼 필요가 있습니다.  


일반적으로 하둡(Hadoop)은 Row 레벨 업데이트, 빠른 응답을 요구하는 쿼리, 그리고 트랜잭션을 지원하지 않습니다. 

반면 HBase를 사용하면 이러한 Row-level Update, Rapid Queries, and Row-Level Transaction을 사용할 수 있습니다. 


HBase를 좀 더 살펴보면 다음과 같습니다. 

응용프로그램은 데이터를 테이블에 저장합니다. 테이블은 로우와 컬럼으로 만들어져 있습니다. 

테이블 셀은 (로우와 컬럼 좌표의 교차지점) 버전 관리됩니다. 

기본적으로 버전을 셀 생성 시점에 HBase에 의해 자동 할당된 타임스탬프이며 셀의 내용은 원시 바이트 배열이라고 합니다. 


HBase 테이블은 RDBMS와 유사하지만 오직 셀들만이 버전 관리되고, 로우들은 정렬되어 있습니다. 

컬럼은 소속된 컬럼패밀리가 존재하는 한, 클라이언트가 동적으로 추가할 수 있습니다. 


HBase는 칼럼 패밀리로 구성된 칼럼(Column) 기반으로 되어 있습니다. (NoSQL의 대표주자인 Cassandra도 칼럼패밀리를 사용합니다.)

그리고 Key-Value 저장 구조를 가지고 있습니다. 

각각의 Row에 하나의 Single Key가 사용되기 때문에 해당 Row의 칼럼이나 칼럼 패밀리에 빠르게 읽고 쓸 수 있게 됩니다.  


그리고 timestamp를 활용해서 각 칼럼 값들의 버전 관리가 가능합니다. 

즉, 필요할 경우 과거 특정 시점으로 되돌아 갈 수도 있다는 것입니다. 


그리고 테이블은 HBase에 의해 리전(Region)으로 자동 수평분할됩니다. 각 리전은 테이블의 로우의 부분집합으로 구성됩니다. 

리전은 첫 번째 로우(포함)과 마지막 로우(포함하지 않음), 추가로 무작위 생성된 리전 식별자에 의해 정의된다고 합니다. 

하둡(Hadoop)이 네임노드와 데이터노드로 구성되어 있고, 맵리듀스가 잡트래커와 태스크트래커로 구분되어 있는 것처럼

HBase에서는 HBase 마스터노드가 하나 이상의 리전 서버를 조율하게 됩니다. 


그리고 환경설정은 HBase.conf, hbase-site.xml, hbase-env.sh 파일들로 이루어져 있는데요.  

부모 프로젝트인 하둡의 환경 설정 파일들과 동일한 포맷과 이름을 사용하고 있음을 알 수 있습니다. 


HDFS와 맵리듀스가 대량의 데이터 집합에 대한 배치 작업을 처리하기에 강력한 도구임에는 틀림 없지만, 

개별 레코드를 효과적으로 읽거나 쓰는 방법을 제공하지는 않고 있습니다. 

이런 실시간 처리 기능을 위해 HBase를 활용하게 됩니다  


또한 HBase는 하둡처럼 Java로 만들어져 있으며 Java 응용 프로그램과 잘 호환됩니다. 

다른 언어로 개발된 응용프로그램과 상호작용하기 위해서 REST와 thrift 인터페이스도 포함하고 있다고 합니다. 


다만, HBase는 SQL과 같은 Query Language를 지원하고 있지는 않습니다. 

그래서 최근  SQL과 유사한 HiveQL을 사용하는 Hive를 HBase와 연동하는 것도 진행중이라고 하네요. 


주키퍼 (Zookeeper)

주키퍼는 하둡의 분산 상호 조정 서비스를 이용하여 분산환경에서 노드들간의 정보 공유, 락, 이벤트 등의 보조 기능을 제공하는 것입니다.

분산 프로그램에서는 부분적 실패 (Partial failure)라는 것이 발생할 수 있습니다.  

예를 들면, 두 노드 사이의 메시지가 송신되고 네트워크가 끊어졌을때 송신자는 수신자가 메시지를 받았는지를 모른다는 것이죠.

즉, 연산이 실패했는지조차도 모르는 상황이 바로 부분적 실패라고 한다고 합니다.


 

주키퍼는 이런 부분적 실패를 안전하게 다루면서 분산 응용 프로그램을 구축할 수 있도록 도와주는 도구를 제공합니다.

주키퍼를 활용해 분산 환경에서 상호 조정 기능을 처리함으로써, 

개발자들은 어플리케이션 개발에 집중해 서비스를 구성할 수 있도록 한 것입니다. 

실제로 하둡, HBase, Kafka 등이 주키퍼를 활용하고 있습니다. 


주키퍼의 특징을 살펴보면 다음과 같습니다.

  • 주키퍼는 단순하다.
  • 주키퍼는 다양하게 활용된다.
  • 주키퍼는 고가용성을 지원한다.
  • 주키퍼는 느슨하게 연결된 상호작용을 제공한다.
  • 주키퍼는 라이브러리이다.

 

주키퍼는 고가용, 고성능을 위한 상호 조정 서비스로서 znode라는 노드 계층적 트리를 유지한다고 합니다.

이 znode는 데이터를 저장하는 것인데요. 큰 용량의 데이터를 저장하는 용도로 사용되지 않으며,

znode에 저장할 수 있는 데이터 양도 1MB로 제한된다고 합니다.


주키퍼는 대용량을 처리하도록 구성되어 있지 않기 때문에, 

만약 주키퍼를 사용해서 새로운 어플리케이션을 설계한다면, 반드시 어플리케이션 데이터와 상호 조정 데이터를 분리해야 합니다. 

예를 들어, 웹 메일 서비스를 분산 환경으로 만든다면 어플리케이션 데이터는 메일박스의 컨텐츠라고 할 수 있습니다. 

반면에 주키퍼와 같은 조정 데이터는 분산된 메일 서버에 각 메일 박스를 매핑하는 것이라고 할 수 있겠죠. 

이렇게 데이터를 분리한다는 관점에서 보면, 주기퍼의 처리 용량이 왜 작게 설계 되어 있는지 충분히 이해할 수 있습니다. 


또한 주키퍼의 기본 연산은 다음과 같은 9가지가 있다고 하네요.

  • create: znode 생성 (부모 znode가 이미 존재해야 함)
  • delete: znode 삭제 (어떤 znode도 존재하지 않아야 함)
  • exists: znode가 존재하는지 확인하고 메타데이터를 구함
  • getACL, setACL: znode에 대한 ACL 정보를 가져오거나 설정함
  • getChildren: znode 자식의 목록을 얻음.
  • sync: znode의 클라이언트 뷰와 주키퍼 동기화함.

 

주키퍼는 클라이언트를 위해 자바와 C 언어를 위한 바인딩을 제공하며, 펄/파이썬/REST 클라이언트를 위한 contrib 바인딩도 제공한다고 합니다.

 

주키퍼 구현의 기본을 이해하면 서비스의 일관성 보장을 이해하는데 도움이 된다고 합니다.

주키퍼는 개념적으로 매우 간단하다. znode의 트리에 대한 모든 수정이 앙상블 노드에 복제되도록 보장한다.

만약 소수 컴퓨터에 장애가 생기면, 최소한 한 개의 컴퓨터는 가장 최신 상태를 간직한 채 살아남을 것이다.

결국, 다른 남은 복제 노드가 이 최신 상태를 복제해 갈 것이다.


하지만, 이러한 간단한 아이디어의 구현이 쉽지만은 않다. 

주키퍼는 두 개의 단계로 동작하는 Zab이라는 프로토콜을 사용하는데 무한 반복될 수도 있다.


단계1: 책임자 선출

앙상블 컴퓨터들은 책임자라 불리는 특별한 멤버를 선출하는 과정을 거친다.

다른 컴퓨터는 후보자가 된다.

과반수(또는 정족수)의 후보자 상태가 책임자와 동기화되면 즉시 이 단계가 끝난다.

 

단계2: 원자적 브로드캐스트

모든 쓰기 요청은 책임자로 보내지고, 책임자는 후보자에게 업데이트 상태를 브로드캐스트한다.

과반수 노드에서 변경이 완료되면, 책임자는 업데이트 연산을 커밋하고, 클라이언트는 업데이트가 성공했다는 응답을 받게 된다.

합의를 위한 프로토콜을 원자적으로 설계되었기 때문에 변경의 결과는 성공이나 실패 둘 중 하나이다.

그것은 2단계 커밋과 닮았다.


만약 책임자에게 문제가 생기면, 남은 컴퓨터(후보자)가 새로운 책임자를 선출하고 새로운 책임자를 따라 서비스를 계속한다. 

또 만약 예전 책임자가 복구되면 후보자로서 시작한다. 

책임자 선출은 매우 빠르고, 책임자를 한 번 선출하는데 약 200ms가 걸린다. 

따라서 책임자를 선출하는 동안 성능이 눈에 띄게 저하되지 않는다. 

 

이상으로 한빛미디어에서 나온 "Hadoop 완벽 가이드"의 피그, HBase, 주키퍼의 내용을 요약해 봤습니다. 


-- 2012년 9월 6일 작성한 글 중 HBase의 내용을 업데이트했습니다.

 




Trackback 0 And Comment 0