지난 포스팅에서 설명된 여러 조인 알고리즘은 실제 조인 로직을 리듀서에서 실행하기 때문에 리듀스 사이드 조인이라고 함
리듀스 사이드 접근에서는 입력 데이터에 대한 특정한 가정이 필요하지 않음. 매퍼는 각 입력 레코드에서 키와 값을 추출해 리듀서 파티션으로 할당하고 키별로 정렬 즉, 입력 데이터를 준비하기 때문
다만, 정렬 후에 리듀서로 복사된 입력을 병합하는 모든 과정에 드는 비용이 상당히 큰 것이 단점임. 맵리듀스 단계에서 허용된 메모리 버퍼에 따라 데이터를 여러 번 디스크에 저장해야 할 수도 있음
반면, 입력 데이터에 대해 특정 가정이 가능하다면 맵사이드 조인을 사용해 조인을 더 빠르게 수행할 수 있음
간단히 말해 축소된 맵리듀스 작업으로 이해할 수 있으며, 리듀서는 물론 정렬 작업도 없고, 대신 각 매퍼가 할 작업을 분산 파일 시스템에서 입력 파일 블럭 하나를 읽어 다시 해당 분산 파일 시스템에 출력하는 형태로 이루어짐
위와 같은 예시에서 매퍼는 시작할 때 분산 파일 시스템에서 사용자 데이터베이스를 읽어서 인메모리 해시 테이블에 넣어서 처리함
즉, 작은 입력을 큰 입력의 모든 파티션에 브로드캐스트하며, 이 입력을 해시 테이블에 적재하기에 이름 붙여짐
실제로 피크(복제 조인), 하이브(맵조인), 크런치, 임팔라에서 사용하는 방식
브로드캐스트 해시 조인과 같은 방식으로 입력을 파티셔닝한다면 해시 조인 접근법을 각 파티션에 독립적으로 적용할 수 있음
예를 들어 활동 이벤트와 사용자 데이터베이스를 사용자 ID의 마지막 십진수를 기준으로 파티셔닝해 재배열할 수 있음
이러한 방식의 장점은 각 매퍼의 해시 테이블에 적재해야할 데이터의 양을 줄일 수 있다는 점(왜나하면 조인할 레코드는 모두 같은 번호의 파티션에 위치할 것이기 때문에 매퍼는 입력 데이터셋 중 파티션 하나만 읽어도 되기 때문)
이를 하이브에서는 버킷 맵 조인(bucketed map join)이라고 부름
입력 데이터셋이 같은 방식으로 파티셔닝됐고 같은 키를 기준으로 정렬됐다면, 변형된 맵사이드 조인을 적용할 수 있음
이때는 입력 크기가 메모리에 적재 가능한지 고려할 필요가 없으며, 매퍼는 리듀서에서 일반으로 수행하는 것과 동일한 병합 연산을 수행할 수 있음
맵리듀스 조인에서 맵 사이드 조인을 사용할지 리듀스 사이드 조인을 사용할지에 따라 그 출력 구조가 달라짐
리듀스 사이드 조인은 조인 키로 파티셔닝하고 정렬해서 출력
맵 사이드 조인은 큰 입력과 동일한 방법으로 파티셔닝하고 정렬
맵 사이드 조인을 수행하기 위해서는 크기, 정렬, 입력 데이터의 파티셔닝과 같은 제약사항이 따르며, 이를 위해서는 분산 파일 시스템 내 저장된 데이터셋의 물리적인 레이아웃을 파악해야 함
파티션의 수가 몇 개인지, 데이터가 어떤 키를 기준으로 파티셔닝되고 정렬됐는지 등에 관한 메타 데이터는 HCatalog나 Hive MetaStore를 사용할 수 있음
일괄처리를 OLTP, OLAP 어디에 적합할까?
트랜잭션 처리도 아니고, 분석도 아님. 일괄처리는 입력 데이터셋 대부분을 스캔하는 것이 일반적이라 분석에 가깝다고 말할 수 있지만, 맵리듀스 작업의 워크플로는 분석 목적의 SQL 질의와는 다름
맵리듀스는 구글에서 검색 엔진에 사용할 색인을 구축하기 위해 처음 사용됨
검색 색인에서 색익은 용어 사전 파일로서 효율적으로 특정 키워드를 조회해 키워드가 포함된 문서 ID의 목록을 찾는 역할
정해진 문서 집합을 대상으로 전문 검색이 필요하다면 일괄 처리가 색인을 구축하는 데 매우 효율적임
즉, 매퍼는 문서 집합을 파티셔닝하고 각 리듀서가 해상 파티션에 대한 색인을 구축함
이후 색인 파일을 분산 파일 시스템에 저장하며, 이때 문서를 기준으로 파티셔닝해 색인을 구축하는 과정은 병렬화가 매우 잘 이루어짐.
색인된 문서 집합이 변한다면 전체 문서 집합을 대상으로 주기적으로 전체 색인 워크 플로를 재수행할 수 있음
전체 색인 워크 플로의 비효율성이 느껴진다면 증분 색인을 구축할 수도 있음(ex. 루씬은 세그먼트 파일을 기록하며 백그라운드에서 증분식으로 부분 파일을 병합하고 압축함)
일괄 처리는 머신러닝 시스템이나 추천 시스템을 구축하는 데 사용될 수 있음
일괄 처리 작업의 출력을 일종의 데이터베이스처럼 사용하는 방식임. 예를 들어 사용자에게 추천할 친구를 가져오기 위해 사용자 ID로 질의하는 데이터베이스 또는 관련 상품 목록을 가져오기 위해 상품 ID로 질의하는 데이터베이스처럼 사용하는 방식
이러한 데이터베이스는 일괄 처리 작업 내부에 완전히 새롭게 구축되며 분산 파일 시스템의 작업 출력을 디렉터리에 저장하는 방식으로 사용됨
이때 데이터 파일은 한 번 기록되면 불변이고 서버에 벌크로 적재해 읽기 전용 질의를 처리할 수 있음. 다양한 키-값 저장소가 맵리듀스 작업 내에서 데이터베이스 파일을 구축하는 기능을 지원(볼드모트, 테라핀, 엘리펀트DB, HBase 벌크 적재 등)
맵리듀스 작업은 입력을 불변으로 처리하고 외부 데이터베이스에 기록하는 등의 부수 효과를 피하기 때문에 좋은 선능을 내면서도 유지보수가 훨씬 간단함
코드에 버그가 있어 출력이 잘못된다면, 코드를 이전 버전으로 돌리고 작업을 재수행해 간단하게 출력을 고칠 수 있음(읽기 쓰기 트랜잭션이 있는 데이터베이스는 이런 속성이 없음) 이러한 개념(버그 있는 코드로부터 복원할 수 있는지)을 인적 내결함성이라고 함
쉽게 되돌릴 수 있는 속성의 결과로 실수가 발생하면 손상을 되돌릴 수 없는 환경에서보다 개발을 빠르게 진행할 수 있음
맵이나 리듀스가 실패하더라도 해당 태스크는 자동으로 다시 스케줄링되고 동일한 입력을 사용해 재실행됨. 이는 일시적 문제로 발생한 실패를 해결할 수 있음
맵리듀스 작업은 입출력 디렉터리를 설정하는 등의 연결 작업과 로직을 분리하여, 각각 따로 처리하거나 코드 재사용을 가능하게 함
하둡은 유닉스의 분산 버전과 비슷. HDFS는 파일 시스템이고 맵리듀스는 특별한 방식으로 구현된 유닉스 프로세스라고 이해할 수 있음
맵리듀스가 처음 나왔을 때, 어떻게 보면 전혀 새로운 개념은 아니었음. 처리 알고리즘과 병렬 조인 알고리즘은 대규모 병렬 처리(massively parallel proccessing, MPP) 데이터베이스에서 모두 구현됐던 것이기 때문
맵리듀스와 가장 큰 차이점은 MPP 데이터베이스는 장비 클러스터에서 분석 SQL 질의를 병렬로 수행하는 것에 초점을 두는 반면, 맵리듀스와 분산 파일 시스템의 조합은 아무 프로그램이나 실행할 수 있는 운영체제와 비슷한 속성을 제공한다는 것임
데이터베이스는 특정 모델(관계형 또는 문서형)에 따라 데이터를 구조화해야하지만, 분산 파일시스템은 어떤 데이터 모델과 인코딩을 사용해서도 기록할 수 있음
극단적으로 하둡은 데이터가 어떤 형태라도 상관없이 HDFS로 덤프할 수 있는 가능성을 열어 놓은 형태이며, 데이터를 어떻게 처리할지는 덤프 이후에 생각할 수 있음
이러한 아이디어는 데이터 웨어하우스의 개념과 유사함. MPP가 요구하는 세심한 스키마 설계는 중앙 집중식 데이터 수집을 느리게 만들며, 원시 데이터를 수집하고 스키마 설계는 나중에 고민하면 데이터 수집의 속도가 올라갈 수 있음(Schema-on-read 접근)
MPP 데이터베이스는 일체식 구조로 디스크 저장소 레이아웃과 질의 계획, 스케줄링과 실행을 다루는 소프트웨어 조각들이 긴밀하게 통합되어 구성됨
하지만 SQL 질의로 모든 종류의 처리를 표현할 수는 없음. 예를 들어 머신러닝이나 추천 시스템, 검색 색인을 구축하는 데에는 더 범용적인 데이터 처리 모델이 필요함
맵리듀스는 엔지니어가 작성한 코드를 대용량 데이터셋에서 쉽게 실행할 수 있음. HDFS와 맵리듀스가 있으면 그 위에 SQL 질의 실행 엔진을 구축할 수 있음(ex. hive)
하둡 생태계는 HBase 같은 임의 접근 가능한 OLTP 데이터베이스와 임팔라 같은 MPP 스타일의 분석 데이터베이스를 같은 시스템으로 통합하여 사용할 수 있음(Hbase, 임팔라 기본 개념 파악해보자)
맵리듀스와 MPP 데이터베이스의 큰 차이는 두 가지, 결함을 다루는 방식과 메모리 및 디스크를 사용하는 방식에서 존재
일괄 처리는 온라인 시스템에 비해 결함에 덜 민감함. 일괄 처리 작업이 실패하더라도 즉시 사용자에게 영향을 주지 않으면서 언제든지 다시 실행할 수 있기 때문
하지만 MPP 데이터베이스에서 질의 실행 중에 한 장비만 죽어도 전체 질의가 중단됨. 또한, 디스크에서 데이터를 읽는 비용을 피하기 위해 해시 조인 같은 방식을 사용해 가능하면 메모리에 많은 데이터를 유지하는 것을 선호
하지만 맵리듀스는 맵 또는 리듀스의 실패를 견딜 수 있으며, 데이터를 되로록 디스크에 기록하려고 함. 이는 내결함성을 확보하기 위함이며 다른 한편으로는 메모리에 올리기에 데이터셋이 너무 크다는 가정 때문임
즉, 맵리듀스 접근은 대용량 작업에 적합하며, 내결함성을 위해 선능상의 오버헤드를 감안하는 형태의 작업임
하지만, 진짜로 실제 환경에서 내결함성을 위해 성능상의 오버헤드를 감안하는 것이 합리적일까? 여기에는 또 다른 이유가 있음
구글의 예시
혼합 사용 데이터 센터로 구성되며 온라인 프로덕션 서비스와 오프라인 일괄 처리 작업이 같은 장비에서 실행됨
각 태스크는 컨테이너를 사용해 CPU, RAM, DISK 등의 자원을 할당 받음
여기서 어떤 맵리듀스 태스크가 한 시간 정도 수행된다면 높은 우선순위의 프로세스를 위한 공간을 마련해주기 위해 태스크가 종료될 위험이 약 5%로 하드웨어 문제나 장비 재시작 등 다른 이유로 실패할 확률보다 상당히 높아짐
즉, 작업이 5% 선점 확률로 10분간 수행되는 100개의 태스크를 가지고 있다면 작업이 완료되기 전에 적어도 태스크 하나가 종료될 가능성이 50%를 넘는다는 의미
다시 말해, 맵리듀스는 태스크 정료가 예상치 못하게 자주 발생하더라도 견딜 수 있게 설계됨. 이는 하드웨어를 신뢰할 수 없기 때문이 아니라 프로세스를 임의로 종료할 수 있으면 연산 클러스터에서 자원 활용도를 높일 수 있기 때문임
다시 말하자면, 태스크가 자주 종료되지 않는 환경에서라면 맵리듀스의 설계방식(디스크를 활용한 방식)은 비효율적일 수 있음. 다음 장에서는 다른 방식으로 설계된 맵리듀스의 대안을 살펴보고자 함