Proxy lent : 7 raisons de la baisse de vitesse et méthodes d'accélération
La vitesse de connexion proxy influence directement l'efficacité du parsing, de l'automatisation et de toute tâche liée aux requêtes massives. Lorsque le proxy fonctionne lentement, cela entraîne une augmentation du temps d'exécution des scripts, des délais d'attente et des pertes de données. Dans cet article, nous examinerons les raisons techniques de la faible vitesse et montrerons des moyens concrets d'optimisation avec des exemples de code et des résultats de tests.
Distance géographique du serveur
La distance physique entre votre serveur, le proxy et la ressource cible est un facteur principal de latence. Chaque nœud supplémentaire dans la chaîne ajoute des millisecondes qui s'accumulent lors des requêtes massives.
Un schéma typique de requête via un proxy ressemble à ceci : votre serveur → serveur proxy → site cible → serveur proxy → votre serveur. Si votre parser est en Allemagne, le proxy aux États-Unis et le site cible au Japon, les données parcourent des dizaines de milliers de kilomètres.
Exemple pratique : Le test de 1000 requêtes à un site européen a montré une différence dans le temps de réponse moyen : via un proxy en Europe — 180 ms, via un proxy en Asie — 520 ms. Une différence de 340 ms par requête donne 340 secondes (5,6 minutes) pour 1000 requêtes.
Solution : Choisissez un proxy géographiquement proche de la ressource cible. Si vous parsez des sites russes, utilisez des proxies avec des IP russes. Pour travailler avec des services globaux (Google, Amazon), des proxies aux États-Unis ou en Europe de l'Ouest, où se trouvent les principaux centres de données, sont optimaux.
Pour les proxies résidentiels, faites attention à la possibilité de choisir une ville ou une région spécifique, et pas seulement un pays. La différence de ping entre un proxy de Moscou et de Vladivostok lors de l'accès à un serveur moscovite peut atteindre 150-200 ms.
Impact du protocole sur la vitesse de transmission des données
Le choix du protocole proxy influence considérablement la vitesse. Les principales options sont : HTTP/HTTPS, SOCKS4, SOCKS5. Chacun a ses propres caractéristiques de traitement des données et frais généraux.
| Protocole | Vitesse | Frais généraux | Application |
|---|---|---|---|
| HTTP | Élevée | Minimaux | Web scraping, API |
| HTTPS | Moyenne | +15-25% sur SSL | Connexions sécurisées |
| SOCKS4 | Élevée | Faibles | Trafic TCP |
| SOCKS5 | Moyenne-Élevée | +5-10% pour l'authentification | Trafic universel, UDP |
Les proxies HTTP sont optimaux pour le web scraping, car ils fonctionnent au niveau applicatif et peuvent mettre en cache les données. SOCKS5 est plus universel, mais ajoute une couche de traitement supplémentaire. Pour un simple parsing HTML, la différence de vitesse entre HTTP et SOCKS5 peut atteindre 10-15%.
Exemple de configuration en Python (requests) :
import requests
# Proxy HTTP - plus rapide pour les requêtes web
proxies_http = {
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080'
}
# SOCKS5 - plus universel, mais plus lent
proxies_socks = {
'http': 'socks5://user:pass@proxy.example.com:1080',
'https': 'socks5://user:pass@proxy.example.com:1080'
}
# Pour le web scraping, utilisez HTTP
response = requests.get('https://example.com', proxies=proxies_http, timeout=10)
Si votre fournisseur propose les deux options, testez-les sur des tâches réelles. Pour travailler avec des proxies de centre de données, le protocole HTTP montre généralement une vitesse de 12-18% supérieure à celle de SOCKS5 sous une charge identique.
Surcharge du serveur proxy et pools IP
Lorsque un serveur proxy gère trop de connexions simultanées, la vitesse diminue en raison des limitations de bande passante et des ressources de calcul. Cela est particulièrement critique pour les proxies partagés, où une seule IP est utilisée par des dizaines de clients.
Une image typique de surcharge : au début de l'exécution du script, la vitesse est normale (50-100 requêtes par minute), puis chute brusquement à 10-15 requêtes. Cela se produit lorsque le serveur atteint la limite des connexions ouvertes ou de la bande passante.
Signes de surcharge : augmentation du temps de réponse de 200%+, délais d'attente périodiques, erreurs "Connection reset by peer", vitesse instable avec des pics brusques.
Solutions :
- Utilisez un pool de proxies au lieu d'une seule IP. La rotation entre 10-20 proxies répartit la charge et réduit la probabilité de blocage.
- Limitez le nombre de connexions simultanées via un seul proxy (recommandé : pas plus de 5-10 flux parallèles).
- Pour des tâches à forte charge, choisissez des proxies privés (dedicated), où les ressources ne sont pas partagées avec d'autres utilisateurs.
- Surveillez la vitesse en temps réel et excluez automatiquement les proxies lents de la rotation.
Exemple de mise en œuvre d'un pool avec surveillance de la vitesse :
import time
import requests
from collections import deque
class ProxyPool:
def __init__(self, proxies, max_response_time=5.0):
self.proxies = deque(proxies)
self.max_response_time = max_response_time
self.stats = {p: {'total': 0, 'slow': 0} for p in proxies}
def get_proxy(self):
"""Obtenir le prochain proxy du pool"""
proxy = self.proxies[0]
self.proxies.rotate(-1) # Déplacer à la fin
return proxy
def test_and_remove_slow(self, url='http://httpbin.org/ip'):
"""Tester et supprimer les proxies lents"""
for proxy in list(self.proxies):
try:
start = time.time()
requests.get(url, proxies={'http': proxy}, timeout=10)
response_time = time.time() - start
self.stats[proxy]['total'] += 1
if response_time > self.max_response_time:
self.stats[proxy]['slow'] += 1
# Supprimer si plus de 50% des requêtes sont lentes
slow_ratio = self.stats[proxy]['slow'] / self.stats[proxy]['total']
if slow_ratio > 0.5 and self.stats[proxy]['total'] > 10:
self.proxies.remove(proxy)
print(f"Proxy lent supprimé : {proxy}")
except:
self.proxies.remove(proxy)
# Utilisation
proxies = [
'http://proxy1.example.com:8080',
'http://proxy2.example.com:8080',
'http://proxy3.example.com:8080'
]
pool = ProxyPool(proxies, max_response_time=3.0)
pool.test_and_remove_slow()
# Travailler avec le pool
for i in range(100):
proxy = pool.get_proxy()
# Effectuer une requête via proxy
Paramètres de connexion et délais d'attente
Des paramètres de connexion mal configurés sont une cause fréquente de la lenteur apparente des proxies. Des délais d'attente trop longs obligent le script à attendre des proxies inaccessibles, des délais trop courts entraînent des coupures de connexions normales.
Paramètres clés influençant la vitesse :
- Délai de connexion — temps d'attente pour établir la connexion. Optimal : 5-10 secondes pour les proxies résidentiels, 3-5 pour les proxies de centre de données.
- Délai de lecture — temps d'attente pour la réponse après l'établissement de la connexion. Dépend de la tâche : 10-15 secondes pour le parsing, 30+ pour le téléchargement de gros fichiers.
- Keep-Alive — réutilisation des connexions TCP. Économise jusqu'à 200-300 ms sur chaque requête suivante au même domaine.
- Pool de connexions — pool de connexions ouvertes. Critique pour une haute performance lors de requêtes massives.
Configuration optimisée pour requests :
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# Créer une session avec des paramètres optimisés
session = requests.Session()
# Configuration des tentatives de répétition
retry_strategy = Retry(
total=3, # Maximum 3 tentatives
backoff_factor=0.5, # Délai entre les tentatives : 0.5, 1, 2 secondes
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"]
)
# Adaptateur avec pool de connexions
adapter = HTTPAdapter(
max_retries=retry_strategy,
pool_connections=10, # Pool pour 10 hôtes
pool_maxsize=20 # Maximum 20 connexions
)
session.mount("http://", adapter)
session.mount("https://", adapter)
# Configuration du proxy
session.proxies = {
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080'
}
# Requête avec des délais d'attente optimaux
# (connection_timeout, read_timeout)
response = session.get(
'https://example.com',
timeout=(5, 15), # 5 sec pour la connexion, 15 pour la lecture
headers={'Connection': 'keep-alive'} # Réutilisation de la connexion
)
L'utilisation de sessions avec Keep-Alive lors du parsing de 1000 pages d'un même site accélère le travail de 30-40% par rapport à la création d'une nouvelle connexion pour chaque requête. L'économie de temps sur l'établissement de la connexion TCP et le handshake SSL est critique lors d'opérations massives.
Chiffrement et frais généraux SSL/TLS
Les connexions HTTPS nécessitent des ressources de calcul supplémentaires pour le chiffrement/déchiffrement des données et l'exécution du handshake SSL/TLS. Lors de l'utilisation via un proxy, cela se produit deux fois : entre vous et le proxy, entre le proxy et le serveur cible.
Frais généraux typiques SSL/TLS :
- Handshake initial : 150-300 ms (dépend de l'algorithme et de la distance)
- Chiffrement/déchiffrement des données : +10-20% au temps de transmission
- Charge supplémentaire sur le CPU du serveur proxy lors d'un trafic élevé
Méthodes d'optimisation :
1. Utilisez la reprise de session TLS
Permet de réutiliser les paramètres de session SSL et de sauter le handshake complet. Économie jusqu'à 200 ms sur chaque connexion suivante.
En Python, cela fonctionne automatiquement lors de l'utilisation de requests.Session(), mais assurez-vous de ne pas créer une nouvelle session pour chaque requête.
2. Préférez TLS 1.3
TLS 1.3 nécessite un seul aller-retour pour le handshake au lieu de deux avec TLS 1.2. Cela réduit le temps d'établissement de la connexion de 30-50%.
Assurez-vous que votre bibliothèque (OpenSSL, urllib3) prend en charge TLS 1.3 et qu'il n'est pas désactivé dans les paramètres.
3. Pour les tâches internes, envisagez HTTP
Si vous parsez des données publiques qui ne contiennent pas d'informations sensibles et que le site est accessible via HTTP, utilisez une connexion non chiffrée. Cela donnera un gain de vitesse de 15-25%.
Lors de l'utilisation de proxies mobiles, où le canal de communication peut être plus lent, les frais généraux SSL deviennent encore plus visibles. Dans les tests, la différence entre les requêtes HTTP et HTTPS via des proxies 4G était en moyenne de 280 ms.
Résolution DNS et mise en cache
Chaque requête vers un nouveau domaine nécessite une résolution DNS — la conversion d'un nom de domaine en adresse IP. Sans mise en cache, cela ajoute 20-100 ms à chaque requête, et avec un serveur DNS lent, la latence peut atteindre 500 ms ou plus.
Lorsque vous travaillez via un proxy, les requêtes DNS peuvent être effectuées à trois endroits :
- De votre côté (le client résout le domaine et transmet l'IP au proxy)
- Sur le serveur proxy (SOCKS5, HTTP CONNECT — le proxy reçoit le domaine et le résout lui-même)
- Sur le serveur cible (rare, dans des configurations spécifiques)
Pour les proxies SOCKS5, la résolution DNS se fait généralement du côté du serveur proxy, ce qui peut être plus lent si le fournisseur de proxy a de mauvais serveurs DNS. Les proxies HTTP résolvent plus souvent du côté client.
Méthodes pour accélérer DNS :
import socket
from functools import lru_cache
# Mise en cache de la résolution DNS côté client
@lru_cache(maxsize=256)
def cached_resolve(hostname):
"""Mettre en cache les résultats des requêtes DNS"""
try:
return socket.gethostbyname(hostname)
except socket.gaierror:
return None
# Utilisation
hostname = 'example.com'
ip = cached_resolve(hostname)
if ip:
# Utiliser l'IP directement dans les requêtes
url = f'http://{ip}/path'
headers = {'Host': hostname} # Indiquer l'hôte d'origine dans l'en-tête
Une approche alternative consiste à utiliser des serveurs DNS publics rapides au niveau système :
- Google DNS : 8.8.8.8, 8.8.4.4
- Cloudflare DNS : 1.1.1.1, 1.0.0.1
- Quad9 : 9.9.9.9
Sous Linux, la configuration se fait via /etc/resolv.conf :
nameserver 1.1.1.1
nameserver 8.8.8.8
options timeout:2 attempts:2
Pour les scripts Python avec de nombreux domaines, il est recommandé de préchauffer le cache DNS :
import concurrent.futures
import socket
def warmup_dns_cache(domains):
"""Résoudre à l'avance une liste de domaines"""
def resolve(domain):
try:
socket.gethostbyname(domain)
except:
pass
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
executor.map(resolve, domains)
# Liste de domaines à parser
domains = ['site1.com', 'site2.com', 'site3.com']
warmup_dns_cache(domains)
# Maintenant, DNS est déjà dans le cache, les requêtes seront plus rapides
Qualité de l'infrastructure du fournisseur
La vitesse du proxy dépend directement de la qualité du matériel et des canaux de communication du fournisseur. Les proxies bon marché fonctionnent souvent sur des serveurs surchargés avec des interfaces réseau lentes et du matériel obsolète.
Paramètres critiques de l'infrastructure :
| Paramètre | Mauvais | Bon | Impact sur la vitesse |
|---|---|---|---|
| Bande passante du canal | 100 Mbit/s | 1+ Gbit/s | Critique lors du téléchargement de fichiers |
| Processeur du serveur | 2-4 cœurs | 8+ cœurs | Impact sur le traitement SSL/TLS |
| RAM | 4-8 Go | 16+ Go | Mise en cache et buffering |
| Uptime | <95% | 99%+ | Stabilité des connexions |
| Routage | Standard | Optimisé BGP | Latence et pertes de paquets |
Les fournisseurs avec leur propre infrastructure (pas des revendeurs) assurent généralement une vitesse élevée et stable. Ils contrôlent toute la pile : du matériel aux paramètres de l'équipement réseau.
Signes d'une infrastructure de qualité :
- Vitesse stable tout au long de la journée (écarts de pas plus de 15-20% par rapport à la moyenne)
- Faible jitter (variation de latence) — moins de 10 ms
- Pertes de paquets minimales (<0.1%)
- Réaction rapide du support technique aux problèmes (important pour les tâches commerciales)
- Informations transparentes sur l'emplacement des serveurs et les caractéristiques des canaux
Pour des tâches critiques, il est recommandé de tester les proxies dans des conditions aussi proches que possible des conditions réelles. Achetez un accès de test pendant 1-3 jours et exécutez des scripts réels en surveillant toutes les métriques.
Méthodologie de test de la vitesse du proxy
Un bon test aide à identifier les goulets d'étranglement et à comparer objectivement différents fournisseurs. Un simple speedtest est insuffisant — il faut mesurer les paramètres importants pour vos tâches.
Métriques clés à mesurer :
- Latence — temps de passage d'un paquet aller-retour. Critique pour les tâches avec de nombreuses petites requêtes.
- Débit — volume de données par unité de temps. Important pour le téléchargement de fichiers, d'images.
- Temps de connexion — temps d'établissement de la connexion. Montre l'efficacité pour les requêtes uniques.
- Taux de réussite — pourcentage de requêtes réussies. En dessous de 95% — mauvais indicateur.
- Jitter — variation de latence. Un jitter élevé (>50 ms) indique une instabilité du canal.
Script complet pour le test :
import time
import requests
import statistics
from concurrent.futures import ThreadPoolExecutor, as_completed
def test_proxy_performance(proxy, test_url='https://httpbin.org/get', requests_count=50):
"""
Test complet du proxy
Args:
proxy: URL du proxy
test_url: URL pour le test
requests_count: Nombre de requêtes de test
Returns:
dict avec les métriques
"""
results = {
'latencies': [],
'connection_times': [],
'total_times': [],
'successes': 0,
'failures': 0,
'errors': []
}
session = requests.Session()
session.proxies = {'http': proxy, 'https': proxy}
def single_request():
try:
start = time.time()
response = session.get(
test_url,
timeout=(5, 15),
headers={'Connection': 'keep-alive'}
)
total_time = time.time() - start
if response.status_code == 200:
results['successes'] += 1
results['total_times'].append(total_time)
# Estimation approximative de la latence
results['latencies'].append(total_time / 2)
else:
results['failures'] += 1
except Exception as e:
results['failures'] += 1
results['errors'].append(str(e))
# Exécution parallèle des requêtes
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(single_request) for _ in range(requests_count)]
for future in as_completed(futures):
future.result()
# Calcul des statistiques
if results['total_times']:
metrics = {
'proxy': proxy,
'total_requests': requests_count,
'success_rate': (results['successes'] / requests_count) * 100,
'avg_response_time': statistics.mean(results['total_times']),
'median_response_time': statistics.median(results['total_times']),
'min_response_time': min(results['total_times']),
'max_response_time': max(results['total_times']),
'stdev_response_time': statistics.stdev(results['total_times']) if len(results['total_times']) > 1 else 0,
'jitter': statistics.stdev(results['latencies']) if len(results['latencies']) > 1 else 0,
'failures': results['failures']
}
return metrics
else:
return {'proxy': proxy, 'error': 'Toutes les requêtes ont échoué'}
# Test
proxy = 'http://user:pass@proxy.example.com:8080'
metrics = test_proxy_performance(proxy, requests_count=100)
print(f"Proxy : {metrics['proxy']}")
print(f"Taux de réussite : {metrics['success_rate']:.1f}%")
print(f"Temps de réponse moyen : {metrics['avg_response_time']*1000:.0f} ms")
print(f"Médiane : {metrics['median_response_time']*1000:.0f} ms")
print(f"Jitter : {metrics['jitter']*1000:.0f} ms")
print(f"Écart-type : {metrics['stdev_response_time']*1000:.0f} ms")
Pour des résultats plus précis, testez à différents moments de la journée (matin, après-midi, soir) et sur différents sites cibles. La vitesse peut varier considérablement en fonction de la géographie et de la charge du réseau.
Conseil : Créez une ligne de base (baseline) — testez une connexion directe sans proxy. Cela donnera un point de référence pour évaluer les frais généraux du proxy. Les frais généraux normaux : 50-150 ms pour des proxies de qualité.
Optimisation globale : liste de contrôle
L'application de toutes les méthodes décrites dans leur ensemble donne un effet cumulatif. Voici un plan étape par étape pour optimiser la vitesse de fonctionnement via un proxy :
Étape 1 : Choix et configuration du proxy
- Choisissez un proxy géographiquement proche des ressources cibles
- Pour le web scraping, utilisez le protocole HTTP au lieu de SOCKS5
- Préférez les proxies privés pour les tâches à forte charge
- Assurez-vous que le fournisseur prend en charge TLS 1.3
Étape 2 : Optimisation du code
- Utilisez
requests.Session()avec Keep-Alive - Configurez le pool de connexions (10-20 connexions)
- Définissez des délais d'attente optimaux : 5-10 sec pour la connexion, 15-30 pour la lecture
- Implémentez une logique de répétition avec un backoff exponentiel
- Mettez en cache la résolution DNS
Étape 3 : Gestion du pool de proxies
- Créez un pool de 10-50 proxies pour la rotation
- Limitez le nombre de requêtes simultanées via un seul proxy (5-10 flux)
- Surveillez la vitesse et excluez automatiquement les proxies lents
- Utilisez des sessions persistantes pour les tâches nécessitant la conservation de l'IP
Étape 4 : Optimisation système
- Configurez des serveurs DNS rapides (1.1.1.1, 8.8.8.8)
- Augmentez les limites de fichiers ouverts dans l'OS (ulimit -n 65535)
- Pour Linux : optimisez les paramètres TCP du noyau
- Utilisez des SSD pour la mise en cache si vous travaillez avec de grands volumes de données
Étape 5 : Surveillance et test
- Testez régulièrement la vitesse du proxy (au moins une fois par semaine)
- Enregistrez les métriques : temps de réponse, taux de réussite, erreurs
- Comparez la performance des différents fournisseurs
- Configurez des alertes lorsque la vitesse tombe en dessous d'un seuil
Exemple de configuration optimisée pour la production :
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from collections import deque
import time
class OptimizedProxyPool:
def __init__(self, proxies_list):
self.proxies = deque(proxies_list)
self.session = self._create_optimized_session()
self.stats = {p: {'requests': 0, 'avg_time': 0} for p in proxies_list}
def _create_optimized_session(self):
"""Créer une session optimisée"""
session = requests.Session()
# Stratégie de répétition
retry = Retry(
total=3,
backoff_factor=0.3,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST", "PUT"]
)
# Adaptateur avec pool de connexions
adapter = HTTPAdapter(
max_retries=retry,
pool_connections=20,
pool_maxsize=50,
pool_block=False
)
session.mount("http://", adapter)
session.mount("https://", adapter)
# En-têtes Keep-Alive
session.headers.update({
'Connection': 'keep-alive',
'Keep-Alive': 'timeout=60, max=100'
})
return session
def get_best_proxy(self):
"""Obtenir le proxy avec la meilleure performance"""
# Tri par vitesse moyenne
sorted_proxies = sorted(
self.stats.items(),
key=lambda x: x[1]['avg_time'] if x[1]['requests'] > 0 else float('inf')
)
return sorted_proxies[0][0] if sorted_proxies else self.proxies[0]
def request(self, url, method='GET', **kwargs):
"""Effectuer une requête via le proxy optimal"""
proxy = self.get_best_proxy()
self.session.proxies = {'http': proxy, 'https': proxy}
start = time.time()
try:
response = self.session.request(
method,
url,
timeout=(5, 15), # connexion, lecture
**kwargs
)
# Mettre à jour les statistiques
elapsed = time.time() - start
stats = self.stats[proxy]
stats['avg_time'] = (
(stats['avg_time'] * stats['requests'] + elapsed) /
(stats['requests'] + 1)
)
stats['requests'] += 1
return response
except Exception as e:
# En cas d'erreur, déplacer le proxy à la fin de la file d'attente
self.proxies.remove(proxy)
self.proxies.append(proxy)
raise e
# Utilisation
proxies = [
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080'
]
pool = OptimizedProxyPool(proxies)
# Exécution des requêtes
for url in ['https://example.com', 'https://example.org']:
try:
response = pool.request(url)
print(f"Réussi : {url}, statut : {response.status_code}")
except Exception as e:
print(f"Erreur : {url}, {e}")
L'application de cette liste de contrôle permet d'augmenter la vitesse de fonctionnement via un proxy de 2 à 3 fois par rapport aux paramètres de base. Dans des projets de scraping réels, cela réduit le temps d'exécution des tâches de plusieurs heures à quelques minutes.
Conclusion
Le fonctionnement lent des proxies est un problème résoluble si l'on comprend les raisons techniques et applique les bonnes méthodes d'optimisation. Les principaux facteurs de vitesse sont : la proximité géographique, le choix du protocole, la qualité de l'infrastructure du fournisseur et la bonne configuration du code client.
Une approche globale de l'optimisation inclut l'analyse des performances, la configuration des proxies, l'optimisation du code et la surveillance continue pour assurer une vitesse élevée et stable.