이전에 생각했던 프로젝트의 개요를 한번 직접 그려보았다.
좀 더 구체화하는 작업을 진행하며, 각각의 서비스들이 무엇인지, 어떤 역할을 수행하는지 정리해보도록 하자.
- Docker Compose
- Kafka
- Spark
- MySQL
- Airflow
- Grafana
* Yahoo Finance는 주식 데이터를 제공해주는 api 이기에 자세히 설명하지는 않겠다.
Docker Compose란?
도커 컨테이너 기반의 여러 서비스를 정의하고 관리하는데 쓰이는 도구이다!
얼핏 봐도 여러 컨테이너가 존재하는데, docker compose up 과 같은 명령어를 통해 한번에 실행시킬 수 있다!
또한 컨테이너간 네트워크 연결 및 환경변수 설정에도 도움을 준다! (서비스명으로 네트워크 접근 가능)
docker-compose.yml 파일
Apache Kafka란?
분산 메시지 브로커 시스템 ! 실시간 데이터 스트리밍 플랫폼이다.
적은 양의 데이터는 단순히 api를 통해 서버에서 db로 넣을 수 있지만,
요즘 짧은 시간에 들어오는 데이터의 크기가 방대해졌기에 여러곳에서 필수적으로 사용되는 기술이라고 생각한다.
Producer가 데이터를 Kafka에 전송하고, Consumer가 이를 처리하는 방식으로 동작한다.
( 도로에 엄청나게 많은 차들이 이동하려고 하는데, 잘 지나가도록 조율해주는 역할이라고 생각해도 될 것 같다. )
이전 포스팅에서 zookeeper가 아닌 kraft mode에 관한 영상을 언급했었는데,
본 프로젝트에서 무엇을 채택할지는 좀 더 고민이 필요할듯 하다.
어쨋든..! 이 프로젝트에서 kafka는 yahoo finanace api 에서 들어오는 데이터를 Spark에게 "잘" 전달해주는 역할을 한다.
Apache Spark란?
분산 데이터 처리 플랫폼이다!
이전의 kafka는 "스트리밍"을 해주는 녀석이었다면, 이 친구는 "전처리" 해주는 녀석이라고 생각하면 될것 같다.
다만 대규모 데이터를 분산환경에서 빠르게 처리할 수 있는 강력한 친구다!
Spark에 대해 더 궁금하다면, 전 포스팅을 찾아가도록 하자 ㅎㅎ. . .
Spark에 있어서는 PySpark를 사용하기로 했다!!
또한 Spark Streaming Library를 사용하고자 생각중이다!
그래서 이 녀석은 kafka에서 데이터를 가져와서 처리하고, MySQL에 저장해줄 것이다!
MySQL 이란?
음.. 사실 이거는 다들 다른것들에 비해서는 잘 알거라고 생각한다.. ㅎㅎ
RDBMS , 관계형 데이터베이스 관리 시스템이다.
Spark에서 처리해준 데이터를 여기에 저장해두도록 할 것이다!
Airflow 란?
워크플로 및 파이프라인을 관리하는 도구이다!
데이터 파이프라인에 있어 스케줄링을 해줄 수 있다 !
매시간 데이터를 처리하거나 보고서를 만드는것과 같은 주기적인 작업을 자동화 해준다!
특징은 작업의 흐름이 DAG (Directed Acyclic Graph) 구조를 가진다는 것이다!
Grafana란?
데이터 시각화 및 모니터링 도구이다!
전에 다른 프로젝트에서도 잠깐 사용해본적이 있는데, 꽤나 그래프가 깔끔하다!
디자인적인 부분외에도, 어떤 데이터인지에 따라서 어떤 형태의 그래프를 사용해야하는지 고민을 하는 경우가 많은데,
그러한 부분에 있어서도 추천해주는 기능이 있어 좋다고 생각을 많이 했던 것 같다.
본 프로젝트에서는 MySQL에서 저장되어있는 데이터를 시각화하여 사용자에게 제공한다!
이것들이 어우러진다면...?
기대해볼 수 있는 기능들은 아래와 같다.
- 실시간 모니터링 : grafana에서 실시간 주식 가격을 확인 가능
- 알림 시스템 : 본인이 설정해둔 조건에 맞춰 Spark가 데이터 처리과정에서 알림을 생성
- 데이터 분석 : MySQL에 저장된 데이터를 기반으로 다양한 분석을 수행
- 자동화된 파이프라인 : 전체적인 작업 자동화 및 원하는 형식대로 보고서를 받아볼 수 있음
알림 시스템과 같은 경우는 증권 앱에서 하면 안되냐?
라고 묻는다면.... 그것도 좋지만
해당 기술들에 대한 숙련도를 높이기 위한 목적도 있고,
어플에서 설정가능한 조건은 제한적이라고 생각한다.
1년중 최저가와 같은 경우는 네이버 증권에서 알림을 받고,
실질적인 주식거래는 다른 곳에서 하는데 개별로 알림이 오기에 불편한점이 있다.
이러한 부분도 해당 프로젝트를 통해 내가 원하는 형태의 하나의 보고서로 받아볼수 있을거라 기대하고 있다!
다소 간략하게 기술들을 설명한 부분이 있지만, 하나씩 사용해 나가는 과정에서 더 깊이 다루어볼 예정이다.
아래는 해당 아키텍쳐를 담은 docker-compose.yml 파일이다.
version: '3.8'
services:
kafka:
image: confluentinc/cp-kafka:latest
container_name: kafka
environment:
KAFKA_BROKER_ID: 1
KAFKA_CFG_PROCESS_ROLES: broker
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
KAFKA_CFG_LISTENERS: PLAINTEXT://localhost:9092,CONTROLLER://localhost:9093
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_CFG_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR: 1
ports:
- "9092:9092"
- "9093:9093"
spark-master:
image: bitnami/spark:latest
container_name: spark-master
environment:
- SPARK_MODE=master
ports:
- "8080:8080" # Spark Web UI
- "7077:7077" # Spark Master Port
spark-worker:
image: bitnami/spark:latest
container_name: spark-worker
environment:
- SPARK_MODE=worker
- SPARK_MASTER_URL=spark://spark-master:7077
depends_on:
- spark-master
database:
image: mysql:latest
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- "3306:3306"
airflow:
image: apache/airflow:2.5.0
container_name: airflow
environment:
- AIRFLOW__CORE__EXECUTOR=LocalExecutor
- AIRFLOW__CORE__SQL_ALCHEMY_CONN=mysql+mysqldb://user:password@mysql-db/mydb
- AIRFLOW__CORE__LOAD_EXAMPLES=False
volumes:
- ./dags:/opt/airflow/dags
- ./logs:/opt/airflow/logs
- ./plugins:/opt/airflow/plugins
ports:
- "8081:8081"
depends_on:
- database
grafana:
image: grafana/grafana:latest
container_name: grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_SECURITY_ADMIN_USER=admin
ports:
- "3000:3000"
volumes:
- grafana-storage:/var/lib/grafana
volumes:
grafana-storage:
어서 빨리 완성하고 싶다...!!
(어제 저녁에는 kakao tech meet에 참여했는데, 이에 관한 포스팅도 조만간 올리도록 하겠다. ! ! !)