지난 글에서는 아파치 카프카(Apache Kafka)의 정의에 대해서 알아보았다.
이번 글에서는 아파치 카프카를 관리하기 위해서는 반드시 필요한 코디네이션 애플리케이션인 주키퍼(Zookeeper)를 설치 실습을 진행해 보겠다(아파치 카프카 설치는 다음 글에서 진행할 것이다)
이 글의 진행 순서는 다음과 같다.
1. 서버 준비
2. 주키퍼 설치하기
3. 주키퍼 실행하기
1. 서버 준비
우선 주키퍼를 설치할 서버가 필요하다.
주키퍼는 서버 3대에 설치를 진행하도록 하겠다(다음 글에서 카프카는 서버 2대에 설치를 진행할 것이다)
사실 아파치 카프카 및 주키퍼 모두 각각 서버 1대에 설치를 진행해도 되지만, 클러스터 구성을 맛보기 위해서 주키퍼는 3대의 서버에 설치할 것이다. 또한 주키퍼는 클러스터로 구성할 경우 과반수 이상의 서버가 정상일 때만 지속적인 서비스가 가능하기 때문에 홀수로 구성을 해줘야 한다. 그렇기 때문에 서버 2대가 아닌 3대에 설치를 할 것이다.
- 서버Spec : AWS EC2 인스턴스(Amazon Linux 2 AMI (HVM) t2.micro. cpu 1, memory 1G) 3대
2. 주키퍼 설치하기
2-1. 주키퍼란?
카프카와 같은 분산 애플리케이션을 사용하게 되면, 분산 애플리케이션 관리를 위한 코디네이션 애플리케이션이 추가로 필요한데, 코디네이션 애플리케이션 중 안정적인 코디네이션 서비스로 검증된 주키퍼(ZooKeeper)를 많이 사용하고 있다. 주키퍼(ZooKeeper)는 분산 애플리케이션이 안정적인 서비스를 할 수 있도록 분산되어 있는 각 애플리케이션의 정보를 중앙에 집중하고 구성관리, 그룹관리 네이밍, 동기화 등의 서비스를 제공한다. 주키퍼는 본래 하둡(Hadoop)의 서브 프로젝트 중 하나였으며, 현재는 카프카 뿐만 아니라, 스톰, 에이치베이스 등 많이 애플리케이션에서 사용되고 있다.
1) 앙상블 : 주키퍼는 서버 여러대를 앙상블(클러스터)로 구성한다. 주키퍼 앙상블로 구성되면, 해당 앙상블 안에 있는 서버(노드) 수가 과반수 이상이 유지될 때 지속적인 서비스가 가능하며, 그렇지 않으면 장애가 발생한다(그렇기 때문에 주키퍼 서버는 홀수대로 구성한다).
2) 지노드 : 주키퍼 내에 분산 애플리케이션 상태정보가 저장되는 곳. 분산 애플리케이션들은 각각 클라이언트가 되어 주키퍼 서버들과 연결을 맺은 후 상태 정보를 주고받게 된다. 상태정보는 주키퍼의 지노드(znode)에 Key-Value 형태로 저장되며, 지노드에 저장된 것을 이용하여 분산 애플리케이션들은 서로 데이터를 주고받게 된다. 지노드에 저장되는 데이터 크기는 바이트~킬로바이트 정도이며, 자식노드를 가지고 있는 계층형 구조로 구성되어 있다. 각 지노드는 데이터 변경 등에 대한 유효성 검사 등을 위해 버전 번호를 관리하며, 지노드 데이터가 변경될 때마다 버전 번호가 증가한다. 또한 주키퍼에 저장되는 데이터는 모두 메모리에 저장되어 처리량이 매우 크고 빠르다.
2-2. 서버 호스트네임 변경
우선 주키퍼를 설정하기 전에 root 계정이 아닌 경우 root계정으로 접속하자
$ sudo passwd root #root 패스워드 변경
$ su #root로 접속
다음으로 실습 편의를 위해 3개의 주키퍼 서버에 접속하여 서버 호스트네임을 변경해주자.
호스트네임은 zk01, zk02, zk03으로 변경할 것이다.
$ hostnamectl set-hostname zk01
2-3. JDK 설치
호스트네임이 변경되었으면 JDK를 설치해보자.
주키퍼는 자바 애플리케이션이기 때문에 자바가 설치되어 있어야 실행할 수 있다.
$ yum list *openjdk* #openjdk 리스트 확인
$ yum -y install java-1.8.0-openjdk.x86_64
2-4. 주키퍼 다운로드
다음으로 주키퍼를 다운로드해보자.
zookeeper.apache.org/releases.html 로 이동한 후 주키퍼 최신버전을 선택한다.
최신버전을 선택하게 되면 Apache Download Mirror 라는 사이트로 이동하게 되는데, 그곳에서 주키퍼 다운로드 받을 수 있는 URL을 확인할 수 있다.
해당 URL과 wget을 활용하여 주키퍼를 다운받아보자.
$ cd /usr/local
$ wget https://downloads.apache.org/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz
다운이 완료되었으면 압축을 해제해보자.
$ tar xvf apache-zookeeper-3.6.2-bin.tar.gz
압축을 풀어서 디렉토리가 생겼다면, 심볼릭 링크를 생성해보도록 하자(만약 심볼릭 링크가 없다면 주키퍼 버전이 변경되게 되면 배포 스크립트 등에 설정되어 있는 경로를 매번 변경해야 하기 때문에 심볼릭 링크를 생성해 주는것이 좋다)
$ ln -s apache-zookeeper-3.6.2-bin zookeeper
2-5. 주키퍼 설정
다음으로 지노드의 복사본인 스냅샷과 트랜잭션 로그들이 저장될 별도의 데이터 디렉토리를 생성해주자(지노드에 변경사항이 발생하면 이러한 변경사항은 트랜잭션 로그에 추가되며, 로그가 어느정도 커지면 현재 모든 지노드의 상태 스냅샷이 파일시스템에 저장된다. 중요한 디렉토리므로 설치경로와는 다른 경로로 설정하자)
$ mkdir -p /data
다음으로 앙상블 내 주키퍼 노드를 구분하기 위한 정수형태의 ID(주키퍼에서는 myid라고 함)를 만들어주자. zk01서버는 myid를 1, zk02 서버는 myid를 2, zk03 서버는 myid를 3으로 만들어주자.
$ echo 1 > /data/myid
다음으로 주키퍼 환경설정 파일인 zoo.cfg 파일을 만들어주자.
$ vi /usr/local/zookeeper/conf/zoo.cfg
/usr/local/zookeeper/conf/zoo.cfg :
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data
clientPort=2181
server.1=zk01:2888:3888
server.2=zk02:2888:3888
server.3=zk03:2888:3888
각 항목에 대한 설명은 다음과 같다(상세한 내용은 http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_configuration 참고)
- tickTime : 주키퍼가 사용하는 시간에 대한 기본 측정 단위(밀리초)
- initLimit : 팔로워가 리더와 초기에 연결하는 시간에 대한 타임아웃 tick의 수
- syncLimit : 팔로워가 리더와 동기화 하는 시간에 대한 타임아웃 tick의 수(주키퍼에 저장된 데이터가 크면 더 크게 잡아야 함)
- dataDir : 주키퍼의 트랜잭션 로그와 스냅샷이 저장되는 저장경로. 이 글에서는 /data로 생성했었기 때문에 zoo.cfg에서도 /data로 지정함
- clientPort : 주키퍼 사용 TCP 포트
- server.x : 주키퍼 앙상블 구성을 위한 서버 설정. server.myid 형식으로 사용. 2888:3888은 기본 포트이며, 앙상블 내 노드끼리 연결 & 리더 선출에 사용
간혹 주키퍼 기동 시 server.x에 명시된 자기 자신의 호스트명을 인식하지 못하는 경우가 있다. 그럴 경우 자기 자신의 호스트명은 0.0.0.0으로 변경해주면 정상 동작한다(stackoverflow.com/questions/30940981/zookeeper-error-cannot-open-channel-to-x-at-election-address 참고)
zk01 서버의 /usr/local/zookeeper/conf/zoo.cfg 예시 :
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data
clientPort=2181
server.1=0.0.0.0:2888:3888 # 이 부분 변경
server.2=zk02:2888:3888
server.3=zk03:2888:3888
2-6. 호스트파일 및 방화벽 설정
zoo.cfg에서 로컬 서버의 호스트명을 제외한 호스트명(예를 들면 zk01 서버에서의 zk02, zk03)은 인식이 안되므로 zk01, zk02, zk03서버의 /etc/hosts 파일에 호스트명을 추가해줘야 한다.
/etc/hosts :
..
[zk02서버의 ip] zk02
[zk03서버의 ip] zk03
또한 zoo.cfg에서 사용한 주키퍼 클라이언트 포트인 2181, 그리고 앙상블끼리 연결 & 리더 선출에 사용하는 2888, 3888 포트도 방화벽 을 오픈해줘야 한다(필자는 EC2를 사용했기 때문에 인바운드 정책에 각 포트정보를 추가해줬다)
3. 주키퍼 실행하기
3-1. 주키퍼 실행하기
설정이 완료되었으면 아래 명령어를 통해 각 서버에서 주키퍼를 실행시켜보자.
$ /usr/local/zookeeper/bin/zkServer.sh start
만약 실행시킨 주키퍼를 중지시키려면 stop 명령어를 사용하면 된다.
$ /usr/local/zookeeper/bin/zkServer.sh stop
3-2. 주키퍼 실행 확인하기
주키퍼가 정상적으로 실행되고 있는지 확인해보자.
아래 명령어를 통해서 해당 주키퍼 서버가 리더인지 팔로워인지 확인할 수 있다.
$ /usr/local/zookeeper/bin/zkServer.sh status
또한 /usr/local/zookeeper/logs에서 주키퍼 로그를 확인하여 주키퍼가 정상적으로 실행되고 있는지도 확인할 수 있다.
만약 status나 log를 통해서 주키퍼가 정상적으로 실행되지 않는 것을 확인했다면 재 실행을 해보자.
재 실행은 zkServer.sh에 restart 옵션을 주면 된다
$ /usr/local/zookeeper/bin/zkServer.sh restart
3-3. systemd로 주키퍼 관리하기
명령어를 통해 수동으로 실행시킬 수도 있지만, 리눅스에서는 여러 프로세스를 효율적으로 관리하기 위해 systemd에 등록하여 운영할 수 있다(서버의 오작동으로 인해 리부팅 된 경우 자동으로 시작해야 하는 경우 등).
만약 주키퍼를 systemd에 등록하고 싶다면 주키퍼용 systemd 파일을 별도로 만들어야 한다. 이 글에서는 zookeeper-server.service 라는 파일을 만들어 볼 것이다(systmed로 관리하지 않고 수동으로 관리하고 싶다면 3-2는 생략해도 된다)
주키퍼를 실행시키고 싶은 서버에 zookeeper-server.service 파일을 생성해준다.
/etc/systemd/system/zookeeper-server.service :
[Unit]
Description=zookeeper-server
After=network.target
[Service]
Type=forking
User=root
Group=root
SyslogIdentifier=zookeeper-server
WorkingDirectory=/usr/local/zookeeper
Restart=always
RestartSec=0s
ExecStart=/usr/local/zookeeper/bin/zkServer.sh start
ExecStop=/usr/local/zookeeper/bin/zkServer.sh stop
systemd의 파일을 새로 만들거나 기존 파일을 수정한 후에는 systemd를 반드시 재시작해줘야 한다. 때문에 systemctl daemon-reload 명령어를 통해 systemd를 재시작해주자.
$ systemctl daemon-reload
이제 각 서버에서 아래 명령어를 통해 주키퍼를 실행시켜보자. 주키퍼를 실행시키기 전에 이미 주키퍼가 zkServer.sh 명령어에 의해 실행중이라면 중지시키고 시작하자(명령어 : /usr/local/zookeeper/bin/zkServer.sh stop)
$ systemctl start zookeeper-server
마치며
이번 글에서는 코디네이션 애플릴케이션인 주키퍼 설치를 진행해 보았다.
다음 글에서는 아파치 카프카를 설치해보고 실행하여 주키퍼와 연동시키는 실습을 진행해보자(다음글 : 리눅스에 아파치 카프카(Apache Kafka) 설치하기)
참고
- 카프카, 데이터 플랫폼의 최강자 - 고승범. 공용준 지음
'IT > MSA' 카테고리의 다른 글
리눅스에 아파치 카프카(Apache Kafka) 설치하기 (0) | 2020.12.09 |
---|---|
아파치 카프카 실행 에러(Classpath is empty. Please build the project first e.g. by running) (0) | 2020.11.22 |
아파치 카프카(Apache Kafka) 정의 및 특징 (0) | 2020.10.17 |
Jaeger를 활용한 분산 환경 서비스 로그 트레이싱(SpringBoot, Spring Cloud Gateway 활용) (1) | 2020.07.11 |
Zipkin과 ElasticSearch, Kibana 연동하기 (1) | 2020.07.05 |
댓글