WebAssembly 사용자 정의 함수
개요
wasm32-unknown-unknown)로 컴파일해야 합니다. 또한 기본 32비트 WebAssembly 대상만 지원됩니다(wasm64 확장은 지원되지 않음).
모듈은 ClickHouse와 상호작용하기 위해 지원되는 통신 프로토콜(ABI) 중 하나를 따라야 합니다.
컴파일이 완료되면 모듈의 바이너리 코드는 system.webassembly_modules 테이블에 삽입되어 ClickHouse에 로드됩니다.
그 후 CREATE FUNCTION ... LANGUAGE WASM 구문을 사용해 모듈이 내보낸 함수를 참조하는 UDF를 생성할 수 있습니다.
사전 요구 사항
빠른 시작
wat2wasm 또는 wasm-tools의 parse 명령을 사용할 수 있습니다.
FORMAT RawBlob을 사용해 ClickHouse client로 직접 파이프하여 system.webassembly_modules 테이블에 삽입합니다.
그런 다음 모듈이 내보내는 steps 함수를 참조하는 UDF를 정의합니다:
:: 뒤에는 모듈의 함수 이름을 지정한다는 점에 유의하십시오.
이제 쿼리에서 collatz_steps 함수를 사용할 수 있습니다:
number 컬럼은 UInt32로 명시적으로 CAST됩니다. 이는 WebAssembly 함수가 CREATE FUNCTION 문에 지정된 시그니처와 정확히 일치하는 타입을 요구하기 때문입니다.
그 결과, 1부터 100까지의 수에 대한 Collatz 단계 수열을 얻을 수 있으며, 이는 OEIS의 A006577 수열에 해당합니다.
시스템 테이블을 통해 WASM 모듈 관리
system.webassembly_modules 테이블에 저장됩니다:
- 컬럼
nameString — 모듈 이름입니다. 비어 있을 수 없으며, 영문자, 숫자, 밑줄 문자만 사용할 수 있습니다.codeString — 원시 바이너리 WASM 코드입니다. 쓰기 전용이며, 읽기 시 빈 문자열이 반환됩니다.hashUInt256 — 모듈 바이너리의 SHA256입니다(디스크에는 존재하지만 아직 로드되지 않은 경우 0).
모듈 삽입
클러스터 전체에 모듈 배포
system.webassembly_modules는 인스턴스별 table이므로 INSERT는 connection을 처리하는 레플리카에만 적용됩니다. INSERT 문에는 ON CLUSTER 형식이 없으므로, 이어서 CREATE FUNCTION ... ON CLUSTER를 실행하면 모듈이 없는 레플리카에서는 실패합니다:
system.webassembly_modules 테이블 대신 cluster 테이블 함수에 쓰세요:
이 패턴은 기본 분산 쓰기 경로가 각 세그먼트 내의 모든 레플리카를 거치는 방식에 의존하며, 이는 클러스터가
internal_replication=false로 구성된 경우에만 가능합니다. internal_replication=true인 경우(ReplicatedMergeTree를 사용해 자체적으로 복제를 수행하는 클러스터의 기본 설정), 삽입은 세그먼트당 정상인 단일 레플리카에만 전달되고 system.webassembly_modules는 이 경로로 복제되지 않으므로 일부 레플리카에는 여전히 모듈이 없을 수 있습니다. 이 구성에서는 각 레플리카에 대해 개별적으로 삽입해야 합니다. 예를 들어 system.clusters를 순회하면서 각 호스트별로 remote(...)를 통해 기록하거나, 모든 호스트의 user_scripts/wasm/에 바이너리를 복사할 수 있습니다.클러스터의 internal_replication 설정은 SELECT cluster, shard_num, internal_replication FROM system.clusters로 확인할 수 있습니다.CREATE FUNCTION ... ON CLUSTER가 성공합니다:
clusterAllReplicas를 사용하면 모든 레플리카에 모듈이 로드되었는지 확인할 수 있습니다:
system.webassembly_modules에 대한 삽입은 동일한 (name, hash) 쌍에 대해 멱등적이므로, 팬아웃된 삽입을 다시 실행해도 안전하며 레플리카 교체 후 상태를 복구하는 합리적인 방법입니다. 새로 추가된 서버에는 기존 모듈이 자동으로 전달되지 않는다는 점에 유의하십시오. 업데이트된 클러스터를 대상으로 삽입을 다시 실행하거나, 새 호스트의 user_scripts/wasm/ 디렉터리에 바이너리를 배치해야 합니다.
모듈 목록 보기
모듈 삭제
DELETE FROM system.webassembly_modules WHERE name = '...' 문을 사용해 수행합니다.
프레디케이트는 정확한 일치에는 name = 'literal', 패턴과 일치하는 모든 모듈을 삭제할 때는 name LIKE 'pattern'여야 하며, 그 밖의 형태는 허용되지 않습니다.
WebAssembly UDF 생성하기
function_name: ClickHouse에서의 함수 이름입니다. 모듈의 내보낸 함수 이름과 다를 수 있습니다.FROM 'module_name' :: 'source_function_name': 사용할 로드된 WASM 모듈 이름과 WASM 모듈 내 함수 이름입니다(기본값은 function_name).ARGUMENTS: 인수 이름과 타입 목록입니다(이름은 선택 사항이며, 이름 있는 필드를 지원하는 직렬화 포맷에서 사용됩니다).ABI: Application Binary Interface 버전입니다.ROW_DIRECT: 직접 타입 매핑, 행 단위 처리BUFFERED_V1: 직렬화를 사용하는 블록 기반 처리ASSEMBLYSCRIPT: AssemblyScript 컴파일러로 생성된 모듈을 위한 행 단위 처리입니다. 숫자 타입은 AssemblyScript 기본 타입에 매핑되며, ClickHouseString은 AssemblyScriptstring에 매핑됩니다.
DETERMINISTIC: 함수를 결정적으로 선언합니다 — 동일한 입력에 대해 항상 동일한 출력을 반환합니다. 지정하면 모든 인수가 상수인 호출에 대해 ClickHouse가 상수 폴딩을 수행할 수 있습니다. 함수는 쿼리 분석 시점에 한 번 평가되며, 결과는 모든 행에 재사용됩니다.SHA256_HASH: 검증에 사용할 예상 모듈 해시입니다(생략하면 자동으로 채워짐). 서로 다른 레플리카에서 올바른 WASM 모듈이 로드되었는지 확인하는 데 사용할 수 있습니다.SETTINGS: 함수별 설정serialization_formatString — ABI에 필요할 때 사용하는 직렬화 포맷입니다. 지원되는 값:MsgPack,JSONEachRow,CSV,TSV,TSVRaw,RowBinary,Buffers. 기본값:MsgPack.Buffers와 같은 블록 기반 포맷은 선언된 함수 시그니처와 타입이 일치하는 단일 컬럼 하나를 반환해야 합니다.webassembly_udf_enable_fuelBool — 함수에 대한 제한된 연료 예산을 활성화합니다. 기본값:true.false이면 이 함수에서는 쿼리 수준 설정webassembly_udf_max_fuel이 무시됩니다.wasmtime엔진을 사용할 때 연료 제한을 비활성화하면 성능이 향상될 수 있습니다. 하지만 신뢰할 수 없거나 버그가 있는 게스트 코드의 경우, 제어되지 않는 실행 위험이 커질 수 있습니다.
ABI 버전
ROW_DIRECT: 직접 타입 매핑(기본 타입Int32,UInt32,Int64,UInt64,Float32,Float64만 지원)BUFFERED_V1: 직렬화를 사용하는 복합 타입ASSEMBLYSCRIPT: AssemblyScript 모듈과의 행 단위 상호 운용; 숫자 타입과String을 지원
ABI ROW_DIRECT
- 인수와 반환 타입은 숫자 타입
Int32/UInt32/Int64/UInt64/Float32/Float64/Int128/UInt128입니다. - 이 ABI에서는 문자열을 지원하지 않습니다.
- 시그니처는 WASM 내보내기(
i32/i64/f32/f64/v128)와 일치해야 합니다. - 모듈에서 내보내야 하는 지원 함수는 필요하지 않습니다.
ABI BUFFERED_V1
이 ABI는 실험적이며 향후 릴리스에서 변경될 수 있습니다.
i32 인수를 받아 하나의 i32 값을 반환합니다.
게스트 코드는 데이터를 처리한 후 직렬화된 결과 데이터가 들어 있는 결과 버퍼를 가리키는 포인터를 반환합니다.
게스트 코드는 이러한 버퍼를 생성하고 해제하는 두 개의 함수를 제공해야 합니다.
ABI ASSEMBLYSCRIPT
-
숫자형:
Int8/UInt8,Int16/UInt16(경계에서i32로 확장),Int32/UInt32,Int64/UInt64,Float32,Float64 -
String— AssemblyScriptstring에 매핑됩니다(WASM 메모리에서는 UTF-16). ClickHouse가 UTF-8 ↔ UTF-16 변환을 자동으로 처리합니다. - 사용자 정의 AssemblyScript 클래스는 인수 또는 반환 타입으로 지원되지 않습니다. 런타임 클래스 id가 컴파일할 때마다 안정적이지 않기 때문입니다(AssemblyScript#2982 참조).
__new, __pin, __unpin이 내보내지도록 AssemblyScript 관리 런타임으로 컴파일되어야 합니다. 표준 문자열 입출력 처리는 이를 전제로 합니다. 권장 호출 방식은 다음과 같습니다.
env.abort도 가져옵니다. ClickHouse는 이 import를 자동으로 제공합니다. abort가 트리거되면 현재 실행 중인 쿼리가 실패하며, 디코딩된 AssemblyScript 메시지와 소스 위치가 포함된 WASM_ERROR 예외가 반환됩니다.
예시:
asc로 컴파일하고 생성된 .wasm을 system.webassembly_modules에 로드한 후, UDF를 다음과 같이 선언합니다:
Rust로 UDF를 개발할 때 참고할 사항
clickhouse_create_buffer와 clickhouse_destroy_buffer 함수를 직접 구현할 필요 없이 크레이트를 의존성으로 추가하면 됩니다. 또한 일반적인 Rust 함수를 필요한 ABI 형식으로 감싸는 매크로 #[clickhouse_wasm_udf]도 제공합니다.
이 크레이트를 사용하면 다음과 같이 UDF를 작성할 수 있습니다:
serde를 사용해 직렬화/역직렬화를 자동으로 처리합니다.
모듈에서 사용할 수 있는 호스트 API
clickhouse_server_version() -> i64— ClickHouse 서버 버전을 정수로 반환합니다(예: v25.11.1.1은 25011001).clickhouse_throw(ptr: i32, size: i32)— 지정된 메시지로 오류를 발생시킵니다. 오류 메시지 문자열이 저장된 메모리 위치의 포인터와 문자열 크기를 인수로 받습니다.clickhouse_log(ptr: i32, size: i32)— 메시지를 ClickHouse 서버 텍스트 로그에 기록합니다.clickhouse_random(ptr: i32, size: i32)— 메모리를 무작위 바이트로 채웁니다.env.abort(message: i32, fileName: i32, line: i32, column: i32)— AssemblyScript 호환 모듈을 위해 제공됩니다. 이를 호출하거나(또는 이를 호출하는 AssemblyScript 런타임 트랩이 트리거되면) 디코딩된 메시지와 소스 위치가 포함된WASM_ERROR예외와 함께 UDF가 종료됩니다.env.abort를 import하지 않는 모듈은 영향을 받지 않습니다.
설정
-
webassembly_udf_max_fuel— WebAssembly UDF 인스턴스 실행당 연료 한도입니다. 각 WebAssembly 명령어는 일정량의 연료를 소비합니다. 이 값은 런타임에 전달되기 전에 1024배로 스케일되므로,webassembly_udf_max_fuel = 1은 약 1024 연료 단위에 해당합니다. 유한한 제한을 두지 않으려면 0으로 설정합니다. 이는 함수별 설정인webassembly_udf_enable_fuel이 true인 함수에만 적용되며, 기본값은 true입니다. -
webassembly_udf_max_memory— WebAssembly UDF 인스턴스당 바이트 단위의 메모리 한도입니다. -
webassembly_udf_max_input_block_size— 단일 블록에서 WebAssembly UDF에 전달되는 최대 행 수입니다. 모든 행을 한 번에 처리하려면 0으로 설정합니다. -
webassembly_udf_max_instances— 함수별로 병렬 실행할 수 있는 WebAssembly UDF 인스턴스의 최대 개수입니다.