storgate draft

/usr/local/m2/setting.json 다음 영역에 대해 기술한다.

{
  "functions": {
    "backend": {
      "storgate": {
      }
    }
  }
}
../../../../_images/buckets_architecture.png

전체 설정 아키텍쳐

buckets

버킷 구성의 역할은 크게 3가지이다.

  • 멀티 백엔드를 통합한다.

  • 클라이언트에게 위치투명성을 제공한다.

  • 파일을 실시간/배치로 가공한다.

"buckets": [
   {
     ...
   },
   {
     ...
   }
]

meta

개별 버킷의 기본설정을 정의한다.

"meta": {
  "enable": true,
  "name": "mybucket",
  "region": "ap-northeast-2",
  "expose": true
}
enable (기본: true)

버킷 활성화

name

버킷 이름

region (기본: ap-northeast-2)

버킷 리전

expose

(S3 브라우저등) 외부 인터페이스 노출 여부

Note

onBatch 전용으로 사용되는 버킷이라면 노출될 필요가 없다.

mounts

백엔드 엔드포인트를 구성한다.

"mounts": [
  {
    "mountPoint": "/image1",
    "originPath": "mystorage@aws_s3",
  },
  {
    "mountPoint": "/image2",
    "originPath": "/mnt/nas/images"
  },
  {
    "mountPoint": /_this_path_is_hidden",
    "originPath": "google_storage@aws_s3/skip/this/path",
    "expose": false
  }
]
mountPoint (기본: null)

버킷에 마운트될 경로. 값이 null 인 경우 루트로 마운트된다.

originPath

원본 백엔드

  • / 로 시작하는 경우 로컬 파일시스템을 가리킨다.

  • aws_s3 에 정의된 버킷의 이름을 사용하면 해당 백엔드로 연결된다. 연결뒤에 건너띌 경로를 지정할 수 있다.

expose (기본: true)

외부 인터페이스 노출 여부

Note

expose 속성이 존재하는 이유는 tasks.savePath 설정으로 접근할 수 있는 경로가 여기서 구성한 경로로 한정되기 때문이다. 다시 말해 클라이언트에게 경로를 숨기며 내부적인 저장경로로 사용할 경우 이 속성을 false 로 설정한다.

멀티 origin 을 한데 묶을 경우 경로 충돌이 발생할 수 있다.

  1. 명시적으로 선언된 mountPoint 경로가 우선한다.

  2. mountPoint 경로가 없다면 먼저 선언된 origin 이 우선한다.

경로 추상화

mounts 기능은 분산된 백엔드 멀티 스토리지를 하나의 경로체계로 통합한다. 따라서 workflows , onBatch 등에서는 프로토콜과 무관하게 일관된 경로체계를 사용한다.

../../../../_images/mounts.png

모든 기능은 동일한 경로체계를 사용한다.

access

클라이언트 접근권한을 설정한다.

Note

거부된 접근은 403 Forbidden 으로 응답한다.

get

읽기 권한을 설정한다.

"get": {
  "enable": true
}
enable (기본: true)

권한 활성화

put

쓰기 권한을 설정한다.

"put": {
  "enable": true
}
enable (기본: true)

권한 활성화

delete

삭제 권한을 설정한다.

"delete": {
  "enable": true
}
enable (기본: true)

권한 활성화

events

사전 정의된 시점에 발생하는 이벤트 처리를 정의한다.

"events": {
  "onBatch": [ ],
  "onGet": { },
  "onPut": { },
  "onDelete": { }
}

시점

설명

onBatch

정해진 시간(주기)마다 일괄처리

onGet

데이터 읽기 시점

onPut

데이터 쓰기 시점

onDelete

데이터 삭제 시점

모든 이벤트는 filter , trigger , webhook 설정을 지원한다.

"on***": {
  "enable": false,
  "filter": {
    "patterns": [ "*.old" , "*.log.gz" ],
    "excludes": [ "*.conf", ".git" ],
    "filetype": "file",
    "recursive": true,
    "age": "2d",
    "size": "1m"
  },
  "trigger": {
    "workflow": "migrate_tmpimg",
    "timing": "post"
  },
  "webhook": {
    "onItemCompleted": "/usr/local/m2/webhook/call.js",
    "onItemAborted": "/usr/local/m2/webhook/call_err.js"
  }
}
enable (기본: false)

활성화

filter (기본: null)

필터 ( ansible.builtin.find module – Return a list of files based on specific criteria 참고)

Hint

개발 후 릴리스 시점에 정리한다.

trigger

수행될 트리거(=워크플로우)

workflow

워크플로우 이름

timing (기본: post)

시점

  • pre 워크플로우 선행 후 클라이언트 요청처리

  • post 클라이언트 요청처리 후 워크플로우 수행

Note

사전 콘텐츠 가공 목적이라면 pre 시점보다 URL 함수체인이 권장된다.

webhook

웹훅을 호출한다.

onItemCompleted

개별 처리가 정상완료 될 때마다 호출된다.

onItemAborted

개별 처리가 에러상황으로 중단될 때마다 호출된다.

onBatch

mounts 를 대상으로 정해진 시간(주기)마다 약속된 작업을 수행한다. 단일 백엔드를 대상으로 멀티 배치를 수행할 수 있다.

"onBatch": [
  {
    "enable": false,
    "chunkSize": 1000,
    "path": "/image/upload",
    "traverse": "depth",
    "cursor": "continue",
    "schedule": "0 1 * * *",
    "filter": { ... },
    "trigger": { ... },
    "webhook": {
      "onChunkExtracted": "/usr/local/m2/webhook/begin_chunk.js",
      "onChunkCompleted": "/usr/local/m2/webhook/end_chunk.js",
      "onItemCompleted": "/usr/local/m2/webhook/kafkapub.js"
    }
  }
]
chunkSize (기본: 1000)

청크 크기(개수)

Note

기본 값이 1천개인 이유는 AWS S3에서 한번에 리스팅할 수 있는 최대 객체수가 1,000개이기 때문이다. (2024년 12월 기준)

path

경로 추상화 된 디렉토리 ( / 루트)

Note

  • 로컬 경로라도 반드시 mounts 구성이 필요하다.

  • 여러 디렉토리를 추출하려면 워크플로우를 멀티로 구성할 것을 권장한다.

traverse (기본: depth)

파일트리 탐색방법 ( depth 또는 breadth )

Hint

[개발단계 체크] S3에선 설정이 불가할 수 있다.

cursor (기본: continue)

작업목록(청크) 추출 정책

  • continue (기본) 이전 청크의 마지막부터 이어서 진행한다.

  • reset 항상 처음부터 진행한다.

    Warning

    reset 정책은 원본이 onComplete 설정에 의해 삭제, 이동된 경우에만 사용한다. 원본이 그대로 존재하는 경우 무한루프가 발생할 수 있다.

schedule

추출 스케쥴. cron 형식

webhook

각 시점마다 약속된 웹훅을 호출한다.

onChunkExtracted (리더만 수행)

chunkSize 만큼 작업목록이 준비된 직후 호출된다.

onChunkCompleted (리더만 수행)

chunkSize 단위 작업이 완료된 시점에 호출된다.

onItemCompleted

개별 처리가 완료될 때마다 호출된다.

onGet

읽기 이벤트를 정의한다.

"onGet": {
  "enable": false,
  "filter": null,
  "trigger": {
    "workflow": "migrate_tmpimg",
    "timing": "post"
  }
}

Hint

[백업용] 현재 개발단계에서 cache 기능은 제외한다.

"cache": {
  "enable": false,
  "vhost": "foo.com"
}

onPut

쓰기 이벤트를 정의한다.

"onPut": {
  "enable": true,
  "trigger": {
    "workflow": "migrate_tmpimg",
    "timing": "post"
  }
}
enable (기본: false)

활성화

filter (기본: null)

필터

trigger

워크플로우 트리거

workflow

워크플로우 이름

timing (기본: post)

시점

  • pre 워크플로우 선행 후 클라이언트 요청처리

  • post 클라이언트 요청처리 후 워크플로우 수행

onDelete

삭제 이벤트를 정의한다.

"onDelete": {
  "enable": true,
  "trigger": {
    "workflow": "migrate_tmpimg",
    "timing": "post"
  }
}

workflows

워크플로우는 콘텐츠를 가공하는등 수행해야하는 구체적인 작업을 의미한다. 단일 원본에 대해 동시에 여러 작업을 진행할 수 있다.

"workflows": [
  {
    "name": "migrate_tmpimg",
    "enable": true,
    "tasks": [ ]
  },
  {
    "name": "remove_old",
    "tasks": [ ]
  }
]
name

워크플로우 이름

enable (기본: true)

워크플로우 활성화

tasks

워크플로우의 개별 아이템(원본 데이터)당 처리 작업을 정의한다.

tasks

단일 원본에 대해 동시에 여러 산출물을 생산하고,저장하는 것까지 담당한다.

"tasks": [
  {
    "function": "/hyperdims/format/avif/optimize",
    "savePath": "/newimg/{{ item.path }}",
    "whenExist": "overwrite",
    "timeout": 60
  },
  {
    "function": "/hyperdims/format/webp/resize/500",
    "savePath": "/{{ item.path | relpath(source_dir) | dirname }}/{{ item.path | basename | rsplit('.', 1)[0] }}_m.{{ item.path | basename | rsplit('.', 1)[-1] }}",
  },
  {
    "function": "/hyperdims/format/webp",
    "savePath": "/newimg/#2",
    "pathPattern": "/([^/]+)/(.*)"
  }
]
function

가공 함수체인. 소스는 events 가 발생한 개별 파일로 지정된다.

savePath

값이 유효하지 않거나 null 이라면 원본 경로에 덮어쓰기한다. Nunjucks 표현이며 사용할 수 원본경로는 item 에 바인딩된다.

Note

  • null 은 허가하지 않는다.

  • 원본 덮어쓰기라도 명시적으로 {{ item.path }} 로 지정한다.

  • 소속 bucket 의 상대경로만 접근할 수 있다. (참조 - mounts )

변수

설명

예시

item.path

파일의 전체 경로

/dir/sample.jpg

item.filename

파일명

sample.jpg

item.dirname

파일이 위치한 디렉토리 경로

/dir

item.state

파일의 상태

file

item.size

파일의 크기 (bytes)

123456

item.owner

파일의 소유자

root

item.group

파일의 소유 그룹

users

item.mode

파일의 권한 모드

0644

item.mtime

파일의 최종 수정 시간 (UNIX 타임스탬프)

1622555123

item.atime

파일의 마지막 접근 시간 (UNIX 타임스탬프)

1622555200

item.ctime

파일의 생성 시간 (UNIX 타임스탬프)

1622554987

item.inode

파일의 inode 번호

12345

pathPattern

savePath 에서 사용할 정규표현식 패턴. #1 , #2 등으로 소스경로를 참조할 수 있다.

Note

pathPatternsavePath 생성을 위한 Nunjucks 실행 이전에 동작한다.

whenExist (기본: overwrite)

savePath 에 파일이 존재할 경우 정책

  • overwrite (기본) 항상 덮어쓴다.

  • skip 덮어쓰지 않는다.

  • diff 파일이 변경되었을 때만 덮어쓴다.

timeout (기본: 60초)

실패 타임아웃

onComplete

모든 tasks 이 완료된 상태에서 수행된다.

"onComplete": {
  "src": {
    "op": "none"
  }
}
src

개별 아이템 작업 완료 후 소스 파일에 대한 처리

op (기본: none)

오퍼레이션

  • none (기본) 아무 작업도 진행하지 않는다.

  • delete 삭제한다.

  • move 약속된 디렉토리로 이동시킨다.

    "src": {
      "op": "move",
      "path": "/processed/{{ item.path }}"
    }
    

distribution

멀티노드 환경에서 workflows 분산처리 설정을 정의한다.

meta

"meta" : {
  "enable": true
}
enable (기본: true)

활성화. false 라면 분산없이 모든 노드는 리더로 동작한다.

leader

대규모 onBatch 작업들을 관리할 리더를 선출한다.

"leader": {
  "url": "file://mnt/nas/images/temp/.{vhost}.m2leader",
  "authEndpoint": null
}
url

리더선출에 사용할 락파일의 URL. 락은 고유하게 생성되기 때문에 멀티 가상호스트에 의해 동시수행되어도 충돌하지 않는다. 파일시스템 file:// , S3 https:// 등을 지원한다.

authEndpoint

인증이 필요한 백엔드와 연결할 경우 aws_s3 에 정의된 name 을 지정한다.

leader 선출

../../../../_images/leader_election.png
  1. leader 노드가 없다면 모든 노드는 leader 설정을 기반으로 leader 를 선출한다. 단일 노드로 구동되는 환경이라도 동일하다.

  2. leader 노드는 지속적으로 임기(기본: 5분)를 연장한다.

  3. leader 노드 장애시 임기동안은 작업이 중단된다.

  4. 임기가 만료된 상태에서 leader 노드가 없다면 1번 단계를 수행한다.

leader 노드 장애

리더에 장애가 발생한다면 수행중인 청크는 일시 중단되며, 리더 재선출을 수행한다.

../../../../_images/leader_election2.png

새로운 리더에 의해 이전 워크플로우가 재개된다.

리더 재선출 후 진행 중인 청크는 재개된다.

Note

leader 는 재작업을 최소화하기 위해 실시간으로 완료된 진행상황을 모든 노드와 공유한다.

수행노드 장애

수행노드의 장애가 발생하면 리더가 배제시키고 워크플로우를 완수한다.

Warning

최악의 경우 해당 노드가 수행중이던 작업은 1회 더 수행될 수 있다.

throttling

CPU 가용량에 충분한경우에만 tasks 를 수행한다.

"throttling": {
  "enable": true,
  "cpu": {
    "deactive": 60,
    "reactive": 40
  }
}
enable (기본: true)

throttling 을 활성화한다.

cpu

평균 CPU 사용량에 따라 동적으로 워크플로우를 수행한다.

Note

평균 cpu 사용량 기준은 전역으로 변경이 가능하다.

deactive (기본: 60, 범위: 0 ~ 100)

평균 CPU 사용량이 설정 값 이상이라면 부하를 낮추기 위해 수행을 잠시 중단한다.

reactive (기본: 40, 범위: 0 ~ 100)

( deactive 상태에서) 평균 CPU 사용량이 설정 값 미만이라면 다시 수행을 재개한다.

Note

reactive 값이 deactive 값을 초과하거나 유효 범위가 아니라면 deactive2/3 수치로 적용된다.

분산처리와 장애복구

정상적인 경우 리더에 의해 모든 작업이 관리된다.

../../../../_images/etlfail1.png

workflow는 chunkSize 단위로 작업을 분할하여 수행한다. 리더에 장애가 발생한다면 리더 재선출 후 진행 중인 청크는 재개된다.

../../../../_images/etlfail3.png

장애노드의 작업은 새로운 리더에 의해 균등하게 분배된다.

leader 는 재작업을 최소화하기 위해 실시간으로 완료된 진행상황을 모든 노드와 공유한다.

Note

리더승계시 마커(marker)의 이해

  • AWS S3 ListObjects 의 경우 NextMarker 를 모든 청크 단위로 공유한다.

  • NTFS/VFS인 경우 새로운 리더가 동일한 알고리즘으로 해당 지점까지 traverse를 수행한 뒤 재개한다.

설정예제

NFS 랜딩존

특정 디렉토리를 감지하여 서비스 디렉토리로 이관한다.

../../../../_images/useland1.png

설정 예제는 아래와 같다.

"storage": {
  "buckets": [
    {
      "name": "image_landing_bucket",
      "expose": true,

      # /image_landing 디렉토리만 노출한다.
      # /image_service 디렉토리는 노출하지 않는다.
      "mounts": [
        {
          "mountPoint": "/image_landing",
          "originPath": "/mnt/nas/upload"
        },
        {
          "mountPoint": "/image_service",
          "originPath": "/mnt/nas/image/service",
          "expose": false
        }
      ],

      # 5분마다 /image_landing 디렉토리를 스캔하여, migrate_tmpimg 워크플로우를 실행한다.
      # 배치로 개별 아이템이 처리될 떄마다 CDN에 Purge한다.
      "events": {
        "onBatch": [
          {
            "enable": true,
            "chunkSize": 1000,
            "path": "/image_landing",
            "schedule": "*/5 * * * *"
            "trigger": {
              "workflow": "migrate_tmpimg"
            },
            "webhook": {
              "onItemCompleted": "/usr/local/m2/webhook/purge_cdn.js"
            }
          }
        ]
      }

      # workflow 정의
      # /image_landing 디렉토리의 파일을 /image_service 디렉토리로 이관한다.
      # 이관후 원본파일은 삭제한다.
      "workflows": [
        {
          "name": "migrate_tmpimg"
          "tasks": [
            {
              "function": null,
              "savePath": "/image_service/{{ item.path }}",
              "whenExist": "overwrite",
              "timeout": 60
            }
          ],
          "onComplete": {
            "src": {
              "op": "delete"
            }
          }
        }
      ]
    }
  ]
}