init auth and main function
This commit is contained in:
+409
@@ -0,0 +1,409 @@
|
||||
"""
|
||||
Точный тест потребления памяти с отслеживанием ВСЕХ процессов.
|
||||
Измеряет память Python + браузерных процессов отдельно.
|
||||
Запуск: python -u test_memory_processes.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
import gc
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
def print_flush(*args, **kwargs):
|
||||
print(*args, **kwargs, flush=True)
|
||||
|
||||
import psutil
|
||||
from config.settings import settings
|
||||
from managers.proxy_manager import ProxyManager
|
||||
from services.browser_service import BrowserService
|
||||
|
||||
print_flush("=" * 70)
|
||||
print_flush("🧠 ТОЧНЫЙ ТЕСТ ПАМЯТИ (ВСЕ ПРОЦЕССЫ)")
|
||||
print_flush("=" * 70)
|
||||
print_flush(f"Время: {datetime.now().strftime('%H:%M:%S')}")
|
||||
print_flush()
|
||||
|
||||
|
||||
def get_process_tree_memory() -> dict:
|
||||
"""
|
||||
Получает память текущего процесса и всех его дочерних процессов.
|
||||
Возвращает детальную информацию.
|
||||
"""
|
||||
current = psutil.Process()
|
||||
total_rss = current.memory_info().rss
|
||||
|
||||
children = []
|
||||
try:
|
||||
for child in current.children(recursive=True):
|
||||
try:
|
||||
child_rss = child.memory_info().rss
|
||||
children.append({
|
||||
"pid": child.pid,
|
||||
"name": child.name()[:50],
|
||||
"rss_mb": child_rss / (1024 * 1024),
|
||||
"status": child.status()
|
||||
})
|
||||
total_rss += child_rss
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
return {
|
||||
"python_rss_mb": current.memory_info().rss / (1024 * 1024),
|
||||
"children_count": len(children),
|
||||
"children_rss_mb": sum(c["rss_mb"] for c in children),
|
||||
"total_rss_mb": total_rss / (1024 * 1024),
|
||||
"children": children
|
||||
}
|
||||
|
||||
|
||||
def get_browser_processes() -> list:
|
||||
"""
|
||||
Ищет все браузерные процессы (chromium, chrome, firefox).
|
||||
"""
|
||||
browser_names = ["chromium", "chrome", "firefox", "camoufox", "playwright"]
|
||||
browsers = []
|
||||
|
||||
for proc in psutil.process_iter(['pid', 'name', 'memory_info']):
|
||||
try:
|
||||
name = proc.info['name'].lower() if proc.info['name'] else ""
|
||||
if any(bn in name for bn in browser_names):
|
||||
browsers.append({
|
||||
"pid": proc.info['pid'],
|
||||
"name": proc.info['name'],
|
||||
"rss_mb": proc.info['memory_info'].rss / (1024 * 1024)
|
||||
})
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
pass
|
||||
|
||||
return browsers
|
||||
|
||||
|
||||
def get_system_memory() -> dict:
|
||||
"""Получает общую информацию о системной памяти."""
|
||||
mem = psutil.virtual_memory()
|
||||
swap = psutil.swap_memory()
|
||||
|
||||
return {
|
||||
"total_gb": mem.total / (1024**3),
|
||||
"available_gb": mem.available / (1024**3),
|
||||
"used_percent": mem.percent,
|
||||
"used_gb": mem.used / (1024**3),
|
||||
"swap_total_gb": swap.total / (1024**3) if swap.total > 0 else 0,
|
||||
"swap_used_gb": swap.used / (1024**3) if swap.total > 0 else 0,
|
||||
}
|
||||
|
||||
|
||||
async def monitor_memory_during_operation(duration: int, interval: float = 0.5):
|
||||
"""
|
||||
Мониторит память во время операции.
|
||||
Возвращает макс, мин, среднее и временной ряд.
|
||||
"""
|
||||
samples = []
|
||||
start = time.time()
|
||||
|
||||
while time.time() - start < duration:
|
||||
mem_info = get_process_tree_memory()
|
||||
system_mem = get_system_memory()
|
||||
browser_procs = get_browser_processes()
|
||||
|
||||
samples.append({
|
||||
"timestamp": time.time() - start,
|
||||
"python_mb": mem_info["python_rss_mb"],
|
||||
"children_mb": mem_info["children_rss_mb"],
|
||||
"total_mb": mem_info["total_rss_mb"],
|
||||
"browser_processes": len(browser_procs),
|
||||
"browser_rss_mb": sum(b["rss_mb"] for b in browser_procs),
|
||||
"system_used_percent": system_mem["used_percent"],
|
||||
"children_count": mem_info["children_count"]
|
||||
})
|
||||
|
||||
await asyncio.sleep(interval)
|
||||
|
||||
return samples
|
||||
|
||||
|
||||
async def test_single_visit_memory():
|
||||
"""Тест памяти при одном посещении."""
|
||||
print_flush("\n" + "=" * 70)
|
||||
print_flush("🧪 ТЕСТ: ОДИНОЧНОЕ ПОСЕЩЕНИЕ (ПОЛНЫЙ ЦИКЛ)")
|
||||
print_flush("=" * 70)
|
||||
|
||||
# Информация о системе
|
||||
sys_mem = get_system_memory()
|
||||
print_flush(f"\n💻 Система:")
|
||||
print_flush(f" RAM всего: {sys_mem['total_gb']:.1f} GB")
|
||||
print_flush(f" RAM доступно: {sys_mem['available_gb']:.1f} GB")
|
||||
print_flush(f" RAM используется: {sys_mem['used_percent']:.1f}%")
|
||||
print_flush(f" Swap: {sys_mem['swap_total_gb']:.1f} GB")
|
||||
|
||||
# Память до
|
||||
mem_before = get_process_tree_memory()
|
||||
browsers_before = get_browser_processes()
|
||||
|
||||
print_flush(f"\n📊 До запуска:")
|
||||
print_flush(f" Python процесс: {mem_before['python_rss_mb']:.1f} MB")
|
||||
print_flush(f" Дочерние процессы: {mem_before['children_count']} шт, "
|
||||
f"{mem_before['children_rss_mb']:.1f} MB")
|
||||
print_flush(f" ВСЕГО: {mem_before['total_rss_mb']:.1f} MB")
|
||||
print_flush(f" Браузерных процессов в системе: {len(browsers_before)}")
|
||||
if browsers_before:
|
||||
for b in browsers_before:
|
||||
print_flush(f" - {b['name']} (PID {b['pid']}): {b['rss_mb']:.1f} MB")
|
||||
|
||||
# Запускаем мониторинг
|
||||
print_flush(f"\n🔄 Запуск браузера и посещение...")
|
||||
|
||||
monitor_task = asyncio.create_task(
|
||||
monitor_memory_during_operation(duration=60, interval=0.3)
|
||||
)
|
||||
|
||||
proxy_manager = ProxyManager()
|
||||
browser_service = BrowserService(proxy_manager)
|
||||
|
||||
url = "https://httpbin.org/headers"
|
||||
reading_time = 15
|
||||
|
||||
print_flush(f" URL: {url}")
|
||||
print_flush(f" Время чтения: {reading_time}с")
|
||||
|
||||
try:
|
||||
result = await browser_service.visit_page(url, reading_time)
|
||||
print_flush(f" Статус: {'✅' if result.success else '❌'}")
|
||||
except Exception as e:
|
||||
print_flush(f" ❌ Ошибка: {e}")
|
||||
|
||||
# Ждем завершения мониторинга
|
||||
await asyncio.sleep(3)
|
||||
monitor_task.cancel()
|
||||
try:
|
||||
samples = await monitor_task
|
||||
except asyncio.CancelledError:
|
||||
samples = []
|
||||
|
||||
# Память после
|
||||
await asyncio.sleep(2)
|
||||
gc.collect()
|
||||
await asyncio.sleep(1)
|
||||
|
||||
mem_after = get_process_tree_memory()
|
||||
browsers_after = get_browser_processes()
|
||||
|
||||
print_flush(f"\n📊 После посещения:")
|
||||
print_flush(f" Python процесс: {mem_after['python_rss_mb']:.1f} MB")
|
||||
print_flush(f" Дочерние процессы: {mem_after['children_count']} шт, "
|
||||
f"{mem_after['children_rss_mb']:.1f} MB")
|
||||
print_flush(f" ВСЕГО: {mem_after['total_rss_mb']:.1f} MB")
|
||||
print_flush(f" Браузерных процессов в системе: {len(browsers_after)}")
|
||||
|
||||
# Анализ семплов
|
||||
if samples:
|
||||
total_samples = [s["total_mb"] for s in samples]
|
||||
print_flush(f"\n📈 Во время посещения ({len(samples)} замеров):")
|
||||
print_flush(f" ПИК всего: {max(total_samples):.1f} MB")
|
||||
print_flush(f" Мин всего: {min(total_samples):.1f} MB")
|
||||
print_flush(f" Среднее всего: {sum(total_samples)/len(total_samples):.1f} MB")
|
||||
|
||||
browser_proc_count = [s["browser_processes"] for s in samples]
|
||||
if max(browser_proc_count) > 0:
|
||||
print_flush(f" Макс браузерных процессов: {max(browser_proc_count)}")
|
||||
|
||||
# Дельта
|
||||
delta_total = mem_after["total_rss_mb"] - mem_before["total_rss_mb"]
|
||||
peak_total = max(s["total_mb"] for s in samples) if samples else mem_after["total_rss_mb"]
|
||||
peak_delta = peak_total - mem_before["total_rss_mb"]
|
||||
|
||||
print_flush(f"\n📊 ИТОГО:")
|
||||
print_flush(f" Прирост TOTAL (до→после): {delta_total:+.1f} MB")
|
||||
print_flush(f" ПИКОВЫЙ прирост: {peak_delta:+.1f} MB")
|
||||
print_flush(f" Системная память: {get_system_memory()['used_percent']:.1f}%")
|
||||
|
||||
return {
|
||||
"mem_before": mem_before,
|
||||
"mem_after": mem_after,
|
||||
"samples": samples,
|
||||
"peak_delta": peak_delta,
|
||||
"delta_total": delta_total
|
||||
}
|
||||
|
||||
|
||||
async def test_multiple_sequential(count: int = 5):
|
||||
"""Тест последовательных посещений с отслеживанием пиков."""
|
||||
print_flush("\n" + "=" * 70)
|
||||
print_flush(f"🧪 ТЕСТ: {count} ПОСЛЕДОВАТЕЛЬНЫХ ПОСЕЩЕНИЙ")
|
||||
print_flush("=" * 70)
|
||||
|
||||
proxy_manager = ProxyManager()
|
||||
browser_service = BrowserService(proxy_manager)
|
||||
|
||||
results = []
|
||||
peak_memory = 0
|
||||
|
||||
for i in range(count):
|
||||
gc.collect()
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
mem_before = get_process_tree_memory()
|
||||
system_before = get_system_memory()
|
||||
|
||||
url = f"https://httpbin.org/headers?seq={i}"
|
||||
|
||||
# Мониторим во время визита
|
||||
monitor_task = asyncio.create_task(
|
||||
monitor_memory_during_operation(duration=30, interval=0.3)
|
||||
)
|
||||
|
||||
try:
|
||||
result = await browser_service.visit_page(url, reading_time=8)
|
||||
success = result.success
|
||||
except Exception as e:
|
||||
success = False
|
||||
print_flush(f" ❌ Ошибка: {e}")
|
||||
|
||||
await asyncio.sleep(1)
|
||||
monitor_task.cancel()
|
||||
try:
|
||||
samples = await monitor_task
|
||||
except asyncio.CancelledError:
|
||||
samples = []
|
||||
|
||||
mem_after = get_process_tree_memory()
|
||||
system_after = get_system_memory()
|
||||
|
||||
visit_peak = max(s["total_mb"] for s in samples) if samples else mem_after["total_rss_mb"]
|
||||
if visit_peak > peak_memory:
|
||||
peak_memory = visit_peak
|
||||
|
||||
delta = mem_after["total_rss_mb"] - mem_before["total_rss_mb"]
|
||||
sys_delta = system_after["used_percent"] - system_before["used_percent"]
|
||||
|
||||
results.append({
|
||||
"visit": i+1,
|
||||
"mem_before": mem_before["total_rss_mb"],
|
||||
"mem_after": mem_after["total_rss_mb"],
|
||||
"peak": visit_peak,
|
||||
"delta": delta,
|
||||
"system_delta": sys_delta,
|
||||
"success": success
|
||||
})
|
||||
|
||||
status = "✅" if success else "❌"
|
||||
print_flush(f" Визит {i+1}: {mem_before['total_rss_mb']:.1f} → "
|
||||
f"{mem_after['total_rss_mb']:.1f} MB (Δ={delta:+.1f} MB, "
|
||||
f"пик={visit_peak:.1f} MB) {status}")
|
||||
|
||||
await asyncio.sleep(random.randint(3, 7))
|
||||
|
||||
# Итоги
|
||||
print_flush(f"\n📊 Итого за {count} посещений:")
|
||||
print_flush(f" ПИКОВАЯ память за все время: {peak_memory:.1f} MB")
|
||||
|
||||
avg_peak = sum(r["peak"] for r in results) / len(results)
|
||||
print_flush(f" Средний пик: {avg_peak:.1f} MB")
|
||||
|
||||
return results, peak_memory
|
||||
|
||||
|
||||
async def main():
|
||||
"""Главная функция."""
|
||||
|
||||
# Тест 1: одиночное посещение
|
||||
single_result = await test_single_visit_memory()
|
||||
|
||||
# Тест 2: последовательные
|
||||
seq_results, seq_peak = await test_multiple_sequential(5)
|
||||
|
||||
# Тест 3: сборка мусора и финальный замер
|
||||
print_flush("\n" + "=" * 70)
|
||||
print_flush("🧹 ОЧИСТКА ПОСЛЕ ФИНАЛЬНОГО ТЕСТА")
|
||||
print_flush("=" * 70)
|
||||
|
||||
gc.collect()
|
||||
await asyncio.sleep(3)
|
||||
|
||||
mem_final = get_process_tree_memory()
|
||||
system_final = get_system_memory()
|
||||
|
||||
print_flush(f" Python: {mem_final['python_rss_mb']:.1f} MB")
|
||||
print_flush(f" Дочерние: {mem_final['children_count']} шт, {mem_final['children_rss_mb']:.1f} MB")
|
||||
print_flush(f" ВСЕГО: {mem_final['total_rss_mb']:.1f} MB")
|
||||
print_flush(f" Система: {system_final['used_percent']:.1f}%")
|
||||
|
||||
# ИТОГОВЫЕ ОЦЕНКИ
|
||||
print_flush("\n" + "=" * 70)
|
||||
print_flush("📊 ИТОГОВЫЕ ОЦЕНКИ ДЛЯ МАСШТАБИРОВАНИЯ")
|
||||
print_flush("=" * 70)
|
||||
|
||||
peak_per_visit = single_result["peak_delta"]
|
||||
print_flush(f"\n📈 На основе ПИКОВОГО потребления одного браузера:")
|
||||
print_flush(f" Пиковый прирост: {peak_per_visit:.1f} MB")
|
||||
|
||||
# Если пиковый прирост маленький, используем абсолютные значения
|
||||
if peak_per_visit < 50:
|
||||
# Браузер уже был в памяти, используем системную дельту
|
||||
estimate_per_browser = 200 # Консервативная оценка MB на браузер
|
||||
print_flush(f" ⚠️ Прирост маленький (браузер уже в памяти)")
|
||||
print_flush(f" Используем консервативную оценку: {estimate_per_browser} MB/браузер")
|
||||
else:
|
||||
estimate_per_browser = peak_per_visit
|
||||
|
||||
print_flush(f"\n📊 ОЦЕНКИ ДЛЯ РАЗНОГО КОЛИЧЕСТВА ЗАДАЧ:")
|
||||
print_flush(f" {'Задач':<10} {'RAM (MB)':<15} {'RAM (GB)':<15} {'+50% запас (GB)':<20}")
|
||||
print_flush(f" {'-'*60}")
|
||||
|
||||
for n in [5, 10, 20, 30, 40, 50]:
|
||||
ram_mb = estimate_per_browser * n
|
||||
ram_gb = ram_mb / 1024
|
||||
ram_safe = ram_mb * 1.5 / 1024
|
||||
print_flush(f" {n:<10} {ram_mb:<15.0f} {ram_gb:<15.2f} {ram_safe:<20.2f}")
|
||||
|
||||
# Системные ограничения
|
||||
sys_mem = get_system_memory()
|
||||
usable_ram = sys_mem["total_gb"] * 0.8 # 80% от всей RAM
|
||||
|
||||
print_flush(f"\n💻 ТЕКУЩАЯ СИСТЕМА:")
|
||||
print_flush(f" Всего RAM: {sys_mem['total_gb']:.1f} GB")
|
||||
print_flush(f" Можно использовать (80%): {usable_ram:.1f} GB")
|
||||
print_flush(f" Максимум задач на этой машине: {int(usable_ram * 1024 / estimate_per_browser)}")
|
||||
|
||||
print_flush(f"\n🎯 РЕКОМЕНДАЦИЯ:")
|
||||
ram_for_50 = estimate_per_browser * 50 * 1.5 / 1024
|
||||
|
||||
if ram_for_50 < 4:
|
||||
print_flush(f" Сервер: 8 GB RAM, 4 vCPU (бюджет)")
|
||||
elif ram_for_50 < 8:
|
||||
print_flush(f" Сервер: 16 GB RAM, 8 vCPU")
|
||||
elif ram_for_50 < 16:
|
||||
print_flush(f" Сервер: 32 GB RAM, 16 vCPU")
|
||||
else:
|
||||
print_flush(f" Сервер: 64 GB RAM, 32 vCPU")
|
||||
|
||||
print_flush(f" Диск: 100+ GB SSD")
|
||||
print_flush(f" Сеть: 100+ Mbps")
|
||||
|
||||
print_flush("\n" + "=" * 70)
|
||||
print_flush("✅ ВСЕ ТЕСТЫ ЗАВЕРШЕНЫ")
|
||||
print_flush("=" * 70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import random
|
||||
try:
|
||||
asyncio.run(main())
|
||||
except KeyboardInterrupt:
|
||||
print_flush("\n⚠️ Прервано")
|
||||
except Exception as e:
|
||||
print_flush(f"\n❌ Ошибка: {e}")
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
print_flush("\nНажмите Enter...", end="")
|
||||
try:
|
||||
input()
|
||||
except:
|
||||
time.sleep(3)
|
||||
Reference in New Issue
Block a user