[DOCKER] L'environnement sans serveur est-il plus de 600 fois plus lent? ~ J'ai essayé l'analyse comparative avec Go, Node.js et Python! ~

Serverless est-il lent?

Quand j'ai écrit Article précédent, la réponse de l'environnement sans serveur que j'ai construit moi-même était lente. Il y avait une sensation de peau. J'imaginais que ce serait plus lent qu'un serveur général car le conteneur a été démarré en utilisant Docker en interne. Mais dans quelle mesure la vitesse de réponse se détériore-t-elle? Il n'y a pas beaucoup d'articles comparatifs, j'ai donc décidé de le mesurer.

Quelle est la vitesse d'AWS Lambda?

Bref aperçu du domaine technique de l'architecture sans serveur

Selon l'article

Est écrit. Cela signifie que dans un environnement sans serveur similaire, on peut prévoir que le temps de réponse sera à peu près le même ou un peu plus lent.

Environnement sans serveur à tester

Nous utilisons un environnement sans serveur qui s'exécute sur site appelé Iron Functions. À ce sujet, j'ai écrit un article d'introduction dans le passé, alors jetez un œil là-bas.

Faites en 1 heure! Environnement sans serveur domestique facile! -Introduction à l'application sans serveur pour la première fois-

En gros, c'est un produit pratique qui vous permet d'introduire facilement un environnement sans serveur tel qu'AWS Lambda.

référence

Cette fois, le langage utilisé pour le benchmark est Go, Node.js et Python. Dans chaque langue, écrivez un code qui fonctionne presque de la même manière. Voyons quelle différence il y a lors de leur exécution sur Serverless et sur des serveurs HTTP intégrés pour chaque langue (natif).

Go Serverless

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

type Person struct {
	Name string
}

func main() {
	p := &Person{Name: "World"}
	json.NewDecoder(os.Stdin).Decode(p)
	fmt.Printf("Hello %v!", p.Name)
}

Go Native

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type Person struct {
	Name string
}

func handler(w http.ResponseWriter, r *http.Request) {
	p := &Person{Name: "World"}
	json.NewDecoder(r.Body).Decode(p)
	fmt.Fprintf(w, "Hello %v!", p.Name)
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":2000", nil)
}

Node.js Serverless

name = "World";
fs = require('fs');
try {
	obj = JSON.parse(fs.readFileSync('/dev/stdin').toString())
	if (obj.name != "") {
		name = obj.name
	}
} catch(e) {}
console.log("Hello", name, "from Node!");

Node.js Native

const http = require('http');
name = "World";

http.createServer(
    (req, res) => {
         var body = "";
         req.on(
            "data",
            (chunk) => { body+=chunk; }
         );

         req.on(
            "end",
            () => {
                 obj = JSON.parse(body);
                 res.writeHead(200, {'Content-Type': 'text/plain'});
                 res.end('Hello ' + obj.name + " from Node Native!");
            }
         );

    }
).listen(6000);

Python Serverless

import sys
sys.path.append("packages")
import os
import json

name = "World"
if not os.isatty(sys.stdin.fileno()):
	obj = json.loads(sys.stdin.read())
	if obj["name"] != "":
		name = obj["name"]

print "Hello", name, "!!!"

Python Native

from http.server import BaseHTTPRequestHandler,HTTPServer
from json import loads
from io   import TextIOWrapper

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers.get('content-length'))
        text  = TextIOWrapper(self.rfile).read(content_length)

        self.send_response(200)
        self.send_header('Content-type','text/plain')
        self.end_headers()

        obj = loads(text)
        self.wfile.write("Hello {name} !! Welcome to Native Python World!!".format(name=obj["name"]).encode("utf-8"))

PORT = 1000
server =  HTTPServer(("127.0.0.1", PORT), Handler)

print("serving at port", PORT)
server.serve_forever()

Méthode de banc

Le serveur de chaque benchmark s'exécute sur la même machine. Ubuntu 16.04 sur une machine virtuelle avec 1 cœur et 2 Go de mémoire. Le serveur qui place la charge et le serveur qui reçoit la charge sont les mêmes et utilisent Apache Bench. Préparez les json et

johnny.json


{
    "name":"Johnny"
}

La charge est appliquée en lançant le post-traitement avec Apache Bench. Le nombre de requêtes est de 100 et le nombre de parallèles est de 5. (Le nombre de demandes est petit sera décrit plus tard) À ce moment, le temps jusqu'à ce que la réponse soit renvoyée du serveur (temps de réponse) est mesuré.

#XXXX/XXXX complète le cas échéant
ab -n 100 -c 5 -p johnny.json -T "Content-Type: application/json" http://localhost:XXXXX/XXXXX

Résultats de référence

Response Time min[ms] mean[ms] std[ms] median[ms] max[ms] Ratio natif(mean)
Go Serverless 3951 6579 1010 6512 8692 1644.75
Go Native 0 4 5 2 37 -
Node Serverless 5335 14917 3147 15594 20542 621.54
Node Native 5 24 45 12 235 -
Python Serverless 5036 13455 4875 14214 29971 840.94
Python Native 6 16 4 16 26 -

** Veuillez noter que l'axe vertical de la figure ci-dessous est une échelle logarithmique (la relation d'amplitude est exprimée en logarithme pour une meilleure compréhension) **

image.png

Considération

Comme vous pouvez le voir dans le tableau, avec ** Go, l'environnement sans serveur est plus de 1600 fois plus lent que l'environnement natif. Vous pouvez voir que les autres Node.js sont 600 fois plus lents et Python 800 fois plus lent. ** ** Si vous comparez les résultats de Python et Node.js, vous pouvez trouver étrange que Python soit plus rapide. Lorsque j'ai essayé un test de suivi dans l'environnement natif, Python était parfois plus rapide lorsque le nombre de requêtes était petit et le nombre de parallèles était petit. Lorsque le nombre de requêtes est supérieur ou égal à 10000, Node.js peut traiter de manière plus stable et le traitement se termine plus rapidement que Python. De plus, l'implémentation native de Python entraînait parfois une erreur et la requête ne pouvait pas être traitée normalement. Probablement, Go, qui a une différence de vitesse avec ce nombre de requêtes, est réglé de manière anormale. Ici, je voudrais le comparer avec le "AWS Lambda a un temps de traitement de 250 ms à 8 000 ms" mentionné ci-dessus. Le résultat de cette référence était un résultat avec peu d'inconfort personnellement. Quand j'ai fait une demande à Iron Functions par moi-même avec Curl, je me sentais "lent", et si je fais un Docker pour chaque demande, je pense qu'il n'y a aucune aide pour cela. En revanche, j'avais l'impression que les 250ms d'AWS Lambda sont très rapides.

Tune Up AWS Lambda

En regardant, AWS Lambda semble avoir deux types de méthodes de démarrage, démarrage à froid et démarrage à chaud. Le premier n'est pas différent du sans serveur intuitif, et l'image est qu '"un conteneur est créé pour chaque requête", et le second semble être "un conteneur une fois créé est réutilisé". De cette manière, l'implémentation Lambda est plus rapide car elle risque de ne pas créer de conteneur. Il paraît que. Je pense que c'est la raison pour laquelle nous pouvons répondre en 250 ms au plus vite. D'un autre côté, Iron Functions n'implémente probablement que le démarrage à froid, donc je pense que ce n'est pas si rapide. Cependant, lorsque Go est exécuté sur Serverless dans un environnement créé par moi-même, je pense que Max d'environ 8600ms est une bonne vitesse de traitement. Bien sûr, il y a une différence dans le nombre de clients traités, mais la vitesse de création / élimination des conteneurs n'est-elle pas réellement la même? J'ai pensé.

L'hôte AWS Lambda est-il une bonne machine?

Vous trouverez ci-dessous un lien vers la liste de prix AWS Lambda.

Tarification AWS Lambda https://aws.amazon.com/jp/lambda/pricing/

Le plan tarifaire semble être facturé en fonction du temps d'utilisation * de l'utilisation de la mémoire, et il semble que vous ne puissiez pas sélectionner le processeur. Alors, comment le CPU est-il alloué? Il a été écrit dans Aide.

Et un autre article, l'article suivant

L'histoire de l'introduction en production du Framework Serverless

C'était énoncé. J'ai fait quelques tests d'environnement sans serveur, mais l'utilisation du processeur de la machine hôte augmente considérablement. Par conséquent, je me demandais comment le côté hôte (Amazon) pourrait payer, mais il semble que le prix unitaire horaire soit élevé du côté Amazon. De plus, sans serveur est essentiellement conçu pour que la réponse ne puisse être renvoyée qu'après le démarrage et la suppression du conteneur, je me demande donc si le processeur est réglé sur un bon processeur pour une réponse à haute vitesse. J'ai pensé.

Supplément banc

Normalement, le nombre de points de repère est de 10 000, ou je pense que certains modèles sont exécutés. Cependant, dans cette expérience, le nombre de requêtes est limité à environ 100. Il y a deux raisons. La première est qu'elle est «lente». Lors de l'exécution avec Serverless, cela prend environ 4000 ms au plus rapide. Par conséquent, nous n'avons pas évalué les demandes à grande échelle parce que ce n'était pas réaliste. Le second est parce qu'il est "instable". Iron Functions a un comportement instable. Par conséquent, même si la demande est environ 100 fois, elle peut échouer environ 10 fois. Par conséquent, si vous augmentez le nombre de parallèles ou le nombre de requêtes, il y a une forte probabilité que le traitement ne soit pas possible. Cela semble également dépendre du cycle de vie du conteneur Doquer de Iron Functions, et c'était un produit qui avait expiré ou pas même si la même demande était envoyée, et il était difficile d'obtenir une valeur précise. Par conséquent, les données décrites dans cet article suivent la valeur de temps de traitement elle-même. Je pense plutôt qu'il est plus exact de reconnaître qu'il y a un ordre de temps de traitement par rapport à Native. De plus, le fait que la machine qui applique la charge et la machine qui reçoit la charge soient les mêmes peut être un point de repère légèrement inexact. C'est simplement que je n'ai pas préparé deux environnements, mais si vous regardez la différence de vitesse entre l'implémentation native et l'implémentation sans serveur, cela peut ne pas poser de problème si vous ne gardez que l'état du serveur. .. Je pense.

Impressions

Cette référence a pris un temps très long. L'affichage a été considérablement retardé car il a fallu 3 à 4 heures pour demander au maximum 600 fois. Et la lenteur de Serverless est devenue un résultat vraiment frappant. Utilisons-le. J'ai pensé, mais je devrais arrêter ça pendant un moment ... D'un autre côté, AWS Lambda est excellent ... Et la vitesse du serveur http de Go est incroyable. Je n'ai jamais pensé que même un si petit banc serait rapide. De plus, Iron Functions est douloureux car il n'a presque pas de savoir-faire japonais. En fait, il existe un proxy inverse appelé fnlb, et une méthode de clustering par celui-ci est également officiellement préparée. Ensuite, ce sera plus facile à mettre à l'échelle. Bien que je pense que, l'opération en elle-même est trop lente, il peut donc être essentiel de régler davantage ou d'améliorer le goulot d'étranglement. Iron Functions lui-même est écrit en Go en premier lieu, donc ça ne devrait pas être aussi lent, mais ... je me demande si c'est autour du conteneur docker ... Hmm. Il y a un long chemin à parcourir sans serveur.

Recommended Posts

L'environnement sans serveur est-il plus de 600 fois plus lent? ~ J'ai essayé l'analyse comparative avec Go, Node.js et Python! ~
J'ai défini des variables d'environnement dans Docker et je les ai affichées en Python.
J'ai essayé de "lisser" l'image avec Python + OpenCV
J'ai essayé de "différencier" l'image avec Python + OpenCV
J'ai essayé la différenciation jacobienne et partielle avec python
J'ai essayé la synthèse de fonctions et le curry avec python
J'ai essayé de "binariser" l'image avec Python + OpenCV
J'ai essayé d'exécuter faiss avec python, Go, Rust
J'ai essayé de toucher un fichier CSV avec Python
J'ai essayé de résoudre Soma Cube avec python
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
[New Corona] Le prochain pic est-il en décembre? J'ai essayé l'analyse des tendances avec Python!
J'ai essayé de résoudre le problème avec Python Vol.1
J'ai essayé de comparer la vitesse de traitement avec dplyr de R et pandas de Python
J'ai essayé de frapper l'API avec le client python d'echonest
J'ai essayé la même analyse de données avec kaggle notebook (python) et PowerBI en même temps ②
J'ai essayé la même analyse de données avec kaggle notebook (python) et PowerBI en même temps ①
J'ai aussi essayé d'imiter la fonction monade et la monade d'état avec le générateur en Python
J'ai essayé d'exécuter le système de reconnaissance vocale hors ligne Julius avec python dans l'environnement virtuel Docker
J'ai essayé la "correction gamma" de l'image avec Python + OpenCV
J'ai essayé d'utiliser la bibliothèque Python de Ruby avec PyCall
J'ai essayé la gestion du suivi avec l'API Twitter et Python (facile)
J'ai essayé de programmer le test du chi carré en Python et Java.
J'ai essayé d'énumérer les différences entre java et python
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai essayé de créer un traitement par lots sans serveur pour la première fois avec DynamoDB et Step Functions
Le dernier NGINX est un serveur d'applications! ?? J'ai mesuré le benchmark de NGINX Unit avec PHP, Python, Go! !!
J'ai comparé la vitesse de Hash avec Topaz, Ruby et Python
J'ai essayé de gratter le classement du calendrier de l'avent Qiita avec Python
J'ai essayé de résoudre l'édition du débutant du livre des fourmis avec python
J'ai essayé de faire un processus d'exécution périodique avec Selenium et Python
J'ai essayé de savoir si ReDoS est possible avec Python
J'ai essayé de détecter facilement les points de repère du visage avec python et dlib
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
J'ai essayé Grumpy (allez exécuter Python).
J'ai aimé le tweet avec python. ..
J'ai joué avec PyQt5 et Python3
J'ai essayé d'obtenir et d'analyser les données statistiques de la nouvelle Corona avec Python: données de l'Université John's Hopkins
J'ai essayé d'exécuter prolog avec python 3.8.2.
J'ai essayé la communication SMTP avec Python
J'ai essayé de livrer du courrier depuis Node.js et Python en utilisant le service de livraison de courrier (SendGrid) d'IBM Cloud!
[Python] J'ai essayé de visualiser la nuit du chemin de fer de la galaxie avec WordCloud!
J'ai essayé d'exprimer de la tristesse et de la joie face au problème du mariage stable.
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
J'ai essayé d'apprendre l'angle du péché et du cos avec le chainer
J'ai essayé avec les 100 meilleurs packages PyPI> J'ai essayé de représenter graphiquement les packages installés sur Python
J'ai essayé de vérifier et d'analyser l'accélération de Python par Cython
J'ai essayé de rationaliser le rôle standard des nouveaux employés avec Python
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
J'ai essayé de créer un environnement de développement Mac Python avec pythonz + direnv
J'ai mesuré la vitesse de la notation d'inclusion de liste, pendant et pendant avec python2.7.
J'ai essayé de mettre à jour le calendrier Google avec des rendez-vous CSV à l'aide de Python et de l'API Google