Informations indépendantes de la plate-forme pour créer des fonctions externes

La plupart des informations relatives au développement d’un service proxy et d’un service distant dépendent de la plate-forme. Cependant, de nombreux détails supplémentaires sont indépendants de la plate-forme.

Cette rubrique décrit ces détails indépendants de la plate-forme.

Dans ce chapitre :

Service à distance

Format des données

Snowflake appelle une ressource d’un service proxy en émettant une requête HTTP POST. Ce POST contient des données dans un format spécifique, ainsi que des en-têtes. Les données renvoyées à la suite du POST doivent également être conformes à un format spécifique. Les deux formats sont décrits ci-dessous.

Format de données envoyé par Snowflake

Chaque requête HTTP faite à partir de Snowflake est un POST. La requête POST contient des en-têtes et un corps. Les métadonnées sont transmises dans les en-têtes HTTP. Les données sont groupées et transmises dans le corps de la requête POST.

Les informations d’en-tête comprennent :

  • Métadonnées décrites dans les propriétés « headers » et « context_headers » de CREATE EXTERNAL FUNCTION.

  • Les en-têtes HTTP suivants :

    • En-têtes qui décrivent comment les données sont sérialisées dans le corps de la requête :

      • « sf-external-function-format » : ceci est actuellement toujours réglé sur « json ».

      • « sf-external-function-format-version » : ceci est actuellement toujours défini sur « 1.0 ».

    • « sf-external-function-current-query-id » : ceci contient l’ID de requête de la requête qui a appelé cette fonction externe. Vous pouvez l’utiliser pour corréler les requêtes Snowflake aux appels du service distant, par exemple pour aider au débogage des problèmes.

Le corps de la requête POST contient les données, sérialisées au format JSON. Le schéma pour JSON est :

  • L’objet JSON de niveau supérieur est un dictionnaire de paires nom/valeur.

  • Actuellement, il y a exactement un élément dans le dictionnaire ; la clé de cet élément est nommée « données ».

  • La valeur de cet élément « données » est un tableau JSON, dans lequel chaque élément du tableau est une ligne de données.

  • Chaque ligne de données est un tableau JSON d’une ou plusieurs colonnes.

  • La première colonne est toujours le numéro de ligne (c’est-à-dire l’index basé sur 0 de la ligne dans le lot).

  • Les colonnes restantes contiennent les arguments de la fonction.

  • Les types de données sont sérialisés comme suit :

    • Les nombres sont sérialisés en tant que nombres JSON.

    • Les booléens sont sérialisés en tant que booléens JSON.

    • Les chaînes sont sérialisées en tant que chaînes JSON.

    • Les variantes sont sérialisées en tant qu’objets JSON.

    • Tous les autres types de données pris en charge sont sérialisés en tant que chaînes JSON.

    • NULL est sérialisé en tant que JSON null.

Voici un exemple de demande sérialisée pour un service distant avec la signature f(integer, integer, varchar, timestamp):

{
    "data": [
                [0, 10, "Alex", "Wed, 01 Jan 2014 16:00:00 -0800"],
                [1, 20, "Steve", "Wed, 01 Jan 2015 16:00:00 -0800"],
                [2, 30, "Alice", "Wed, 01 Jan 2016 16:00:00 -0800"],
                [3, 40, "Adrian", "Wed, 01 Jan 2017 16:00:00 -0800"]
            ]
}

Facultativement, le JSON peut être compressé pour la transmission sur le réseau. La compression est documentée dans CREATE EXTERNAL FUNCTION.

Snowflake envoie ces données au service proxy, pas directement au service distant. Par conséquent, le service proxy doit recevoir (et renvoyer) les données dans un format compatible avec Snowflake. Bien que le service proxy transmette généralement des données inchangées, le proxy peut reformater les données (à la fois en envoi et en réception) pour répondre aux besoins du service distant et de Snowflake.

Par souci de simplicité et pour illustrer les formats que Snowflake s’attend à envoyer et à recevoir, la plupart des exemples de cette section supposent que le service distant lit et écrit des données dans le même format que Snowflake le prévoit et que le service proxy transmet les données sans les modifier dans les deux directions.

Format de données reçu par Snowflake

Le format des données reçues par Snowflake est similaire au format des données envoyées par Snowflake. La valeur renvoyée est au format JSON.

{
    "data":
        [
            [ 0, 1995 ],
            [ 1, 1974 ],
            [ 2, 1983 ],
            [ 3, 2001 ]
        ]
}

La réponse JSON renvoyée à Snowflake doit contenir une ligne pour chaque ligne envoyée par Snowflake. Chaque ligne renvoyée contient deux valeurs :

  • Le numéro de ligne (c’est-à-dire l’index basé sur 0 de la ligne dans le lot).

  • La valeur renvoyée par la fonction pour cette ligne. La valeur peut être une valeur composée (par exemple, un VARIANT), mais elle doit être exactement une valeur car toutes les fonctions scalaires Snowflake (externes ou autres) renvoient une seule valeur.

Les numéros de ligne dans les données renvoyées doivent correspondre aux numéros de ligne dans les données envoyées par Snowflake et doivent être renvoyés dans le même ordre qu’ils ont été reçus.

Ce JSON est le corps de la réponse HTTP. La réponse contient également des en-têtes HTTP et un code de statut (par exemple, le code de statut 200 indique la réussite).

Facultativement, le JSON peut être compressé pour la transmission sur le réseau. La compression est documentée dans CREATE EXTERNAL FUNCTION.

Snowflake reconnaît les codes de statut HTTP suivants :

Code

Description

200

Pas d’erreur

Les autres valeurs sont traitées comme des erreurs.

Cette liste de codes de statut peut s’étendre avec le temps.

Pour plus d’informations sur les délais d’expiration et les tentatives, voir Tenir compte des erreurs d’expiration de délai et Ne supposez pas que le service distant a validé chaque ligne exactement une fois.

Meilleures pratiques

Les meilleures pratiques suivantes s’appliquent à la plupart des fonctions externes, en particulier la partie de service à distance.

Traiter une ligne à la fois

Pour réduire les frais de mise en réseau, Snowflake regroupe généralement les lignes à envoyer aux services distants. Le nombre de lots et la taille de chaque lot peuvent varier.

En outre, l’ordre des lots peut varier et l’ordre des lignes d’un lot peut varier. Même si la requête contient une clause ORDER BY, le ORDER BY est généralement appliqué après l’appel de la ou des fonctions externes.

Etant donné que la taille du lot et l’ordre des lignes ne sont pas garantis, l’écriture d’une fonction qui renvoie une valeur pour une ligne qui dépend de toute autre ligne de ce lot ou des lots précédents peut produire des résultats non déterministes.

Snowflake recommande fortement que le service distant traite chaque ligne indépendamment. La valeur de retour pour chaque ligne d’entrée doit dépendre uniquement de cette ligne d’entrée, pas des autres lignes d’entrée. (Actuellement, les fonctions externes ne prennent pas en charge les fonctions de fenêtre, par exemple.)

Notez également que la taille des lots n’étant pas garantie, le comptage des lots n’est pas significatif.

Voir aussi Assurez-vous que votre fonction externe est Stateless.

Ne supposez pas que le service distant a validé chaque ligne exactement une fois

Si Snowflake appelle un service distant et que le service distant reçoit la demande et renvoie un résultat, mais Snowflake ne reçoit pas le résultat en raison d’un problème de réseau temporaire, Snowflake peut répéter la demande. Si Snowflake réessaie, le service distant peut voir la même ligne deux fois (ou plus).

Cela peut provoquer des effets inattendus. Par exemple, étant donné que le service distant peut être appelé plusieurs fois pour la même valeur, un service distant qui affecte des IDs uniques peut présenter des lacunes dans la séquence de ces IDs.

Snowflake réessaie lorsqu’il reçoit les erreurs suivantes :

  • Toutes les erreurs de transport de réseau transitoires.

  • Toutes les demandes qui échouent avec le code de statut 429.

  • Toutes les demandes qui échouent avec le code de statut 5XX.

Les demandes sont réessayées avec une interruption exponentielle jusqu’à ce qu’un délai de relance total soit atteint. Le délai d’expiration total des nouvelles tentatives n’est actuellement pas documenté et n’est pas configurable par l’utilisateur. Snowflake pourrait ajuster cette limite à l’avenir.

Lorsque le délai d’expiration total des tentatives est atteint sans nouvelle tentative, la requête échoue.

Si votre appel de fonction externe expire lorsque le service distant fonctionne et que tous les éléments entre Snowflake et le service distant semblent fonctionner, vous pouvez essayer une taille de lot plus petite pour voir si cela réduit les erreurs de délai d’attente.

Pour savoir comment définir la taille de lot maximale, voir CREATE EXTERNAL FUNCTION.

Assurez-vous que votre fonction externe est Stateless

Tous les aspects d’une fonction externe (y compris le service distant) devraient éviter de stocker des informations d’état, à la fois :

  • Etat interne (indiquer que le service distant effectue un stockage en interne).

  • Etat externe (état stocké en dehors du service distant, par exemple des informations d’état envoyées à et/ou lues à partir d’un autre service distant qui lui-même conserve l’état).

Si le service distant modifie les informations d’état et utilise ensuite ces informations pour affecter les sorties futures, la fonction peut renvoyer des valeurs différentes de celles attendues.

Par exemple, considérons un service distant simple qui contient un compteur interne et renvoie le nombre de lignes reçues depuis le premier démarrage du service distant. S’il y a un problème de réseau temporaire et que Snowflake répète une demande avec les mêmes données, le service distant comptera les lignes renvoyées deux fois (ou plus).

Pour un exemple impliquant un état externe, voir Evitez les effets secondaires.

Dans les très rares cas où une fonction n’est pas Stateless, la documentation pour les appelants doit indiquer clairement que la fonction n’est pas Stateless et que la fonction doit être marquée comme volatile.

Evitez les effets secondaires

Une fonction externe (y compris le service distant) devrait éviter les effets secondaires, tels que le changement d’état externe (informations stockées en dehors du service distant).

Par exemple, si le service distant signale des valeurs hors limites à une agence gouvernementale, cela est un effet secondaire.

Les effets secondaires peuvent être utiles, mais les effets secondaires de l’appel d’une fonction externe ne sont pas toujours prévisibles. Par exemple, supposons que vous appeliez un service distant qui analyse un dossier de santé anonyme et renvoie un diagnostic. Supposons également que si le diagnostic est que le patient a une maladie contagieuse, alors le diagnostic est signalé à une agence qui tient compte du nombre de cas de cette maladie. Ceci est un effet secondaire utile. Cependant, cela est vulnérable à des problèmes tels que les suivants :

  • Si un appel de fonction externe se trouve dans une transaction annulée, les effets secondaires ne sont pas annulés.

  • Si le service distant est appelé plusieurs fois avec la même ligne (par exemple, en raison de pannes de réseau temporaires et de nouvelles tentatives), l’effet secondaire peut se produire plusieurs fois. Par exemple, un patient infecté peut être compté deux fois dans les statistiques.

Il existe également des situations dans lesquelles les lignes peuvent être sous-comptées plutôt que sur-comptées.

Dans les très rares cas où une fonction a des effets secondaires, la documentation destinée aux appelants doit indiquer clairement quels sont les effets secondaires et la fonction doit être marquée comme volatile.

Classez votre fonction comme volatile ou immuable

Les fonctions peuvent être classées comme volatiles ou immuables. (L’instruction CREATE EXTERNAL FUNCTION permet à l’utilisateur de spécifier si la fonction est volatile ou immuable.)

Pour qu’une fonction externe soit considérée comme immuable, elle doit répondre aux critères suivants :

  • Si on lui donne la même valeur d’entrée, la fonction renvoie la même valeur de sortie. (Par exemple, la fonction SQRT renvoie la même sortie lorsqu’elle reçoit la même entrée, mais la fonction CURRENT_TIMESTAMP ne renvoie pas nécessairement la même sortie lorsqu’elle reçoit la même entrée.)

  • La fonction n’a aucun effet secondaire.

Si une fonction répond à ces deux critères, Snowflake peut utiliser certains types d’optimisations pour réduire le nombre de lignes ou de lots envoyés au service distant. (Ces optimisations peuvent évoluer avec le temps et ne sont pas décrites en détail ici.)

Snowflake ne peut pas détecter ou imposer l’immuabilité ou les facteurs qui affectent l’immuabilité (par exemple, les effets secondaires). Le rédacteur d’un service distant doit documenter si le service distant répond aux critères pour être considéré comme immuable. Si un service distant a des effets secondaires, la fonction externe qui appelle ce service distant doit être marquée comme volatile, même si l’appel de fonction renvoie la même valeur de sortie pour la même valeur d’entrée. Si vous n’êtes pas certain qu’un service distant est immuable, toute fonction externe qui appelle ce service distant doit être considérée comme volatile.

Tenir compte des erreurs d’expiration de délai

Un appel de fonction externe implique Snowflake, un service distant, un service proxy et potentiellement d’autres éléments de la chaîne. Aucun de ces éléments ne sait combien de temps un appel de fonction particulier devrait prendre, donc aucun ne sait exactement quand arrêter d’attendre et renvoyer une erreur d’expiration de délai. Chaque étape peut avoir son propre délai d’expiration indépendant. Pour plus d’informations sur les délais d’expiration, voir Ne supposez pas que le service distant a validé chaque ligne exactement une fois.

Réduire la latence

Pour réduire la latence et améliorer les performances des appels de fonctions externes, Snowflake recommande de procéder comme suit lorsque cela est possible :

  • Placez API Gateway dans la même plate-forme et région Cloud que les instances Snowflake qui l’appellent le plus souvent (ou avec la plus grande quantité de données).

  • Si vous avez rédigé le service distant (plutôt que d’utiliser un service existant), déployez ce service distant dans la même plate-forme et région Cloud que celle d’où il est appelé.

  • Envoyez le moins de données possible. Par exemple, si le service distant examine les valeurs des entrées et n’opère que sur un sous-ensemble d’entre elles, il est généralement plus efficace de filtrer dans SQL et d’envoyer uniquement les lignes pertinentes au service distant, plutôt que d’envoyer toutes les lignes au service à distance et laisser le filtre opérer.

    Comme autre exemple, si vous traitez une colonne qui contient de grandes valeurs de données semi-structurées et que le service distant ne fonctionne que sur une petite partie de chacune de ces valeurs de données, il est généralement plus efficace d’extraire l’élément pertinent à l’aide de Snowflake SQL et de n’envoyer que cet élément, plutôt que d’envoyer la colonne entière et demander au service distant d’extraire le petit élément avant le traitement.

Développement et test de fonctions externes

Snowflake vous recommande de tester sans Snowflake avant de tester avec Snowflake.

Pendant les premières étapes du développement d’une fonction externe, utilisez la console de service proxy de la plate-forme Cloud (par exemple, la console AWS API Gateway) et la console de développement de service à distance (par exemple, la console AWS Lambda) pour aider à développer et tester le service proxy et le service distant.

Par exemple, si vous avez développé une fonction Lambda, vous souhaiterez peut-être la tester de manière approfondie via la console Lambda avant de la tester en l’appelant depuis Snowflake.

Les tests via la console de service proxy et la console de service distante présentent généralement les avantages suivants :

  • Cela peut faciliter le diagnostic du problème car il y a moins d’endroits pour rechercher la cause du problème.

  • L’affichage de la charge utile des données peut fournir des informations de débogage utiles. Snowflake n’affiche aucune partie de la charge utile des données dans les messages d’erreur ; bien que cela améliore la sécurité, cela peut ralentir le débogage.

  • Snowflake réessaie automatiquement les erreurs HTTP 5xx, ce qui peut rendre le débogage plus lent ou plus difficile dans certaines situations.

  • Les tests via Snowflake consomment des crédits Snowflake en plus des crédits de la plate-forme Cloud.

Bien sûr, après avoir testé le service distant et le service proxy autant que possible sans Snowflake, vous devez les tester avec Snowflake. Voici une sélection des avantages des tests avec Snowflake :

  • Vous testez toutes les étapes impliquées dans la fonction externe.

  • L’utilisation d’une table Snowflake comme source de données facilite le test avec de grands volumes de données pour obtenir une estimation réaliste des performances de la fonction externe.

Considérez les cas de test suivants :

  • valeurs NULL.

  • Valeurs « vides » (par exemple, chaînes vides, types de données semi-structurés vides).

  • Valeurs VARCHAR et BINARY très longues, le cas échéant.

Service proxy

Sécurisez votre point de terminaison de service proxy

Snowflake recommande fortement de sécuriser vos points de terminaison de service proxy.

Snowflake utilise des objets d’intégration API sans informations d’identification pour s’authentifier auprès du point de terminaison du service proxy. Les intégrations API sans informations d’identification séparent les responsabilités entre les administrateurs et les utilisateurs. Une intégration API permet à un administrateur de créer une politique de confiance entre Snowflake et le fournisseur Cloud à l’aide du mécanisme d’authentification et d’autorisation natif du fournisseur Cloud. Lorsque Snowflake se connecte au fournisseur Cloud, le fournisseur Cloud authentifie et autorise l’accès via cette politique de confiance. A l’aide d’une intégration API spécifique, l’administrateur peut également restreindre les services proxy et les ressources que Snowflake peut utiliser, ce qui lui permet d’appliquer des politiques organisationnelles pour la sortie et l’entrée de données.

Des instructions plus détaillées pour sécuriser des points de terminaison de service proxy spécifiques, telles qu’une AWS API Gateway, figurent dans les instructions spécifiques à la plate-forme.