Les requêtes HTTP de l'extrêmeLes requêtes HTTP de l'extrême
Vincent Cassé - @vcasseVincent Cassé - @vcasse
Les requêtes HTTP de l'extrêmeLes requêtes HTTP de l'extrême
Etape 1 :Présenter la problématique
Etape 1 :Présenter la problématique
Problématique de l'épisodeProblématique de l'épisode
● Gérer des fichiers dans le cloud
● Application web
● Utilisation d'un object storagehttps://www.ovh.com/fr/cloud/storage/object-storage.xml
● Gérer des fichiers dans le cloud
● Application web
● Utilisation d'un object storagehttps://www.ovh.com/fr/cloud/storage/object-storage.xml
Architecture de l'applicationArchitecture de l'application
Navigateur web
Serveur applicatif
Object storage
Etape 2 :Étudier chaque problème,
de manière temporelle
Etape 2 :Étudier chaque problème,
de manière temporelle
Télécharger des fichiersTélécharger des fichiers
D'habitudeD'habitude
● Stockage en local temporaire
● Risque 1 : disque pleins
● Risque 2 : timeouts
● Stockage en local temporaire
● Risque 1 : disque pleins
● Risque 2 : timeouts
Timeout ?Timeout ?
Navigateur web
Serveur applicatif
Object storage
Timeout ?Timeout ?
● Connexion HTTP en attente sans traffic
● Passage par des load balancers
● Ressemble à une attaque SYN
● Connexion HTTP en attente sans traffic
● Passage par des load balancers
● Ressemble à une attaque SYN
Le callback de curl est un amiLe callback de curl est un ami
● Exécution à chaque paquet reçu
● Temps curl non décompté
● Permet d'éviter stockage local
● Permet d'envoyer du contenu : pas de timeout
● Exécution à chaque paquet reçu
● Temps curl non décompté
● Permet d'éviter stockage local
● Permet d'envoyer du contenu : pas de timeout
Le callback de curl est un amiLe callback de curl est un ami
curl_setopt($curl, CURLOPT_WRITEFUNCTION, function($a,$b) {echo $b;flush();return strlen($b);
);
curl_setopt($curl, CURLOPT_WRITEFUNCTION, function($a,$b) {echo $b;flush();return strlen($b);
);
Et plusieurs fichiers ?Et plusieurs fichiers ?
Enregistrer le fichier sous...Enregistrer le fichier sous...
// Frontend
Iframe + formulaire à valider pour charger le fichier sans recharge la page
// Backend
header('CacheControl: nocache, nostore, maxage=0, mustrevalidate');header("ContentType: application/jpeg”);header('ContentLength: 1337”);header("ContentTransferEncoding: binary");header('ContentDisposition: attachment;filename="picture.jpg"');
// Frontend
Iframe + formulaire à valider pour charger le fichier sans recharge la page
// Backend
header('CacheControl: nocache, nostore, maxage=0, mustrevalidate');header("ContentType: application/jpeg”);header('ContentLength: 1337”);header("ContentTransferEncoding: binary");header('ContentDisposition: attachment;filename="picture.jpg"');
Zip obligatoireZip obligatoire
● Un seul fichier par download
● Le format zip permet de faire un seul fichier (même sans compression)
● Stockage local avant de zipper ?
● Un seul fichier par download
● Le format zip permet de faire un seul fichier (même sans compression)
● Stockage local avant de zipper ?
Les streams sont vos amisLes streams sont vos amis
● Stream permet la lecture / écriture d'une ressource
● Stream se comporte comme les fichiers
● Plus d'infos sur les streams http://php.net/manual/en/intro.stream.phphttps://blog.pascal-martin.fr/post/slides-presentation-flux-forum-php-2015.html
● Stream permet la lecture / écriture d'une ressource
● Stream se comporte comme les fichiers
● Plus d'infos sur les streams http://php.net/manual/en/intro.stream.phphttps://blog.pascal-martin.fr/post/slides-presentation-flux-forum-php-2015.html
Les streams sont vos amisLes streams sont vos amis
// Register stream zipstream_wrapper_register("zip", "ZipClassName");
// Use stream zip with curl return$fp = fopen("zip://uniqNameByDownload”, "r+");curl_setopt($curl, CURLOPT_FILE, $fp);fclose( $fp );
// Register stream zipstream_wrapper_register("zip", "ZipClassName");
// Use stream zip with curl return$fp = fopen("zip://uniqNameByDownload”, "r+");curl_setopt($curl, CURLOPT_FILE, $fp);fclose( $fp );
Et les miniatures ?Et les miniatures ?
Imagick ?Imagick ?
● Limité à l'application web
● Prend des ressources CPU
● Comment distribuer le cache ?
● Limité à l'application web
● Prend des ressources CPU
● Comment distribuer le cache ?
Réducteur d'image à la voléeRéducteur d'image à la volée
Navigateur web
Serveur applicatif
Object storage
Miniatures
Houston : on reçoit des erreurs 0Houston : on reçoit des erreurs 0
Des erreurs 0 ?Des erreurs 0 ?
● Pas d'erreur 0 dans les logs
● Sur IE, l'erreur n'appelle même pas le callback d'erreur …
● Mais des 499
● What ?
● Pas d'erreur 0 dans les logs
● Sur IE, l'erreur n'appelle même pas le callback d'erreur …
● Mais des 499
● What ?
Suppression d'un fichierSuppression d'un fichier
● L'erreur arrive sur les suppressions de gros fichiers
● L'action est longue coté Object Storage
● Timeout php ?
● L'erreur arrive sur les suppressions de gros fichiers
● L'action est longue coté Object Storage
● Timeout php ?
Code HTTP 0 ?Code HTTP 0 ?
● Soucis réseau : ça a tranché sur la route
● Timeout du load balancer !
● Solution : faire de l'async ?
● Soucis réseau : ça a tranché sur la route
● Timeout du load balancer !
● Solution : faire de l'async ?
Suppression programméeSuppression programmée
● Object storage permet de programmer une suppression
● Pas d'attente ! C'est juste programmé !
● Et si on programmait dans une seconde ?
● Object storage permet de programmer une suppression
● Pas d'attente ! C'est juste programmé !
● Et si on programmait dans une seconde ?
Heu… y'a encore des erreurs 0 !Heu… y'a encore des erreurs 0 !
Encore des erreurs 0 ?Encore des erreurs 0 ?
● Sur un upload : y'a du traffic -_-
● Seulement sur les gros fichiers
● Sur un upload : y'a du traffic -_-
● Seulement sur les gros fichiers
Firebug ...Firebug ...
● Analyseur de code dans Firefox / Chrome
● Coupe le traffic sur les requêtes > 100 Mo.
● Paf timeout ...
● Analyseur de code dans Firefox / Chrome
● Coupe le traffic sur les requêtes > 100 Mo.
● Paf timeout ...
Et si on parlait d'upload ?Et si on parlait d'upload ?
Comment on upload ?Comment on upload ?
<form enctype="multipart/formdata" action="upload.php” method="POST"><input type="hidden" name="META1" value="file" /><input name="content" type="file" /><br /><input type="submit" value="Upload File" />
</form>
● Recharge la page
● Ne permet pas d'afficher la progression
● AJAX ?
<form enctype="multipart/formdata" action="upload.php” method="POST"><input type="hidden" name="META1" value="file" /><input name="content" type="file" /><br /><input type="submit" value="Upload File" />
</form>
● Recharge la page
● Ne permet pas d'afficher la progression
● AJAX ?
AJAX ?AJAX ?
● Permet de suivre la progression
● Format binairexhr = new XMLHttpRequest();xhr.addEventListener("load", successCallback, false);xhr.addEventListener("error", errorCallback, false);xhr.addEventListener("abort", abortCallback, false);xhr.upload.addEventListener("progress", progressCallback, false);xhr.open('POST', url, true);xhr.send(data);
● Permet de suivre la progression
● Format binairexhr = new XMLHttpRequest();xhr.addEventListener("load", successCallback, false);xhr.addEventListener("error", errorCallback, false);xhr.addEventListener("abort", abortCallback, false);xhr.upload.addEventListener("progress", progressCallback, false);xhr.open('POST', url, true);xhr.send(data);
Et mon formulaire ?Et mon formulaire ?
● L'object storage attend un formulaire
● On crée le formulaire en javascript● http://caniuse.com/#search=formdata
http://caniuse.com/#search=file
formData = new FormData();formData.append('meta1', “file”);formData.append('content', fp);…xhr.send(formData);
● L'object storage attend un formulaire
● On crée le formulaire en javascript● http://caniuse.com/#search=formdata
http://caniuse.com/#search=file
formData = new FormData();formData.append('meta1', “file”);formData.append('content', fp);…xhr.send(formData);
Contraintes des uploadsContraintes des uploads
● Adsl répandu
● Upload de l'adsl : max 128 Ko/s (1Mbps)
● Les uploads durent des heures
● Adsl répandu
● Upload de l'adsl : max 128 Ko/s (1Mbps)
● Les uploads durent des heures
Fiabiliser les uploadsFiabiliser les uploads
Navigateur web
Serveur applicatif Object
storage
Upload
Chef ça a cassé !Chef ça a cassé !
● Same origin policy !
● Aucun appel Ajax sur un autre domaine
● C'était trop beau…
● Same origin policy !
● Aucun appel Ajax sur un autre domaine
● C'était trop beau…
CORSCORS
● Permet de définir les serveurs autorisés
● Configuration sur les serveurs● http://caniuse.com/#search=cors
// Requête de firefoxGET /fileList/ HTTP/1.1Origin: http://mywebapp.ovh
// Réponse du serveur cluster.objectstorage.ovhAccessControlAllowOrigin: http://mywebapp.ovh
● Permet de définir les serveurs autorisés
● Configuration sur les serveurs● http://caniuse.com/#search=cors
// Requête de firefoxGET /fileList/ HTTP/1.1Origin: http://mywebapp.ovh
// Réponse du serveur cluster.objectstorage.ovhAccessControlAllowOrigin: http://mywebapp.ovh
Au fait, tu dois gérer IE8 !Au fait, tu dois gérer IE8 !
● Dernier IE de Windows XP...
● Gére pas formData (IE10)
● Gére pas CORS (IE10) ...
● Dernier IE de Windows XP...
● Gére pas formData (IE10)
● Gére pas CORS (IE10) ...
Au fait, tu dois gérer IE8 !Au fait, tu dois gérer IE8 !
● On crée une iframe sur cluster.objectstorage.ovh
● Contenant un formulaire
● On simule le clic sur le bouton
● On crée une iframe sur cluster.objectstorage.ovh
● Contenant un formulaire
● On simule le clic sur le bouton
Les autres blagues de IE < 10Les autres blagues de IE < 10
● Upload de .jpeg ?
● Sélection multiple ?
● Windows phone 8 ?
● Upload de .jpeg ?
● Sélection multiple ?
● Windows phone 8 ?
On peut uploader un dossier ?On peut uploader un dossier ?
● Chrome le peut. C'est deprecated
● Firefox bute sur l'ergonomie
● WebAPI ?
● Chrome le peut. C'est deprecated
● Firefox bute sur l'ergonomie
● WebAPI ?
Etape 3 :La réalisation et ses aléas
Etape 3 :La réalisation et ses aléas
Les bugs poilusLes bugs poilus
Remontées des utilisateursRemontées des utilisateurs
● Mon download a crashé au bout de 27h
● Mon zip est corrompu
● Mon download a crashé au bout de 27h
● Mon zip est corrompu
Ce qu'en pense les sysadminsCe qu'en pense les sysadmins
● Non pas de reboot de serveur
● Aucune alerte du monito
● Au fait, pendant que tu es là, tu as vu mon mail sur la conso de RAM ?
● Non pas de reboot de serveur
● Aucune alerte du monito
● Au fait, pendant que tu es là, tu as vu mon mail sur la conso de RAM ?
Conso de RAM ?Conso de RAM ?
● Pas possible : je stream
● Je reproduis pas en dev : c'est le serveur qui est mal configuré
● Monito des process PHP : non c'est pas eux qui mangent la RAM !
● Pas possible : je stream
● Je reproduis pas en dev : c'est le serveur qui est mal configuré
● Monito des process PHP : non c'est pas eux qui mangent la RAM !
Nginx ?Nginx ?
location /webapp $ {proxy_pass http://localhost:81;proxy_set_header Host $host;
}
…
server {listen 81;location ~ \.php$ {
try_files $uri =404;fastcgi_pass unix:/var/run/php5fpm.sock;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}}
location /webapp $ {proxy_pass http://localhost:81;proxy_set_header Host $host;
}
…
server {listen 81;location ~ \.php$ {
try_files $uri =404;fastcgi_pass unix:/var/run/php5fpm.sock;fastcgi_index index.php;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}}
Nginx ?Nginx ?
Syntax: proxy_buffering on | off;Default: proxy_buffering on;Context: http, server, location
http://nginx.org/en/docs/http/ngx_http_proxy_module.html
Syntax: proxy_buffering on | off;Default: proxy_buffering on;Context: http, server, location
http://nginx.org/en/docs/http/ngx_http_proxy_module.html
proxy_bufferingproxy_buffering
Listen 80Internet
Object
Storage
Listen 81
PHP-fpm
ProxyF
astcgi
Tout est bien qui finit bienTout est bien qui finit bien
En fait, le dev web c'estEn fait, le dev web c'est
● Multi – navigateur
● Ça doit gérer le réseau
● C'est comme les oignons, ça a des couches
● Multi – navigateur
● Ça doit gérer le réseau
● C'est comme les oignons, ça a des couches
Merci !
Des questions ?
Merci !
Des questions ?
Les requêtes HTTP de l'extrêmeLes requêtes HTTP de l'extrême
Vincent Cassé - @vcasseVincent Cassé - @vcasse