[운영#4] 성능 튜닝 & 확장 (멀티스레드·비동기·큐 기반 처리)

한줄 요약:
자동화 규모가 커지면 “하루 5개 URL”이 “하루 500개 URL”이 된다.
👉 이때 필요한 건 멀티스레드/비동기/작업 큐/캐싱/병렬 LLM 호출 최적화다.


🎯 목표

  • 멀티스레드/비동기로 크롤링/HTML 처리 속도 3~20배 향상
  • 작업 큐(Queue) 도입으로 안정성 & 처리량 상승
  • 캐싱으로 같은 요청 중복 처리 방지
  • LLM 호출 정렬(batch)·요약단위 조정으로 비용·속도 최적화

1. 병목(Bottleneck) 분석부터 시작

자동화 파이프라인은 보통 이렇게 생긴다:

(1) URL 요청 → (2) HTML 파싱 → (3) 요약 → (4) LLM 종합리포트 → (5) 포스팅

이중 가장 느린 부분은:

단계병목(원인)
(1) HTTP 요청네트워크 지연, 요청 수 많아지면 느림
(3) Sumy/YakeCPU 단일 스레드
(4) LLM 호출레이트 리미트, 응답시간

➡️ 그래서 병렬화·비동기 처리가 1·2·3단계에서 가장 큰 효과를 낸다.


2. 멀티스레드 크롤링(10~30배 빨라짐)

Python GIL 때문에 CPU에는 불리하지만 “I/O 작업(웹 요청)”에서는 거의 100% 효율

# fast_crawler.py
import concurrent.futures
import requests

def fetch(url):
    try:
        r = requests.get(url, timeout=5)
        return url, r.text
    except Exception as e:
        return url, None

def fast_fetch(urls, max_workers=20):
    results = {}
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as ex:
        for url, html in ex.map(fetch, urls):
            results[url] = html
    return results

20개씩 병렬 요청 → 20배 빨라짐


3. Async/Await 기반 대규모 크롤링(수백 단위 최적)

aiohttp + asyncio 기반 → 가장 빠른 방식

# async_crawler.py
import aiohttp, asyncio

async def fetch(session, url):
    try:
        async with session.get(url, timeout=8) as resp:
            return url, await resp.text()
    except:
        return url, None

async def run(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, u) for u in urls]
        return await asyncio.gather(*tasks)

def fetch_async(urls):
    return asyncio.run(run(urls))

🚀 200개 URL도 5~8초 내 처리 가능.


4. CPU 작업(문서 요약/키워드) — 멀티프로세스

요약(Sumy) / 키워드(Yake)는 CPU 중심
➡️ 멀티스레드는 소용 없음, 반드시 멀티프로세스 필요

from multiprocessing import Pool

def summarize_block(text):
    # sumy 요약 코드
    return my_summary(text)

def multi_summarize(text_list):
    with Pool(processes=6) as p:
        return p.map(summarize_block, text_list)

CPU 코어 수만큼 병렬 요약 가능.


5. LLM 최적화 — “배치로 던져라”

대규모 데이터면 한 URL마다 LLM 호출하면 비용↑·속도↓
➡️ 여러 URL을 하나의 LLM 요청으로 묶는 방식 추천

# llm_batch_prompt.py
chunks = [
    "\n".join(report_list[i:i+5])      # 5개 문서씩
    for i in range(0, len(report_list), 5)
]

full_reports = []
for ch in chunks:
    resp = client.responses.create(
        model="o4-mini",
        input=f"다음 소스 5개를 요약해줘:\n{ch}"
    )
    full_reports.append(resp.output_text)

효과:

  • 호출 횟수 5배 감소
  • 비용 절감
  • 속도 상승

6. 큐 기반 처리(중규모~대규모 시스템 핵심)

자동화가 커지면 워크플로우는 “텍스트 파일들”이 아니라 “작업들(job)”이 된다.

추천 아키텍처

Producer(수집) → Queue(Redis/RabbitMQ) → Workers(요약/LLM) → Storage(DB) → Poster

파이썬 간단 버전:

from queue import Queue
from threading import Thread

q = Queue()

def producer(urls):
    for u in urls:
        q.put(u)

def worker():
    while True:
        url = q.get()
        html = fetch(url)
        summary = summarize(html)
        save(summary)
        q.task_done()

# 실행
for _ in range(10):  # 워커 10개
    Thread(target=worker, daemon=True).start()

producer(my_urls)
q.join()  # 모든 작업 완료

효과:

  • 워커 수 조절 → 처리량(Throughput) 조절 가능
  • 중간 장애에도 큐에 남아 “재처리 가능”
  • 대규모 시스템에서 업계 표준 패턴

7. 캐싱(중복 요청 방지)

동일 페이지 반복 크롤링 방지
➡️ 운영 시 비용·시간 절감

import hashlib, os

def get_cache_key(url):
    return hashlib.md5(url.encode()).hexdigest()

def fetch_with_cache(url):
    key = get_cache_key(url)
    path = f"cache/{key}.html"
    
    if os.path.exists(path):
        return open(path, "r", encoding="utf-8").read()

    html = requests.get(url).text
    os.makedirs("cache", exist_ok=True)
    open(path, "w", encoding="utf-8").write(html)
    return html

8. 전체 성능 튜닝 조합 예시

단계최적화 방식
URL 크롤링ThreadPool(20~50) 또는 aiohttp
본문 추출멀티프로세스 Pool
요약멀티프로세스(코어 수 만큼)
LLM 종합보고Batch 처리
포스팅단일(오류 시 재시도)
전체 워크플로큐 기반 + 장애복구

9. 실제 “최대 성능형” 워크플로 구조

[async crawler(200req/초)]
    → [멀티프로세스 요약 클러스터]
    → [LLM Batch Summarizer]
    → [큐 기반 Poster]
    → [WP REST API]

이 구성은

  • 500~2000페이지 규모도
  • 30~120초 내 처리 가능.

10. 체크리스트

  • 크롤링: ThreadPool or aiohttp 비동기화
  • 요약/키워드: 멀티프로세스
  • LLM: Batch 호출
  • 캐싱 적용
  • 큐 기반 구조 도입
  • throughput(처리량) 모니터링
  • 병목 포인트 계속 측정

🎯 요약 한 줄

병목은 “네트워크·CPU·LLM”.
스레드 + 비동기 + 프로세스 + 배치 + 큐
이 5가지를 조합하면 자동화 시스템은 상업 서비스급 성능을 낼 수 있다 🚀


이전 강좌 👈 [운영#3] 장애 복구 자동화 (리트라이·백오프·대체 경로·휴면 후 재시도)
다음 강좌 👉 [운영#5] 비용 최적화 & 모델 선택 전략(o4-mini, gpt-4.1, embeddings, 캐시 전략)

댓글 남기기

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.