본문 바로가기
엑셈 경쟁력/Apache Druid가 궁금하면 드루와요

궁금하면 드루와요 | Druid without Middle Manager

by blcuwjl 2024. 1. 25.

Part.5 Druid without Middle Manager (MM less): k8s 리소스(파드)를 사용한 드루이드 태스크 관리 개선


Part.1 Apache Druid란(링크)

Part.2 Druid Operator: 드루이드 오퍼레이터 도입으로 드루이드 설치부터 관리까지의 과정 개선 (링크)

Part.3 Druid Tuning: 제한된 자원속에서 카프카 스트림으로부터 데이터 수집하는 기능(성능)의 최적화(링크)

Part.4 Druid Tiering: 데이터가 조회되는 빈도 기준으로 데이터를 구분 (링크)

Part.5 Druid without Middle Manager (MM less): k8s 리소스(파드)를 사용한 드루이드 태스크 관리 개선


 

이번 글에서는 Apache Druid Middle Manager 없이 사용하는 법을 살펴보겠습니다. 

 

  1. K8S환경에서 Middle manager 없이 드루이드 task 관리(mm less)
  2. MM Less의 특징
  3. DataSaker에서 MM Less 적용
  4. MM Less 사용방법
  5. 마치며

 

K8S환경에서 Middle Manager 없이 드루이드 task 관리(MM Less)

드루이드에서 Middle Manager(이하 MM)는 데이터 수집, 압축 등을 수행하는 작업을 관리하는 서비스입니다.  K8S 환경에서는 MM을 사용하지 않고, K8S의 일부 기능인 Job과 Pod를 활용하여 이를 대체할 수 있습니다.

 

MM Less의 특징

기존 MM에서는 작업을 하나의 프로세스 형태로 실행했습니다. 이로 인해 서비스에 고정적인 자원을 할당하는 문제가 있었고, 필요에 따라 자원을 유동적으로 사용하는 것이 어려웠습니다. 또한, MM에 문제가 발생하거나 특정 작업에 문제가 생겨 MM에 영향을 미치면, 다른 작업에도 장애가 전파되는 문제가 있었습니다.

 

MM을 제거하고 K8S 환경을 사용함으로써 다음과 같은 특징을 얻을 수 있습니다.

 

  1. Worker node가 제공하는 범위 내에서 자원을 자유롭게 사용 가능
  2. MM 의존성 제거
  3. 장애 전파 최소화
  4. 작업 타입 별 자원 및 설정 관리 용이성 향상

 

DataSaker에서 MM Less 적용

DataSaker는 실시간으로 데이터를 수집, 가공, 표시하는 과정에서 복잡한 데이터 처리가 이루어집니다. 작은 장애라도 치명적인 문제를 일으킬 수 있어, 데이터 수집 과정에서 의존성을 제거하고 작업을 독립적으로 분리하여 장애 전파를 방지하는 구조로 전환하기로 결정했습니다.

 

MM Less 사용 방법

MM Less를 적용하는 방법은 아래와 같습니다.

 

  • extension 추가
  • task를 실행할 pod 스펙 작성
  • overlord에 task pod spec 추가

 

1. extension 추가

K8S 연동해서 사용하기 위한 extension을 다음과 같이 추가합니다.

druid.extensions.loadList=[“druid.kubernetes.overlord.-extensions”]

 

2. pod spec 정의

task가 사용할 수 있는 pod spec을 정의할 수 있도록 합니다.

pod spec은 다음과 같이 구성했으며, 환경과 구성에 따라 값이 바뀔 수 있습니다.

 

apiVersion: "v1"
kind: "PodTemplate"
template:
  metadata:
    labels:
      app.kubernetes.io/name: "druid-realtime-backend"
  spec:
    containers:
    - command:
        - sh
        - -c
      args:
        - /peon.sh /druid/data 1 --loadBroadcastSegments true
      env:
      - name: POD_NAME
        valueFrom:
          fieldRef:
            fieldPath: metadata.name
      - name: POD_NAMESPACE
        valueFrom:
          fieldRef:
            fieldPath: metadata.namespace
      # 2023-11-03
      # jvm.options 파일을 이용해 JVM 설정을 할 수 있지만, 현재 jvm.options가 정상적으로 반영되지 않는 문제가 있어 환경변수로 JVM 옵션을 설정하고 있습니다.
      # 태스크의 튜닝과 관련된 내용은 아래 링크를 확인해주세요.
      # 중요!!! MaxDirectMemorySize 최소 설정 값 = ((druid.processing.numThreads + druid.processing.numMergeBuffers + 1) * druid.processing.buffer.sizeBytes)
      # https://druid.apache.org/docs/latest/operations/basic-cluster-tuning/#task-configurations
      - name: JAVA_OPTS
        value: -server -Xmx512m -Xms256m -XX:MaxDirectMemorySize=1500m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -Djava.io.tmpdir=/druid/data -Ddruid.port=8100 -Ddruid.plaintextPort=8100 -Ddruid.tlsPort=-1 -Ddruid.task.executor.tlsPort=-1 -Ddruid.log.path=log -Ddruid.node.type=peon
      - name: druid_host
        valueFrom:
          fieldRef:
            apiVersion: v1
            fieldPath: status.podIP
      - name: HOSTNAME
        valueFrom:
          fieldRef:
            apiVersion: v1
            fieldPath: metadata.name
      # 2023-11-03
      # 사용되는 드루이드 버젼입니다.
      # 2023-11-03 기준 최신 버전은 27.0.0이며 드루이드의 메이저 버전업 주기는 3~4개월입니다.
      image: apache/druid:27.0.0
      name: main
      ports:
      - containerPort: 8091
        name: druid-tls-port
        protocol: TCP
      - containerPort: 8100
        name: druid-port
        protocol: TCP
      resources:
        requests:
          memory: 256Mi
        limits:
          # 2023-11-03
          # (Xmx + MaxDirectMemorySize) + 200~300MiB 기준으로 합니다.
          # (Xmx + MaxDirectMemorySize)로만 할 경우 여유 메모리가 없어 Pod Event에서 OOMKilled 발생 가능성이 있습니다.
          memory: 2300Mi
      volumeMounts:
        - mountPath: /opt/druid/conf/druid/cluster/_common
          name: common-config-volume
          readOnly: true
        - mountPath: /opt/druid/conf/druid/cluster/master/coordinator-overlord # runtime props are still mounted in this location because that's where peon.sh looks for configs
          name: nodetype-config-volume
          readOnly: true
        - mountPath: /druid/data
          name: data-volume
        - mountPath: /druid/deepstorage
          name: deepstorage-volume
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access-fhld8
          readOnly: true
    restartPolicy: "Never"
    securityContext:
      fsGroup: 1000
      runAsGroup: 1000
      runAsUser: 1000
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
            - matchExpressions:
                - key: druid/server
                  operator: In
                  values:
                    - data
    tolerations:
    - effect: NoExecute
      key: node.kubernetes.io/not-ready
      operator: Exists
      tolerationSeconds: 300
    - effect: NoExecute
      key: node.kubernetes.io/unreachable
      operator: Exists
      tolerationSeconds: 300
    - key: druid/data
      effect: NoSchedule
      operator: Exists
    - key: druid/component
      effect: NoSchedule
      value: middlemanager
      operator: Equal
    volumes:
      - configMap:
          defaultMode: 420
          name: druid-druid-common-config
        name: common-config-volume
      - configMap:
          defaultMode: 420
          name: druid-peons-config
        name: nodetype-config-volume
      - emptyDir: {}
        name: data-volume
      - emptyDir: {}
        name: deepstorage-volume
      - name: kube-api-access-fhld8
        projected:
          defaultMode: 420
          sources:
            - serviceAccountToken:
                expirationSeconds: 3607
                path: token
            - configMap:
                items:
                  - key: ca.crt
                    path: ca.crt
                name: kube-root-ca.crt
            - downwardAPI:
                items:
                  - fieldRef:
                      apiVersion: v1
                      fieldPath: metadata.namespace
                    path: namespace

 

3. overlord에 pod spec 추가

MM Less를 사용하게 될 경우 task의 메타성 정보 관리는 overlord로 이관하게 됩니다. 따라서 overlord에 pod spec 정보를 올린 뒤 사용할 수 있도록 합니다.

 

volumeMounts:
  - name: base-pod-spec
    mountPath: /opt/druid/conf/basePodSpec.yaml
    subPath: basePodSpec.yaml
volumes:
  - name: base-pod-spec
    configMap:
      name: druid-yaml-config
      items:
        - key: basePodSpec.yaml
          path: basePodSpec.yaml

 

configmap을 이용하여 yaml파일을 configmap에 저장한 뒤 서비스가 올라올 때 마운트 하는 형식으로 구성했습니다.

 

구성 후

 

 

구성 후 kubectl get job 명령어로 job을 통해 task가 생성되고 삭제되고 있는 것을 볼 수 있습니다.

이처럼 node가 허용되는 자원 속에서 자유롭게 생성되고 삭제가 됨으로써 자원을 효율적으로 사용할 수 있고, 각 task가 하나의 job형태로 구분되어서 task에 문제가 발생하더라고 다른 task에 장애가 전파되지 않을 수 있습니다.

 

node가 허용하는 자원 범위 내에서 작업이 자유롭게 생성되고 삭제됨으로써 자원을 효율적으로 사용할 수 있습니다. 각 작업이 하나의 Job 형태로 구분되어, 한 작업에 문제가 발생해도 다른 작업에 장애가 전파되지 않는 구조가 됩니다.

 

 

마치며

MM Less를 통해 자원을 효율적으로 사용하게 됨으로써 서비스를 안정적으로 관리할 수 있습니다. 또한 불필요한 자원을 계속 잡을 필요가 없어 운영비용 면에서도 상당한 이점이 있습니다. 

 

지금까지 드루이드에 대해 5편의 콘텐츠를 통해 체계적으로 알아봤는데요. 여러분들께 조금이나마 도움이 되셨기를 바랍니다. 그럼, 우리 모두 즐거운 드루이드 생활을 하면서 또 궁금한 게 있으시면 언제나 저희와 소통해주세요. 

 

 

 

 

 

글 | 플랫폼 3팀 윤혁준, 박준수

 

 

 

 

 

 

댓글