새소식

데이터 엔지니어링/기술스택 및 알쓸신잡

[Spark] 스파크...왜 쓰는걸까? (하둡부터 스파크까지)

  • -

지금까지는 전체적인 데이터 파이프라인 작업을 관리하는 Airflow에 대해 알아봤으니,

이번엔 작업 들 중 '분산 데이터 처리'의 대명사로 불리는 Spark에 대한 포스팅을 시작해보려한다.

당연히 이번에도 시작은 스파크가 왜 필요한지부터 이해하는 것으로 시작~!


TODO List

  • 스파크는 왜 필요한가?
  • 하둡의 등장
  • 스파크의 등장
  • 스파크 핵심 이론 (파티셔닝, 맵리듀스...)
  • 마무리

1. 스파크는 왜 필요한가?

일단 스파크가 왜 필요한지에 대해 이해하려면 '데이터 처리 과정'부터 알아야한다.

데이터 처리 과정이라고 하면, 어려울 것 같지만 기본 전제만 알면 된다.

 

'데이터를 처리하려면, 일단 데이터를 메모리에 올려야한다.'

 

일전에 CS지식 포스팅하면서 잠깐 언급했지만, 컴퓨터는 기본적으로 데이터를 메모리에 올려놓고 CPU 연산을 수행한다.

판다스에서 CSV파일을 읽어오면 메모리에 파이썬 객체로 올라가는 것이라고 생각하면 이해하기 쉽다.

(https://9unu.tistory.com/23)

 

그럼 위의 링크에서도 잠깐 언급했던건데,

 

'처리해야하는 데이터의 크기가 메모리 용량보다 크면 어떻게 해야 할까?'

 

이에 대한 해결책은 대충 2가지 일 것이다.

  1. 데이터를 쪼개서 처리한다.
  2. RAM을 키운다.

1번은 굉장히 심플하지만, 한계가 명확하다.
'느리다'

 

2번은 어느정도 말이되면서, 한편으로는 말이 안된다.
클라우드 플랫폼이 등장하면서 RAM 용량을 빠르게 키울 수 있으니 말은 되지만, 클라우드에서도 최대 RAM용량은 정해져있다.
그리고 RAM 용량만 커지면 되나? 그정도 데이터를 처리하려면 CPU 자원도 만만치 않게 들어갈 것이다.

 

'그래서 뭐 어쩌라는겨?'

 

정답은 1번과 2번을 통합 및 변형하는 것이다.

  1. 여러 컴퓨터로 전체 데이터를 쪼개서 넘겨주고, 각 컴퓨터로 처리한다
  2. 모든 데이터는 각 컴퓨터의 RAM에 올라가서 마치 하나의 RAM에 올라간 것처럼 여겨진다.

말그대로 통신을 통해 여러 컴퓨터를 하나의 컴퓨터처럼 묶어버리고, 데이터를 동시에 처리하는 것이다.

 

즉, 우리는 병렬처리의 기본 개념으로 다시 돌아온다.

 

"백지장도 맞들면 낫다"

(https://9unu.tistory.com/20)


2. 하둡의 등장

위와 같은 문제를 해결하기 위해 등장한 것이 바로 그 유명한 하둡(Hadoop)이다.

하둡은 대용량 데이터를 분산 처리할 수 있는 자바 기반의 오픈소스 프레임워크다.

하둡의 핵심 컴포넌트는 HDFS, MapReduce 크게 두 가지다.

2.1 HDFS (Hadoop Distributed File System)

HDFS는 하둡의 분산 파일 시스템으로, 대용량 데이터를 여러 서버에 나눠서 저장한다.

HDFS의 주요 특징:

  1. 블록 단위 저장: 기본적으로 128MB 단위로 파일을 나눠 저장 (설정 가능)
  2. 복제(Replication): 각 블록을 여러 서버에 복제하여 저장 (기본 3개)
  3. 마스터-슬레이브 구조:
    • 네임노드(NameNode): 메타데이터 관리, 데이터 위치 추적
    • 데이터노드(DataNode): 실제 데이터 저장

HDFS의 장점은 저렴한 서버 여러 대로 고가용성 파일 시스템을 구축할 수 있다는 것이다.
하지만 작은 파일이 많으면 네임노드에 부담이 커지는 단점이 있다.

2.2 MapReduce

MapReduce는 대용량 데이터 처리를 위한 프로그래밍 모델이다.
이름 그대로 Map과 Reduce 두 단계로 데이터를 처리한다.

MapReduce 처리 과정:

  1. Map 단계: 입력 데이터를 키-값 쌍으로 변환하고 처리
  2. Reduce 단계: 같은 키를 가진 값들을 집계하여 최종 결과 생성

예를 들어, 로그 파일에서 접속자 수를 세는 작업은:

  • Map: 각 로그 라인에서 IP 주소 추출해 (IP, 1) 형태로 출력
  • Reduce: 같은 IP별로 숫자를 합쳐 (IP, 접속횟수) 형태로 출력

장점:

  • 대용량 데이터를 여러 서버에서 병렬 처리 가능
  • 서버 장애에도 자동 복구 가능

단점:

  • 모든 중간 결과를 디스크에 저장 (느림!!!!!!!!!!!!)

3. 스파크의 등장

그럼 스파크는 왜나왔을까?

 

한 마디로 정리하면 빠른 처리 속도 때문이다.

앞에서 하둡의 단점으로 모든 중간 결과를 디스크에 저장해서 느리다고 언급했다. 이게 무슨 의미냐면,

  1. 데이터를 분산 저장하는 HDFS에서 데이터를 읽어옴
  2. Map 단계 수행
  3. 중간 결과를 디스크에 저장
  4. 중간 결과를 다시 디스크에서 읽어옴
  5. Reduce 단계 수행
  6. 최종 결과를 다시 디스크에 저장

이런 식으로 중간 과정마다 디스크 I/O가 발생한다는 뜻이다.

그말은 뭐다? 처리가 엄 ~ 청 느리다는 것.

RAM 접근 속도와 디스크 접근 속도는 대략 1만배 정도 차이난다. (RAM은 ns 단위, 디스크는 ms 단위)

 

그래서 등장한 것이 바로 인메모리 컴퓨팅을 지원하는 스파크다.

스파크는 중간 연산 결과를 메모리에 유지하면서 작업을 수행한다.

 

굳이 비교하자면...

하둡 : "작업할 때마다 메모장 열고, 작업 끝나면 저장하고, 다음 작업할 때 다시 열고..."

스파크 : "작업 시작할 때 메모장 한 번 열고, 모든 작업 끝날 때까지 계속 열어둔다."


4. 스파크의 핵심 이론

4.1 RDD (Resilient Distributed Dataset)

스파크의 가장 기본적인 데이터 추상화 단위는 RDD다.

이름에서 알 수 있듯이 '회복 가능한(Resilient) + 분산된(Distributed) + 데이터셋(Dataset)'을 의미한다.

개념적으로는 여러 노드에 분산된 데이터의 집합을 의미하고, 이 데이터는 변경 불가능(Immutable)하다.

RDD는 크게 아래 특징을 가진다:

  1. 내결함성(Fault Tolerance): 노드 하나가 죽어도 다른 노드에서 데이터를 복구할 수 있음
  2. 불변성(Immutability): 한번 생성된 RDD는 변경 불가능 (변경하려면 새 RDD 생성)
  3. 지연 연산(Lazy Evaluation): 실제 연산이 필요한 시점까지 연산을 미룸
  4. 파티셔닝(Partitioning): 데이터가 여러 노드에 분산됨
  5. 계보(Lineage): 데이터가 어떻게 변환되었는지 추적

이 중에서 지연 연산파티셔닝은 스파크의 핵심 개념이니 좀 더 자세히 알아보자.

4.2 지연 연산 (Lazy Evaluation)

스파크는 Transformation(변환)과 Action(액션) 두 종류의 연산으로 나뉜다.

 

Transformation은 기존 RDD에서 새 RDD를 만드는 연산으로, map(), filter(), flatMap() 등이 있다.
Action은 실제 결과값을 반환하는 연산으로, count(), collect(), first() 등이 있다.

 

중요한 점은, Transformation은 바로 실행되지 않고 실행 계획만 세워둔다는 것이다.
실제 연산은 Action이 호출될 때 한번에 수행된다.

이게 왜 효율적일까?

예를 들어 다음 코드를 보자:

# 10TB 데이터 로드
huge_data = spark.read.csv("hdfs://huge_data.csv")

# 필터링 (Transformation)
filtered_data = huge_data.filter(huge_data.value > 100)

# 또 다른 필터링 (Transformation)
final_data = filtered_data.filter(huge_data.type == "important")

# 결과 개수 세기 (Action)
result_count = final_data.count()

지연 연산이 없다면, 각 변환을 순차적으로 처리해야 한다. 즉 10TB 데이터를 풀스캔하여 필더링된 5TB데이터를 또 풀스캔하여 필터링 과정을 거쳐야한다.

하지만 스파크는 Action 연산인 count()가 호출될 때까지 기다렸다가, 최적화된 실행 계획을 세운다.

이 경우 데이터를 한번만 스캔하면서 두 필터 조건을 한번에 적용하는 식으로 최적화 될 것이다.

4.3 파티셔닝 (Partitioning)과 셔플링 (Shuffling)

파티셔닝은 데이터를 여러 노드 (컴퓨터)에 어떻게 분산시킬 것인가에 관한 개념이다.

예를 들어 고객 데이터가 있다면:

  • ID를 기준으로 파티셔닝: ID가 1-1000인 고객은 노드1, 1001-2000은 노드2...
  • 지역을 기준으로 파티셔닝: 서울 거주 고객은 노드1, 부산 거주 고객은 노드2...

셔플링은 파티션 간 데이터 이동이 발생하는 연산이다.
예를 들어 groupBy()join() 같은 연산은 같은 키를 가진 데이터가 같은 파티션에 모여야 하므로 셔플링이 발생한다.

셔플링은 네트워크 비용이 크기 때문에 성능에 큰 영향을 미친다.
그래서 스파크에서는 셔플링을 최소화하거나, 파티셔닝시 그룹을 유지하면서 파티셔닝하는 전략이 필수적이다.

4.4 맵리듀스 (MapReduce)

스파크도 기본적으로 맵리듀스 패러다임을 따른다. 다만 메모리에서 처리될 뿐.


5. 스파크의 장단점

장점

  1. 빠른 처리 속도: 인메모리 처리로 하둡 대비 100배 이상 빠름
  2. 호환성: 하둡 등 다양한 데이터 소스와 연동 가능

단점

  1. 메모리 사용량: 많은 메모리 필요 (충분한 메모리가 없으면 성능 하락)
  2. 튜닝 복잡성: 최적 성능을 위한 파라미터 튜닝이 복잡함 (배치 사이즈, 파티셔닝 사이즈 등)
  3. 실시간 처리의 한계: 밀리초 단위 실시간 처리에는 한계 있음

6. 마무리

이번 포스팅에서는 스파크의 기본 개념과 필요성에 대해 알아봤다.

  1. 빅데이터 처리를 위해 분산 처리 프레임워크가 필요함
  2. 하둡은 HDFS와 MapReduce를 통해 대용량 데이터 처리의 기반을 마련했지만, 디스크 I/O가 병목이었음
  3. 하둡의 디스크 I/O 병목을 해결하기 위해 스파크의 인메모리 컴퓨팅이 등장함
  4. RDD, 지연 연산, 파티셔닝과 같은 핵심 개념들이 스파크의 성능을 극대화함
  5. 스파크는 큰 데이터 처리에 뛰어난 성능을 보이지만, 메모리 사용량이 많다는 단점도 있음

다음 포스팅에서는 스파크 클러스터를 쉽게 세팅하기 위한 도커 스웜에 대해 알아볼 예정이다!

꼭 세팅을 위해서만이 아니라, 분산 처리를 이해하는데 내 기준 가장 도움이 됐던 기능이니,

분산처리에 관심있으면 다음 포스팅도 보면 좋을 것 같다ㅎㅎ

 

 

"언제나, 이 세상 어딘가에 있는 나같은 사람을 위해 족적을 남긴다."

ㄱㅊㅁ_ㅇㅈ

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.