HDFS 데이터 저장 방식

1. 애플리케이션이 HDFS 클라이언트에 파일저장 요청

2. HDFS 클라이언트가 네임노드에 사용자가 요청한 파일경로 생성 요청

3. 네임노드가 데이터노드들(파이프라인) 반환 (복제개수만큼)

4. 첫번째 데이터노드에 저장, 첫번째 데이터노드는 두번째 데이터노드로 전송, 로컬 저장 후 세번쨰로 전송... 완료 후 첫번 째 데이터노드에 완료 사실 반환

5. 데이터노드장애 시 파이프라인에서 제거 후 네임노드가 다른 데이터노드 배치

6. 첫번째 데이터노드가 클라이언트에게 저장완료 응답

7. 클라이트가 애플리케이션에 완료 응답



HDFS 데이터 읽기

1. 네임노드에게 요청한 파일의 블록 위치 정보 요청

2. 클라이언트에 가까운 순서대로 정렬하여 데이터노드 목록 반환.

3. 클라이언트는 데이터노드에 파일 조회 요청



NameNode

1. 네임노드는 HDFS 메타데이터를 메모리에서 처리하지만, 유실 방지를 위해 에디트로그(EditLog)와 파일시스템이미지(FsImage) 파일 사용.

2. 에디트로그는 HDFS 메타데이터의 모든 변화를 기록(파일 저장, 파일 삭제, 위치 변경 등의 파일 상태 변화)

3. 에디트로그는 용량 제한 없이 커질 수 있으며 네임노드의 로컬 파일 시스템에 파일로 저장

4. 파일시스템이미지(FsImage) 파일은 파일 시스템의 네임스페이스(디렉터리명, 파일명, 상태 정보)와 파일에 대한 블록 매핑 정보를 저장하는 파일(HDFS의 스냅샷)

5. FsImage도 EditLog처럼 네임노드의 로컬파일시스템에 파일로 저장



NameNode 구동 단계

1. 로컬에 저장된 FsImage, EditLog 조회

2. EditLog 파일 내용 토대로 메모리에 올라간 FsImage 갱신

3. 갱신된 FsImage 로컬에 있는 FsImage 파일에 적용

4. EditLog 파일 초기화



SecondaryNameNode (체크포인팅 서버) (feat. 보조네임노드는 백업서버가 아니다!)

1. EditLog 파일이 제한없이 커질 시 FsImage 갱신할 수 없을 정도로 메모리에 로딩못하는 사태가 일어날 수 있어서...

2. 주기적으로 네임노드의 FsImage 갱신하는 역할(Checkpoint)



SecondaryNameNode 역할 구동 단계

0. Default로 1시간에 한 번씩 (fs.checkpoint.period) 구동

1. 네임노드에게 EditLog 파일 롤링 요청 (파일 롤링은 현재 로그파일이름을 변경하고, 원래 이름으로 새 로그 파일 만드는 것)

2. 그러면 네임노드는 파일 롤링 실행

3. Secondary Namenode에서 네임노드의 롤링된 기존 EditLog와 FsImage 다운로드 (HTTP GET)

4. 받아온 FsImage 메모리에 올리고 EditLog를 적용하여 새로운 FsImage 생성(체크포인트용 파일시스템이미지)

5. 체크포인트용 파일시스템이미지를 NameNode에 전송(HTTP POST)

6. 네임노드는 기존 FsImage 파일을 체크포인트용 파일시스템이미지파일로 변경, EditLog도 새로 생성된 것으로 변경

7. 메모리에 올라간 FsImage 최신 내역으로 갱신



\-\- 고찰: 보조네임노드가 동작하지않을 떄 네임노드 동작에 상관없지만\.\. EditLog가 과도하게 쌓인 경우\, 그리고 네임노드 재구동을 해야할 경우 과도하게 쌓인 EditLog를 메모리에 올리지 못하는 상황이 발생할 수 있다\.\!



HDFS HA 구성

0. HADOOP2 부터 보장하는 세팅

1. Zookeeper(QuorumPeerMain) 에서 네임서비스별 active/standby namenode 상태정보 저장

2. DFSZKFailoverController: NameNode 모니터링, active 죽으면 standby를 (JournalNode의 Editlog모두 읽은 후) active로 전환 Zookeeper 정보 갱신

3. JournalNode: active NameNode의 namespace 수정될떄 발생한s editlog 저장. (최소 3대 앙상블)

4. Active Namenode: editlog를 JournalNode에 기록

5. Standby Namenode: JournalNode에서 editlog를 읽어와 fsimage 갱신

6. DataNode: active/standby NameNode 모두에 Block정보와 HeartBeat 보냄





잡트래커

- 하둡1 네임노드에서 실행

- 맵리듀스는 잡이라는 하나의 작업 단위로 관리됨

- 하둡클러스터에 등록된 전체 잡의 스케쥴링 관리 및 모니터링

-- 새로운 잡 요청 시 잡트래커가 잡을 처리하기 위해 몇 개의 맵과 리듀스를 실행할지 계산

-- 어떤 태스크트래커에서 실행할지 결정

-- 잡 할당

- 전체 클러스터에서 하나의 잡트래커 실행



태스크트래커

- 하둡1 데이터노드에서 실행

- 잡 트래커의 작업 수행 요청을 받아 맵리듀스 프로그램 실행

- 잡트래커가 요청한 매퍼와 리듀서 갯수 만큼 맵, 리듀스 태스크 생성

- 새로운 JVM 구동해 맵, 리듀스 태스크 실행

-- 이 때, JVM은 재사용할 수 있게 설정 가능. 데이터노드가 하나라도 여러 개의 JVM 실행해서 병렬처리 가능



YARN (MRv2)

- 기존 잡 트래커의 기능을 리소스매니저와 애플리케이션 마스터로 분리.



리소스매니저

- 애플리케이션에 할당해야 하는 클러스터의 리소스를 관리,

- YARN의 마스터 역할

- 전체 클러스터의 리소스(CPU, 디스크, 네트워크) 관리

- 내부적으로 스케줄러와 애플리케이션 매니저 실행

- 스케줄러: 노드매니저와 통신하며 필요한 리소스에 대한 스케줄링 수행. (FIFO, Capacity, Pair) 확인

- 애플리케이션 매니저: 애플리케이션 마스터의 상태 관리(실행, 모니터링, 재실행), 스케줄러에게 애플리케이션 마스터 실행 시키기 위한 노드매니저 할당 받음.

- 할당 받은 노드매니저에게 애플리케이션 마스터 수행 요청

- 노드매니저는 애플리케이션 마스터 실행

- 애플리케이션 마스터는 리소스매니저에게 컨테이너 실행 요청할 노드매니저 목록 할당 받음 (and 요청)

- 노드매니저는 컨테이너 실행. 애플리케이션 종료되면 컨테이너와 애플리케이션 마스터 종료



\- 노드매니저: 데이터노드 당 1개씩\, 컨테이너 리소스 사용량 모니터링\, 관련 정보를 리소스매니저에게 알림\.

- 애플리케이션 마스터: YARN에서 실행되는 하나의 태스크를 관리(애플리케이션 당 1개)



하둡에코시스템

HDFS 발란서 : 지나치게 자주 사용되는 데이터노드의 블럭을 덜 사용되는 데이터노드로 옮겨줌.(백그라운드로 실행)

Redis 란 ?

Redis는 NO Sql의 일종으로 기존 MySQL, Maria DB와는 다르게 In Memory를 사용하여 많은 장점이 있다.
처리 속도가 빠르다.

  • 당연히 데이터가 메모리+Disk에 저장된다. 그러나, 속도는 Memcached와 큰 차이가 없다.

데이터가 메모리+Disk에 저장된다.

  • 프로세스가 죽거나 장비가 Shutdown되더라도 Data의 복구가 가능하다

만료일을 지정하여 만료가 되면 자동으로 데이터가 사라진다.

  • 동일한 기능을 지원한다.

저장소 메모리 재사용 하지 않는다.

  • 명시적으로만 데이터를 제거할 수 있다.

 

Redis 설치 과정

:: 내부 IP에 대해선 10.xxx.xxx.xxx 로 마스킹 처리 하였습니다. 서버에 맞게 수정 바랍니다.

 

1 . Redis 설치

  • redis를 /home1/username/apps/redis 경로로 설정하기 위해, make install 파라미터 로써 "PREFIX=/home1/username/apps/redis install" 를 추가하여주었다.
cd /home1/username/stage/

sudo wget http://download.redis.io/releases/redis-4.0.8.tar.gz

sudo tar xvzf redis-4.0.8.tar.gz

cd redis-4.0.8

sudo make PREFIX=/home1/username/apps/redis install

sudo mkdir -p /home1/username/apps/redis/etc

 

2. Redis 설정

redis 소스 디렉토리에 있는것을 복사하는 방법도 좋지만, redis 설치패키지에 포함된 sh 스크립트를 사용하여주자

  • Util로 Redis 자동 구성
sudo /home1/username/stage/redis-4.0.8/utils/install_server.sh

# 아래와 같이 순서대로 설정 
Port           : 6379
Config file    : /home1/username/apps/redis/etc/6379.conf
Log file       : /home1/username/apps/redis/logs/redis_6379.log
Data dir       : /home1/username/apps/redis/data/6379
Executable     : /home1/username/apps/redis/bin/redis-server
Cli Executable : /home1/username/apps/redis/bin/redis-cli
  • conf 수정
cd /home1/username/apps/redis/etc/

...
vi 6379.conf
# 메모리 설정
maxmemory 1024*1024*1024*10
bind 127.0.0.1 10.XXX.XXX.XXX(내부아이피로 기재)
...
  • Q&A ) bind 설정값에 따른 차이점은 ?
    ㄴ conf 속성중 하나인 bind는 아래 규칙을 따릅니다.

    bind 127.0.0.1 로 설정시 - 127.0.0.1로 접속하는 클라이언트만 접근가능. 즉 내부 클라이언트에서만 접속 가능.
    bind 127.0.0.1 10.XXX.XXX.XXX(내부아이피) - 내부 클라이언트와, 내부망으로 연결된 모든 클라이언트에서 접속 가능.
    bind 0.0.0.0 or 주석처리 - 모든 ip에서 접속 허용(ifconfig 상 설정된 모든 ip에서 접속 가능). 권장하지 않음.

 

2-1. Redis 를 Master - Slave 추가 구성 하고 싶은 경우.

  • port의 경우 서버 상황에 맞게 수행하여 주세요.
sudo /home1/username/stage/redis-4.0.8/utils/install_server.sh

# 아래와 같이 순서대로 설정
Port           : 6389
Config file    : /home1/username/apps/redis/etc/6389.conf
Log file       : /home1/username/apps/redis/logs/redis_6389.log
Data dir       : /home1/username/apps/redis/data/6389
Executable     : /home1/username/apps/redis/bin/redis-server
Cli Executable : /home1/username/apps/redis/bin/redis-cli
  • conf 수정
cd /home1/username/apps/redis/etc/

vi 6389.conf
maxmemory 1024*1024*1024*5
bind 127.0.0.1 10.XXX.XXX.XXX(내부아이피로 기재)

slaveof 10.XXX.XXX.XXX 6379 (Master의 Redis 인스턴스)
or slaveof 127.0.0.1 6379

 

3. Redis 중지 / 실행

중지

sudo /etc/init.d/redis_6389 stop
sudo /etc/init.d/redis_6379 stop

실행

sudo /etc/init.d/redis_6379 start
sudo /etc/init.d/redis_6389 start

 

Redis 구동 테스트 

  • 방법 1) Redis-CLI 활용

/home1/username/apps/redis/bin/redis-cli

127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set abc 123
OK
127.0.0.1:6379> get abc
"123"
127.0.0.1:6379> monitor
OK
...
...

 

  • 방법 2) telnet 활용

# at Master
telnet 10.xxx.xxx.xxx 6379
set test test

# at Slave
telnet 10.xxx.xxx.xxx 6389
monitor
...
...
+1579754709.406515 [0 10.xxx.xxx.xxx:6379] "PING"
+1579754659.538290 [0 10.xxx.xxx.xxx:6379] "set" "test" "test"
+1579754709.406515 [0 10.xxx.xxx.xxx:6379] "PING"

 

개요

  • 2019년 1월 1일 부터 Oracle JDK의 라이센스 정책변경으로 Oracle JDK를 OpenJDK 로 교체가 필요해짐.
  • openjdk는 zulu 등 여러가지 종류가 있지만 내부결정으로 adoptOpenJDK로 결정됨.

 

고려사항

  • 기준 운용중인 JDK와 호환되는지 확인.
  • 특별한 클래스를 사용하지 않는한 버전 일치시 큰 이슈 없음 ( ex. oracle jdk 7 --> AdoptOpenJDK 1.7)

 

작업내용

 

JDK 설치

mkdir -p /home1/username/stage ; 
mkdir -p /home1/username/apps ; 
wget https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u192-b12/OpenJDK8U-jdk_x64_linux_hotspot_8u192b12.tar.gz  ; 
tar -xvzf /home1/username/stage/OpenJDK8U-jdk_x64_linux_hotspot_8u192b12.tar.gz ;
rm /home1/username/apps/jdk  ; 
ln -s /home1/username/stage/jdk8u192-b12 /home1/username/apps/jdk

 

시스템 환경변수 등록

sudo vi /etc/profile

>> 아래 내용 추가후 저장
export JAVA_HOME=/home1/username/apps/jdk
export PATH=${JAVA_HOME}/bin:$PATH

 

하둡 설정 변경

클라우데라 > 호스트 > 구성 > 고급 > java 홈 디렉토리 설정.
[ /home/username/apps/jdk ]

 

cloudera manager tomcat서버 restart

#모니터링 웹페이지 서버 접속
#웹서비스 restart
sudo service cloudera-scm-server restart

 

Hadoop Cluster 전체 Restart

Introduction

Cloudera Manager ?

  • 하둡 에코 시스템 관리를 편하게 하기위해 만들어진 Cloudera GUI 오픈소스

 

왜 업그레이드를 해야하는가?

  • 관리하는 DMP의 버전이 5.6로, 하이브 접속시 auth방식이 5.7과 상이함
  • auth 방식 추가를 위해, DMP Cloudera Manager 버전을 5.6 --> 5.7로 업그레이드를 진행함.
  • 참고 document URL : [링크 이동]

 

Step 1 - 기본 정보 수집.

  • Cloudera manager가 설치된 서버의 sudo 권한 계정 확인.
  • Cloudera Manager > 지원 > 정보 에서 JDK 버전 확인
  • 각 호스트별로 OS 버전 확인 (클러스터 -> 호스트 )

 

Step 2 - 업그레이드 전 사전 준비

  • 업그레이드 대상 버전이 현재 OS와 JDK를 지원하는지 확인 - [링크 이동]
  • Kafka 1.2가 설치되어있을경우 아래 순서에 따라 진행
    • 1. Select Administration > Settings.
    • 2. Click the Custom Service Descriptors category.
    • 3. Retrieve the directory from the Local Descriptor Repository Path property.
    • 4. Delete the KAFKA CSD from directory

현재 교체하려는 DMP는 Kafka가 깔려있지않아 해당사항이 없지만 추후 Kafka 추가시 Step2과정을 포함해야함

 

Step 3 - JDK

  • JDK 버전 업그레이드가 필요할 경우 다음 포스트를 참고 - [링크 이동]

 

Step 4 - Backup

 

1. cloudera manager 정보 수집

 

Cloudera Server가 설치된 호스트 접속

ssh root@cdh.hostname.com 

 

scm서버의 db information 확인

cat /etc/cloudera-scm-server/db.properties

>>>
# Auto-generated by initialize_embedded_db.sh
#
# 20160304-181141
#
# These are database settings for CM Manager
#
com.cloudera.cmf.db.type=postgresql
com.cloudera.cmf.db.host=localhost:7432
com.cloudera.cmf.db.name=***
com.cloudera.cmf.db.user=***
com.cloudera.cmf.db.password=******

 

Activity Monitor 데이터베이스 정보 수집

  • 클라우데라 매니저 관리자 콘솔에서
    • 클러스터 > Cloudera Management Service > 구성 에서 데이터베이스 카테고리 선택. 나머지 정보는 라이센스가 유효하지않아 필요 없음.

 

Service Monitor가 어디서 실행되는지 확인

  • 클러스터 > Cloudera Management Service > 인스턴스

 

 

2.Cloudera Manager Agent Backup

  • Cloudera Manager Agent 가 설치된 모든 호스트에 대해 아래 내용 수행
# Create a top level backup directory.

export CM_BACKUP_DIR="`date +%F`-CM5.6"
echo $CM_BACKUP_DIR
mkdir -p $CM_BACKUP_DIR

# Back up the Agent directory and the runtime state.
sudo -E tar -cf $CM_BACKUP_DIR/cloudera-scm-agent.tar --exclude=*.sock /etc/cloudera-scm-agent /etc/default/cloudera-scm-agent /var/run/cloudera-scm-agent /var/lib/cloudera-scm-agent

# Back up the existing repository directory.
sudo -E tar -cf $CM_BACKUP_DIR/repository.tar /etc/yum.repos.d

 

 

3.Cloudera Management Service Backup

  • Cloudera Management Service 가 설치된 호스트에 대해 아래 내용 수행.
sudo cp -rp /var/lib/cloudera-service-monitor /var/lib/cloudera-service-monitor-`date +%F`-CM5.6

#On the host where the Host Monitor role is configured to run, backup the following directory:
sudo cp -rp /var/lib/cloudera-host-monitor /var/lib/cloudera-host-monitor-`date +%F`-CM5.6

#On the host where the Event Server role is configured to run, back up the following directory:
sudo cp -rp /var/lib/cloudera-scm-eventserver /var/lib/cloudera-scm-eventserver-`date +%F`-CM5.6

 

4.Cloudera Manager Server와 Cloudera Management Service 중지

 

1. Cloudera Management Service 중지

 

2. Cloudera Manager Server 중지

sudo service cloudera-scm-server stop

 

5.Cloudera Manager의 Databases 백업

 

Cloudera Manager Server DB 백업

pg_dump -h database_hostname -U user_name -W -p database_port database_name > $HOME/database_name-backup-`date +%F`-CM5.6.sql
예 ) pg_dump -h localhost -U scm -W -p 7432 scm > $HOME/database_name-backup-`date +%F`-CM5.6.sql

 

Activity Monitor DB 백업

  • 생략

 

6.Cloudera Manager Server Backup

 

cloudera manager (scm)가 설치된 호스트에서 아래 내용 수행

export CM_BACKUP_DIR="`date +%F`-CM5.6"
echo $CM_BACKUP_DIR
mkdir -p $CM_BACKUP_DIR

sudo -E tar -cf $CM_BACKUP_DIR/cloudera-scm-server.tar /etc/cloudera-scm-server /etc/default/cloudera-scm-server

sudo -E tar -cf $CM_BACKUP_DIR/repository.tar /etc/yum.repos.d

 

7.Cloudera Manager Server와 Cloudera Management Service 시작

 

1. Cloudera Manager Server 시작

sudo service cloudera-scm-server start

 

2. Cloudera Management Service 시작

 

 

Step 5 - Cloudera Manager Server 업그레이드 하기

 

1. Software 접근 경로 구축


# 이전 yum repo 지우기
sudo rm /etc/yum.repos.d/cloudera*manager.repo*

#yum repo 수정
sudo vi /etc/yum.repos.d/cloudera-manager.repo 

>>> 버전에 따라 경로 수정. 세부버전을 적지않으면 해당 릴리즈의 가장 최신버전이 다운됨.
[cloudera-manager]
# Packages for Cloudera Manager
name=Cloudera Manager
baseurl=https://archive.cloudera.com/cm5/redhat/6/x86_64/cm/5.7.1
gpgkey=https://archive.cloudera.com/cm5/redhat/6/x86_64/cm/RPM-GPG-KEY-cloudera
gpgcheck=1

 

2. Cloudera Manager Server 업그레이드

 

1. Cloudera Management Service 중지

 

2. Cloudera Manager Server 중지

sudo service cloudera-scm-server stop

 

3. Cloudera Manager Agent 중지

sudo service cloudera-scm-agent stop

 

4. package 업그레이드

sudo yum clean all
sudo yum upgrade cloudera-manager-server cloudera-manager-daemons cloudera-manager-agent

아래 2개의 prompt 결과에 대해서 N으로 Answer (비슷하게 출력됨)

#1. Configuration file '/etc/cloudera-scm-agent/config.ini'
#2. Configuration file/etc/cloudera-scm-server/db.properties
# 출력 예
==> Modified (by you or by a script) since installation.
==> Package distributor has shipped an updated version.
What would you like to do about it ? Your options are:
Y or I : install the package maintainer's version
N or O : keep your currently-installed version
D : show the differences between the versions
Z : start a shell to examine the situation
The default action is to keep your current version.

아래 prompt 결과에 대해서 y로 Answer

Retrieving key from https://archive.cloudera.com/.../cm/RPM-GPG-KEY-cloudera
Importing GPG key ...
 Userid     : "Yum Maintainer  <webmaster@cloudera.com>"
 Fingerprint: ...
 From       : https://archive.cloudera.com/.../RPM-GPG-KEY-cloudera</webmaster@cloudera.com>

 

5. 올바른 package가 설치되었는지 확인

rpm -qa 'cloudera-manager-*'

>>> 
cloudera-manager-server-5.7-..cm...
cloudera-manager-agent-5.7-..cm...
cloudera-manager-daemons-5.7-..cm...

 

6. Cloudera Manager Agent 시작

sudo service cloudera-scm-agent start

 

7. Cloudera Manager Server 시작

sudo service cloudera-scm-server start

 

Step 6 - Cloudera Manager Agent 업그레이드

 

Cloudera Manager 업그레이드 마법사로 Agent 업데이트

 

페이지 이동후 가이드에 따라 진행

[http://cloudera.manager.net:7180/cmf/upgrade-wizard/welcome]

  • 도중 ssh 설정은 다음과 같이 설정하여줍니다
    • 계정명 : root (혹은 root권한의 계정)
    • ssh key file : 삽입 (cloudera manager가 설치된 호스트의 의 id_rsa keyfile 입니다.)
    • 암호 미사용

 

cloudera manager 업데이트 여부 확인

  • 상단탭의 지원 > 정보

 

개요

  • 임팔라는 hive에서 쓰던 java UDF 뿐만 아니라 C++로 UDF가 등록 가능합니다.
  • Hive에서 쓰던 UDF를 Impala에 사용하면 구글에 오픈소스가 많을 뿐더러, Java기반이기에 친숙하여 손쉽게 등록이 가능합니다. 단, 문제점이 하나 있는데, python(내부적으로 unicode 사용) 기반의 impala와 한글 호환이 정상적으로 이루어지지 않는것입니다.

1. Impala UDF 개발을 위한 환경 패키지 구축

  • Impala에 정상적으로 UDF 등록을 위해서는 선행작업 - 즉 개발을 위한 환경패키지를 구축해야합니다.
  • Version 정보를 정확하게 파악 후 진행하여줍니다.

http://archive.cloudera.com/cdh5 에서 버전에 맞는 impala-udf-devel 패키지를 다운받아 줍니다.

  • 제가 개발을 진행하는 DMP는 centos 6(Red Hat 계열 리눅스) / CDH 5.7.6 환경입니다.
#임팔라데몬이 설치된 데이터노드 접속
cd ~/stage
wget http://archive.cloudera.com/cdh5/redhat/6/x86_64/cdh/5.7.6/RPMS/x86_64/impala-udf-devel-2.5.0+cdh5.7.6+0-1.cdh5.7.6.p0.7.el6.x86_64.rpm

다운받은 rpm 패키지 설치.

# 기 설치 여부 확인
sudo rpm -qa | grep impala
>> 결과 없음.

# rpm 설치
sudo rpm -ivh impala-udf-devel-2.5.0+cdh5.7.6+0-1.cdh5.7.6.p0.7.el6.x86_64.rpm

# 설치 확인
rpm -qa | grep impala

# 설치된 패키지 경로 확인
rpm -ql impala-udf-devel-2.5.0+cdh5.7.6+0-1.cdh5.7.6.p0.7.el6.x86_64

2. impala UDF 샘플 코드 환경 구축.

  • 1번 과정을 통해 impala udf 개발을 위한 환경을 구축하였습니다.
  • rpm으로 설치된 패키지중 /usr/include/impala_udf/udf.h 는 가장 중요한 역할을합니다.
    • 스칼라 UDF를 작성하는 데 필요한 기본 선언이 명시됨.
    • AddUdf () 를 사용하며, UDF 작성 후 컴파일에 꼭 필요한 메소드.
  • 기본적인 개발 환경 구축을 하였으니, 컴파일이 바로 가능한 샘플 코드를 다운로드 해줍니다.

CDH 공식 github에서 impala UDF 샘플 코드 다운.

github 주소 : https://github.com/cloudera/impala-udf-samples

# 깃헙 클론
git clone https://github.com/cloudera/impala-udf-samples.git

3. impala UDF C++ 소스 작성.

  • 샘플 소스를 다운받은 뒤, CMakeLists.txt 에서 빌드할 소스를 자유롭게 등록 할 수 있습니다.
  • 우선, 소스목록편집/빌드 전에 C++ 기반의 소스를 작성해야합니다

헤더소스 url-coding.h (url decode 소스)

cd /home1/username/stage/impala-udf-samples
vi url-coding.h
#ifndef URLTOOL_UDF_H
#define URLTOOL_UDF_H

#include <impala_udf/udf.h>
#include 

using namespace impala_udf;
using namespace std;


StringVal UrlDecoder(FunctionContext* context, const StringVal& arg1);

StringVal UrlEncoder(FunctionContext* context, const StringVal& arg1);

std::string UrlEncode(const std::string& str);

std::string UrlDecode(const std::string& str);

unsigned char FromHex(unsigned char x);

unsigned char ToHex(unsigned char x);

#endif

메인소스 udf-urltool.cc (url decode 소스)

vi udf-urltool.cc
#include "udf-urltool.h"

#include 
#include 
#include 
#include 
using namespace std;


StringVal UrlDecoder(FunctionContext* context, const StringVal& arg1){
    if (arg1.is_null) return StringVal::null();

    try {
        std::string original((const char *)arg1.ptr,arg1.len);
        std::string decoded = UrlDecode(original);

        StringVal result(context, decoded.size());
        memcpy(result.ptr, decoded.c_str(), decoded.size());

        return result;
    }catch(...){
        return StringVal::null();
    }

}

StringVal UrlEncoder(FunctionContext* context, const StringVal& arg1){
    if (arg1.is_null) return StringVal::null();

    try {
        std::string original((const char *)arg1.ptr,arg1.len);
        std::string encoded = UrlEncode(original);

        StringVal result(context, encoded.size());
        memcpy(result.ptr, encoded.c_str(), encoded.size());

        return result;
    }catch(...){
        return StringVal::null();
    }
}




inline unsigned char ToHex(unsigned char x) {
    return  x > 9 ? x + 55 : x + 48;
}

inline unsigned char FromHex(unsigned char x) {
    unsigned char y;
    if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
    else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
    else if (x >= '0' && x <= '9') y = x - '0';
    else y = ' ';
    return y;
}

inline std::string UrlEncode(const std::string& str) {
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        if (isalnum((unsigned char)str[i]) ||
            (str[i] == '-') ||
            (str[i] == '_') ||
            (str[i] == '.') ||
            (str[i] == '~'))
            strTemp += str[i];
        else if (str[i] == ' ')
            strTemp += "+";
        else
        {
            strTemp += '%';
            strTemp += ToHex((unsigned char)str[i] >> 4);
            strTemp += ToHex((unsigned char)str[i] % 16);
        }
    }
    return strTemp;
}

inline std::string UrlDecode(const std::string& str) {
    std::string strTemp = "";
    size_t length = str.length();
    for (size_t i = 0; i < length; i++)
    {
        if (str[i] == '+') strTemp += ' ';
        else if (str[i] == '%')
        {
            unsigned char high = FromHex((unsigned char)str[++i]);
            unsigned char low = FromHex((unsigned char)str[++i]);
            strTemp += high*16 + low;
        }
        else strTemp += str[i];
    }
    return strTemp;
}

CMakeLists.txt 수정

  • 위 에서 설명한 /usr/include/impala_udf/udf.h 헤더를 이용하여 컴파일을 할 목록을 추려내는 CMakeLists.txt를 수정하여줍니다.
vi CMakeLists.txt
# Copyright 2012 Cloudera Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 2.6)

# where to put generated libraries
set(LIBRARY_OUTPUT_PATH "build")
# where to put generated binaries
set(EXECUTABLE_OUTPUT_PATH "build")

find_program(CLANG_EXECUTABLE clang++)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb")

# Function to generate rule to cross compile a source file to an IR module.
# This should be called with the .cc src file and it will generate a
# src-file-ir target that can be built.
# e.g. COMPILE_TO_IR(test.cc) generates the "test-ir" make target.
# Disable compiler optimizations because generated IR is optimized at runtime
set(IR_COMPILE_FLAGS "-emit-llvm" "-c")
function(COMPILE_TO_IR SRC_FILE)
  get_filename_component(BASE_NAME ${SRC_FILE} NAME_WE)
  set(OUTPUT_FILE "build/${BASE_NAME}.ll")
  add_custom_command(
    OUTPUT ${OUTPUT_FILE}
    COMMAND ${CLANG_EXECUTABLE} ${IR_COMPILE_FLAGS} ${SRC_FILE} -o ${OUTPUT_FILE}
    DEPENDS ${SRC_FILE})
  add_custom_target(${BASE_NAME}-ir ALL DEPENDS ${OUTPUT_FILE})
endfunction(COMPILE_TO_IR)

# Build the UDA/UDFs into a shared library.
add_library(udfurltool SHARED udf-urltool.cc)


# Custom targest to cross compile UDA/UDF to ir

if (CLANG_EXECUTABLE)
  COMPILE_TO_IR(udf-urltool.cc )
endif(CLANG_EXECUTABLE)


# This is an example of how to use the test harness to help develop UDF and UDAs.

target_link_libraries(udfurltool ImpalaUdf)

4. 컴파일 & HDFS 업로드

  • 위에서 url decode를 위한 헤더파일과 C++ 소스를 작성하였습니다.
  • CMakeLists.txt 에서 빌드할 소스목록도 편집하였습니다.
  • 소스 작성과 리스트를 편집하였으니, 빌드 후 HDFS에 업로드를 해야합니다.

build 파일 제작(컴파일)

cd /home1/username/stage/impala-udf-samples
cmake .
make

HDFS에 소켓 업로드

cd build
hadoop fs -put libudfurltool.so /tmp/

5. impala에 udf 등록

  • HDFS에 빌드한 소켓 업로드를 완료 하였으니, impala UDF를 등록 하여줍니다.
  • UDF 등록에 관한 자세한 내용은 [링크] 참조 부탁드립니다.

등록

impala-shell
...
[hdfs.datanode.host:21000] > 
create function urldecode_test (string) returns string location 'hdfs://hdfs.namenode.host:8020/tmp/libudfurltool.so' symbol='UrlDecoder';

테스트

select default.urldecode_test(encoded_text) as decoded_text from db.table;

>>>
+--------------+
| decoded_text |
+--------------+
| 테스트1   |
| 테스트2   |
| 테스트3   |
| 테스트4   |
| 테스트5   |
| 테스트6   |
| 테스트7   |
+----------+

:: reference

https://www.cloudera.com/documentation/enterprise/5-8-x/topics/impala\_udf.html
https://data-flair.training/blogs/impala-udf/

impala 에 hive udf를 등록하기 위한 가이드 포스트.

임팔라에 하이브-HIVE UDF 등록

 

1. java로 쓰여진 Hive UDF 파일을 준비.

  • Location : hdfs://my.namenode.com:8020/user/username/lib/my-udf.jar

 

2. impala-shell 실행

impala-shell

 

3. impala-shell에서 함수 등록

  • hive와 다르게 function parameter와 return 타입을 명시해줘야 합니다.
  • location 경로는 local 경로가 아닌 hdfs 경로로 지정해주셔야 합니다.

     

    create function my_urldecode(string, string) returns string location 'hdfs://my.namenode.com:8020/user/username/lib/my-udf.jar' symbol='com.my.udf.MyURLDecode'

     

impala shell 기타 명령어

  • drop function

    DROP FUNCTION my_urldecode(STRING, STRING);
  • show function

    show functions;

 

UDF 등록후 impala에서 데이터 조회시 정상적이지 않은 값 return 시

  • impala는 유니코드 기반의 python이고, hive udf는 java기반이기 때문에 한글에 있어서 인코딩 문제가 발생함.
  • 이 내용은 다음 포스트에서 다루도록 하겠습니다

+ Recent posts