From 453ffa40ceb00eca50a0dff28fb4979df0022988 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Wed, 21 Oct 2026 06:15:02 +0900 Subject: [PATCH] =?UTF-8?q?chore(=EC=A1=B0=EC=82=AC):=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=20309=20=EB=B6=84=EC=84=9D=20A=20=E2=80=94=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EB=8A=90=EB=A6=BC(DB=20=EC=93=B0=EA=B8=B0?= =?UTF-8?q?=20=EB=8B=A4=EC=84=AF=20=C2=B7=20vite=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=C2=B7=20=EB=90=98=ED=8A=95=EA=B9=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../조사/2026-10-21_요구309_A_로그인느림.md | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 docs/raw/조사/2026-10-21_요구309_A_로그인느림.md diff --git a/docs/raw/조사/2026-10-21_요구309_A_로그인느림.md b/docs/raw/조사/2026-10-21_요구309_A_로그인느림.md new file mode 100644 index 000000000..519cbaa5b --- /dev/null +++ b/docs/raw/조사/2026-10-21_요구309_A_로그인느림.md @@ -0,0 +1,141 @@ +# 요구 309-1 서버 로그인 느림 — 원인 조사 (측정 · 코드 고침 없음) + +- 원문 = `docs/raw/요구_1021/사용자요구_1021.md` 요구 309-1. +- 기준 = `sub_laptop_8` `878376e29`(로그인 관련 파일 8 개 = `main_laptop_1` `d4da1f29d` 와 같은 내용) · 랩탑 · 서버 8010 · 5183 · 랩탑 메인 8000 은 로그인 요청만. +- 데스크탑(임시 배포) 접속 안 함 — 데스크탑 값은 추정. `.env` 는 데스크탑 브랜치와 같은 내용(차이 0 줄)만 확인. + +## 0. 결론 + +1. 로그인 요청 하나 = 서버 안 **약 1.0 s**(0.8~1.7 s) — 그중 **DB 쓰기 다섯 번 0.7~0.8 s**(한 번 60~240 ms · NAS MariaDB 가 쓰기마다 디스크 기록) · 비밀번호 확인(bcrypt 12) 0.2 s · 읽기 0.05 s. +2. 임시 배포가 **개발 서버(vite) 그대로** — 낱개 파일 · 압축 없음 · 열 때마다 재확인. 왕복 80 ms 가정 시 로그인 화면 2.0 s · 로그인→대시보드 4.3 s · 다시 열기 3.1 s(빌드본이면 1.0 · 3.1 · 2.0 s). +3. **되튕김 흠** — 로그인 화면이 뜬 뒤 약 4 s 안에 [로그인]을 누르면 성공해도 로그인 화면 그대로(0.5 · 2 s 누름 = 되튕김 · 4 · 6 · 8 s = 대시보드) → 다시 눌러야 함. +4. **간헐 큰 지연** — 같은 측정 5 번 중 4 번이 6~38 s 인 묶음 한 번. DB 행 잠금 대기 통계 4 일 631 번 · 평균 0.54 s · 최대 50 s(시간 초과) — 배포 서버가 개발 창 여럿과 같은 DB · 같은 NAS 를 씀. +5. 고칠 차례 = ③ 한 줄 → ① 로그인 쓰기 한 묶음 → ② 빌드본 배포(사용자 결정) · DB 설정 · 배포 DB 분리는 사용자 결정. + +## 1. 로그인 길 (코드) + +| 단계 | 하는 일 | 근거 | +|---|---|---| +| 화면 첫 열림 | `index.html` → `main.ts` → 셸 · 라우터 · A06 지연 로딩 · 셸이 세션 확인 한 번(빈 값 5 s 캐시) | `A00_Common/main.ts` · `A00_Common/app_shell.ts:284` · `A06_Login/A06_Login_Api_Fetch.ts:45` | +| 로그인 요청 | `POST /api/auth/login/request`(vite 프록시 → 백엔드) | `A06_Login/A06_Login_Api_Fetch.ts:32` · `vite.config.ts` proxy | +| 사용자 읽기 | `SELECT * FROM users` 1 왕복 | `common_util/common_util_auth_repository.py:21` | +| 비밀번호 | `bcrypt.checkpw` cost 12 · **동기 호출 = 서버 전체 멈춤** | `common_util/common_util_auth.py:30-31` · `A06_Login/A06_Login_Router.py:69` | +| 신뢰 브라우저 | 쿠키 있으면 SELECT + UPDATE | `A06_Login/A06_Login_Router.py:87` · `..._repository.py:228` | +| 메일 OTP | 개발 설정이라 건너뜀(로그 한 줄) · 외부 메일 · IP 조회 없음 | `A06_Login/A06_Login_Router.py:93` | +| 마무리 쓰기 | 실패 횟수 지움 → 신뢰 기기 갱신 → `last_login` → 세션 INSERT → `login_logs` INSERT — 각자 커넥션 · 각자 커밋 | `A06_Login/A06_Login_Router.py:111-129` · `common_util/common_util_auth.py:97` | +| 보안 장치 | 5 번 틀리면 15 분 잠금 · 호출량 감시(메모리 · 막지 않음) · 일부러 늦추는 장치 없음 | `..._repository.py:199` · `main.py:514` | +| 대시보드 | 셸 다시 그림 → 라우터 가드 세션 확인 → B01 지연 로딩 → API 13~15 개(관리자 계정) | `A00_Common/router.ts:187` · `B01_Dashboard/B01_Dashboard_UI_Page.ts:80` | + +## 2. 서버 측정 + +### 2-1 로그인 요청 시간 (httpx · 같은 계정 · 매번 로그아웃) + +| 길 | 횟수 | 최소 | 중앙 | 최대 | +|---|---|---|---|---| +| 8010 직접 | 30 | 0.79 s | 0.97~1.23 s | 1.70 s | +| 5183 vite 프록시 (2 · 3 회차) | 10 | 0.96 s | 1.10 s | 1.43 s | +| 5183 vite 프록시 (1 회차) | 5 | 1.83 s | 8.89 s | **38.10 s** | +| Tailscale 주소 → 5183 (자기 기기) | 5 | 1.05 s | 1.23 s | 1.81 s | +| 랩탑 메인 8000 직접 | 5 | 0.91 s | 1.05 s | 1.59 s | +| 비교 — 세션 확인(DB 읽기 1) | 45 | 10 ms | 14~25 ms | 44 ms | +| 비교 — 쿠키 없는 세션 확인(DB 없음) | 20 | 0.7 ms | 1~3 ms | 20 ms | + +- 1 회차 38 · 9.5 · 8.9 · 6.0 s = 같은 시각 세션 확인은 15~37 ms → 서버 멈춤 아님 · DB 쓰기 대기로 봄(원인 행 미확정). + +### 2-2 서버 안 단계 (서버와 같은 함수를 따로 불러 잼 · 5 번 × 2 회차 중앙) + +| 단계 | 시간 | 비고 | +|---|---|---| +| 사용자 SELECT | 10~12 ms | 1 왕복 | +| bcrypt 확인 (cost 12) | 200~209 ms | 이벤트 루프 막음 | +| 신뢰 브라우저 SELECT + UPDATE | 200~218 ms | 쿠키 있는 다시 로그인 때만 | +| 실패 횟수 지움 (바뀌는 값 없음) | 22 ms | 2 왕복 · 디스크 기록 없음 | +| 신뢰 기기 갱신 | 90~98 ms | | +| `last_login` UPDATE | 156~191 ms | | +| 세션 INSERT | 70~79 ms | | +| `login_logs` INSERT | 169~194 ms | | +| **합계** | **0.97~1.00 s** | 2-1 직접 값과 맞음 | +| DB 왕복 `SELECT 1` · 빈 COMMIT | 10.5 ms · 10~12 ms | | + +- 값이 바뀌는 쓰기 = 왕복(10 ms)의 7~20 배 · 값이 안 바뀌는 쓰기 = 왕복 2 번 → **커밋마다 디스크 기록이 느림**. +- DB = MariaDB 10.11 · Linux · 인터넷 너머 공인 주소 · `innodb_flush_log_at_trx_commit=1`(커밋마다 fsync) · `innodb_buffer_pool_size` 32 MB · doublewrite 켬 · 연결 36(35 쉼). +- 행 잠금 대기(가동 4.1 일) = 631 번 · 합 343 s · 평균 0.54 s · 최대 50 s(`innodb_lock_wait_timeout` 50 s 에 닿음). + +### 2-3 동시 로그인 (8010 · 쿠키 없는 세션 확인을 20 ms 마다 같이 보냄) + +| 동시 | 전체 | 한 사람 | 다른 요청 최대 멈춤 | +|---|---|---|---| +| 1 | 1.02 s | 1.02 s | 0.19 s | +| 5 | 2.30 s | 2.10~2.30 s | 0.95 s | + +- bcrypt 가 서버 한 줄(단일 워커 · 리로드 모드)을 막아 줄 섬. 다른 사용자의 무거운 동기 계산도 같은 식으로 로그인을 막음(데스크탑 미측정). + +## 3. 화면 측정 (Playwright 머리 없는 Chrome · 빈 캐시 · 관리자 계정 · [로그인]은 화면 뜬 뒤 6 s 에 누름) + +| 경우 | 로그인 화면 첫 열림 | 로그인 → 대시보드 그려짐 | 대시보드 다시 열기(캐시) | +|---|---|---|---| +| localhost 5183 (개발 서버) | 0.27 s · 43 요청 · 1,395 KB | 1.68 s · 93 요청 · 389 KB | 0.85 s · 90 요청 | +| Tailscale 주소 5183 (자기 기기) | 0.27 s · 43 · 1,393 KB | 1.89 s · 93 · 457 KB | 0.86 s · 90 | +| 개발 서버 + 왕복 30 ms · 20 Mbps | 1.44 s | 3.40 s | 1.89 s | +| 개발 서버 + 왕복 80 ms · 10 Mbps | 2.01 s | 4.29 s | 3.08 s · 86 | +| 빌드본(10-18 묶음 · vite preview) | 0.18 s · 17 · 181 KB | 1.83 s · 54 · 98 KB | 0.87 s · 44 | +| 빌드본 + 왕복 30 ms · 20 Mbps | 0.33 s | 2.30 s | 1.41 s | +| 빌드본 + 왕복 80 ms · 10 Mbps | 0.98 s | 3.05 s | 1.96 s | + +- 왕복 · 대역은 Chrome 흉내(CDP) — 데스크탑 실제 회선은 안 잼. +- 개발 서버 응답 = 압축 없음 · `Cache-Control: no-cache` → 다시 열어도 모듈 75 개를 하나씩 재확인. +- 로그인 화면이 끌어오는 것 = 언어 파일 9 개 461 KB(`ui_template_locale_b2` 192 KB · `_b1` 96 KB) · `/@vite/client` 205 KB · `b_page_state.ts` 84 KB · `B04_PreProcess_Api_Fetch.ts` 53 KB(`A06_Login_Api_Fetch.ts` → `b_page_state` · `b_project_switch` 사슬). + +가장 느린 요청 열 (localhost · 로그인 → 대시보드) + +| 요청 | ms | KB | +|---|---|---| +| `/api/auth/login/request` | 816 | 0.6 | +| `/api/dashboard/admin/resources` | 352 | 8.4 | +| `/api/dashboard/admin/projects` | 269 | 29.5 | +| `/api/dashboard/admin/audit-logs` | 134 | 1.6 | +| `/api/dashboard/admin/users` | 123 | 1.1 | +| `/api/dashboard/admin/join-requests` | 123 | 0.2 | +| `/api/temp-uploads` | 37 | 0.2 | +| `/api/dashboard/me` (두 번) | 31 · 28 | 0.5 | +| `/api/dashboard/company/assets/5/file` | 26 | 8.2 | + +- 왕복 80 ms 로그인 화면 첫 열림 열 = 모두 모듈 파일 279~494 ms(언어 파일 · `app_shell.ts` · `router.ts` · `/@vite/client` · `ui_template_loupe.ts` · `config_frontend.ts`). +- 관리자 아닌 계정 대시보드는 안 잼(관리자 API 다섯 대신 프로젝트 · 회사 API). + +### 3-1 되튕김 (빈 브라우저마다 · 화면 뜬 뒤 N s 에 [로그인]) + +| N | 0.5 s | 2 s | 4 s | 6 s | 8 s | +|---|---|---|---|---|---| +| 결과 | 로그인 화면 그대로 | 로그인 화면 그대로 | 대시보드 | 대시보드 | 대시보드 | + +- 까닭 = 셸이 화면 열 때 「로그인 안 됨」을 5 s 캐시(`A06_Login_Api_Fetch.ts:45` · `app_shell.ts:284`) · `requestLogin`(`:32`)은 캐시를 안 비움(`verifyLogin` `:37` · `logout` `:91` 만 비움) → 라우터 가드(`router.ts:187`)가 옛 「안 됨」을 읽고 로그인 화면으로 돌려보냄. 서버 로그인은 이미 성공 · 세션 한 줄이 헛으로 남음. +- 브라우저 자동 채움이면 2 s 안에 누르기 쉬움. + +## 4. 원인 순위 · 고칠 길 + +| 순위 | 원인 | 몫 (수치) | 고칠 길 (크기 · 위험) | +|---|---|---|---| +| 1 | 로그인 DB 쓰기 다섯 번 · 커밋마다 NAS 디스크 기록 | 요청 1.0 s 중 0.7~0.8 s | (가) 로그인 쓰기를 한 트랜잭션 · 한 커넥션으로 묶음 — 커밋 1 번 · 약 −0.5 s 추정 · 작음 · 위험 낮음 (나) `login_logs` · `last_login` 을 응답 뒤로 미룸 — 약 −0.35 s · 작음 · 꺼질 때 기록 한 줄 잃을 수 있음 (다) DB 설정 `innodb_flush_log_at_trx_commit=2` · buffer pool 키움 — 모든 저장 빨라짐 · 설정만 · 정전 때 마지막 1 s 잃을 수 있음(사용자 결정) | +| 2 | 임시 배포 = 개발 서버(낱개 · 무압축 · 매번 재확인) | 왕복 80 ms 에서 로그인 화면 +1.0 s · 로그인→대시보드 +1.2 s · 다시 열기 +1.1 s | (가) 임시 배포를 빌드본으로(백엔드 `/static` 이나 preview) — 중간 · 배포 절차 바뀜 · 빌드 깨지면 화면 안 뜸(사용자 결정) (나) 로그인 화면이 언어 파일 전부 · B04 fetch 를 끌어오는 사슬 끊기 — 중간 · 낮음 (다) 앞단 압축 켬 — 작음 · 낮음 | +| 3 | 되튕김 흠 — 로그인 성공 뒤 옛 세션 캐시 | 4 s 안 누름 = 한 번 더 눌러야 함(+1~5 s) | (가) `requestLogin` 성공 때 `clearSessionCache()` 한 줄 — 아주 작음 · 위험 거의 없음 (나) 「안 됨」은 캐시하지 않음 — 작음 | +| 4 | 간헐 DB 대기 — 배포 · 개발 서버가 한 DB · 한 계정 · 한 NAS | 1 회차 6~38 s · 잠금 대기 최대 50 s | (가) 배포용 DB(또는 스키마) 분리 — 큼(사용자 결정) (나) 잠금을 오래 쥔 트랜잭션 찾기 — 조사 필요 (다) 1-(가)로 쓰기 수를 줄여 맞닥뜨림 줄임 | +| 5 | bcrypt 12 동기 호출 — 서버 전체 0.2 s 멈춤 | 5 명 동시 = 한 사람 2.1~2.3 s · 다른 요청 0.95 s 멈춤 | (가) `asyncio.to_thread` 로 돌림 — 작음 · 낮음(본인 시간은 그대로) (나) cost 10(약 0.05 s) — 작음 · 보안 판단(사용자 결정) | + +## 5. 사용자 결정이 필요한 것 + +- 임시 배포를 개발 서버에서 빌드본으로 바꿀지 — 4-2(가). +- DB 서버 설정(`innodb_flush_log_at_trx_commit` · buffer pool) 손댈지 — NAS · 모든 창 공용이라 영향이 넓음 · 4-1(다). +- 배포용 DB 를 개발 DB 와 나눌지 — 4-4(가). +- bcrypt cost 를 낮출지 — 4-5(나). +- 데스크탑 실제 회선(사용자 → 데스크탑 · 데스크탑 → DB) 을 잴지 — 지금 값은 흉내 · 데스크탑 접속이 필요함. + +## 6. 곁가지 (로그인 직접 원인 아님) + +- 자동 리로드가 저장소 뿌리를 통째로 감시 — uvicorn 0.24 가 현재 폴더를 늘 더함(`venv/Lib/site-packages/uvicorn/supervisors/watchfilesreload.py:69-72`) → `main.py:699` 의 감시 폴더 좁히기가 안 먹음 · `tmp/` 의 `.py` 하나로 서버 재시작(서브 8 로그 재시작 1,105 번 · 예 `tmp\2982\pw_flow.py`). 재시작 도중 로그인은 끊김 · 데스크탑(코드 고침 없음)은 영향 작음. +- 측정 흔적 = `login_logs` +75 줄 · `trusted_devices` +31 줄(로그인 한 번과 같은 양) · 만든 세션은 모두 로그아웃으로 지움 · 서버 재시작 0 번(스크립트 확장자 `.py.txt`). +- 안 잰 것 = vite 다시 켠 직후 첫 변환 시간 · 관리자 아닌 계정 · 데스크탑 실제 값. + +## 7. 자료 + +- 스크립트 · 원자료 = `C:/Aislo_wt/sub_laptop_8/tmp/req309_login/` — `api_timing.py.txt`(2-1) · `server_steps.py.txt`(2-2) · `db_inspect*.py.txt`(DB 설정 · 통계 · 읽기만) · `concurrent.py.txt`(2-3) · `page_load.py.txt`(3) · `bounce.py.txt`(3-1) · 결과 `*.json`.