Data Analysis : Prologue - EMQ + Kafka + openTSDB + Grafana


사실 이 포스팅의 제목을 어떻게 정해야 할지 고민이 많았다. 일단 클러스터 설치는 마쳤으니 당연히 이전 포스팅의
카테고리에서는 벗어나야 할 것이고, 실제 데이터를 다루기 시작하였으니 데이터 분석의 시작은 시작인데…
수집되는 데이터 자체가 딱히 분석할만한 데이터는 아니고…암튼 조금은 모호한 지점에 있는 작업이 되어버렸다.
더군다나 본격적인 데이터 분석은 아직 한참 더 공부한 이후 시작될 터인데…


하지만 역시나 데이터를 다루기 시작했으니 데이터 관련 제목을 붙여야 하겠다고 결정을 했다. Prologue라는 부제와
함께. 이후 The Beginning을 시작하게 되겠지만 아마도 시간이 조금 걸리지 않을까 싶다. 오늘은 가볍게나마
이전에 클러스터 구성 내용을 정리할 때 누락된 openTSDB와 Grafana 설치에 대한 내용과 EMQ -> Kafka ->
openTSDB -> Grafana로 이어지는 데이터 수집/저장/시각화 과정을 정리해보도록 하겠다.


시나리오


직전 포스팅(아두이노 온습도계 제작)에서도 언급했듯이 좀 더 그럴싸한 데이터를 모아 분석을 해보고 싶었지만
막상 작업을 시작하고 보니 마땅히 모을 수 있는 데이터가 없었다. 그렇다고 데이터를 찾아 다닐수만은 없기에
우선 쉽게 접근할 수 있는 것으로부터 시작해보기로 했다. 시나리오는 다음과 같다.


  1. 아두이노로 제작된 온습도 및 먼지 센서를 통해 온도,습도,먼지 농도,시간 데이터 수집
  2. MQTT 프로토콜을 통해 EMQ 서버로 데이터 전송
  3. EMQ 서버로 publishing 된 데이터를 Kafka에서 subscribing
  4. Kafka에 들어온 데이터를 openTSDB에 저장
  5. openTSDB에 저장된 데이터를 Grafana로 시각화
  6. Spark를 이용하여 데이터 분석 (이상 감지)


EMQ를 통해 M2M 통신을 하는 상황이거나 데이터 누락을 어느 정도 허용하는 작업이라면 굳이 Kafka가 필요하진
않을 것이다. 하지만 일단 데이터를 수집하고 분석하는 작업을 전제로 하였기에 누락되는 데이터를 Kafka에서 1차로
완충하도록 구성하였다. 최종 분석단계에 해당하는 6번 Spark를 이용한 데이터 분석은 아직 좀 더 학습이 진행되어야
할 부분이다.


openTSDB 설치 및 실행


최근 시계열 데이터를 처리하는 NoSQL로는 influxDB가 대세인듯하다. 다만 openTSDB가 HBase를 기반으로
작동한다는 한 가지 이유만으로 나는 openTSDB를 선택하였다. 설치 및 연동 과정에서 후회를 많이 했지만 결국
불굴의 의지로 제대로 연동 시키고야 말았다…ㅠ.ㅠ influxDB가 대세라는 것은 구글링만 해봐도 충분하다. 이놈에
openTSDB는 검색을 해도 설치 외에는 쓸만한 정보가 없더라…-.-


간단하게 openTSDB의 개요를 말하자면 TSD라는 데몬을 통해 외부의 시계열 데이터를 HBase에 생성된 테이블에
저장하는 구조이다.




설치 시 유의사항

현재 최신 릴리즈는 2.3.0 이며 pre-release가 2.4.0 RC2까지 나와있다. 아래 설명할 kafka와의 연동을
위한 opentsdb-rpc-kafka라는 plugin을 사용하기 위해서는 반드시 2.4.0 RC2 버전을 설치해야 한다.
나는 이 사실을 모르고 2일간 삽질을 했다…ㅠ.ㅠ 


설치는 역시 간단하다. 압축 파일을 다운로드 받아 적당한 디렉토리(나는 당근 /opt)에서 압축을 풀고 압축을 푼
디렉토리 내에 있는 build.sh를 실행시키는 것만으로 설치는 끝이다. 


path


다만 앞서 말한 것처럼 openTSDB는 HBase 기반으로 작동을 하기 때문에 HBase가 이미 설치 되어있다는 것을 
전제로 한다. 나는 이미 이전에 클러스터를 구성하였기에 바로 설치에 들어갔다.


설치가 끝나면 build.sh 파일이 있는 그 경로에 build라는 경로가 추가되고 그 안에 openTSDB 실행 파일 등이
위치하게 된다. 설치가 끝나면 가장 먼저 테이블을 생성해주어야 한다. 테이블 생성 스크립트는 build/src 아래에
있다. 아래와 같이 실행해준다.


$ cd /opt/opentsdb/build
$ env COMPRESSION=NONE HBASE_HOME=/opt/hbase ./src/create_table.sh


이렇게 실행하면 ‘tsdb’, ‘tsdb-uid’, ‘tsdb-tree’, ‘tsdb-meta’ 이렇게 4개의 테이블이 HBase 상에 생성된다.


HBase

그리고 마지막으로 설정을 한다. 설정파일은 최초에 압축을 푼 디렉토리 밑에 있는 src 디렉토리에 있다.
나의 경우에는 /opt/opentsdb/src가 그 경로이며 파일 이름은 opentsdb.conf이다. 이 파일을 build로
복사한다. 즉, /opt/opentsdb/build로 복사를 하는 것이다. 수정해야 할 설정 내용은 간단하다.


# The TCP port TSD should use for communications
# *** REQUIRED ***
tsd.network.port = 4242
...
# The location of static files for the HTTP GUI interface.
# *** REQUIRED ***
tsd.http.staticroot = /opt/opentsdb/build/staticroot

# Where TSD should write it's cache files to
# *** REQUIRED ***
tsd.http.cachedir = /tmp/opentsdb
...
# Whether or not to automatically create UIDs for new metric types, default
# is False
tsd.core.auto_create_metrics = true


여기까지 모두 마쳤으면 /opt/opentsdb/build아래 있는 tsdb를 다음과 같이 실행해준다.


$ /opt/opentsdb/build/tsdb tsd


실행한 콘솔창에 로그가 올라가는 것이 보일 것이고 localhost:4242로 접속을 하면 아래 이미지와 같은 콘솔
화면을 볼 수 있다.


openTSDB


센서 데이터의 포맷 변경


기존에 아두이노 온습도계에서 EMQ 서버로 전송하던 데이터는 포맷을 좀 바꾸어야 한다. openTSDB에 저장하기
위한 데이터 포맷은 JSON 형식으로 모두 3가지 유형이 있다.


  • Metric
  • Aggregate
  • Histogram


자세한 설명은 생략하고…-.- 나는 가장 기본적인 Metric 형태로 데이터를 저장하기로 했다. Metric 형태로 저장할
경우 JSON 포맷은 다음과 같다(여러건을 한번에 보내려면 아래 형식을 배열 안에 넣으면 된다).


{
    "metric": "sys.cpu.nice",
    "timestamp": 1346846400,
    "value": 18,
    "tags": {
       "host": "web01",
       "dc": "lga"
    }
}


metric은 전체 측정 단위를, timestamp는 이름 그대로 long 타입의 타임스탬프를 value는 측정 값을, tags는
세부 분류를 위한 키-값 쌍을 추가하면 된다. 나의 예로 좀더 자세하게 살펴보자.


[
   {
      "type": "Metric",
      "metric": "mqtt.home.pcroom",
      "timestamp": 1346846400,
      "value": 22.5,
      "tags": {
         "type": "temperature",
         "loc": "pcroom"
      }
   },
   {
      "type": "Metric",
      "metric": "mqtt.home.pcroom",
      "timestamp": 1346846400,
      "value": 18.2,
      "tags": {
         "type": "humidity",
         "loc": "pcroom"
      }
   },
   {
      "type": "Metric",
      "metric": "mqtt.home.pcroom",
      "timestamp": 1346846400,
      "value": 22.3,
      "tags": {
         "type": "dust",
         "loc": "pcroom"
      }
  }
]


위 내용을 살펴보면 우선 같은 시점에 측정된 온도/습도/먼지의 측정값을 배열로 넘기고 있다. 이 데이터를
만드는 것은 아두이노에서 처리하며 관련 내용은 아래 링크의 소스코드 부분을 참조하면 된다.


아두이노를 이용한 온도/습도/먼지 측정기


최상위에 있는 type 값은 openTSDB 자체를 위한 것이 아니라 opentsdb-rpc-kafka plugin에서 필요한
것이다. 3가지 유형 중 하나를 지정하기 위한 속성이다.



metric의 값은 임으로 정하면 되는 것으로 나의 경우 그 의미는 mqtt를 이용하여 home에 있는 컴퓨터방
pcroom의 측정값이라는 뜻이다. 


timestamp와 value는 달리 설명할 부분이 없고 tags에 보면 type에 각각 temperaturehumiditydust
라는 값이 들어있는데 의미 그대로 온도와 습도와 먼지를 뜻한다.


이렇게 3개의 값을 하나의 배열에 포함시켜 보내는 것이다. tags에서 loc는 큰 의미는 없다. 필요에 따라 추가적인
값을 지정하면 된다.


Kafka와 openTSDB 연동


openTSDB 자체에 대한 자료 혹은 openTSDB와 Grafana 연동에 대한 자료는 그럭저럭 찾을 수 있었는데
Kafka와 openTSDB와의 연동에 대한 자료는 거의 찾을 수가 없었다. 구글링을 하면 가장 상위에 검색되는
내용이 2개인데 하나는 opentsdb-rpc-kafka라는 openTSDB의 plugin이고 다른 하나는 
kafka-connect-opentsdb라는 Kafka connector이다. 뭔가 사용하기에는 connector쪽이 쉬워보였으나
openTSDB의 HTTP API를 이용한다는 점이 맘에 들지 않았다. 그래서 opentsdb-rpc-kafka를 선택하게
되었고 그렇게 고난의 길은 시작되었다…ㅠ.ㅠ


일단 opentsdb-rpc-kafka는 Github에서 소스를 내려받은 후 빌드를 하여 jar 파일을 만들어야 한다.
소스는 Maven 프로젝트로 되어있어 이클립스에서 빌드하거나 또는 프로젝트 디렉토리 아래에서 man package
명령으로 빌드하면 된다.


플러그인 소스 경로는 다음과 같다.

https://github.com/OpenTSDB/opentsdb-rpc-kafka


이렇게 빌드된 jar 라이브러리를 /opt/opentsdb/build 아래에 plugins 디렉토리를 만들어 그 안에 넣는다.
plugin 라이브러리의 최종 위치는 다음과 같다. 그리고 이 plugin의 경로는 반드시 classpath에 추가시켜주어야 한다.


$ /opt/opentsdb/build/plugins/opentsdb-rpc-kafka-2.3.2-SNAPSHOT.jar


그리고 opentsdb.conf 설정 파일에 plugin과 관련된 내용을 추가해주어야 하는데 아래와 같은 내용을 설정 파일의
제일 하단에 추가해주면 된다. 물론 각 설정 값은 각자의 환경에 맞게 입력해야 한다. 고정이라고 주석을 달아놓은
설정 외에는 각자 환경에 맞춰 수정을 하자.


# --------- PLUGINS ---------------------------------
tsd.core.plugin_path = /opt/opentsdb/build/plugins
## 고정
tsd.core.storage_exception_handler.enable = true
## 고정
tsd.core.storage_exception_handler.plugin = net.opentsdb.tsd.KafkaStorageExceptionHandler
## 고정
tsd.rpc.plugins = net.opentsdb.tsd.KafkaRpcPlugin
KafkaRpcPlugin.kafka.zookeeper.connect = rpi1:2181,rpi2:2181,rpi3:2181
KafkaRpcPlugin.kafka.metadata.broker.list = rpi1:9092,rpi2:9092,rpi3:9092
KafkaRpcPlugin.groups = mqtt
KafkaRpcPlugin.mqtt.topics = mqtt-kafka
## 고정
KafkaRpcPlugin.mqtt.consumerType = raw
## 고정
KafkaRpcPlugin.mqtt.deserializer = net.opentsdb.data.deserializers.JSONDeserializer
#KafkaRpcPlugin.mqtt.rate = 5
KafkaRpcPlugin.mqtt.threads = 3
## 고정
KafkaRpcPlugin.seh.topic.default = seh


앞서 말한 바와 같이 이 플러그인을 사용하기 위해서는 openTSDB 2.4.0 RC2 버전을 설치해야 한다.
한동안 자바 개발을 등한시 했더니 아주 사소한 것을 파악하지 못해 삽질을 따따블로 했다. 분명 빌드는 잘 되는데
plugin 설치하고 openTSDB를 기동하면 쌩뚱맞게 속성에 접근하지 못한다느니, 메소드가 존재하지 않는다느니
하는 메시지가 나오면서 plugin이 제대로 작동하지 않는 것이다.


나중에 확인해보니 소스에 포함된 openTSDB 라이브러리는 2.4.0 버전이고 내가 설치한 openTSDB는 2.3.0
이었다. 전체적인 패키지 구조는 같지만 클래스 내에 변화가 있었기 때문에 속성이나 메소드 사용에 문제가
있었던 것이다. 확인 후 부랴부랴 2.4.0 RC2 버전으로 다시 설치를 하였다.


이제 다시 한 번 openTSDB를 실행해보자(이미 실행중이라면 실행 중인 콘솔에서 ctrl+c를 눌러 종료시키자).
드디어 Kafka에서 데이터를 쭈~욱 쭉 뽑아오는 모습을 볼 수 있을 것이다.

 

data


이 데이터는 이전에 클러스터 관련 포스팅 중 EMQ와 Kafka의 연동을 통해 가져온 데이터들이다. 관련 내용은 아래 
링크에서 확인할 수 있다.


Cluster : The Beginning - Apache Kafka와 EMQ 연동

주의 사항

EMQ에서 Kafka로 전송된 데이터의 포맷은 형태가 다르다. 실제로 openTSDB에 저장하기 위한 내용은
payload 부분에 들어있는데 이 payload의 값은 Base64 인코딩이 되어 저장된다. kafka와 EMQ 연동을
위해 사용한 connector에서 그렇게 처리를 하고 있다. 따라서 opentsdb-rpc-kafka plugin에서 데이터를
제대로 처리하기 위해서는 Kafka에서 받아온 값에서 payload의 값만을 추출한 뒤 이 값을 Base64 디코딩
하여 전달해야 한다. 


이 부분을 처리해야 하는 소스는 net.opentsdb.tsd.KafkaRpcPluginThread.java의 run 함수이다.


이렇게 모든 과정이 끝나면 앞서 localhost:4242로 접근했던 웹 콘솔을 통해 쿼리가 가능하다. 그런데 어쩐 일인지
나의 경우 오류가 발생하면서 데이터 조회가 되지 않았다. 콘솔창에 찍히는 URL이 조금 이상해 보이긴 한데 그것이
원인인지는 잘 모르겠다. 결국 openTSDB 자체 웹 화면에서 데이터를 조회하는 것은 성공하지 못했다.


openTSDB


Grafana 설치 및 설정


적어도 설치에 있어서는 지금껏 설치한 모든 시스템 중 Grafana가 가장 친절하였다.
운영체제별로 다운로드 버튼이 있고 이 버튼을 누르면 해당 운영체제에 설치하는 방법이 나온다.
나는 현재 Mac mini에 설치를 하고 있기 때문에 Mac에 대한 설치 방법을 제공해 주는 것이 얼마나
반가웠는지 모른다…ㅠ.ㅠ 설치는 매우 간단하다.


brew update 
brew install grafana


이렇게 설치를 하고나면 다음과 같은 내용이 콘솔 화면에 표시된다.


To have launchd start grafana now and restart at login:
  brew services start grafana
Or, if you don't want/need a background service you can just run:
  grafana-server —config=/usr/local/etc/grafana/grafana.ini —homepath /usr/local/share/grafana cfg:default.paths.logs=/usr/local/var/log/grafana cfg:default.paths.data=/usr/local/var/lib/grafana cfg:default.paths.plugins=/usr/local/var/lib/grafana/plugins


친절하게 Grafana의 실행 방법을 알려주는 것이다. 나는 그냥 간단하게 brew를 통해 실행을 하였다.
설정파일은 상당히 긴 편인데 따로 변경해주어야 할 것은 아무것도 없다. 웹 화면의 포트를 바꾸는 정도?


openTSDB와의 연동


설정을 바꾸지 않았다면 localhost:3000으로 Grafana 웹 콘솔에 접근할 수 있다. 처음 접속하면 계정을 물어보는데
기본 계정은 admin / admin이다. 접속을 해서 가장 먼저 수행해야 하는 작업은 Datasource를 연결하는 것이다.
Grafana는 다양한 DB와 연동 가능한데 type 항목에서 select box를 클릭하면 다음과 같이 목록이 표시된다.



나머지 설정들은 자료도 많고 하니 참고해서 입력하면 되는데 나같은 경우 HTTP settings에서 Access를 Direct로
설정하니 데이터 소스에 연결이 되지 않았다. Access를 proxy로 설정하고 HTTP Auth를 With Credentials로
설정하니 비로소 데이터소스 연결에 성공했다는 메시지가 표시되었다. 이 과정에서도 왜 연결이 안되는지 Grafana의
소스까지 까뒤집고 난리를 치면서 상당한 시간을 보냈다…ㅠ.ㅠ 전체적인 설정은 다음과 같다(OpenTSDB settings
의 Version은 현재 2.3까지만 선택 가능한데 2.4.0 RC2를 설치한 경우에도 2.3을 선택하면 된다).


Grafana


Datasource를 성공적으로 연결했다면 이제 대시보드를 만들면 된다. 좌측 메인 메뉴에서 Dashbord에 마우스를
올리면 나타나는 서브 메뉴에서 + New를 선택하여 새로운 대시보드를 만드는데 처음 나타나는 화면은 대시보드에
표현할 유형을 선택하는 화면이다. 나머지는 차차 알아보고 나는 우선 맨 앞의 Graph를 선택했다.


Grafana


Graph를 선택하면 아래 이미지와 같이 비어있는 Graph panel이 덩그러니 하나 나온다. 여기서 상단의 Panel Title을
클릭하면 몇가지 메뉴가 나오는데 Edit를 선택하자


Grafana


Edit를 선택하면 Graph panel 하단으로 Graph 조건을 입력하는 화면이 나온다. 역시 다른 항목들은 차차
알아보기로 하고 중요한 몇가지만 살펴보자.


먼저 General 항목으로 가서 Graph 이름을 지정해준다. 그러면 Graph 화면 상단에 있던 Panel Title이라는
문구가 지정해준 이름으로 바뀐다. 일단 TEST라고 입력해 보았다.


Grafana


다음 가장 중요한 Metric 설정이다. 역시 많은 항목이 있지만 꼭 필요한 2가지만 설정해보자.
먼저 Metric 값을 입력한다. 기억하시겠지만 openTSDB로 넘기는 JSON 문자열에 metric이라는 키가 있는데
바로 그 값을 넣어주면 된다. 나는 mqtt.home.pcroom이었다. Metric 값만 입력해도 벌써 챠트가 그려지는데
나의 경우 하나의 Metric에 온도/습도/먼지 3가지 데이터가 들어있었다. 


이 시점에 나타나는 그래프는 설정화면의 Metric 옆에 보이는 Aggregator가 sum으로 되어있기 때문에 
온도 + 습도 + 먼지의 값으로 그려진 그래프다. 한마디로 쓰레기다…-.- 물론 이런 값이 필요한 경우도 분명 있을 
것이다. 각각의 데이터로 그래프를 그리기 위해서는 tags에 지정한 구분값을 추가로 입력해주어야 한다. 


아래 그림과 같이 내가 tags에 지정한 type키와 그에 대한 값인 temperature를 입력해주었다. 입력 후 우측에 
있는 add tag 버튼을 눌러야 반영된다.


Grafana

Grafana


이제 온도에 대한 데이터만 Graph에 표시된다.
그렇다면 하나의 Graph에 여러 데이터를 표시하려면 어떻게 하면 될까?
Edit 영역 하단에 보면 Add Query라는 파란색 버튼이 있다. 이 버튼을 클릭하면 동일한 입력 폼이 하나 더 생기며
이렇게 새로 생긴 입력 폼에 tags를 구분해서 입력해주면 된다.


Grafana


최종 화면은 요렇게 보인다.


Grafana


정리


이거 은근히 내용이 길어져버렸다. 달리 생각하면 이 작업에 그만큼 많은 시행착오와 노력이 들어갔다는 말이 되겠지만
최근에는 시계열 데이터도 Elasticsearch와 Kibana를 이용하여 처리하는 것이 대세인 것 같아 내가 이러려고
openTSDB를 선택했던가 하는 자괴감이 든다는 철지난 개그가 절로 나오게 되었다…ㅠ.ㅠ 아무래도 본격적으로
데이터 처리를 하게 되면 바로 이 Elasticsearch + Kibana 조합으로 가지 않을까 싶다.


그래도 클러스터 구성에서부터, 작은 데이터를 가지고 클러스터의 일부분만 사용하는 작업이긴 하지만 실제 데이터를
다루어보았다는 점에서 상당한 만족감을 느낀다.


원래 최종 목표는 이렇게 수집한 데이터를 인공지능으로 분석하는 것이었다. 그리고 그 내용에는 트위터의 데이터를
수집하여 RNN 분석을 하는 것도 있었는데 앞으로의 계획이 너무 거창해져서 일단 그 부분은 보류를 해야 할 것 같다.


앞으로의 계획은 이렇다.

  1. 아두이노와 메카넘휠을 이용한 차량형 로봇 제작, 수집 대상은 모터 회전수, 초음파 센서를 이용한 장애물과의 거리 데이터, 충돌 센서를 이용하여 장애물과의 충돌이 발생했을 때의 false 정보, 바퀴의 둘레와 모터 회전수를 조합한 이동 거리 정보, 기타 부가 정보로 카메라를 이용한 영상 정보 등이다.
  2. 정보의 활용은 2가지이다. DQN을 이용한 강화학습을 통해 낮은 수준의 자율주행 구현이 그 하나이고 gazebo simulator를 이용한 Digital Twin을 구현하는 것이 다른 한가지다.


무식하면 용감하다고…그래도 그간 조금씩 습득해온 지식으로는 뭔가 어렵지 않게 될 것 같기도 한데 현실은 
어떨지…-.-


이제 긴 여정을 위해 잠시 학습하는 시간을 갖고 이후 블로그 포스팅은 주로 학습 내용을 정리하는 수준이 될 것 같다.
그럼 다음에…

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^









Cluster : The Beginning - Spark 2.2.1 설치


이제 클러스터 구축의 마지막 포스팅이다!
엄밀하게 말해 제대로 된 테스트를 진행하지 않았으니 껍데기만 설치해놓으 것이나 다름 없지만
이 분야의 초보자나 다름 없는 입장에서 일단 이렇게나마 설치를 해놓고 실제 데이터를 분석하면서 부족한
부분을 채워 나가는 것이 더 바람직하지 않나 하는 판단이다.


사실 Kafka 이후 어떤 내용을 더 추가할 것인가 고민을 좀 했었다. 워낙 방대한 하둡 생태계에서 무엇을 선택해야 할지
길을 잃었다고 하는 것이 옳은 표현이겠다. 하지만 선택은 빨랐다. 하둡 생태계의 많은 시스템들이 주목을 받고 있지만
그 중에서도 Spark의 지위는 상당한 것으로 보였다. 게다가 아무래도 머신러닝과 딥러닝 등 인공 지능이 대세인 이 
시점에서 머신 러닝 라이브러리인 Spark ML을 제공해주는 Spark는 분명 배워볼만한 시스템임이 틀림 없었다.


다만…In-Memory 시스템인 Spark를 겨우 8Gb 메모리를 장착한 가정용 PC 5대로 원활히 돌려볼 수 있을지는
의문이다.


사전 준비


Spark의 클러스터 관리를 위한 시스템 설치(Mesos또는 Hadoop YARN) 외에 특별한 사전 준비가 필요한 것은 
아니지만 JAVA 버전은 1.8.X 이상이어야 한다. 공식 문서에 보니 2.1.X 버전에서는 JAVA 1.7까지 지원했으나
2.2.0으로 버전이 올라가면서 1.8 이상을 필요로 하게 되었다.


설치


타 시스템과 다를 바 없이 먼저 바이너리 압축 파일을 다운로드 받는다 내가 받은 파일은 아래와 같다.


spark-2.2.1-bin-hadoop2.7.tar.gz


앞선 포스팅에서도 언급했듯이 나는 현재 모든 하둡 생태계의 시스템들을 /opt 아래에 설치하고 있기에 Spark 역시
/opt 압축을 풀었다. 생성된 디렉토리에서 버전정보는 뺐기 때문에 최종 경로는 /opt/spark가 되었다.


설정


기본적인 설정 파일은 spark-defaults.conf와 slaves 파일이며 cluster 모드로 설정하기 위해서는 spark-env.sh에
필요한 환경 변수를 설정해주면 된다. 나는 YARN을 이용한 cluster모드로 설치하기로 했기에 다음과 같이 설정하였다.


spark-env.sh

export JAVA_HOME=/Library/Java/Home
export HADOOP_HOME=/opt/hadoop
export SPARK_HOME=/opt/spark

##하둡과 YARN의 설정파일 경로를 추가해준다.
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export YARN_CONF_DIR=$HADOOP_HOME/etc/hadoop


spark-defaults.conf

## 클러스터 매니저가 접속할 마스터 서버 URI
spark.master                     spark://SECONDARY-NAMENODE.local:7077
##Spark 이벤트를 기록할지 여부. 응용 프로그램이 완료된 후 웹 UI를 재구성하는 데 유용
spark.eventLog.enabled           true

# spark.eventLog.dir               hdfs://NAMENODE.local:8021/sparkdir
##이벤트 로그를 기록할 경로
spark.eventLog.dir		 file:///opt/spark/sparkeventlog

##네트워크를 통해 전송되거나 직렬화 된 형식으로 캐시되어야하는 객체를 직렬화하는 데 사용할 클래스
spark.serializer                 org.apache.spark.serializer.KryoSerializer

##드라이버 프로세스, 즉 SparkContext가 초기화되는 곳에 사용할 메모리 크기
##클라이언트 응용프로그램에서 직접 변경하면 안됨
spark.driver.memory              2g

##YARN 관련 설정들

##YARN 응용 프로그램 마스터에 사용할 메모리 크기
##클러스터 모드에서는 spark.driver.memory를 사용하라는데...필요 없는 설정일지도...-.-
spark.yarn.am.memory             1g

##정적 할당에 대한 집행자의 수. spark.dynamicAllocation.enabled를 사용하면 실행 프로그램의 
##초기 세트가 최소한이 정도 커짐
spark.executor.instances           2
# spark.executor.extraJavaOptions  -XX:+PrintGCDetails -Dkey=value -Dnumbers="one two three"

##실행 프로그램에 추가할 JVM 옵션 설정. 스파크 속성 또는 최대 힙 크기 (-Xmx) 설정을 지정하는 것은 안됨
spark.executor.extraJavaOptions        -Dlog4j.configuration=file:/opt/spark/conf/log4j.properties

##드라이버에 추가할 JVM 옵션 설정. 스파크 속성 또는 최대 힙 크기 (-Xmx) 설정을 지정하는 것은 안됨
spark.driver.extraJavaOptions        -Dlog4j.configuration=file:/opt/spark/conf/log4j.properties


slaves

##슬레이브 노드로 사용할 서버들의 호스트명
DATANODE1.local
DATANODE2.local
DATANODE3.local


마지막으로 이전 포스팅에서도 언급한 바와 같이 Mac에 설치하는 경우 spark-env.sh파일에서 nohup으로 시작하는
명령행에서는 nohup을 삭제한 후 실행시켜야 한다.


클러스터 노드에 배포


설정이 모두 끝났으면 전체 배포본을 압축하여 클러스터를 구성할 각 노드들에 복사를 해준다.
나는 DATANODE1.local, DATANODE2.local,DATANODE3.local 3대의 노드를 슬레이브 노드로 사용하기에
아래와 같이 복사를 해주었다.


$ scp spark.tar.gz hadoop@DATANODE1.local:/opt
$ scp spark.tar.gz hadoop@DATANODE2.local:/opt
$ scp spark.tar.gz hadoop@DATANODE3.local:/opt

그리고 각각의 노드에서 압축을 풀어주면 된다.


실행


마스터 노드에서 아래와 같이 실행한다.

$ /opt/spark/sbin/start-all.sh 


실행 확인


마스터 노드에서 포트번호 8080으로 접속하게 되면 Spark 관리 콘솔이 브라우저 화면에 보여진다.



정리


이렇게 Spark를 마지막으로 클러스터를 구성하는 1차 목표가 완료되었다.
물론 이후에도 몇가지 목적에 의해 openTSDB를 추가로 설치하였으며 앞으로 또 어떤 시스템을 더 설치하게 될지
모르겠다. 하지만 애초에 설치를 목표로 했던 시스템들은 모두 설치가 되었다.


하지만 구슬이 서말이라도 꿰어야 보배라고…이렇게 설치한 클러스터를 이용하여 실제 데이터의 흐름을 이해하고
또 이렇게 모아진 데이터를 분석하는 더 큰일이 남아있다. 


전에도 말했지만 이미 Spark까지의 모든 시스템은 1월 초에 모두 설치가 완료되었고 이 블로그를 정리하는 시점에는 


아두이노를 이용한 온도/습도/먼지 센서를 이용하여 데이터를 수집하는 작업을 시작했는데 역시나 생각만큼 쉽지 않다.
잠시 쉬는 기간이라 생각하고 차근차근 연구를 해봐야 할 것 같다.


본격적인 싸움은 이제부터다!!!

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^








Cluster : The Beginning - HBase 1.2.6 설치


직전에 포스팅한 Hadoop 설치를 기점으로 복잡한 과정은 거의 끝이 난 듯싶다.
사실 하둡에서 바로 MapReduce를 사용하거나 Spark와 같은 분석 툴을 설치하는 것으로 마무리해도 좋겠으나
그래도 구색을 갖춰보려고 굳이 NoSQL을 하나 설치해보기로 했다.


HBase는 예전에 설치해보기도 하였고 Cassandra가 더 좋은 성능을 보인다는 말도 있고 또 진입 장벽도 비교적
낮다고 하여 Cassandra를 설치해볼까 고민을 하다가 그래도 Hadoop을 설치해놓은 터라 아무래도 HBase를
설치하는 것이 낫다고 판단되어 결국은 HBase로 결정을 하였다.


하지만 개인적으로 학습하는 수준이라는 것이 뻔한 것이다보니 과한 짓을 하는 것은 아닌가 하는 생각도 든다.
(그렇게 따지자면 지금껏 해온 모든 작업이 다 우도살계인 격이지만…-.-)


설치


앞서 포스팅한 다른 시스템들과 마찬가지로 바이너리 패키지를 다운로드 받아 적절한 위치에 압축을 풀면 설치
끝이다. 나는 1.2.6 버전을 다운로드 받아 /opt 아래 압축을 풀었다. 다른 시스템들과 마찬가지로 버전 번호는
과감히 삭제하고 HBase 홈 디렉토리를 /opt/hbase로 만들었다.




사전 준비


HBase를 설치하기 꺼려졌던 가장 큰 이유는 HBase도 클러스터 관리를 위해 zookeeper를 사용한다는 점이었다.
그리고 예전에 처음 설치할 때부터 의문이었지만 zookeeper가 필요한 시스템들 각각을 위해 별도의 zookeeper
앙상블을 만들어야 하는 것인지 아니면 하나의 zookeeper 앙상블로 다수의 클러스터 시스템을 관리할 수 있는 것인지
하는 부분도 잘 알지 못했다. 잘 알지 못하다보니 가급적이면 zookeeper와 엮이지 않는 시스템을 찾고 싶기도 했다.


그러던 차에 구글 그룹과 호튼웤스 커뮤니티에서 도움이 될만한 글타래들을 찾아 어느정도 답을 얻을 수 있었다.
사실 zookeeper에 대해 조금만 공부를 했더래도 알 수 있는 내용이었지만…


결론부터 말하자면 하나의 zookeeper 앙상블로 다수의 클러스터(나의 경우 Kafka, HA Hadoop, HBase)를
관리할 수 있으며 웬만큼 큰 규모가 아니면 3노드 정도의 앙상블로 충분하다는 것이다(처음 Kafka와 HBase를
설치했을 때는 zookeeper 앙상블을 5대의 노드에 구성했더랬다…-.-).


관련 글타래를 아래에 링크한다.


https://groups.google.com/forum/#!topic/storm-user/cYSZE8RDHJ0

https://community.hortonworks.com/questions/35287/how-to-decide-how-many-zookeepers-should-i-have.html 



설정



Hadoop에 비한다면 크게 설정할 것은 없다.

backup-master

# HA 클러스터를 구성할 경우 백업 마스터로 사용할 호스트명을 기록한다.
SECONDARY-NAMENODE.local


base-site.xml

<!-- 
HBase가 지속적으로 실행되면서 regionserver들과 정보를 공유하는 경로
Hadoop의 core-site.xml에 있는 fs.defaultFS 설정과 동일하게 한다
--> 
<property>
	<name>hbase.rootdir</name>
	<value>hdfs://NAMENODE.local:8020/hbase</value>
</property>
<!--
마스터가 될 노드의 URI
-->
<property>
	 <name>hbase.master</name>
	<value>NAMENODE.local:6000</value>
</property>
<!--
zookeeper 앙상블을 구성하는 노드들의 호스트명
나의 경우 Kafka 설치시 설치했던 라즈베리파이의 호스트명을 적었다.
-->
 <property>
	 <name>hbase.zookeeper.quorum</name>
	<value>rpi1,rpi2,rpi3</value>
</property>
<!--
zookeeper 클라리언트가 사용할 포트. 기본 포트인 2181을 사용한다.
-->
<property>
	<name>hbase.zookeeper.property.clientPort</name>
	<value>2181</value> 
</property> 
<!--
데이터 복제 계수를 3으로 지정하였다.
-->
<property>
	<name>dfs.replication</name>
	<value>3</value>
</property>
<!--
HBase를 완전 분산모드로 사용하기로 하였다.
-->
<property>
	<name>hbase.cluster.distributed</name>
	<value>true</value>
</property>
<!--
하나의 Datanode에서 동시에 서비스 가능한 block 개수 제한.
-->
<property>
	<name>dfs.datanode.max.xcievers</name>
	<value>4096</value>
</property>


regionservers

# regionserver로 사용될 노드들의 호스트명을 적는다.
DATANODE1.local
DATANODE2.local
DATANODE3.local


이렇게 간단하게 설정을 마쳤다.
그런데 각 설정에 대한 설명을 찾다보니 내가 한 설정 항목의 일부는 최근 버전에서는 name이 바뀐 것들이
조금 있었다. 아무래도 공식 사이트를 참조하지 않고 여기 저기 블로그를 기웃거리며 정리하다보니 이런 문제가
생겨버렸다.


게다가 HBase 홒메이지의 설정 관련 항목에 하둡 버전과 그 버전에서 지원하는 HBase 버전을 표로 정리한
내용이 있는데 이상하게도 하둡 3.0.0은 목록에 있는데 내가 설치한 2.9.0은 목록에 없다… 과연 내가 설치한
하둡 2.9.0 + HBase 1.2.6은 올바른 조합인지도 잘 모르겠다…ㅠ.ㅠ 아직도 갈길이 멀다…


https://hbase.apache.org/book.html



일단 이렇게 설정을 하고 배포본을 압축하여 sap 명령으로 backup master와 regionserver들엑 복사를
해준다.


실행


실행은 간단하다. 마스터 노드에서 아래와 같이 실행하면 regionserver들도 함께 실행된다.

hadoop@NAMENODE.local $ /opt/hbase/bin/start-hbase.sh


마지막으로 backup master에서 아래와 같이 실행한다.

hadoop@SECONDARY-NAMENODE.local $ /opt/hbase/bin/master-backup.sh



확인


모든 노드에서 HBase가 정상적으로 실행되면 NAMENODE.local:16010과 SECONDARY-NAMENODE.local:16011에서 아래와 같은 화면을 볼 수 있다.




정리


설정 부분에서도 말한 바와 같이 사실 제대로 설치를 하고 설정을 하기 위해서는 공식 홈페이지만한 참고 자료가
없으나 영어의 압박으로 아무래도 한글로 정리해놓은 블로그를 주로 찾게 된다. 그러다보니 설치하는 버전도
제각각이고 설정의 내용도 제각각이어서 간혹 내가 제대로 하고 있는지 의심이 든다. 추후 공식 자료를 통해 한 번 더 
정리하는 작업을 거쳐야 제대로 된 정보의 공유라고 할 수 있을 것 같다.


이제 계획했던 작업은 Apache Spark 하나가 남았다. Spark에 대한 정리가 끝나면 본격적으로 데이터를 수집하고
저장하고 분석하는 단계를 진행해야 할텐데 이 과정에는 프로그래밍도 필요하기에 더 어려운 작업이 될 것 같다.
하지만 한편으로는 매번 시스템 설치만 해놓고 마치 장식장 안의 인형을 보듯이 지켜보기만 했는데 이제 뭔가 실질적인
작업을 해본다는 측면에서 기대가 되기도 한다.


얼른 달려보자~






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

main










Cluster : The Beginning - Hadoop 2.9.0 설치


이제 라즈베리파이의 구성은 모두 정리가 되었고 맥미니에 클러스터를 구성할 차례이다.
이 글을 쓰는 시점에는 이미 모든 클러스터 구성이 완료 되었으나 여전히 많은 작업이 남아있다.


하지만 모든 클러스터를 구성하는 것 까지는 초보 수준에서 가장 기초적인 설정만으로 진행하고 있으니
같은 맥락에서 진행을 하도록 하겠다.


맥미니에 설치할 Hadoop ecosystem은 3가지로 Hadoop과 HBase 그리고 Spark이다.
HBase는 Cassandra와 고민을 좀 했는데 아무래도 하둡과의 궁합을 생각해서 HBase를 설치하기로 했다.
Spark의 경우 Spark MLlib 때문에 설치해보기로 했는데 메모리를 이용한 시스템이다보니 가정용 PC의 뻔한
메모리 용량으로 제대로 써먹기나 할지 모르겠다(다른 시스템들도 마찬가지지만…).


하둡 배포판 선정


사실 예전에 하둡 1.4와 HBase를 설치했을 때 여러가지 설정과 배포본을 노드에 카피하는 등 많은 작업들이
매우 번거롭게 느껴져서 이번에는 아주 좋은 툴인 Apache Ambari를 사용하여 설치해볼까하고 시도를 해봤다.
그런데 시작부터 막힌 것이 Mac을 지원하지 않아 WMWare에 설치된 Ubuntu에 Ambari를 설치하게 되었다.



일단 설치는 간단하게 되었는데…정작 웹 콘솔을 시작하고 클러스터를 만드는 과정에서 각 노드에 연결을
하지 못하는 문제가 발생을 하였다. 아무래도 Mac에서 진행을 하다보니 지원이 안되는 부분이 있나보다 하고
과감하게 포기를 하고 다시 맨땅에 헤딩하면서 진행을 할 수밖에 없었다.


우선 설치할 시점에서의 최신 버전인 2.9.0 버전을 다운로드 받아 설치하기로 하였다. 그런데 오늘 가서 보니 그새
3.0.0이 새로 릴리즈가 되어있고 2.6.X, 2.7.X, 2.8.X, 2.9.X, 3.0.X가 각각 업데이트가 진행되는 것 같은데
어떤 기준으로 버전이 나누어지고 또 업데이트가 되는지 잘 모르겠다.


배포버전 참조 링크 : http://hadoop.apache.org/releases.html#Download


어쨌든 나는 2.9.0 버전을 선택하여 설치하였다.


설치 환경 및 모드


일단 앞선 몇 번의 포스팅에서 언급한 것과 같이 현재 내가 보유하고 있는 장비는 총 5대의 Mac mini이다.
즉 5대의 PC에 완전 분산모드로 설치를 진행하게 될 것이다. 5대의 host 이름은 각각 다음과 같다.
괄호 안은 떠있게 될 기본 프로세스다. 


  • NAMENODE.local (Active NameNode, JournalNode, ResourceManager, DFSZKFailoverController)
  • SECONDARY-NAMENODE.local (Standby NameNode, JournalNode, DFSZKFailoverController)
    (과거 1.4 설치 때 secondary namenode였음…)
  • DATANODE1.local (DataNode, JournalNode, NodeManager)
  • DATANODE2.local (DataNode , NodeManager)
  • DATANODE3.local (DataNode , NodeManager)


JournalNode 구성 때문에 1대를 더 영입하려다가 참았다…-.-
이후 작성하는 모든 글에서 각 노드는 위에 적은 호스트명을 사용하도록 하겠다.


설치


앞서 설치한 다른 시스템들과 마찬가지로 다운로드 받은 압축 패키지를 적당한 위치에 풀면 설치 끝이다…-.-
나는 현재 모든 시스템들을 /opt 아래에 설치 중이다. 따라서 hadoop의 경로는 /opt/hadoop이고 
버전 정보는 과감하게 빼버렸다.




사전 준비


하둡을 설치하기 전에 한 가지 준비할 것이 있는데 하둡은 마스터(NameNode)와 슬레이브(Datanode)간에
통신을 하는데 SSH를 이용하게 된다. 이 때 SSH 접근 시 비밀번호 인증을 거치게 되면 정상적으로 통신을 할 수
없기 때문에 먼저 비밀번호 인증 없이 접속을 하기 위해 다음과 같은 절차로 준비를 해야 한다.


일반적으로 사용자 계정의 홈 디렉토리에 있는 .ssh라는 디렉토리에 SSH 관련 인증키들이 들어있다. 만일 기존에
사용 중인 인증 키(보통 id_rsa, id_rsa.pub이라는 이름) 파일들이 보이면 그 파일들을 이용하면 될 것이고 파일이
없거나 .ssh 디렉토리 자체가 없다면 다음과 같이 SSH 키를 생성해준다. 이 작업은 Active NameNode 서버와
Standby NameNode 서버에서 각각 진행한다. 아래는 Active NameNode 기준으로 기록하였다.


'hadoop@NAMENODE.local$ ssh-keygen -t rasa -f  ~/.ssh/id_rsa

당연한 이야기이겠지만 Standby NameNode에서 할 때는 nn2_id_rsa와 같이 키 파일 이름을 다르게 해야
나중에 DataNode로 복사를 할 때 파일을 덮어쓰는 문제를 피할 수 있다.


이렇게 하면 인증키 파일이 생성이 된다. 이제 이 인증키 파일 중 공개키에 해당하는 id_rsa.pub 파일을 각 
DataNode들로 복사를 해준다.


'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE1.local:/Users/hadoop/.ssh/id_rsa.pub 
'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE2.local:/Users/hadoop/.ssh/id_rsa.pub 
'hadoop@NAMENODE.local$ scp ~/.ssh/id_rsa.pub hadoop@DATANODE3.local:/Users/hadoop/.ssh/id_rsa.pub 


다음 각각의 DataNode의 ~/.ssh 디렉토리로 이동하여 아래와 같이 인증 키 목록에 NameNode에서 받은
인증키의 내용을 추가해준다.


hadoop@DATANODE1.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys
hadoop@DATANODE2.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys
hadoop@DATANODE3.local$ cat  ~/.ssh/id_rsa.pub >> authorized_keys


이렇게 만들어진 authorized_keys 파일을 열어보면 대략 이렇게 생겼다.




마지막으로 ssh-agent를 실행하고 ssh-add를 해준다(예전에도 이런 것을 해줬는지 가물가물한데 해야 한다는
것을 보니 아무래도 예전에 내가 뭘 잘못했던게지…-.-)


hadoop@NAMENODE.local$ eval "$(ssh-agent -s)"  
Agent pid 59566  
hadoop@NAMENODE.local$ ssh-add ~/.ssh/id_rsa


가운데 줄은 첫 줄 실행의 결과다. 주의할 것은 콘솔창에서 이렇게만 실행하면 그 콘솔창의 세션 내에서만 반영이
된다. 즉, 콘솔창을 죽였다가 새로 실행하면 이 작업을 다시 해줘야 비밀번호 인증 없이 ssh 접속이 가능하게 된다.
또한 이 세션은 실행한 계정 내에서만 유효하다.


하둡 1.X vs 2.X


간단하게 예전에 설치했던 하둡 1.4와 비교를 하고 넘어가겠다. 생각외로 변경된 사항 때문에 설정해야 할 것들이
많아져서 가볍게라도 언급을 해두어야 할 것 같다. 우선 아래 그림을 먼저 보자.




중요한 변화를 2가지만 짚어보면


HA(High Availability) Cluster 구성

하둡 1.X에서는 NameNode는 1대만 설치가 가능하였으나 하둡 2.X에서는 2대 이상의 
NameNode를 설치할 수 있는데 이 모든 NameNode가 동시에 작동하는 것이 아니라
이 중 1대만이 Active NameNode로 활성화 되고 다른 NameNode들은 Standby
NameNode로, 말 그대로 대기를 하고 있다가 Active NameNode가 다운되었을 경우 
Active 상태가 되어 NameNode로서의 임무를 수행하게 된다. 

이런 운영이 가능하려면 NameNode들 간에 항상 데이터가 공유되어야 하며 그 방법에는
NFS(NAS와 같은 공유 저장소)를 이용하는 방법과 zookeeper와 JournalNode를 이용하는
방법이 있는데 보통 zookeeper와 JournalNode를 이용하는 방법을 많이 쓴다고 한다.
JournalNode는 3개 이상 홀수로 구성을 해야 한다.


YARN의 등장

기존에 MapReduce의 작동이 JobTracker와 TaskTracker를 통해 이루어지던 것이
YARN의 ResourceManager와 NodeManager를 통해 자원 관리 및 모니터링이
이루어지도록 바뀌었다.


하둡 1.X에서는 Secondary NameNode라는 개념이 있었는데 2.X에서도 여전히 사용 가능하며
다만 HA 클러스터를 구성하는 경우에는 Secondary NameNode를 사용할 수 없다.


이런 변화로 인해 하둡 2.X에서는 zookeeper에 대한 설정을 해야 하며 JournalNode 프로세스를
띄워야 하고 YARN을 구동시켜야 하는 등 1.X에 비해 해야 할 일이 늘었다. 


참고로 zookeeper는 이전에 Kafka 설치 시 라즈베리파이에 함께 설치한 zookeeper를 함께 사용한다. 


아래 이미지는 2.X의 구조를 나타낸 그림이다.




설정


설치는 언급할 것도 없이 매우 간단하였고…이제는 설정이다. 역시나 설정도 필수적인 몇몇 항목만 제대로 
설정을 하면 나머지는 기본값으로 그냥 사용하면 된다. 그리고 경로도 좀 독특해서 아래와 같은 경로에 설정 파일들이 
존재한다.


/opt/hadoop/etc/hadoop


그런데!
다른 시스템들과는 달리 하둡은 설정 파일에 기본 값들이 들어있지 않다! 즉, 파일에 최상위 엘리먼트 태그만
덩그러니 있고 내용은 비어있다. 따라서 일단 잘 설명되어있는 블로그나 사이트로 가서 기본적인 내용을 
복사해와야 한다…ㅠ.ㅠ 내가 설정한 내용은 다음과 같다.


  • core-site.xml
<!-- 필수 설정 -->
<property>
      <name>fs.defaultFS</name>
      <value>hdfs://NAMENODE.local:9090</value>
</property>
<!-- 아래 2개의 설정은 옵션~
<property> 
      <name>io.file.buffer.size</name>
      <value>131072</value>
</property>
<property> 
      <name>hadoop.tmp.dir</name>
      <value>/opt/hadoop/temp</value>
</property>
-->
<!--
HA Cluster를 구성할 때 JournalNode를 관리하기 위한 zookeeper 서버를 설정 
이 서버들은 이전에 포스팅한 Kafka 설치 관련 내용에서 이미 설치해둔 라즈베리파이들이다. 
-->
<property> 
      <name>ha.zookeeper.quorum</name>
      <value>rpi1,rpi2,rpi3</value>
</property>



  • hdfs-site.xml
<!-- 
아래 내용 중 데이터 복제 계수를 의미하는 dfs.replication가 설정되지 않았는데 기본값으로
3이 적용 된다.
-->
<!-- NameNode가 namespace와 transaction 로그를 저장하기 위한 경로 -->
<property>
          <name>dfs.namenode.name.dir</name>
          <value>/Users/hadoop/data/dfs/namenode</value>
</property>
<!-- DataNode 자체 및 클러스터와의 관계에 대한 메타데이터를 저장하기 위한 경로 -->
<property>
          <name>dfs.datanode.data.dir</name>
          <value>/Users/hadoop/data/dfs/datanode</value>
</property>
<!-- JournalNode의 메타데이터를 저장하기 위한 경로 -->
<property>
          <name>dfs.journalnode.edits.dir</name>
          <value>/Users/hadoop/data/dfs/journalnode</value>
</property>
<!-- 이하는 HA Cluster 구성을 위해 필요한 내용 -->
<!-- 클러스터 내의 nameservice를 대표하는 논리적인 이름 -->
<property>
	<name>dfs.nameservices</name>
         <value>mazberrycluster</value>
</property>
<!-- 위에서 설정한 nameservice 내에서 사용될 NameNode들의 논리적 이름 -->
<property>
	<name>dfs.ha.namenodes.mazberrycluster</name>
	<value>nn1,nn2</value>
</property>
<!-- 첫 번째 NameNode(nn1)에서 사용할 RPC 호스트:포트 -->
<property>
	<name>dfs.namenode.rpc-address.mazberrycluster.nn1</name>
	<value>NAMENODE.local:8020</value>
</property>
<!-- 두 번째 NameNode(nn2)에서 사용할 RPC 호스트:포트 -->
<property>
	<name>dfs.namenode.rpc-address.mazberrycluster.nn2</name>
	<value>SECONDARY-NAMENODE.local:8020</value>
</property>
<!-- 첫 번째 NameNode(nn1)에서 사용할 Web UI 호스트:포트 -->
<property>
	<name>dfs.namenode.http-address.mazberrycluster.nn1</name>
	<value>NAMENODE.local:50070</value>
</property>
<!-- 두 번째 NameNode(nn2)에서 사용할 Web UI 호스트:포트 -->
<property>
	<name>dfs.namenode.http-address.mazberrycluster.nn2</name>
	<value>SECONDARY-NAMENODE.local:50070</value>
</property>
<!-- 각 JournalNode에서 공유할 데이터를 저장할 URI -->
<property>
	<name>dfs.namenode.shared.edits.dir</name>
	<value>qjournal://NAMENODE.local:8485;SECONDARY-NAMENODE.local:8485;DATANODE1.local:8485/mazberrycluster</value>
</property>
<!-- 클라이언트가 Active NameNode에 접근할 때 사용할 JAVA 클래스 -->
<property>
	<name>dfs.client.failover.proxy.provider.mazberrycluster</name>
	<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- Failover가 발생했을 때 Active NameNode로의 접근을 차단할 방법 -->
<property>
        <name>dfs.ha.fencing.methods</name>
        <value>sshfence</value>
</property>
<!-- 위에서 ssh를 사용하기로 했기 때문에 ssh 인증키 경로를 설정해준다. -->
<property>
        <name>dfs.ha.fencing.ssh.private-key-files</name>
        <value>/Users/hadoop/.ssh/id_rsa</value>
</property>
<!-- 자동으로 Failover 처리를 할 것인지 -->
<property>
        <name>dfs.ha.automatic-failover.enabled</name>
        <value>true</value>
</property>



  • slaves
## Slave. 즉, DataNode로 사용할 서버의 호스트명을 적어준다.
DATANODE1.local
DATANODE2.local
DATANODE3.local



  • mapred-site.xml
<!-- Map-Reduce 실행 시 관리 프레임워크로 YARN을 지정 -->
<property>
      <name>mapreduce.framework.name</name>
      <value>yarn</value>
</property>



  • yarn-site.xml
<!-- Map-Reduce 실행시 사용할 셔플 서비스 설정 -->
<property>
      <name>yarn.nodemanager.aux-services</name>
      <value>mapreduce_shuffle</value>
</property>
<!-- 위에 설정한 셔플 수행을 위한 JAVA 클래스 -->
<property>
      <name>yarn.nodemanager.auxservices.mapreduce.shuffle.class</name>
      <value>org.apache.hadoop.mapred.ShuffleHandler</value>
</property>
<!-- 위에 설정한 셔플 수행을 위한 JAVA 클래스 -->
<property>
          <name>yarn.nodemanager.local-dirs</name>
          <value>/opt/hadoop/data/yarn/nm-local-dir</value>
</property>
<!-- ResourceManager 상태가 저장될 경로 -->
<property>
          <name>yarn.resourcemanager.fs.state-store.uri</name>
          <value>/opt/hadoop/data/yarn/system/rmstore</value>
</property>
<!-- ResourceManager가 수행될 노드의 호스트명 -->
<property>
          <name>yarn.resourcemanager.hostname</name>
          <value>NAMENODE.local</value>
</property>
<!-- YARN의 web proxy 주소:포트 -->
<property>
          <name>yarn.web-proxy.address</name>
          <value>0.0.0.0:8089</value>
</property>


휴…이제 설정이 끝난 것 같다.
이렇게 설정이 끝났으면 설치한 하둡 배포판을 모든 노드의 같은 경로에 복사해준다.



마지막으로 데몬 실행 파일들에 보면 실제로 데몬을 실행하는 코드가 모두 nohup으로 시작하는데 Mac에서는
nohup 명령어가 없다. 따라서 파일을 열어 nohup으로 시작하는 명령 코드에서 nohup을 모두 제거해주어야 한다.


실행


상당히 많은 분량의 설정이 있었던 만큼 실행 역시 순탄치 않다.
일단 기본적으로 위에 언급된 것만 해도 NameNode, DataNode, JournalNode, YARN 등이 있다.
게다가 Active와 Standby NameNode를 지정해주기 위한 단계와 Failover 처리를 위한 프로세스도
띄워주어야 한다.


이제부터 차근차근 순서를 밟아 실행을 해보자. 우선 $HADOOP_HOME으로 이동하자.


$ cd /opt/hadoop



  • Failover 컨트롤러 실행을 위해 먼저 zookeeper를 초기화 해주어야 한다.
hadoop@NAMENODE.local$ bin/hdfs zkfc -formatZK



  • JournalNode로 사용할 서버에서 각각 JournalNode 프로세스를 실행한다.
    나의 경우 NAMENODE.local, SECONDARY-NAMENODE.local, DATANODE1.loca의 3대이다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start journalnode
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start journalnode
hadoop@DATANODE1.local$ sbin/hadoop-daemon.sh start journalnode



  • NameNode를 포맷한다.
hadoop@NAMENODE.local$ bin/hdfs namenode -format



  • Active NameNode를 실행한다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start namenode



  • zookeeper Failover 컨트롤러를 실행한다.
hadoop@NAMENODE.local$ sbin/hadoop-daemon.sh start zkfc



  • 전체 DataNode를 실행한다 (각각의 DataNode에서 hadoop-daemon.sh로 실행해도 된다.)
hadoop@NAMENODE.local$ sbin/hadoop-daemons.sh start datanode



  • Standby NameNode로 이동하여 Active NameNode의 메타 데이터를 Standby NameNode로 
    복사한다.
hadoop@SECONDARY-NAMENODE.local$ bin/hdfs namenode -bootstrapStandby



  • Standby NameNode를 실행한다.
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start namenode



  • Standby NameNode용 zookeeper Failover 컨트롤러를 실행한다.
hadoop@SECONDARY-NAMENODE.local$ sbin/hadoop-daemon.sh start zkfc



  • 다시 Active NameNode로 돌아와 YARN을 실행한다.
hadoop@NAMENODE.local$ sbin/start-yarn.sh



  • 마지막으로 Map-Reduce를 위한 history 서버를 실행한다.
hadoop@NAMENODE.local$ sbin/mr-jobhistory-daemon.sh start historyserver


이렇게 해서 하둡으로의 긴 여정이 끝이났다…ㅠ.ㅠ


모니터링


하둡을 설치하고 나면 아래와 같이 Active NameNode와 Standby NameNode에서 각각 관리 사이트로
접속을 할 수 있다. 기본 포트는 50070이다.




정리


전체적으로 상당히 긴 과정이었다. 이 것이 그저 꼴랑 5대의 노드로 구성된 클러스터이니 망정이지 수 백, 수 천 대의
노드로 구성된 클러스터라면 정말 관리 시스템의 도움이 없이는 제대로 운영할 수 없을 것이다.


일단 전체 에코시스템 구성에서 가장 큰 고비를 넘긴 것 같다. 이제 정리할 것은 HBase와 Spark만 남겨두고 있다.
하지만 이미 모든 시스템을 설치한 후 각 시스템들을 어떻게 연동하여 데이터를 다룰 것인지에 대해 고민을 하다보니
이후가 더 어려울 것 같다는 생각이 든다.


그래도 차근차근 끝까지 가봐야겠다.






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^








Cluster : The Beginning - Apache Kafka와 EMQ 연동


HAProxy, EMQ, Kafka 설치를 통해 일단 입구는 마련이 되었다…고 생각했으나 아직 한 가지 남은 것이 있었다.
단순한 메신저 기능이나 M2M 통신만을 위한 것이 아니라 데이터 분석이 목적이라면 EMQ를 통해 들어온 데이터를 
저장해야 할텐데 아직 그 기능이 구현되지 않았다.


EMQ의 토픽을 영구 저장소에 저장하는 다른 방법이 있는지는 모르겠으나 나의 경우 일단 Kafka가 설치되어있고
곧 Hadoop과 HBase를 설치할 예정이기에(2018년 1월 2일 현재 설치 완료됨) 다음과 같은 경로로 저장을 하기로
했다.




그리 어렵지 않은 내용이니 간단하게 소개하고 마치도록 하겠다.


1차시기 실패 : emqttd_plugin_kafka_bridge


우선 처음 검색해서 찾아낸 것이 emqttd_plugin_kafka_bridge란 놈이었다. 이름으로 알 수 있듯이 EMQ와의
연동을 고려하여 만들어진 것 같은데…어쩐 일인지 빌드가 되지 않았다. 우선은 라즈베리파이라서 그런가보다 하고
넘어 가고 다른 대안을 찾기 시작했다. mqttKafkaBridge와 같은 몇몇 도구들도 찾아보았으나 라즈베리파이에서는
잘 실행이 안되었다 (아래 링크는 시도를 해보았거나 검색 결과로 찾은 도구들이다). 



결국 아래 링크된 페이지를 참조하여 kafka에 있는 connect-standalone.sh를 이용하여 연동하는데 성공하였다.


https://howtoprogram.xyz/2016/07/30/apache-kafka-connect-mqtt-source-tutorial/


connect-standalone.sh 이용하기


우선 나의 경우 위에 링크한 페이지를 참고로 하여 mqtt 연동을 위한 설정은 mqtt.properties 파일에 
아래와 같이 하였다. 이 파일은 $KAFKA_HMOE/config에 위치해야 한다.

# 이 커넥터의 이름과 커넥터로 사용할 클래스 그리고 task의 최댓값을 설정한다.
name=mqtt
connector.class=com.evokly.kafka.connect.mqtt.MqttSourceConnector
tasks.max=1

# kafka쪽에서 사용할 토픽 이름이다.
kafka.topic=mqtt-kafka

# mqtt에 연결할 kafka broker의 아이디이다. 나머지 2대의 kafka broker에는 각각
# mqtt-kafka-2, mqtt-kafka-3으로 설정이 되어있다.
mqtt.client_id=mqtt-kafka-1

# 연결 관련 설정으로 위에 링크한 참조 페이지 내용을 그대로 사용하였다.
mqtt.clean_session=true
mqtt.connection_timeout=30
mqtt.keep_alive_interval=60

# MQTT 관련 설정. mqtt.server_uris는 나의 경우 EMQ를 노드 2개의 클러스터로 구성하였고
# 부하 분산을 위해 HAProxy가 설치된 서버 주소로 설정하였다. 그리고 EMQ에서 사용할 토픽은
# /mqtt로 설정하였다.
mqtt.server_uris=tcp://172.30.1.23:1884
mqtt.topic=/mqtt


이와 같이 설정한 후 connect-standalone.sh를 다음과 같이 실행한다(물론 이미 zookeeper와 kafka는 
실행이 된 상태여야 한다).

$ cd $KAFKA_HOME/bin
$ ./connect-standalone.sh config/connect-standalone.properties config/mqtt.properties


connect-distribute.sh도 있는데 standalone과 어떤 차이가 있는지 잘 모르겠다. 추후 다시 확인을 해봐야겠다.


연동 결과


connect-standalone.sh를 실행하고 나면 잠시 후 EMQ의 웹 화면에 아래와 같이 mqtt.properties에 설정한
mqtt.client_id 값들이 메뉴 곳곳에 보이는 것을 확인할 수 있다.


EMQ에 연결된 클라이언트로 mqtt.properties에 설정한 클라이언트 Id가 보인다.

현재 연결된 세션에도 역시 클라이언트 Id가 보인다.


마찬가지로 구독자 목록에도 클라이언트 Id가 보이며 구독하는 토픽은 mqtt.topic에 설정해준 값인 /mqtt
보인다.


마지막으로 Kafka Manager에서 Topic List메뉴를 보면 mqtt.properties의 kafka.topic 항목에 설정한
mqtt-kafka가 보이는 것을 확인할 수 있다.




정리


앞서 정리한 내용과 마찬가지로 세세한 부분까지 확인하지는 못했지만 우선 Kafka와 EMQ를 연동하는 것 까지
작업을 완료 하였다. 이제 EMQ -> Kafka -> Hadoop(HBase)로 이어지는 프로세스에는 아두이노로 만들
온습도계의 데이터를 저장할 것이고 Kafka Producer -> Kafka -> Hadoop(HBase)로 이어지는 프로세스에는
일반 텍스트 데이터를 저장하게 될 것이다.


이렇게 해서 데이터 컬렉션을 담당할 부분은 모두 설치가 완료가 되었다.
다음 시간부터는 데이터 저장 및 분석을 위한 Hadoop과 HBase 설치에 대한 내용을 정리하고 그 이후 데이터의 
실시간 분석 및 머신 러닝을 위한 Apache Spark 설치에 대한 내용으로 마무리를 하도록 하겠다.


어느덧 해가 바뀌었고 다행히 설치 자체는 순조롭게 진행이 되고 있다.
부디 늦지 않게 데이터가 수집되고 수집한 데이터를 분석하는 것 까지 정리 할 수 있기를 바란다.


이 글을 보고 계시는 분들께 새해 인사 전하면서 이만 줄인다.


무술년 한 해 모두 행복하시기를 바랍니다.
새해 복 많이 받으세요!!! 






블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^








Cluster : The Beginning - Raspberry pi에 Apache Kafka 설치하기


이전 작업으로 일단 기본적인 출발은 마무리가 되었다.
하지만 EMQ를 설치한 내용에서 언급했듯이 MQTT는 경량화 프로토콜로 주로 IoT에 특화되어 있다고 볼 수 있어
(Facebook Messanger에서 MQTT를 사용한다고 하는데 현재형인지 또 어떤 영역에 어떻게 사용하는지는 잘
모르겠다) 아직은 절반의 성공일 뿐이다.


센서 데이터 분석을 위한 환경 뿐만 아니라 일반적인 데이터 분석에 대한 환경을 갖추기 위해서는 MQTT라는 진입점
만으로는 부족한 것이다. 그래서 일반 데이터를 수집하는 부분은 예전에 한 번 시도를 해보았던 Apache Kafka를
이용하기로 했다. Kafka를 이용해 수집할 데이터도 예전과 마찬가지로 트위터의 데이터가 될 것이다. 다만 클라이언트는
예전에는 Node.js를 이용하여 구현했으나 이번에는 다른 방식을 찾아볼 생각이다.


이번 포스팅은 바로 이 Apache Kafka를 라즈베리파이에 설치하고 구동하는 과정을 정리해보겠다.
사실 2016년도에 정리한 내용의 축약 버전이나 다름없어 마지막 정리에 2016년에 포스팅한 내용을 모두
링크하였으니 참고하시길 바란다.


개요 - Kafka는 MQTT와 뭐가 다른가?


일단 Kafka 역시 Message Queue기반의 시스템이다. 용어의 차이는 있지만 대체로 구성이 비슷하다.




아주 심플하고 직관적인(하지만 정확하진 않은…-.-) 비유를 들자면 다른 Message Queue 시스템을 퀵서비스라고
한다면 Kafka는 택배라고 할 수 있을 것이다. 퀵서비스는 작은 물건이나 서류를 송신자로부터 수신자 에게 직접 전달을
해주지만 택배는 큰 덩치의 물건들을 물류창고에 집하했다가 다시 배송을 한다. 하지만 이 것은 어디까지나 간단한 비유고
자세한 차이점은 아래 블로그에 잘 정리가 되어있다.

http://epicdevs.com/17


일단 Kafka는 용량이 큰 데이터 전송에 유리하고 클러스터를 통해 데이터를 ‘복제’해둘 수 있으며, Message Queue가
broker에서 subscriber로 topic을 push해주는 반면 kafka는 consumer가 필요할 때 broker로부터 pull 방식으로
가져다 쓸 수 있다는 차이 정도만 알아두면 될 것 같다.


zookeeper 설치, 설정, 실행


개요에서 설명한 것과 같이 Kafka의 경우 클러스터를 구성하여 분산처리를 할 수 있으며 전송되는 데이터를 여러 노드에
복제해놓을 수도 있다. 하지만 이러한 분산 처리를 하기 위해서는 zookeeper라는 분산 코디네이터의 도움을 받아야
한다. 즉, Kafka를 사용하기 위해서는 zookeeper를 먼저 설치해야 한다는 뜻이다.


라즈베리파이에 zookeeper 설치는 매우 간단해서 그냥 바이너리 배포판을 다운로드 받아 적당한 위치에 압축을
풀고 환경에 맞게 설정한 후 실행을 하면 된다…-.-


나는 일단 3.4.10 버전을 받아서 /opt/zookeeper에 압축을 풀었다.
설정은 딱 3가지만 하면 된다.

#데이터를 저장할 디렉토리를 설정한다.
dataDir=/var/lib/zookeeper

#간단하게 기본 설정 파일에서 주석만 풀어주면 된다. 
#주석 처리되어있으면 서버간 통신 때 connection refused가 발생한다.
maxClientCnxns=60

#zookeeper의 클러스터는 별도로 앙상블이라고 불리우는데 앙상블을 구성할 서버 주소를 적어준다.
server.0=172.30.1.54:2888:3888
server.1=172.30.1.13:2888:3888
server.2=172.30.1.42:2888:3888


zookeeper 앙상블이 정상적으로 실행되기 위해서는 dataDir에 지정된 경로에 myid 파일이 필요하며 이 파일에는
3번째 서버 설정에서 정의된 서버 ID가 적혀있어야 한다. 위 설정을 기준으로 보자면 server.0 서버에는 0이,
server.1 서버에는 1이, server.2 서버에는 2가 적혀 있어야 한다.


앙상블(클러스터)을 구성하는 모든 서버에 동일한 설정을 해주고 나서 각 서버에서 아래와 같이 zookeeper 서버를
실행해준다.

$ $ZOOKEEPER_HOME/bin/zkServer.sh start


한가지 주의할 사항은 클라이언트의 요청을 처리하는데 있어서 leader 역할을 하는 한 대의 노드에서만 읽기와 쓰기가
모두 가능하다. follower에서는 오직 읽기만 처리 가능하며, 만일 쓰기 요청이 오면 각 follower 노드들은 그 요청을
leader 노드에 위임하게 된다.


어느 서버가 leader고 어느 서버가 follower인지는 zookeeper에서 확인 가능한데 다음 명령어로 확인 가능하다. 
아래는 현재 노드가 follower임을 보여준다.




zookeeper에 대한 기본적인 내용은 이 것이 전부다. 하지만 분산 시스템을 관리한다는 본연의 임무를 생각해본다면
zookeeper에 대해 알아야 할 내용은 상당히 많다. 또한 zookeeper API를 이용하면 zookeeper를 통해 관리되는
분산 시스템을 직접 만들 수도 있다. 한마디로 zookeeper에 대한 것만 공부하자고 해도 상당히 많은 시간이 필요하므로
여기서는 이정도로 마무리 하겠다.


Kafka 설치


지금껏 진행해온 다른 시스템 설치와 마찬가지로 설치 자체는 매우 간단하다. 바이너리 배포본을 다운로드 한 후
압축을 풀고, 설정하고, 실행하면 된다.


나의 경우 일단 Kafka는 2.11-1 버전을 다운로드 받았고 /opt/kafka에 압축을 풀었다.




Kafka 설정


Kafka의 설정 파일 위치는 다음과 같다. 나는 /opt/kafka에 설치를 했으니 /opt/kafka/config 아래에 있는
server.properties를 수정하면 된다.




이전과 마찬가지로 반드시 설정해야 할 내용만 정리해보자.

#앞서 zookeeper 설정에서 설명한 서버 아이디를 적어준다. 여기는 172.30.1.54 서버이므로
#server.0=172.30.1.54:2888:3888 설정을 참고하여 0으로 설정하였다.
broker.id=0

#로그를 기록할 경로를 지정한다.
log.dirs=/var/lib/kafka-logs

#topic을 저장할 파티션을 몇개로 할 지 지정한다. 서버가 3대이니 일단 3으로 지정해보았다.
#이렇게 설정하면 하나의 데이터 파일이 3개로 쪼개져서 저장이 된다.데이터 파일이 Topic으로 들어오는 데이터가       #3영개의 영역으로 나뉘어서 저장이 된다.
#하지만 partition이란 하나의 Topic을 몇 개로 나눌지를 결정하는 것이지 #물리적 서버의 댓수와는 상관이 없다. num.partitions=3 #데이터 파일의 복제본을 몇개나 가지고 있을지 설정한다. 3으로 설정했으니 3개의 복제본이 존재하게 된다. offsets.topic.replication.factor=3 #클러스터 관리를 위한 zookeeper 서버 목록을 적는다. zookeeper 설정에서는 IP 주소로 설정했는데 #여기서는 host 이름으로 설정하여 일관성이 없는 설정이 되긴 했지만...-.- #각 서버는 다음과 같이 매핑되니 참고하시길 바란다. #rpi1=172.30.1.54, rpi2=172.30.1.13, rpi3=172.30.1.42 zookeeper.connect=rpi1:2181,rpi2:2181,rpi3:2181


위 내용만 설정하면 kafka 서버를 실행할 수 있다.


마지막으로 num.partitions과 offsets.topic.replication.factor 설정이 어떻게 반영되는지에 대해 아래와 같이
그림으로 간단하게 표현을 할 수 있다.




위 그림을 설명하자면 다음과 같은 구조의 경우라 볼 수 있다.

  • 3개의 노드 
  • 3개의 파티션(num.partitions=3)
  • 3개의 복제본(offsets.topic.replication.factor=3)


여기서 주의해서 볼 것은 leader와 follower로 항상 leader에만 쓰기가 가능하며 leader에 데이터가 기록되면
기록된 데이터가 follower로 복제된다는 것이다.


보다 상세한 내용은 좀 더 공부를 한 후 다시 정리해보도록 하겠다.


실행


실행은 /opt/kafka/bin경로로 이동하여 다음과 같이 입력하면 된다.

$ ./kafka-server-start.sh ../config/server.properties


만일 JMX를 이용한 모니터링 도구를 이용하고자 한다면 다음과 같이 실행한다.

$ env JMX_PORT=9000 ./kafka-server-start.sh ../config/server.properties


이렇게 실행을 한 후 아래 2개의 모니터링 도구를 사용할 수 있다.

Kafka Offset Monitor : http://quantifind.github.io/KafkaOffsetMonitor/

Kafka Manager : https://github.com/yahoo/kafka-manager


주의 사항


2016년도에 Kafka를 설치할 때는 맥미니에 설치하였지만 이번에는 라즈베리파이에 설치를 하였다.
이 차이는 결코 작은 차이가 아니다. 하드웨어 사양으로 인해 라즈베리파이에서는 사용할 수 있는 자원이
매우 한정적인 것이다. 실제로 라즈베리파이에서 kafka를 실행했을 때 잦은 빈도로 메모리 부족 현상이
발생을 하였다. 따라 일단 라즈베리파이에서 안정적으로 실행을 하기 위해서는 kafka-server-start.sh 파일의
다음 부분을 찾아 Xmx와 Xms를 적절히 수정해주어야 한다. 기본 값은 1G이다.

export KAFKA_HEAP_OPTS="-Xmx512M -Xms512M"



정리


사실 라즈베리파이에서 설치 및 구동을 한 것 외에는 2016년도에 정리했던 내용과 별 다른 점이 없다.
다시 정리한다는 것이 중복된 작업일 수도 있으나 복습한다는 의미로 한 번 더 정리해보았다.
그런 의미에서 가장 중요한 부분은 ‘주의 사항’이 아닐까 싶다.


가장 기초적인 설치,설정,실행 부분만 짚고 넘어갔으니 2016년도의 Kafka 관련 모든 글을 링크하면서
이번 포스팅을 마칠까 한다.











블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^






Cluster : The Beginning - Raspberry pi에 HAProxy 설치하기


지난시간 까지 2대의 라즈베리파이에 EMQ를 클러스터링하여 설치하는 작업을 진행하였다.
그런데 한 가지 문제가 생겼다. 일반 가정집에서 공유기를 통해 접속을 하다보니 2대 중 한대로만 접속이 이루어진다는
점이다. 혹시나 해서 공유기의 트래픽 관리에 외부 포트는 동일하게, 내부 서버는 서로 다르게 설정을 해보아도 역시나
가장 마지막에 등록된 정보로만 통신이 이루어졌다.


이렇게 되면 세션은 공유가 되지만 만약 외부에서 접속되는 한 대의 서버가 다운되면 전체 시스템을 사용할 수 없게
되는 것이다. 결국 접속을 분산시킬 필요가 생겼다. 그리고 그렇게 해서 HAProxy라는 솔루션을 찾아내었다.


더불어 애초에 EMQ 2대 Apache Kafka 3대로 클러스터를 구성할 생각이었는데 부랴부랴 HAProxy를 위한 
1대의 라즈베리파이를 추가로 구입하여 총 6대의 클러스터가 되었다.



Clustering과 Load Balancing


일반적으로 성능 향상을 위해 여러대의 서버에 동일한 구성을 하여 함께 운영하는 경우가 많다.
그리고 이렇게 구성하는 경우 Clustering이라든가 Load Balancing이라는 용어가 많이 쓰이는데 과연 
이 둘의 차이는 무엇일까?


가장 단순하게 표현하자면 Clustering은 여러대의 컴퓨터 그룹이 같은 정보를 가지고 함께 일을 하는 것이고
Load Balancing이라는 것은 각각의 컴퓨터가 공평하게 일할 수 있도록 일감을 나누어 주는 것이라고 생각하면
되겠다. 이렇게 정의할 때 Clustering은 같은 정보에 방점이 찍히고 Load Balancing은 나누어 주는
방점이 찍히게 된다. 즉, Clustering은 그룹을 지어 함께 일을 하는 서버간의 관계에 대한 개념이고 Load Balancing은
클라이언트에서 서버로 접속하는 과정에서의 처리에 대한 개념이라고 보면 되겠다.

 



여러 대의 컴퓨터를 대상으로 한다는 것 외에는 서로 다른 개념이고 종속관계를 나눌 수는 없지만
최근 Clustering을 지원하는 솔루션들은 내부적으로 Load Balancing을 함께 지원하는 경향이 있다. 하지만 
Load Balancing을 위한 솔루션이 Clustering을 지원하는 경우는 거의 없다.


예를 들어 1대의 서버로 서비스를 제공할 경우 그 서버가 다운되면 서비스 자체를 제공하지 못하므로 2대의 서버에 
각각 Tomcat을 설치하여 동일한 서비스를 제공하고 싶다고 하자. 각각을 Tomcat1, Tomcat2라고 했을 때
Tomcat1로만 또는 Tomcat2로만 접속이 가능하다면 2대의 서버를 구성한 의미가 없어진다. 그래서 서버 앞단에
Load Balancing을 위한 장비를 두고 적절한 알고리즘을 통해 각각의 클라이언트들이 Tomcat1과 Tomcat2에
적절하게 분산되어 접속하도록 조정을 해주는 것이다.


그런데 Load Balancing만 하는 경우에는 문제가 발생할 수 있다. 아래 그림을 보면 client1과 client2가 Load 
Balancer를 통해 각각 Tomcat1과 Tomcat2로 적절하게 나누어 요청을 수행하고 있다. client1은 Tomcat1에
문서 파일인 B를 업로드 했고 client2는 Tomcat2에 그림파일인 A를 업로드 했다. 그런데 Tomcat2 서버에
장애가 발생하여 접속이 불가능하게 되면 Load Balancer는 이후 모든 접속을 정상 작동 중인 Tomcat1로 보낸다.
이 때 client2의 입장에서는 Load Balancer 이후의 구조에 대해서는 알지 못하므로 분명 자신은 그림 파일 A를
서버에 업로드 했는데 그 업로드한 파일을 찾을 수 없게 된다.




이러한 문제 때문에 보통 Load Balancing을 하면 Clustering도 함께 고려를 해야 한다. 물론 간단하게 Tomcat은
이중화를 하되 DB는 1대만 설치하여 중요 정보만 공유하는 것도 고려해볼 수 있을 것이다.


결론적으로 Clustering과 Load Balancing은 다음과 같이 구분지어 볼 수 있을 것이다.



HAProxy


EMQ의 경우 clustering을 통해 상태 공유는 되지만 클라이언트와 접속하는 지점에서의 load balancing은 별도의
작업을 해주어야 한다. 일반적으로 널리 알려진 load balancing 장비는 L4 Switch라는 하드웨어 장비가 있다.
하지만 개인이 그런 비싼 네트워크 장비를 사용할 수도 없을뿐더러 사용할 필요도 없다…우도살계인 격이다.


그러다가 발견한 것이 HAProxy라는 솔루션이다. S/W적으로 load balancing을 지원해주는 솔루션이었다.
홈페이지는 다음과 같다.

http://www.haproxy.org


사실 HAProxy는 전체 구성요소에서 고려하고 있지 않던 부분이라 아주 기초적인 부분만 확인했다.
자세한 내용은 HAProxy로 검색하면 많은 정보를 얻을 수 있으니 여기서는 간단하게 설치와 설정 그리고
모니터링 웹 콘솔에 대해서만 살펴보겠다.


설치


역시나 소스를 컴파일하는 설치 방법이 많이 검색되는데 나는 심플하게 apt-get으로 설치하였다.


$sudo apt-get install haproxy 


홈페이지에는 현재 최종 릴리즈 버전이 1.9인데 apt-get으로 설치하니 1.7.5-2 버전이 설치되었다.
이렇게 설치하고 나면 /etc아래에 haproxy 디렉토리가 생성되고 그 아래 설정파일인 haproxy.cfg가
위치한다.


설정


HAProxy의 설정은 몇개의 영역으로 구분되는데 간단하게 살펴보면 다음과 같다.


  • global : 이름 그대로 전역 변수에 대한 설정으로 로그, 상태, 소유자 및 소유 그룹 SSL 관련 설정들이 있다.
  • default : 아래 내오는 세부 설정에서 명시적으로 추가하지 않은 설정은 이 default 설정을 따른다.
  • frontend : 클라이언트가 접속하는 것과 관련된 설정이다. 기본적으로 외부에서 접속할 포트 정도 지정한다.
  • backend : frontend와 짝을 지어 설정하며 frontend 설정을 통해 접속한 클라이언트가 실제 요청을 보낼 서버를 지정한다.
  • listener : frontend와 backend를 한번에 설정할 때 사용한다. 주로 TCP 연결에 사용한다.


각 설정의 뒤에는 설정을 대표하는 이름을 적게 된다. 그 이름은 모니터링 화면에 표시하여 구분할 수 있도록 한다.
앞서 EMQ에서와 마찬가지로 내가 설정한 부분만 간단하게 살펴보자. global과 default에서는 유의미한 수정이
없으므로 frontend와 backend 그리고 listener 설정만 보도록 하겠다.


#frontend와 backend 설정은 EMQ의 모니터링을 위한 웹 접속 설정이다.
#외부에서 8080포트로 접속을 하게 되면 backend에 설정된 172.30.1.9 서버와 172.30.1.25 서버의
#18083 포트로 접속을 하게 되는데 이 때 클라이언트를 두 서버로 분배하는 알고리즘은 roundrobin이다.
#mode는 프로토콜을 설정하는 항목인데 여기서는 지정을 안했기 때문에 default 설정에 있는 http 접속을
#처리한다.
frontend http-in 
	bind    *:8080
	default_backend servers

backend servers
	balance roundrobin
	server server1 172.30.1.9:18083 maxconn 2048
	server server2 172.30.1.25:18083 maxconn 2048

#아래 설정은 클라이언트로부터 EMQ boker에 접속하기 위한 설정이다.
#HAProxy를 사용하게 된 것도 바로 이 설정이 필요했기 때문이다.
#외부에서 1883 포트로 접속을 하게 되면 두 서버의 1883 포트로 접속이 분배되며 역시
#분배 알고리즘은 roundrobin이다. 프로토콜을 설정하는 mode는 tcp로 설정한다.
listen  tcp-in
        balance roundrobin
        bind    *:1883
        log     global
        mode    tcp
        option  tcplog
        server  mtqqserver1     172.30.1.25:1883
        server  mtqqserver2     172.30.1.9:1883

#아래 설정은 위 설정과 동일한데 개인적으로 위 내용은 모바일이나 IoT로부터의 접속에 사용하기 위해
#설정하였고 아래 내용은 kafka에서 EMQ broker의 메시지를 subscribe하기 위해 따로 설정하였다.
listen  mqtt-kafka
        bind    *:1884
        mode    tcp
        option  clitcpka
        timeout client 3h
        timeout server 3h
        option  tcplog
        balance leastconn
        server  mtqqserver1     172.30.1.25:1883        check
        server  mtqqserver2     172.30.1.9:1883         check

#이 설정은 HAProxt의 모니터링을 위한 웹 콘솔에 접근하기 위한 설정이다.
#이 설정의 이름은 stats로 정해져 있으며 uri의 경우 주소:포트 뒤에 따라올 문자열로
#임의로 설정하면 된다.
listen  stats
        bind    *:8081
        mode    http
        stats   enable
        stats   uri     /haproxy?stats
        stats   auth    guest:guest
        stats   refresh 5s


기본적으로 이정도만 해도 원하는 바는 얻을 수 있다. 좀 더 세밀한 설정을 위해서는 보다 많은 내용을 추가해야 하지만
앞서 말했듯이 HAProxy는 가볍게 지나가도록 하겠다.


실행


실행과 종료는 간단하게 다음과 같이 하면 된다.


$/etc/init.d/haproxy start
$/etc/init.d/haproxy stop


설정이 바뀌면 다음과 같이 재시작 한다.


/etc/init.d/haproxy restart

모니터링


위 설정에서 이미 모니터링을 위한 웹 콘솔에 대한 설정은 마친 상태이다. 설정에 적힌 포트로 접속만 하면 된다.
설정에 따라 브라우저에 아래 주소를 입력하면 모니터링 화면이 뜬다.


http://localhost:8081/haproxy?stats




테스트


별다른 스크린샷은 올리지 않겠지만 지난 번 포스팅에 설명했던 MQTT 클라이언트로 connect와 disconnect를
반복해보면 EMQ 모니터링 화면의 Clients 메뉴에 한 번은 172.30.1.9 서버로, 한 번은 172.30.1.25 서버로
번갈아 접속되는 모습을 볼 수 있다.


정리


이렇게 해서 갑작스럽게 설치하게 된 HAProxy에 대한 정리를 마친다.
물론 집에서 개인 프로젝트용으로 구성하는 서버에 뭘 이런 것까지 설치해야 하나 싶지만 기왕에 다수의 장비를
구성하게 된 김에 곁들여서 한 번 설치를 해보았고 나름 작동하는 모습을 보니 재미는 있다^^;;;

다음 포스팅에서는 나머지 3대의 라즈베리파이에 Apache Kafka를 설치하고 설정 및 실행시키는 과정을
정리해보도록 하겠다.







블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^







Cluster : The Beginning - Raspberry pi에 MQTT (EMQ) 설치하기


클러스터의 입구 - MQTT


현재 근무하는 곳에서도 ActiveMQ를 쓰고 있고 RabbitMQ도 많이 들어보았지만 정작 MQTT라는 프로토콜에
대해서는 제대로 모르고 있었다. 그저 위에 언급한 시스템들이 message queue를 구현한 것이라고 막연히 알고
있었을 뿐 그 내부에 대해서는 무지했던 것이다(물론 무지한 것은 지금도 마찬가지다…-.-)


그러다가 이번에 IoT와 관련하여 아두이노로 만든 센서 기반의 작은 소품들로부터도 정보를 받아보겠다고 계획하면서
MQTT를 알게 되었다. 이렇게 해서 또 한 가지 배우게 된 것이다…^^


MQTT(Message Queuing Telemetry Transport)란?


일단 간단하게 정의 내려 보면 “Message Queue 기반의 원격 전송 프로토콜” 정도로 말할 수 있겠다.
그럼 Message Queue란 무엇이냐?…라고 계속 묻고 들어가면 끝이 없으니 자세한 내용은 링크로 대신한다…-.-



네이버 지식 백과 : [http://terms.naver.com/entry.nhn?docId=3386832&cid=58369&categoryId=58369]

Wikipedia : [https://en.wikipedia.org/wiki/MQTT]


중요한 것은 이 프로토콜이 경량화(저전력, 낮은 대역폭 등) 된 프로토콜이며 주로 M2M(Machine-to-Machine)
통신에 특화되어 IoT와 밀접하게 관련되어 있다는 것이다.


브로커 선정


이 MQTT 프로토콜을 이용한 통신 구현체는 보통 Broker라 부른다.
이 Broker라는 이름은 Message Queue의 일반적인 통신 방식으로부터 비롯되었는데 양 끝단에 publisher와
subscriber가 있고, 이 publisher와 subscriber 사이에서 message를 ‘중개’해주는 역할을 한다고 하여 이런
이름이 붙게 되었다(아래 이미지는 네이버 지식 백과에서 가져왔다). 



이러한 MQTT broker는 앞서 언급한 ActiveMQ와 RabbitMQ외에도 mosquitto, moquette, mosca, HiveMQ 등
상당히 많다. 아래 링크는 이러한 브로커들을 비교해놓은 자료이다.


https://github.com/mqtt/mqtt.github.io/wiki/server-support


일단 라즈베리파이에 가장 흔히 쓰이는 것이 mosquitto인데 나는 2대로 클러스터를 만들어보기 위해 기왕이면 
클러스터링을 기본적으로 지원하는 브로커를 찾게 되었고 그 후보자로 HiveMQ와 EMQ가 선정되었다. 
하지만 HiveMQ가 상용이어서 오픈소스 기반인 EMQ로 정하게 되었다. 그리고 위 링크를 보아서도 알 수 있듯이 
EMQ는 체크 대상 전 항목이 구현되어 있어 도표상으로만 보자면 거의 상용 제품에 맞먹는 기능을 가지고 있다.


설치


아재의 잡설이겠지만 예전에는 오픈소스라는 것들이 웬만하면 소스로 내려받아 컴파일을 해야 사용이 가능했는데 
요즘은 대체로 바이너리로 받아도 별 무리 없이 실행이 된다. 그런데 나는 EMQ를 라즈베리파이에 설치할 계획이었고
EMQ 홈페이지에는 안타깝게도 라즈베리파이용 배포판은 없었다. 리눅스 계열의 배포판 중 하나를 받으면 되겠지만
어떤 것을 받아야 할지 대략 난감이었다.


결국 Github에 있는 소스를 내려받아 컴파일을 하게 되었다.


그러나 나에게는 남들에게 없는 오묘한 재주가 있었으니…
바로 너무 쉽게 설명된 것을 너무 어렵게 진행한다는 것이다…-.-


우선 소스의 다운로드와 컴파일은 다음의 과정을 거쳐 진행하면 된다.

$sudo apt-get update
$sudo apt-get install wget
$sudo apt-get install libssl-dev
$sudo apt-get install ncurses-dev
 
#ERLang 설치
$wget http://www.erlang.org/download/otp_src_19.2.tar.gz

$tar -xzvf otp_src_19.2.tar.gz
$cd otp_src_19.2/
$./configure
$make -j 4 
$sudo make install
$cd ..
$rm otp_src_19.2.tar.gz
$sudo rm -R otp_src_19.2/

#EMQ 설치 및 실행
$git clone https://github.com/emqtt/emq-relx.git
$cd emq-relx && make
$cd _rel/emqttd && ./bin/emqttd console


일단 모든 설치는 문제 없이 잘 끝났다.
그런데 정작 emq를 make하는 과정에서 아래와 같은 오류가 발생을 하였다.



원인은 erlang 설치에 있었으며 라즈베리 파이에 설치하기 위해서는 보다 상위 버전이 필요했었던 듯하다.
일단 erlang의 configure 실행 후 아래 화면과 같이 APPLICATIONS DISABLED에 많은 항목이 보이면
문제가 있는 것이라 보면 된다.



이 문제는 erlang의 버전을 20.1 이상으로 설치하면 해결된다.
이렇게 우여곡절 끝에 emq를 설치하였다. 나는 클러스터링을 원했으므로 2대의 라즈베리파이에 각각 설치를 하였다.


설정


이제 설치를 마쳤으니 설정을 해야 한다.
내가 설치한 버전의 emq는 빌드를 하고 나면 git으로부터 복제(위 설치 명령어 참조)한 경로 아래에 _rel이라는
디렉토리가 생기고 그 아래 빌드된 emq가 설치된다. 즉, git clone을 통해 만들어진 디렉토리가 emq-relx라면
emq-relx/_rel/emqttd 아래에 바이너리가 설치된다. 그리고 설정파일은 emq-relx/_rel/emqttd/etc
아래에 있는 emq.conf 파일이다.



설정파일이 상당히 긴데 사실상 변경할 부분은 그리 많지 않다. 내가 수정한 부분만 적는다.

...

#클러스터를 명시적으로 표시하겠다는 의미다.
cluster.discovery = static

...

#클러스터를 명시적으로 표시하겠다고 했으니 명시적으로 표시한다…-.-
cluster.static.seeds = rpi4@172.30.1.25,rpi5@172.30.1.9

...

#현재 노드를 적는다. 물론 172.30.1.25 라즈베리파이에는 rpi4@172.30.1.25라고 적는다.
node.name = rpi5@172.30.1.9

#쿠키 이름을 적는데 이 쿠키 이름을 적지 않거나 쿠키 이름이 일치하지 않으면 제대로 실행이 되지 않는다.
node.cookie = RPI

...

#웹 모니터링 콘솔을 접속하기 위한 포트 설정. 기본 값을 수정하지는 않았지만 중요한 내용이므로 적음
#아래 설정은 EMQ에서 지원하는 REST API 접속을 위해 필요한 포트이다. 모니터링 콘솔 접속 포트는 18083이다!!
listener.api.mgmt = 0.0.0.0:8080

...

node.name을 제외하고는 모두 동일하게 해서 다른 한 서버도 마저 설정을 한다.


실행


이제 실행을 하면 된다. 서비스로 실행을 하는 경우 아래 링크의 맨 마지막 부분을 보면 설명이 나와있다.

http://emqtt.io/docs/v2/install.html


나는 클러스터를 구성하기로 했으니 아래 링크를 따라 진행을 했으나 오류가 발생을 하였다.

http://emqtt.io/docs/v2/cluster.html


그런데 그냥 양쪽에서 아래와 같이 콘솔 모드로 실행을 했더니 자동으로 클러스터링이 이루어졌다.

$cd _rel/emqttd && ./bin/emqttd console


클러스터링이 된 것은 다음과 같이 확인하면 된다.

$sudo ./bin/emqttd_ctl cluster status
Cluster status: [{running_nodes,['rpi4@172.30.1.25','rpi5@172.30.1.9']}]

이렇게 실행까지 완료 되었다.


모니터링


이제 모든 과정이 끝났다. 브로커가 정상적으로 실행 되었다면 이제 확인을 해보자. 브라우저를 실행하고 아래와 같이
주소를 입력해보자.


http://localhost:8080


그러면 아래와 같은 화면이 나타날 것이다.



화면의 Nodes(2)라고 표시된 부분을 보면 내가 2대의 라즈베리파이로 클러스터를 구성했기 때문에 2개의 노드가
표시된 것이 보인다. 또한 우측 상단의 셀렉트 박스의 선택을 통해 각각의 노드 상황(클라이언트나 세션 등)을 볼 수도 
있다. 아래 2개의 이미지는 각각의 노드에 접속되어있는 클라이언트 정보를 보여주는 화면이다. 현재 Kafka까지 설치를
하여 Kafka에서 연결하고 있는 상태이며 이와 관련해서는 다음 포스팅에서 상세하게 다루겠다.



좌측 메뉴 중 Websocket을 이용하여 웹 화면에서 바로 클라이언트를 생성하여 메시지를 보내 테스트 해볼 수도 있다.


테스트


앞서 말했듯이 Websocket 메뉴를 통해서도 간단하게 테스트가 가능하지만 기왕이면 원격에서 클라이언트 접속 
테스트를 진행해보고 싶었다. 다행히도 구글 플레이스토어나 애플 앱스토어에서 MQTT로 검색을 해보면 MQTT
클라이언트가 많이 등록되어있다. 서버 주소와 포트 및 부가적인 몇가지 정보를 입력하면 바로 테스트 가능하다.


여기서는 아이폰용 MQTT 클라이언트 앱인 MQTT Tool을 이용한 테스트 방법을 간단하게 설명한다.

  1. 연결 화면으로 중요 정보인 브로커의 주소와 포트(기본 포트는 1883) 그리고 클라이언트 ID를 임의로 입력한다. ID와 Password역시 임의로 입력하면 된다. 내가 입력한 클라이언트 ID는 mazdah-iphone이다.


  2. 4개의 입력 폼을 가진 화면이 나온다. 가장 위에서부터 subscribe할 토픽 이름 입력, 전송된 토픽의 메시지 표시, publish할 토픽 입력, publish할 메시지 입력 순이다.


  3. 테스트를 위해 우선 subscribe할 토픽을 입력한다. 나는 /mqtt로 정했다. 토픽 입력 후 입력 폼 우측 아래 있는 Subscribe 버튼을 클릭하면 우측의 이미지처럼 Subscribe 버튼이 Unsubscribe로 바뀌고 메시지 표시 창 우측에는 토픽 이름이 적힌 원형 태그가 표시된다.





  4. 그리고 publish할 토픽 이름을 입력한다. subscribe할 토픽 이름이 /mqtt였으니 전송되는 것을 확인하기 위해 여기도 동일하게 /mqtt를 입력한다.


  5. 메시지 입력창을 선택하여 아무 문장이나 메시지를 입력한다. 여기서는 그냥 MQTT TEST라고 입력하였다.


  6. 그리고 마지막으로 메시지 입력창의 우측 하단에 있는 Publish 버튼을 클릭하면 메시지가 전송되고 위에 있는 Subscribe 메시지 창에 전송된 메시지가 출력되는 것을 볼 수 있다.



모니터링 콘솔을 보게되면 Client 메뉴에 내가 클라이언트에서 입력한 mazdah-iphone이라는 ID를 볼 수 있다.


그리고 Sessions 메뉴로 가면 역시 접속된 클라이언트들의 목록이 보이고 오른쪽 끝에쯤에 DeliverMsg 항목에
보면 28이라는 숫자가 보인다. 28건의 메시지가 전송된 것이다. 참고로 mqtt-kafka-1이라는 클라이언트는 다른
3대의 라즈베리파이에 설치된 kafka에서 연결된 subscriber이다. 


왼쪽 이미지는 172.30.1.25 서버의 상태인데 오른쪽의 172.30.1.9 서버의 콘솔에서도 mqtt-kafka-2와 
mqtt-kafka-3 두 개의 subscriber가 동일한 메시지를 전송받은 것을 알 수 있다. 이를 통해 2대의 서버가 
정상적으로 클러스터링 되었다는 것을 확인하였다.



정리


이렇게 라즈베리파이에 MQTT 브로커 중 EMQ라는 브로커를 설치/설정/실행/테스트까지 진행해보았다.
사실 당장에는 어떤 데이터를 어떻게 모을지도 결정된 것이 없기에 전체 클러스터 구성이 완료될 때까지는 이렇게
단순하게 설치와 실행 방법을 기술하게 될 것이다.


전체 클러스터 구성이 완료되면 본격적으로 아두이노를 이용하여 어떤 식으로 센서 데이터를 수집하게 되는지
좀 더 심도 있게 다루어보고자 한다.


우선 다음 단계로는 2개의 노드로 구성된 EMQ 클러스터의 로드 밸런싱을 위한 HAProxy 설치와 실행에 대해
살펴보고 다음으로는 Big Data 프레임워크로의 데이터 수집을 위한 관문으로써 Kafka에 대한 이야기를 정리해보도록
하겠다. 그리고 그 사이에 맥미니에 Haddop 2.0과 HBase 또는 Spark를 설치하는 작업을 진행하게 될 것이다.


이렇게 적어놓고 보니 아직도 할 일이 많다…ㅠ.ㅠ
부지런히 가자!

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^




Cluster : The Beginning - Hadoop, HBase 그리고 Kafka


Prologue


빅데이터를 공부해보겠다고 깝치기 시작한 것이 2013년 5월경이었다.
당시 우선 Hadoop 위주로 공부를 하면서 twitter streaming API를 이용하여 데이터를 모아보려고 하다가
그냥 데이터만 보아보고는 별다른 진척 없이 유야무야 되었다.


그리고 2016년 3월경, Apache Kafka를 알게되면서 다시 의욕이 불타올랐다.
이 때는 이미 하드웨어 장비도 맥미니 5대로 실제 분산 처리를 구현해볼 수 있을만한 상태였다.
이 당시 Kafka에 대한 글을 블로그에 정리하면서도 이와 비슷한 글로 시작을 하고 있었다…-.-


그러나 Hadoop ecosystem이라는 것이 설치는 간단하지만 설정과 운영은 결코 만만치 않았다.
각 시스템 간의 연동이라든지 튜닝, 그리고 데이터를 어떻게 분석할 것인가, 그러기 위해 어떤 형태로 저장할 것인가
등등을 생각하면 공부해야 할 것들이 부지기수로 불어난다.


결국 Kafka에 대한 기초 수준의 공부와 twitter streaming API를 통해 데이터를 받아와 Node로 구현하 producer와 
consumer를 이용한 데이터 전송을 맛배기 수준에서 구현해보고는 역시 봉인 상태에 들어갔었다.


그리고 이 당시 직접 분산 환경을 만들어보고 싶어서 구입한 맥미니 5대도 함께 봉인되었다는 슬픈 전설이…-.-


아래 이미지는 5대의 맥미니인데 최근 드론 만든다고 책상 상태가 조금 심란하다…-.-



이전에 맥미니를 무려 5대나 가지고 있으면서도 제대로 활용하지 못했던 이유 중 하나가 Hadoop ecosystem을
구성하다보니 5대의 서버로는 택도 없다는 것을 깨달았기 때문이다. 기본적으로 Hadoop과 zookeeper 그리고 
HBase를 설치한 후 여기에 다시 Kafka를 올리고…마치 초등학생 가방에 9박 10일치 여행 용품을 쑤셔넣은 듯한
느낌을 지울 수가 없었다…ㅠ.ㅠ (2016년도는 한편 아두이노에 푹 빠져있을 시기이기도 하다)


그렇게 시간은 흐로고 어느날 라즈베리 파이를 알게되고 라즈베리 파이를 이용한 클러스터링에 대한 유튜브 동영상을
접하게 되었다. 다시 나의 쓸데없는 호기심은 고개를 처들기 시작하였고, 나는 라즈베리 파이를 이용한 클러스터링을
준비하게 되는데…


사실 저렴하다고는 하지만 그것은 어디까지나 상대적인 것이고 국내에서 라즈베리 구동을 위해 필요한 것을 구입하자면
네트워크는 Wi-Fi를 사용하고 전원은 컴퓨터에 USB를 연결한다고 치면 라즈베리파이 본체와 마이크로 SD카드의 최소
구성이 5만원이 넘어간다. 3대의 클러스터를 만든다고 해도 최소한 15만원 이상의 투자가 필요하다.


하지만 내가 누군가!
야금야금 모으던 라즈베리 파이가 어언 6대(마지막 한 대는 최근 구성상의 문제로 부랴부랴 구입했다). 
이제 때가 도래한 것이다!


하드웨어 장비로만 보자면 라즈베리 파이가 6대, 맥미니가 5대로 웬만한 클러스터는 충분히 구현할 수 있을만한
요건이 갖추어졌다고 할 수 있을 것이다.


이제 다시 그동안 시도만 하고 끝을 보지 못한 작업을 새롭게 시도를 할 것이며 이제는 그 끝을 보고자 한다.
그리고 그 범위는 매우 방대할 것이다. (어서 보고 들은 것은 있어서) IoT와 Big Data 그리고 Deep Learning으로
이어지는 최신 트렌드를 구현해보고자 한다.


우선은 수박 겉핥기 수준의 구현에 불과하겠으나 한 번 구현된 시스템을 계속 유지하면서 그 깊은 곳으로 들어가보고자
한다. 더이상의 중단이 없는 내 호기심의 마지막 종착역이 되길 빌며 이 프로젝트를 시작한다.



간단한 구성 계획


  • 라즈베리 파이 1 - HAProxy를 통한 로드 밸런싱
  • 라즈베리 파이2, 3 - MQTT 설치. 2대로 클러스터 구성. 모바일 디바이스나 아두이노 등을 활요하여 제작한 IoT 기기 정보 수집. 솔루션은 EMQ 설치
  • 라즈베리 파이4, 5, 6 - Kafka 클러스터 구성. MQTT에서 받은 데이터를 HDFS 또는 HBase로 저장
  • 맥미니 1 ~ 5 - Hadoop 2.0과 HBase 설치

몇가지 우려


일단 어떤 시스템을 어떻게 구성할 것인지에 대해서는 어렴풋이나마 감을 잡겠으나 어떤 데이터를 어떻게 분석할
것인지에 대해서는 아직도 오리무중이다. 그래서 우선 나의 목적과 어느정도 부합한다고 생각되는 책을 한 권 선정하여
이 책을 통해 감을 잡아가려고 한다. 책의 제목은 “하둡과 스파크를 활용한 실용 데이터 과학”이다.


나는 스파크를 이용하지는 않을 것이기에 혼란은 좀 있겠지만 열심히 읽고 나의 방법을 찾아봐야겠다.


이전 학습 내용 링크


이전에 어떤 공부를 했었는지 2013년도 정리한 내용과 2016년 정리한 내용의 최초 포스팅만 링크해본다.

Hadoop : [BigData] 학습 시작을 위한 용어 정리

Kafka : [Kafka]3년만에 찾은 솔루션 kafka…ㅠ.ㅠ










블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^


Kafka 정리를 마치며


분산 시스템 관리의 어려움

얼추 node 모듈을 이용한 kafka 서비스가 구현이 된 것 같았다.
트위터 Streaming API를 이용하여 데이터를 잘 가져오고,
producer는 이 데이터를 broker에게 잘 전달하고,
consumer는 broker로부터 데이터를 잘 가져와 로그를 뿌려주고…


하지만 어느 순간 이러한 프로세스가 중지되어있기 일쑤였다.
zookeeper쪽이나 kafka쪽이나 서버 콘솔에 출력되는 로그는
대체로 네트워크가 끊겼다는 메시지인데 도대체 이 문제가 어떤 원인으로
발생하는 지를 알 수가 없는 것이다.


애초에 분산 시스템에서 장애의 원인을 찾는 것은 매우 어려운 일이라는 것은
알고 있었지만 아무리 작은 클러스터라도 이 문제를 직접 겪으니 참
답이 안나온다.(물론 나의 경험과 지식의 부족이 가장 큰 역할을 했겠지만…ㅠ.ㅠ)


물리적인 네트워크가 문제인지, zookeeper에서 문제가 발생한 것인지
kafka에서 문제가 발생한 것인지…게다가 zookeeper와 kafka의 장애에 대한
상세한 자료들은 찾기가 쉽지 않아서…


결국 이 문제로 거의 2주 가량을 별다른 진척 없이 zookeeper와 kafka의
에러 로그에 대한 구글링만 하면서 보냈다.


혹시나 해서 몇대 안되는 클러스터에서 잔뜩 돌아가고 있던 HBase와
Storm 서버들도 모두 죽여버렸다.

최종적으로 구성된 나의 허접한 클러스터는 아래와 같다.



<가난한 자의 클러스터 이미지>


황당한 원인과 새로운 문제


사실 문제는 너무나 명백한 곳에 있었다.
현재 총 5대의 맥미니로 구성된 클러스터에서 4대는 서버 전용으로만
사용했으나 1대를 일반 가정용 용도로도 사용을 하는 과정에서 서버 전용의
4대는 절전 모드를 꺼놓았는데 이 한 대에 대해서는 절전모드를 켜놓은
상태였던 것이다. 그러니 절전모드로 들어가면서 이 한대에서 돌고있던
zookeeper, kafka는 물론 여기서 돌고 있던 node.js의 producer 모듈까지
모두 맛이 가버린 것이다. 


결국 전기세의 압박에도 불구하고 절전모드를 모두 해제하고 상황을 지켜보았더니
트위터 메시지 건수 기준으로 기존에 4~5천 건에서 죽던 프로세스가
대략 7만 건 이상을 처리할 수 있게 되었다.


하지만 아직도 갈 길이 먼 것이 약 7만 건 정도 처리를 하고 나면 zookeeper에서
Purge task가 발생을 하는데 이 시점에서 producer 프로세스가 멈춰버린다.
zookeeper의 purse 관련 설정에 대해 알아보고는 있으나 역시 자료도 많지 않고
나의 무식은 큰 장애가 되고 있고…ㅠ.ㅠㅠ


일단 다음 단계로


내가 하고자 하는 것은 트위터 데이터를 모아 형태소 분석을 거쳐 특정 시점에
가장 많이 언급된 단어들을 추출하고 그 단어에 대한 긍정/부정의 평가를 한 후
다시 그 단어가 언급된 공인 미디어를 검색하여 긍정/부정 평가에 대한
공신력을 추가하는 작업이다.


그 중에 이제 데이터 수집 단계를 진행하고 있으며 기왕이면 공부좀 해보자고
kafka에 손을 대본 것인데 역시 한계가 있다. 하지만 목표한 바를 진행하면서
최대한 틀린 부분을 바로 잡고 몰랐던 것을 채워 나가야겠다.


당장에 진행할 다음 단계는 현재 일없이 로그만 찍어대고 있는 consumer에
제대로 된 역할, 즉 Hadoop으로 파일을 저장하는 일을 좀 시키려고 한다.
역시 node 모듈을 사용할 것이고 그 과정 또한 차근차근 정리해 볼 생각이다.


선무당이 사람 잡는다.

잘 모르는 내용을 억지로 진행하다보니 잘못된 정보를 기록하게 되는 경우도
많은 것 같다. 앞으로는 가급적 핵심적인 내용은 잘 정리된 외부 사이트를
인용을 하고 내가 실제 눈으로 본 것들을 중심으로 정리를 해야겠다.

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^

티스토리 툴바