All Articles

데이터 중심 애플리케이션 설계 - 10강

시스템 유형

  • 서비스 - 온라인 시스템: 클라이언트에서 요청이 올 때까지 기다림. 요청이 들어오면 가능한 한 빨리 처리해서 응답. 응답 시간이 중요한 지표이며, 때로 가용성이 매우 중요.
  • 일괄 처리 시스템 - 오프라인 시스템: 매우 큰 입력 데이터를 받아, 데이터를 처리하고, 결과 데이터를 생산함. 수 분에서 수 일이 걸리기 때문에 사용자가 작업이 끝날 때까지 기다리지 않음. 처리량이 중요한 지표. (입력 데이터 중 특정 크기만큼 처리할 때 걸리는 시간)
  • 스트림 처리 시스템 - 준실시간 시스템: 요청에 대해 응답하지 않으며 입력 데이터를 소비하고 출력 데이터를 생산함. 스트림 처리는 입력 이벤트가 발생한 직후 바로 처리됨. 일괄 처리 기반이나, 지연 시간이 낮음.

일괄 처리

유닉스 도구로 일괄 처리하기

웹사이트에서 가장 인기 높은 페이지 5개 뽑아내기

cat /var/log/nginx/access.log |  # 로그 읽기
  awk '{print $7}' |             # 공백 기준으로 7번째 필드 (URL) 출력
  sort |                         # URL 정렬
  uniq -c |                      # Group By + Count 처리
  sort -r -n |                   # Count로 내림차순 정렬
  head -n 5                      # 최초 5개 추출

유닉스 철학: 1978년에 기술되었고 현재까지도 매우 잘 Working 함

  • 프로그램이 한 가지 일을 잘 하도록 작성하라. sort 명령: 메모리보다 큰 데이터셋을 자동으로 디스크로 보내고, 자동으로 다중 CPU 코어에서 처리한다. 대부분 언어의 표준 라이브러리보다 뛰어나다.
  • 모든 프로그램의 출력은 아직 알려지지 않은 다른 프로그램의 입력으로 쓰일 수 있다고 생각하라. 유닉스에서의 인터페이스는 파일이다. 파일시스템의 실제 파일, 유닉스 소켓, stdin, stdout, 장치 드라이버, TCP 소켓 등은 파일이라는 인터페이스로 공유된다.

유닉스 도구를 사용하는 데 가장 큰 제약은 단일 장비에서만 실행된다는 점이다. 이 때문에 하둡과 같은 도구가 필요하다.

맵리듀스

  • 유닉스 도구와 유사하나, 수천 대의 장비로 분산 실행이 가능함
  • 단일 맵리듀스 작업은 하나 이상의 입력을 받아 하나 이상의 출력을 만들어 내는 점에서 단일 유닉스 프로세스와 유사함
  • 맵리듀스 작업은 분산 파일 시스템 상의 파일을 입력과 출력에 사용한다.

HDFS (Hadoop Distributed File System)

  • 비공유(Shared Nothing) 방식을 사용하기에 서버 추가하는 만큼 연산기능과 저장기능이 향상됨
  • NameNode: 특정 파일 블록이 어느 장비에 저장되었는지 추적
  • 장비 사망에 대비해 여러 장비에 복제됨

맵리듀스 작업을 생성하려면 매퍼와 리듀서라는 두 가지 콜백 함수를 구현해야 함

  • Mapper: 모든 입력 레코드 당 한 번씩 호출됨. 입력 레코드에서 키-값을 추출.
  • Reducer: Mapper가 생산한 키-값 쌍을 받아 같은 키를 가진 레코드를 모으고, 해당 값의 집합을 반복해 리듀서 함수 호출. 리듀서는 출력 레코드를 생산함.

작업 실행

위의 유닉스 도구를 맵리듀스로 옮기면..

  1. 입력 파일을 읽어 레코드로 쪼갠다.
  2. 맵: 각 입력 레코드마다 매퍼 함수를 호출해 키와 값 추출. 매퍼 함수는 awk '{print $7}' 인데, URL을 키로 추출하고 값은 빈 값으로 한다.
  3. 키를 기준으로 키-값 쌍을 정렬한다. (매퍼의 출력은 자동 정렬되기 때문에 별도 작성 필요 없음)
  4. 리듀스: 정렬된 키-값 쌍 전체를 대상으로 리듀스 함수 호출. 같은 값은 정렬에 의해 인접함. 그래서 메모리에 상태를 유지하지 않고도 결합 가능.
  5. 요청 수가 많은 URL 순으로 정렬: 1-4의 출력을 입력으로 받아 정렬하는 두 번째 맵리듀스를 만들면 된다.

매퍼는 정렬에 적합한 형태로 데이터를 준비하고, 리듀서는 정렬된 데이터를 가공하는 역할을 함.

분산 실행

맵리듀스 프레임워크가 장비 간 데이터와 코드를 이동하는 작업을 알아서 처리해 준다. 작업 입력으로는 HDFS의 디렉터리를 사용하는 것이 일반적.

맵: 각 파일 또는 파일 블록을 독립된 맵 태스크에서 처리할 독립 파티션으로 간주한다. 즉 입력 파일의 블록 수로 결정.

리듀스: 리듀스 태스크 수는 사용자가 설정한다. 맵 태스크 수와 리듀스 태스크 수는 다를 수 있다. 맵리듀스 프레임워크는 같은 키를 가진 모든 키-값 쌍을 같은 리듀서에서 처리하는 것을 보장. (키의 해시값 사용하여 파티셔닝 및 라우팅)

정렬: 매퍼가 계산 후에, 키의 해시값 기반으로 리듀서용으로 파티셔닝 한다. 각 파티션을 매퍼의 로컬 디스크에 정렬된 파일로 기록한다. “SS테이블과 LSM 트리” 와 유사함

워크플로

여러 개의 맵리듀스 작업을 연결해 워크플로로 구성. 각 맵리듀스 작업은 의존성이 있다. Airflow 등 의존성을 관리하는 스케줄러가 있음.

리듀스 사이드 조인과 그룹화

데이터베이스에서 적은 수의 레코드를 찾는다면 index를 사용한다.

맵리듀스는 입력 파일의 전체를 읽기 때문에 full table scan 한다. 분석 질의는 대량의 레코드를 집계하기도 하고 분산처리가 되기 때문에, full table scan은 상당히 합리적이다.

(HDFS에 userid가 포함된 이벤트 로그를 읽어) 조인 시에 (유저 정보가 있는) 원격 DB를 호출할 수도 있지만, 비결정적이고 느리다. 차라리 원격 DB의 덤프를 받아서 HDFS에 둘 다 올려서 처리해라.

리듀스 사이드 조인: 다른 종류의 입력에서 같은 키-값을 매퍼로 추출해 동일한 리듀스로 넘기는 것.

보조 정렬(Secondary sort): 리듀서가 처리하는 키에 대한 값을 재배열 하는 것. 예를 들면 사용자 데이터베이스 먼저 보고 그 다음에 이벤트를 보도록?

(key) userid 104 -> 
(value)  year: 1989
(value)  url: /x
(value)  url: /z

이것을 sort-merge join 이라고 한다. 정렬을 이용한 합병 조인이라는 뜻..

맵리듀스 프로그래밍 모델은 데이터를 모으는 네트워크 측면과 / 받은 데이터를 처리하는 데이터베이스 로직을 분리한다. 따라서 실패한 태스크는 확실히 재시도한다.

그룹화를 진행하는 가장 쉬운 방법은 그룹화할 대상을 키로 하는 것이다. 즉 그룹화와 조인의 구현은 상당히 유사하다. 세션별 활동 이벤트를 수집 분석할 때도 그룹화를 사용하는데, 세션화라고 한다. 세션키, 유저ID 등을 여러 시스템에서 모아 구현한다.

쏠림 다루기

SNS에서 대부분은 수백 명의 팔로워를 가지지만 일부는 수백만명을 가진다. 이를 핫 키라고 한다

  • Pig 에서는 skewed join 알고리즘을 이용한다. 샘플링해서 핫 키를 찾아낸다. When performing the actual join, the mappers send any records relating to a hot key to one of several reducers, chosen at random (in contrast to conventional MapReduce, which chooses a reducer deterministically based on a hash of the key). (실제 조인을 수행 할 때 매퍼는 무작위로 선택된 여러 감속기 중 하나에 핫키와 관련된 모든 레코드를 보냅니다 (키의 해시를 기반으로 결정적으로 감속기를 선택하는 기존 MapReduce와 달리).) 핫 키를 여러 리듀서에 퍼뜨려서 처리하기 때문에 병렬화 효과가 크다.
  • Crunch 에서는 shared join 알고리즘을 사용할 수 있다. 핫 키를 명시적으로 지정해야 함.
  • Hive 에서는 메타데이터에 핫 키를 명시적으로 지정한다. map-side join 을 이용한다.

맵 사이드 조인

리듀스 사이드 조인은 리듀서에서 재정렬하기 때문에 정렬 비용이 크다

브로드캐스드 해시 조인: 상당히 작은 데이터를 큰 데이터와 조인할 때 사용할 수 있다 (메모리 상에 올라갈 정도의)

파티션 해시 조인(버킷 맵 조인): 각 데이터베이스를 파티셔닝 해서 쪼개서 처리한다 (유저 아이디 mod 10 을 파티션 키로 사용한다든지)

맵리듀스를 넘어

맵리듀스는 상당히 저수준 API 이다. 그러기에 피그, 하이브, 캐스캐이딩, 크런치 등이 생겼음.