0Pricing
Scala for Backend Engineering & Functional Programming · 강의

백프레셔

빠른 생산자를 안전하게 처리해 보세요.

백프레셔은(는) CoddyKit의 무료 Scala for Backend Engineering & Functional Programming 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Scala for Backend Engineering & Functional Programming 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Scala for Backend Engineering & Functional Programming 강의에는 총 4개의 강의가 포함되어 있습니다.

역압이란 무엇인가요?

역압은 빠른 생산자가 느린 소비자를 압도하지 않도록 하는 흐름 제어 메커니즘입니다. 소비자는 버퍼를 무한히 늘리거나 데이터를 버리는 대신 자신이 처리할 수 있는 양을 알립니다.

Akka Streams는 Reactive Streams 표준을 구현합니다. 이 표준에서는 수요가 upstream으로 흐르고 요소가 downstream으로 흐릅니다.

수요 기반 흐름

각 스테이지는 다음 스테이지가 수요를 알린 경우에만 요소를 내보냅니다. 싱크가 N개의 요소를 요청하면 그 수요가 upstream으로 전파되어 소스는 요청받은 만큼 정확히 생성합니다.

이 pull 기반 프로토콜에서는 생산자가 소비자가 처리할 수 있는 양보다 많이 보내지 않습니다.

파이프라인에서 역압이 중요한 이유

역압이 없다면 빠른 Kafka 소비자에서 느린 데이터베이스로 데이터를 보낼 때 처리 중인 레코드가 수백만 개 쌓여 메모리가 고갈되고 프로세스가 중단될 수 있습니다.

역압은 자연스럽게 가장 느린 스테이지에 맞춰 upstream을 조절하므로 부하가 걸려도 메모리 사용량을 안정적으로 유지합니다.

// Fast source, slow sink: backpressure slows the source
val g =
  Source(1 to 1000000)
    .map(_ * 2)
    .to(slowDatabaseSink)

내부 버퍼링

비동기 경계 사이에서 Akka Streams는 작은 내부 버퍼를 유지합니다(기본값은 16개 요소). 이 버퍼는 짧은 데이터 급증을 흡수하므로 스테이지가 모든 요소를 매번 동시에 처리할 필요가 없습니다.

버퍼가 가득 차면 역압이 시작되고, 공간이 생길 때까지 upstream은 생성을 멈춥니다.

import akka.stream.Attributes

val buffered =
  Flow[Int]
    .map(identity)
    .addAttributes(Attributes.inputBuffer(initial = 32, max = 32))

Overflow Strategy를 사용한 명시적 버퍼

buffer 연산자는 지정한 크기의 명시적 버퍼를 삽입하고, 버퍼가 가득 찼을 때의 동작을 결정하는 OverflowStrategy를 함께 사용합니다.

이를 통해 생산자와 소비자의 속도를 분리하는 대신 메모리를 사용할지 선택할 수 있습니다.

import akka.stream.OverflowStrategy

val withBuffer =
  Source(1 to 1000)
    .buffer(size = 100, OverflowStrategy.backpressure)

오버플로 전략

전략에는 upstream을 느리게 하는 backpressure, 가장 오래된 요소나 최신 요소를 버리는 dropHead/dropTail, dropBuffer, dropNew, 그리고 오류와 함께 종료하는 fail이 있습니다.

센서 측정값처럼 오래된 값을 안전하게 버릴 수 있는 실시간 데이터에는 삭제 전략이 적합합니다.

import akka.stream.OverflowStrategy

val latestWins =
  liveTicks.buffer(1, OverflowStrategy.dropHead)

val strict =
  liveTicks.buffer(50, OverflowStrategy.fail)

요약을 위한 Conflate

소비자가 느릴 때 conflate는 대기 중인 요소를 모두 버퍼링하는 대신 결합 함수를 사용해 하나로 합칩니다.

예를 들어 여러 숫자 업데이트를 합계 하나로 축약하면 소비자는 놓친 값이 모두 반영된 집계값을 항상 확인할 수 있습니다.

val summarized =
  fastMetrics
    .conflate((acc, next) => acc + next)

// Slow downstream receives summed batches

수요를 채우는 Expand

expand는 conflate의 반대 개념입니다. downstream의 수요가 upstream의 생산보다 빠를 때 마지막으로 확인한 값에서 추가 요소를 만들어 냅니다.

가장 최근의 측정값을 일정한 속도로 계속 내보내야 할 때 유용합니다.

val repeated =
  sensor.expand(last => Iterator.continually(last))

// Downstream always gets the latest sensor value

비동기 경계

기본적으로 융합된 스테이지는 하나의 액터에서 실행되며 스테이지 사이에 버퍼가 없습니다. async를 삽입하면 스테이지가 자체 액터에서 실행되고 버퍼가 추가되어 파이프라인식 병렬 처리가 가능해집니다.

비동기 경계에 실제 역압 버퍼가 존재합니다.

val pipelined =
  Source(1 to 1000)
    .map(slowStep).async
    .map(anotherSlowStep).async
    .to(Sink.ignore)

명시적 속도 제어로서의 Throttle

throttle은 의도적으로 최대 속도를 설정하고 이를 지키도록 upstream에 역압을 발생시킵니다. 따라서 소비자가 더 빠르게 처리할 수 있더라도 속도 제한이 있는 외부 서비스를 보호할 수 있습니다.

버스트 매개변수를 사용하면 일정한 속도를 잠시 초과하는 급증을 허용할 수 있습니다.

import scala.concurrent.duration._

val limited =
  requests
    .throttle(
      elements = 100, per = 1.second, maximumBurst = 20,
      akka.stream.ThrottleMode.Shaping)

역압 관찰하기

upstream이 느려지는지 관찰하거나 버퍼 점유량을 측정하면 역압을 감지할 수 있습니다. log 연산자와 Akka의 스트림 속성을 사용하면 파이프라인이 어느 지점에서 멈추는지 추적할 수 있습니다.

버퍼가 계속 가득 차 있다면 처리량을 제한하는 가장 느린 스테이지가 있다는 뜻입니다.

val traced =
  Source(1 to 100)
    .log("after-source")
    .map(_ * 2)
    .log("after-map")
    .to(Sink.ignore)

빠른 확인

Akka Streams가 빠른 생산자가 느린 소비자를 압도하지 않도록 하는 방법을 생각해 보세요.

복습

역압은 Akka Streams의 수요 기반 핵심 구조입니다. 소비자가 upstream에 수요를 알리므로 생산자가 소비자를 압도할 수 없고, 메모리 사용량도 제한된 범위로 유지됩니다.

내부 버퍼, 오버플로 전략을 사용하는 명시적 buffer 연산자, conflate를 통한 요약, expand를 통한 수요 충족, 비동기 경계, throttle을 통한 의도적인 속도 제어를 살펴보았습니다. 다음에는 완전한 파이프라인을 실행해 보겠습니다.

자주 묻는 질문

“백프레셔” 강의는 무료인가요?

네 — “백프레셔” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Scala for Backend Engineering & Functional Programming 강의 전체를 잠금 해제할 수 있습니다. Scala for Backend Engineering & Functional Programming 강의에는 총 4개의 강의가 포함되어 있습니다.

“백프레셔”에서 뭘 배우나요?

빠른 생산자를 안전하게 처리해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Scala for Backend Engineering & Functional Programming을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Scala for Backend Engineering & Functional Programming을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Scala for Backend Engineering & Functional Programming은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“백프레셔” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Scala for Backend Engineering & Functional Programming 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Scala for Backend Engineering & Functional Programming 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 소스, 플로, 싱크
  2. 스트림 변환하기
  3. 백프레셔
  4. 파이프라인 실행하기
← Scala for Backend Engineering & Functional Programming(으)로 돌아가기