[Résolu] Les objets de liste S3 de Go sont-ils plus lents que Python? problème

introduction

Lors du téléchargement d'un grand nombre d'objets à partir de S3, la vitesse ne sort pas modérément quelle que soit la taille de l'objet. Quand j'écrivais en Python, je faisais de mon mieux avec ** concurrent.futures **, mais peut-être que je peux le faire avec Goroutine? J'ai pensé, j'ai fait mes débuts à Golang.

Ce que je voulais faire

--Utilisez ListObjectV2 pour obtenir toutes les clés sous le préfixe spécifique de S3 --Téléchargez la clé acquise avec Goroutine

Ce qui s'est réellement passé

Hmm? Même vitesse car vous venez de frapper l'API. Si tel est le cas, je suis toujours convaincu, mais je crains un peu que ** Go soit plus lent que le langage de script **. J'ai changé mon horaire à la hâte et j'ai essayé de vérifier un peu cette question.

Code source

Aller version

Donc ici et [ici](https: // Écrivez-le en vous référant à docs.aws.amazon.com/sdk-for-go/api/service/s3/#S3.ListObjectsV2).

main.go


package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"os"
)

func main() {
	bucket := os.Getenv("BUCKET")
	prefix := os.Getenv("PREFIX")
	region := os.Getenv("REGION")

	sess := session.Must(session.NewSession())
	svc := s3.New(sess, &aws.Config{
		Region: &region,
	})
	params := &s3.ListObjectsV2Input{
		Bucket: &bucket,
		Prefix: &prefix,
	}
	fmt.Println("Start:")
	err := svc.ListObjectsV2Pages(params,
		func(p *s3.ListObjectsV2Output, last bool) (shouldContinue bool) {
			for _, obj := range p.Contents {
				fmt.Println(*obj.Key)
			}
			return true
		})
	fmt.Println("End:")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
}

Version Python

J'écrirai ceci aussi. Avec un client de bas niveau pour répondre aux conditions avec Go.

main.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import boto3
bucket = os.environ["BUCKET"]
prefix = os.environ["PREFIX"]
region = os.environ["REGION"]

# r = boto3.resource('s3').Bucket(bucket).objects.filter(Prefix=prefix)
# [print(r.key) for r in r]
#Je l'obtiens généralement comme ci-dessus, mais je le mesure avec le code suivant pour l'envoyer à Golang

s3_client = boto3.client('s3', region)

contents = []
next_token = ''
while True:
    if next_token == '':
        response = s3_client.list_objects_v2(Bucket=bucket, Prefix=prefix)
    else:
        response = s3_client.list_objects_v2(Bucket=bucket, Prefix=prefix, ContinuationToken=next_token)

    contents.extend(response['Contents'])
    if 'NextContinuationToken' in response:
        next_token = response['NextContinuationToken']
    else:
        break

[print(r["Key"]) for r in contents]

environnement

Serveur, etc.

--Exécute essentiellement sur Cloud9 sur EC2 (t2.micro).

Construire / déployer, etc.

――Je ne veux pas polluer l'environnement et c'est gênant, j'ai donc tout construit avec Docker.

$ docker-compose up -d --build

Dockerfile


FROM golang:1.13.5-stretch as build
RUN go get \
  github.com/aws/aws-sdk-go/aws \
  github.com/aws/aws-sdk-go/aws/session \
  github.com/aws/aws-sdk-go/service/s3 
COPY . /work
WORKDIR /work
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main main.go

FROM python:3.7.6-stretch as release
RUN pip install boto3
COPY --from=build /work/main /usr/local/bin/main
COPY --from=build /work/main.py /usr/local/bin/main.py
WORKDIR /usr/local/bin/

docker-compose.yml


version: '3'
services:
  app:
    build:
      context: .
    container_name: "app"
    tty: True
    environment:
      BUCKET: <Bucket>
      PREFIX: test/
      REGION: ap-northeast-1

Seau S3

Créez un bucket dans la région de Tokyo et créez-en environ 1000 avec les outils suivants.

#/bin/bash

Bucket=<Bucket>
Prefix="test"

#Création de fichier de test
dd if=/dev/zero of=testobj bs=1 count=30
#Copie du fichier maître
aws s3 cp testobj s3://${Bucket}/${Prefix}/testobj
#Dupliquer le fichier maître
for i in $(seq 0 9); do
    for k in $(seq 0 99); do
        aws s3 cp s3://${Bucket}/${Prefix}/testobj s3://${Bucket}/${Prefix}/${i}/${k}/${i}_${k}.obj
    done
done

La mesure

Résultat de la mesure (1000 objets)

$ time docker-compose exec app ./main

~ Abréviation ~

real    0m21.888s
user    0m0.580s
sys     0m0.107s
$ time docker-compose exec app ./main.py

~ Abréviation ~

real    0m2.671s
user    0m0.577s
sys     0m0.104s

Go est 10 fois plus lent que Python. Pourquoi!

Essayez d'augmenter le nombre d'objets

#Différence seulement
for i in $(seq 0 99); do
    for k in $(seq 0 99); do

―― En passant, il a fallu 3-4 heures pour terminer le téléchargement. J'aurais dû faire l'outil correctement ...

Résultat de la nouvelle mesure (objet 10000)

$ time docker-compose exec app ./main

~ Abréviation ~

real    0m23.276s
user    0m0.617s
sys     0m0.128s
$ time docker-compose exec app ./main.py

~ Abréviation ~
real    0m5.973s
user    0m0.576s
sys     0m0.114s

Cette fois, la différence est d'environ 4 fois. Au contraire, il semble qu'il y ait une différence d'environ 18 secondes quel que soit le nombre d'objets. Hmmm.

À la fin

――Je pense que je ne comprends pas les spécifications de la langue à cause des paramètres de la bibliothèque, donc j'aimerais obtenir plus d'informations. ――Si l'efficacité du ** traitement de téléchargement parallèle dans Goroutine **, qui est l'objectif initial, est bonne, il semble qu'il y ait une erreur d'environ 20 secondes, donc je vais essayer d'implémenter le reste.

Lieux de préoccupation

Suivi (2020/01/18)

Comme indiqué dans la section des commentaires, j'ai essayé de déboguer le SDK J'ai trouvé qu'il fallait beaucoup de temps pour trouver les informations d'identification IAM. La valeur par défaut du système d'exploitation "-stretch" était-elle mauvaise? Je l'ai essayé plusieurs fois par la suite, mais il n'est pas réapparu dans cet environnement, donc je vais le résoudre. C'est maussade, mais ...

@nabeken Merci!

Recommended Posts

[Résolu] Les objets de liste S3 de Go sont-ils plus lents que Python? problème
La liste Python n'est pas une liste
Golang vs Python - Golang est-il meilleur que Python?