외부 함수 모범 사례¶
이 항목에서는 효율성을 개선하고 원격 서비스가 Snowflake와 호환되도록 설계되지 않은 경우 발생할 수 있는 예기치 않은 결과를 방지해줄 모범 사례를 설명합니다.
다음 문서에서 추가적인 모범 사례를 찾을 수 있습니다.
-
(이는 Microsoft Azure 문서이지만, 여기서 소개하는 조언 중 다수는 모든 클라우드 플랫폼의 원격 서비스에도 해당하는 내용입니다.)
이 항목의 내용:
가능한 경우 원격 서비스의 배치 API 사용¶
일부 원격 서비스는 배치 모드와 단일 행 모드를 모두 제공합니다. 외부 함수를 사용하는 쿼리가 여러 행을 보낼 것으로 예상되는 경우에는 성능 향상을 위해 원격 서비스의 배치 모드를 사용하는 것이 좋습니다.
다음과 같은 경우 이 규칙이 반드시 적용되는 것은 아닙니다.
각 행은 매우 큽니다(예: 수백 킬로바이트 이상).
원격 서비스는 행을 일괄적으로 수신하는 경우와 개별적으로 수신하는 경우에 서로 다르게 행을 처리합니다. (자세한 내용은 한 번에 한 행씩 처리하기 섹션을 참조하십시오.)
한 번에 한 행씩 처리하기¶
네트워킹 오버헤드를 최소화하기 위해, Snowflake는 일반적으로 원격 서비스로 보낼 행을 일괄 처리합니다. 배치의 수와 각 배치의 크기는 다를 수 있습니다.
또한, 배치의 순서가 다를 수 있으며 배치 내 행의 순서가 다를 수 있습니다. 쿼리에 ORDER BY 절이 포함되어 있더라도 ORDER BY는 보통 외부 함수가 호출된 후에 적용됩니다.
배치 크기와 행 순서가 보장되지 않으므로, 이 배치 또는 이전 배치의 다른 행에 따라 달라지는 행의 값을 반환하는 함수를 작성하면 비결정적 결과가 생성될 수 있습니다.
Snowflake는 원격 서비스를 통해 각각의 행을 독립적으로 처리하도록 할 것을 강력히 권장합니다. 각 입력 행의 반환 값은 다른 입력 행이 아니라 해당 입력 행에만 의존해야 합니다. (현재, 예컨대 외부 함수는 윈도우 함수 를 지원하지 않습니다.)
또한, 배치 크기가 보장되지 않으므로 배치 수를 세는 것은 의미가 없습니다.
외부 함수가 상태 비저장인지 확인하기 도 참조하십시오.
원격 서비스가 행마다 정확히 한 번만 전달된다고 가정하지 않기¶
Snowflake가 원격 서비스를 호출하고 원격 서비스가 요청을 수신하여 결과를 반환하지만 Snowflake가 일시적인 네트워크 문제로 인해 결과를 받지 못하는 경우, Snowflake는 요청을 반복할 수 있습니다. Snowflake가 다시 시도하면 원격 서비스에서 똑같은 행을 두 번 이상 볼 수 있습니다.
이로 인해 예기치 않은 영향이 발생할 수 있습니다. 예를 들어 원격 서비스가 같은 값에 대해 두 번 이상 호출될 수 있으므로, 고유한 IDs를 할당하는 원격 서비스는 그러한 IDs의 시퀀스에 간격이 있을 수 있습니다. 경우에 따라, 행의 특정한 배치가 이전에 처리되었는지 여부를 확인하기 위해 요청 헤더의 sf-external-function-query-batch-id
필드에 있는 배치 ID를 추적하여 이러한 영향을 줄일 수 있습니다. Snowflake는 특정 배치에 대한 요청을 다시 시도할 때 똑같은 배치에 대해 이전에 사용한 것과 같은 배치 ID를 사용합니다.
Snowflake는 다음 오류를 수신하면 다시 시도합니다.
모든 일시적 네트워크 전송 오류.
429 상태 코드가 발생하며 실패하는 모든 요청.
5XX 상태 코드가 발생하며 실패하는 모든 요청.
총 재시도 시간 제한에 도달할 때까지 요청을 다시 시도합니다. 사용자가 총 재시도 시간 제한을 구성할 수 없습니다. Snowflake는 향후 이 제한을 조정할 수도 있습니다.
성공적인 재시도 없이 총 재시도 시간 제한에 도달하면 쿼리가 실패합니다.
원격 서비스가 작동 중일 때 외부 함수 호출 시간이 제한 시간을 초과하고 Snowflake와 원격 서비스 사이의 모든 요소가 작동하는 것으로 보이면, 더 작은 배치 크기를 시도하여 시간 제한 오류가 감소하는지 확인할 수 있습니다.
최대 배치 크기를 설정하는 방법을 알아보려면 CREATE EXTERNAL FUNCTION 을 참조하십시오.
외부 함수가 상태 비저장인지 확인하기¶
일반적으로 외부 함수(원격 서비스 포함)는 다음 두 가지 상태 정보를 모두 저장하지 않도록 해야 합니다.
내부 상태(원격 서비스가 내부적으로 저장하는 상태).
외부 상태(원격 서비스 외부에 저장된 상태. 예: 스스로 상태를 보존하는 또 다른 원격 서비스로 보내거나 이런 서비스에서 읽은 상태 정보).
원격 서비스가 상태 정보를 변경한 다음 해당 정보를 사용하여 향후 출력에 영향을 미치는 경우, 함수가 예상했던 것과 다른 값을 반환할 수 있습니다.
예를 들어, 내부 카운터를 포함하고 원격 서비스가 처음 시작된 이후에 수신된 행의 수를 반환하는 간단한 원격 서비스를 생각해 보십시오. 일시적인 네트워크 문제가 있고 Snowflake가 같은 데이터로 요청을 반복하는 경우, 원격 서비스는 재전송된 행을 두 번 또는 그 이상 계산합니다.
외부 상태와 관련된 예는 부작용 방지하기 를 참조하십시오.
함수가 상태 비저장이 아닌 드문 경우에, 호출자에 대한 설명서에 함수가 상태 비저장이 아니며 함수가 휘발성으로 표시되어야 한다는 점을 명확히 설명해야 합니다.
원격 서비스가 요청을 비동기적으로 처리하는 경우, 원격 서비스 작성자는 일부 상태를 임시로 저장하고 관리하도록 원격 서비스를 작성해야 합니다. 예를 들어 원격 서비스는 HTTP GET이 같은 배치 ID와 함께 수신되는 경우 지정된 배치가 아직 처리 중일 때 HTTP 코드 202를 반환할 수 있도록 HTTP POST 요청의 배치 ID를 저장해야 합니다.
쿼리는 다양한 이유로 중단될 수 있는데, 이는 곧 원격 서비스가 결과 생성을 마친 후에 최종 GET이 도착하리라는 보장이 없다는 뜻입니다. 비동기 요청의 상태를 저장하는 원격 서비스는 결국 시간이 초과되어 해당 내부 상태를 정리해야 합니다. 최적의 시간 제한은 앞으로 변경될 수 있지만, 현재는 비동기 요청에 대한 정보를 10분 이상, 가급적이면 12시간 동안 보존한 후에 삭제하는 것이 좋습니다.
부작용 방지하기¶
외부 함수(원격 서비스 포함)는 외부 상태(원격 서비스 외부에 저장된 정보) 변경과 같은 부작용을 방지해야 합니다.
예를 들어, 원격 서비스가 범위를 벗어난 값을 정부 기관에 보고한다면 그건 부작용입니다.
부작용이 유용할 수 있지만, 외부 함수 호출의 부작용이 항상 예측 가능한 것은 아닙니다. 예를 들어, 익명화된 건강 레코드를 분석하고 진단을 반환하는 원격 서비스를 호출한다고 가정해 보십시오. 또한, 진단 결과 환자에게 전염성 질병이 있는 것으로 나온 경우에는 그 질병의 사례 건수를 계속 집계하는 기관에 진단이 보고된다고 가정해 보십시오. 이것은 유용한 부작용입니다. 하지만 다음과 같은 문제에 취약합니다.
외부 함수 호출이 롤백되는 트랜잭션 내부에 있으면 부작용이 롤백되지 않습니다.
(예: 일시적인 네트워크 오류 및 재시도로 인해) 원격 서비스가 같은 행으로 두 번 이상 호출되는 경우 부작용이 두 번 이상 발생할 수 있습니다. 예를 들어, 감염된 환자는 통계에서 두 번 계산될 수 있습니다.
행이 과대 계산되기보다는 과소 계산될 수 있는 상황도 있습니다.
함수에 부작용이 있는 매우 드문 경우에, 호출자에 대한 설명서에 부작용이 무엇인지와 함수가 휘발성으로 표시되어야 한다는 점을 명확히 설명해야 합니다.
함수를 휘발성 또는 변경 불가능으로 분류하기¶
함수를 휘발성 또는 변경 불가능으로 분류할 수 있습니다. (사용자는 CREATE EXTERNAL FUNCTION 문을 통해 함수가 휘발성인지 변경 불가능한지 지정할 수 있습니다.)
외부 함수가 변경 불가능한 것으로 간주되도록 하려면 다음 기준을 충족해야 합니다.
같은 입력값이 주어진 경우 이 함수는 같은 출력값을 반환합니다. (예를 들어, SQRT 함수는 똑같은 입력값이 주어질 때 똑같은 출력값을 반환하지만, CURRENT_TIMESTAMP 함수는 똑같은 입력값이 주어질 때 함수가 꼭 똑같은 출력값을 반환하는 것은 아닙니다.)
이 함수는 부작용이 없습니다. (자세한 내용은 부작용 방지하기 섹션을 참조하십시오.)
함수가 이 두 가지 기준을 충족하는 경우 Snowflake는 특정 유형의 최적화를 사용하여 원격 서비스로 전송되는 행 또는 배치의 수를 줄일 수 있습니다. (이러한 최적화는 시간이 지남에 따라 발전할 수 있으므로 여기에서 자세히 설명하지는 않습니다.)
Snowflake는 불변성 또는 불변성에 영향을 미치는 요인(예: 부작용)을 감지하거나 강제 적용할 수 없습니다. 원격 서비스의 작성자는 원격 서비스가 변경 불가능으로 레이블이 지정되는 기준을 충족하는지 여부를 문서화해야 합니다. 원격 서비스에 부작용이 있는 경우에는 함수 호출이 똑같은 입력값에 대해 똑같은 출력값을 반환하더라도 해당 원격 서비스를 호출하는 외부 함수는 휘발성으로 표시되어야 합니다. 원격 서비스가 변경 불가능한지 확실하지 않은 경우에는 해당 원격 서비스를 호출하는 모든 외부 함수에 휘발성 레이블을 지정해야 합니다.
시간 제한 오류에 대한 설명¶
외부 함수 호출에는 Snowflake, 원격 서비스, 프록시 서비스 그리고 잠재적으로는 체인의 다른 요소가 포함됩니다. 이러한 요소 중 어느 것도 특정 함수 호출에 걸리는 시간을 알지 못하므로, 어떤 요소도 대기를 중지하고 시간 제한 오류를 반환할 때를 정확히 알지 못합니다. 각 단계에는 자체적으로 독립된 시간 제한이 있을 수 있습니다. 시간 제한과 재시도에 대한 자세한 내용은 시간 제한 오류에 대한 설명 및 재시도 를 참조하십시오.
대기 시간 최소화¶
대기 시간을 최소화하고 외부 함수 호출의 성능을 개선하기 위해, Snowflake는 타당할 때는 다음을 수행할 것을 권장합니다.
API Gateway를 가장 자주 호출하거나 가장 많은 양의 데이터를 사용하는 Snowflake 인스턴스와 똑같은 클라우드 플랫폼과 리전에 배치합니다.
기존 서비스를 사용하기보다는 원격 서비스를 작성한 경우 해당 원격 서비스를 호출된 시작 위치와 같은 클라우드 플랫폼과 리전에 배포합니다.
가능한 한 적은 데이터를 보냅니다. 예를 들어, 원격 서비스가 입력값을 검사하고 그중 일부에 대해서만 작동하는 경우, 보통 모든 행을 원격 서비스로 보내어 필터링하도록 하기보다는 SQL에서 필터링하여 적절한 행만 원격 서비스로 보내는 것이 더 효율적입니다.
또 다른 예로, 큰 반정형 데이터 값이 포함된 열을 처리 중이고 원격 서비스가 각 데이터 값의 작은 부분에 대해서만 작동하는 경우에는 보통 전체 열을 보내어 원격 서비스가 그 작은 부분의 추출 작업을 수행하도록 한 후에 처리하기보다는, Snowflake SQL을 사용하여 관련 부분을 추출해 그 부분만 보내는 것이 더 효율적입니다.
한 번에 한 단계씩 외부 함수를 개발해 테스트하기¶
Snowflake로 테스트하기 전에 Snowflake 없이 테스트해보는 것이 좋습니다.
외부 함수 개발의 초기 단계에서 프록시 서비스와 원격 서비스의 개발과 테스트에 도움이 되는 클라우드 플랫폼 프록시 서비스 콘솔(예: Amazon API Gateway 콘솔)과 원격 서비스 개발 콘솔(예: AWS Lambda 콘솔)을 사용하십시오.
예를 들어, Lambda 함수를 개발했다면 Snowflake에서 이 함수를 호출해 테스트하기 전에 Lambda 콘솔을 통해 광범위한 테스트를 진행할 수 있습니다.
프록시 서비스 콘솔과 원격 서비스 콘솔을 통해 테스트하면 대개 다음과 같은 이점이 있습니다.
문제의 원인을 찾아볼 곳이 적으므로 문제를 더 쉽게 진단할 수 있습니다.
데이터 페이로드를 보면 유용한 디버깅 정보를 얻을 수 있습니다. Snowflake는 오류 메시지에 데이터 페이로드의 어떤 부분도 표시하지 않는데, 이를 통해 보안은 강화되겠지만 디버깅 속도가 느려질 수 있습니다.
Snowflake는 HTTP 5xx 오류를 자동으로 재시도하므로, 상황에 따라 디버깅 속도가 더 느려지거나 디버깅하기 더 어려워질 수 있습니다.
Snowflake를 통한 테스트에서는 클라우드 플랫폼 크레딧 외에 Snowflake 크레딧도 사용합니다.
물론, Snowflake 없이 원격 서비스와 프록시 서비스를 최대한 테스트한 후에 Snowflake로 테스트해야 합니다. Snowflake를 사용한 테스트의 이점은 다음과 같습니다.
외부 함수와 관련된 모든 단계를 테스트합니다.
Snowflake 테이블을 데이터 원본으로 사용하면 손쉽게 대용량 데이터로 테스트하여 외부 함수의 성능을 현실적으로 추정할 수 있습니다.
다음 테스트 사례를 고려하십시오.
NULL 값.
“빈” 값(예: 빈 문자열, 빈 반정형 데이터 타입).
매우 긴 VARCHAR 및 BINARY 값(해당되는 경우).
원격 서비스를 비동기로 만들기¶
작성 중인 원격 서비스가 예상 시간 제한 내에 결과를 반환하지 못할 수도 있다면 원격 서비스를 비동기로 만드는 것도 좋은 대안입니다. 자세한 내용은 비동기 원격 서비스와 동기 원격 서비스 섹션을 참조하십시오.
외부 함수에 대한 인자가 원격 서비스에서 구문 분석한 인자와 일치하도록 하기¶
인자를 외부 함수로 전달하거나 외부 함수에서 전달할 때, 데이터 타입이 적절한지 확인하십시오. 전송된 값이 수신 중인 데이터 타입에 맞지 않으면 값이 잘리거나 손상되거나 원격 서비스 호출이 실패할 수 있습니다.
예를 들어, 일부 Snowflake SQL 숫자 데이터 타입은 흔히 사용되는 JavaScript 데이터 타입보다 더 큰 값을 저장할 수 있으므로, JSON에서 큰 숫자를 역직렬화하는 것은 특히 JavaScript에서 민감한 문제입니다.
원격 서비스에 대한 인자의 수, 데이터 타입 또는 순서를 변경할 경우 외부 함수에 대응하는 변경 작업을 수행해야 합니다. 현재, ALTER FUNCTION 명령에는 매개 변수 변경 옵션이 없으므로, 인자를 변경하려면 외부 함수를 삭제하고 다시 만들어야 합니다.