console.time()을 사용해 실제 프로필 저장에 걸리는 시간을 측정
console.time('...');
console.timeEnd('...');
유저 프로필 업로드 form 제출 시 실행되는 코드
const onSubmit = async () => {
console.time('프로필 저장 전체 시간');
console.time('1.이미지 삭제 + 업로드');
// 기존 이미지 삭제 → 새 이미지 압축(webp) → 업로드 로직
...
console.timeEnd('1.이미지 삭제 + 업로드');
console.time('2.patchUser 요청');
await patchUser(...);
console.timeEnd('2.patchUser 요청');
console.time('3.캐시 무효화 + 리디렉션');
queryClient.invalidateQueries(...);
router.push(...);
console.timeEnd('3.캐시 무효화 + 리디렉션');
console.timeEnd('프로필 저장 전체 시간');
};
총 프로필 저장 시간: 3,858 ms
console.time('기존 이미지 삭제');
await supabase.storage.from('profiles').remove([...]);
console.timeEnd('기존 이미지 삭제'); //196.76ms
console.time('압축 시간');
await compressImageToWebp(...);
console.timeEnd('압축 시간'); //85.86ms
console.time('업로드 시간');
await supabase.storage.from('profiles').upload(...);
console.timeEnd('업로드 시간'); //1,280.17ms
await supabase.storage.from('profiles').upload(path, file, { upsert: true });
중간에서 수파베이스 서버가 파일을 한 번 더 받고 처리한 다음, 다시 전달하는 구조라서 네트워크 비용 + 서버 처리 시간이 추가
추가 고민
수파베이스 자체의 업로드 시간이 오래 걸리는 것으로 보인다.
혹시나 Region이 해외로 되어있는지 확인해봤으나 한국으로 되어있었다.
ㅤ
- Region이 해외로 되어있나? NO
- 한국으로 되어 있음
- 무료플랜 업로드 파일 제한을 초과했나? NO
- 무료플랜 최대 파일 크기 제한: 50MB
- 내 사이트에서 업로드 되는 파일 크기: 약 97KB
const { signedUrl } = await getSignedUploadUrl('profiles', filename);
await fetch(signedUrl, {
method: 'PUT',
headers: { 'Content-Type': file.type },
body: file,
});
즉, 수파베이스는 "여기 URL 있으니 이걸로 바로 업로드 해라" 라는 역할만 하고 실제 업로드는 브라우저 → S3로 직접 연결되어 진행된다.
중간 서버 없이 브라우저가 바로 S3에 PUT 요청하기 때문에 빠르고 효율적
| 항목 | 소요 시간 |
|---|---|
| 기존 이미지 삭제 | 261 ms |
| 이미지 압축 | 111 ms |
| 서명 URL 생성 | 558 ms |
| fetch 업로드 | 271 ms |
| 이미지 삭제 + 업로드 합계 | 1,208 ms |
| patchUser 요청 | 1,111 ms |
| 캐시 무효화 + 리디렉션 | 1.92 ms |
| 총 프로필 저장 시간 | 2,321 ms |
Supabase SDK의 이미지 업로드 흐름은 다음과 같다고 했었다.
1. 파일 인코딩(Base64 → Blob)
2. 인증/권한 확인
3. 경로 설정
4. 파일 전송
여기서 3번과 4번을 사용자가 하게 된다고 생각하면 쉽다.
| 처리 단계 | Supabase SDK 방식 | PreSigned URL 방식 |
|---|---|---|
| 1. 파일 인코딩 | 수파베이스 내부 처리 (숨겨짐) | 사용자가 파일을 준비해야 함 (Blob, File, 압축 등) |
| 2. 인증/권한 확인 | Supabase SDK가 자동 수행 | 수파베이스가 URL 발급 시 1회 수행 (서명 포함) |
| 3. 경로 설정 (버킷/파일명) | 수파베이스가 설정함 (from().upload(...)에서 처리) | 사용자가 직접 설정해서 수파베이스에 전달 (getSignedUploadUrl(bucket, path)) |
| 4. 파일 전송 | 수파베이스 서버가 대신 S3에 업로드 | 사용자가 직접 fetch(signedUrl, { PUT })로 업로드 |
지하철에 비유해보자.
| 방식 | 비유 | 경로 | 속도 차이 이유 |
|---|---|---|---|
| Supabase SDK 방식 | 지하철 + 환승 | 브라우저 → 수파베이스 → S3 | 수파베이스가 중간에 파일을 수신하고, 인증도 매번 확인해야 해서 느림 |
| PreSigned URL 방식 | 직통 열차 | 브라우저 → S3 | 중간 경유 없음. 인증은 미리 해결됐고, 바로 전송하니 빠름 |
보안 문제는 signedUrl이 해결해준다.