Summary
boto3.client는 연결된 파이프가 아니라 자격 증명·리전 설정값을 담은 ‘가방’이다- 실제 연결은
get_object같은 메서드를 호출할 때 발생한다- 내부적으로 Connection Pool(물리적 TCP 소켓)을 유지하므로, Client 객체는 반드시 한 번만 생성해 재사용한다
Boto3 Client의 정체
# 이 코드를 실행하는 순간 AWS와 연결될까?
s3 = boto3.client('s3', aws_access_key_id=..., ...)정답은 연결되지 않는다이다. Boto3 Client는 DB 커넥션이 아니라 HTTP(Stateless) 기반으로 작동한다.
- Client는 ‘연결’이 아니라 ‘준비’다.
boto3.client객체는 자격 증명(Key)과 리전(Region) 설정값이 담긴 가방일 뿐이다. 전화기가 통화 중인 상태가 아니라 전화번호부와 신분증을 챙긴 상태에 가깝다. - 연결은 메서드를 호출할 때 발생한다.
s3.get_object()를 실행하는 그 순간에 비로소 HTTP 요청을 만들어 전송한다. - 끊김 방지는
Config가 담당한다. 메서드 호출 시 연결이 실패하면 “끊지 말고 다시 걸어”라고 지시하는 것이Config설정이다.
왜 Client를 재사용해야 하나
“어차피 메서드 호출 때마다 연결하면 Client를 매번 새로 만들어도 되지 않나?”라는 의문이 들 수 있다. 여기서 HTTP Keep-Alive가 등장한다.
논리적으로 HTTP 요청은 매번 연결하고 응답받으면 끝난다(Stateless). 하지만 물리적으로 Boto3 내부의 urllib3는 첫 요청이 끝나도 TCP 소켓을 바로 끊지 않고 잠시 붙들고 있는데, 이것이 Connection Pool이다.
| 구분 | Client 재사용(1회 생성) | Client 매번 재생성 |
|---|---|---|
| 작동 방식 | 뚫려있는 소켓 재사용 | 소켓을 끊고 새로 까는 작업 반복 |
| 비용 | 0 | TCP Handshake + SSL Negotiation |
| 속도 | 매우 빠름 | 네트워크 오버헤드로 느려짐 |
12만 장의 이미지를 처리한다면, Client 재사용만으로 12만 번의 Handshake 비용을 절약한다. Client는 한 번만 생성해 재사용한다.
재시도 전략을 심은 Client
대량 작업 중 네트워크가 잠깐 끊겨도 프로그램이 죽지 않게, botocore.config.Config로 재시도(Retry) 전략을 심는다.
import boto3
from botocore.config import Config
class S3StorageClient:
def __init__(self):
# 네트워크가 끊겨도 버티는 설정
self.s3_config = Config(
retries={
'max_attempts': 5, # 기본(3회)보다 높여 5번까지 재시도
'mode': 'standard' # 지수 백오프 적용
},
connect_timeout=60,
read_timeout=60
)
# 클라이언트 생성 (Connection Pool 준비)
self.client = boto3.client(
's3',
region_name=...,
aws_access_key_id=...,
aws_secret_access_key=...,
config=self.s3_config
)
def get_image(self, key):
# 실패 시 Config에 따라 자동으로 5번까지 재시도
return self.client.get_object(Bucket=..., Key=key)mode='standard'는 지수 백오프(Exponential Backoff)로, 재시도할 때 대기 시간을 점점 늘린다(1차 실패 → 1초, 2차 → 2초, 3차 → 4초). 서버가 일시적으로 바빠서 난 에러라면, 바로 다시 요청하는 것보다 잠깐 쉬는 것이 성공률을 크게 높인다.
Reference