storgate beta¶
함수 가이드
이 함수는 분산 클러스터 노드 를 구성할 수 있다.
이 때, 리더 - 워커간
8588포트 통신이 가능하도록 방화벽 조치해야한다.
/usr/local/m2/setting.json 다음 영역에 대해 기술한다.
{
"functions": {
"backend": {
"storgate": {
}
}
}
}
전체 설정 아키텍쳐¶
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 을 한데 묶을 경우 경로 충돌이 발생할 수 있다.
명시적으로 선언된
mountPoint경로가 우선한다.mountPoint경로가 없다면 먼저 선언된origin이 우선한다.
경로 추상화¶
mounts 기능은 분산된 백엔드 멀티 스토리지를 하나의 경로체계로 통합한다. 따라서 workflows , onBatch 등에서는 프로토콜과 무관하게 일관된 경로체계를 사용한다.
모든 기능은 동일한 경로체계를 사용한다.¶
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": { },
"paramGlobal": null
}
시점 |
설명 |
|---|---|
|
정해진 시간(주기)마다 일괄처리 |
|
데이터 읽기 시점 |
|
데이터 쓰기 시점 |
|
데이터 삭제 시점 |
모든 이벤트는 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",
"matchingList": [
{
"pattern": "*.old",
"workflow": "migrate_oldimg",
}
]
},
"webhook": {
"onItemCompleted": "/usr/local/m2/webhook/call.js",
"param": null
}
}
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 함수체인이 권장된다.matchingList (기본: [])경로 패턴별 워크플로우
pattern파일 경로 매칭 패턴workflow워크플로우 이름timing시점
webhook웹훅을 호출한다.
See also
onItemCompleted개별 처리가 정상완료 될 때마다 호출된다.
param웹훅에 전달할 파라미터
paramGlobal웹훅 전달할 파라미터
Note
param 이 2개인 이유는 전역과 개별 웹축의 param 를 구분하기 위함이다.
{
"param": {
...
"webhook": {
...
}
}
}
웹훅 개발가이드 참고한다.
onBatch¶
mounts 를 대상으로 정해진 시간(주기)마다 약속된 작업을 수행한다. 단일 백엔드를 대상으로 멀티 배치를 수행할 수 있다.
"onBatch": [
{
"enable": false,
"chunkSize": 1000,
"path": "/image/upload",
"traverse": "breadth",
"cursor": "continue",
"schedule": "* * * * * *",
"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 (기본: breadth)파일트리 탐색방법
Hint
NFS 전용, 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": "/([^/]+)/(.*)"
},
{
"savePath": "/{{ item.path | substring(10) | throw }}",
"errorPath": "/error/{{ item.path }}"
}
]
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
errorPathsavePath의 nunjucks 표현 중throw되었다면 이 경로에 기록한다.
Note
throw 표현은 nunjucks 필터이며, 값이 유효하지 않다면 예외를 던진다.
# item.filename: 00001.jpg
savePath: "{{ item.filename | substring(5) | throw }}"
- 기대값: ".jpg", 결과값: ".jpg"
- throw 되지 않는다.
# item.filename: 1.jpg
savePath: "{{ item.filename | substring(5) | throw }}"
- 기대값: ".jpg", 결과값: ""
- throw 되어 errorPath에 기록한다.
pathPatternsavePath에서 사용할 정규표현식 패턴.#1,#2등으로 소스경로를 참조할 수 있다.Note
pathPattern은savePath생성을 위한 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 }}" }
Note
마이그레이션의 목적이 복사가 아닌 삭제 또는 이동이라면,
tasks를 생략할 수 있다."workflows": [ { "name": "remove_old", "onComplete": { "src": { "op": "delete" } } } ]
distribution¶
멀티노드 환경에서 workflows 분산처리 설정을 정의한다.
Important
멀티노드 환경의 리더-워커 노드간 통신 포트는
8588이다.명시적인 방화벽 오픈을 확인해야 한다.
meta¶
"meta" : {
"enable": true
}
enable (기본: true)활성화.
false라면 분산없이 모든 노드는 리더로 동작한다.
leader¶
대규모 onBatch 작업들을 관리할 리더를 선출한다.
"leader": {
"url": "file://mnt/nas/images/temp/.{vhost}.m2leader",
"authEndpoint": null
}
url리더선출에 사용할 락파일의 URL. 락은 고유하게 생성되기 때문에 멀티 가상호스트에 의해 동시수행되어도 충돌하지 않는다. 파일시스템
file://, S3https://등을 지원한다.authEndpoint인증이 필요한 백엔드와 연결할 경우 aws_s3 에 정의된
name을 지정한다.
leader 선출¶
leader노드가 없다면 모든 노드는 leader 설정을 기반으로leader를 선출한다. 단일 노드로 구동되는 환경이라도 동일하다.leader노드는 지속적으로 임기(기본: 5분)를 연장한다.leader노드 장애시 임기동안은 작업이 중단된다.임기가 만료된 상태에서
leader노드가 없다면 1번 단계를 수행한다.
leader 노드 장애¶
리더에 장애가 발생한다면 수행중인 청크는 일시 중단되며, 리더 재선출을 수행한다.
새로운 리더에 의해 이전 워크플로우가 재개된다.¶
리더 재선출 후 진행 중인 청크는 재개된다.
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값을 초과하거나 유효 범위가 아니라면deactive의2/3수치로 적용된다.
분산처리와 장애복구¶
See also
정상적인 경우 리더에 의해 모든 작업이 관리된다.
workflow는 chunkSize 단위로 작업을 분할하여 수행한다.
리더에 장애가 발생한다면 리더 재선출 후 진행 중인 청크는 재개된다.
장애노드의 작업은 새로운 리더에 의해 균등하게 분배된다.¶
leader 는 재작업을 최소화하기 위해 실시간으로 완료된 진행상황을 모든 노드와 공유한다.
Note
리더승계시 마커(marker)의 이해
AWS S3 ListObjects 의 경우
NextMarker를 모든 청크 단위로 공유한다.NTFS/VFS인 경우 새로운 리더가 동일한 알고리즘으로 해당 지점까지 traverse를 수행한 뒤 재개한다.
웹훅 개발가이드¶
events 하위에 정의된 웹훅을 통해 타 시스템과 연동할 수 있다. 각 웹훅 함수는 설정명과 동일한 이름으로 호출되며 2개의 파라미터를 가진다.
function onItemCompleted(context) {
...
}
context이벤트별 컨텍스트 정보
onChunkExtracted¶
작업목록 추출이 완료되었을 떄 호출된다.
{
"meta": {
"vhost": "example.com",
"bucket": "image_bucket",
"basePath": "/",
"event": "batch",
"trigger": {
"workflow": "migrate_tmpimg",
"timing": "post"
},
"timestamps": {
"extract": {
"start": "2024-03-28T10:15:45.256Z",
"end": "2024-03-28T10:15:48.456Z"
}
},
"sum": {
"traverse": {
"count": 10000000,
"size": 1234567893232
},
"complete": {
"count": 9999900,
"size": 1234567102323
},
"abort": {
"count": 100,
"size": 1293821
}
}
},
"chunk": {
"id": "12345678-1234-1234-1234-123456789012",
"iteration": 123,
"type": "depth",
"count": 1000,
"size": 123456789,
"prevPath": "/image/upload/2024/02/11/sample.jpg",
"nextPath": "/image/upload/2024/03/28/test.jpg",
"files": [
{
"path": "/image/upload/2024/02/12/sample.jpg",
"size": 123456,
"mtime": 1622555123
},
{
"path": "/image/upload/2024/02/12/sample_large.jpg",
"size": 45234,
"mtime": 1622555127
},
...
]
},
"paramGlobal": null,
"param": null
}
onChunkCompleted¶
onChunkExtracted 와 같으며 timestamps 하위 excute 필드 및 개별 files[] 처리 결과정보등이 추가된다.
{
"meta": {
"vhost": "example.com",
"bucket": "image_bucket",
"basePath": "/",
"event": "batch",
"trigger": {
"workflow": "migrate_tmpimg",
"timing": "post"
},
"timestamps": {
"extract": {
"start": "2024-03-28T10:15:45.256Z",
"end": "2024-03-28T10:15:48.456Z"
},
"excute": {
"start": "2024-03-28T10:15:49.123Z",
"end": "2024-03-28T10:17:45.789Z"
}
},
"sum": {
"traverse": {
"count": 10000000,
"size": 1234567893232
},
"complete": {
"count": 9999900,
"size": 1234567102323
},
"abort": {
"count": 100,
"size": 1293821
}
}
},
"chunk": {
"id": "12345678-1234-1234-1234-123456789012",
"iteration": 123,
"type": "depth",
"count": 1000,
"size": 123456789,
"prevPath": "/image/upload/2024/02/11/sample.jpg",
"nextPath": "/image/upload/2024/03/28/test.jpg",
"files": [
{
"path": "/image/upload/2024/02/12/sample.jpg",
"size": 123456,
"mtime": 1622555123,
"complete": true
},
{
"path": "/image/upload/2024/02/12/sample_large.jpg",
"size": 45234,
"mtime": 1622555127,
"complete": false,
"error": "timeout"
},
...
]
},
"paramGlobal": null,
"param": null
}
onItemCompleted¶
onChunkExtracted 와 같으며 아래 정보가 추가된다.
{
"meta": {
"vhost": "example.com",
"bucket": "image_bucket",
"basePath": "/",
"event": "batch",
"trigger": {
"workflow": "migrate_tmpimg",
"timing": "post"
}
},
"chunk": {
"id": "12345678-1234-1234-1234-123456789012",
"path": "/image/upload/2024/02/11/sample.jpg"
"size": 123456,
"mtime": 1622555123,
"timestamps": {
"execute": {
"start": "2024-03-28T10:15:49.123Z",
"end": "2024-03-28T10:17:45.789Z"
}
},
"src": "delete",
"tasks": [
{
"function": "/hyperdims/format/avif/optimize",
"savePath": "/newimg/image/upload/2024/02/11/sample.jpg",
"saveSize": 5443,
"diff": true,
"overwrite": true,
"dur": 100,
"error": null
},
{
"function": "/hyperdims/format/webp/resize/500",
"savePath": "/newimg/image/upload/_backup_/20/24/0211/sample.jpg",
"saveSize": 5443,
"diff": true,
"dur": 1,
"error": "notfound"
},
{
"function": "/hyperdims/format/webp",
"savePath": "/newimg2/image/upload/2024/02/11/sample.jpg",
"saveSize": 5443,
"diff": true,
"dur": 40,
}
]
},
"paramGlobal": null,
"param": null
}
설정예제¶
NFS 랜딩존¶
특정 디렉토리를 감지하여 서비스 디렉토리로 이관한다.
설정 예제는 아래와 같다.
"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"
}
}
}
]
}
]
}