Writing
14개의 게시글
- AI 조교 부하 테스트를 다시 - prefix cache가 만든 속도, 그리고 부하 속에서 잰 품질
로컬이 아닌 실서비스 배포본에, 실제 힌트 페이로드 그대로. 모델을 Qwen3.6로 바꾼 뒤 다시 부하를 걸며 prefix cache가 TTFT의 대부분을 만든다는 걸 캐시 유무 비교로 확인하고, 형식 준수율까지 자동으로 쟀다.
- 로그인만 안 됐다 - DNS는 되는데 나가지 못한 컨테이너
구글 로그인만 "server configuration" 에러로 막혔다. 원인은 콜백 등록이 아니라 컨테이너가 밖으로 못 나가는 것이었고, DNS는 되는데 연결만 안 되는 상태였다. env - prisma - ufw - MTU - docker0 대 compose 브리지로 계층을 좁혀 NAT 유실을 찾고, 결국 clean 재부팅으로 엉킨 iptables 상태를 정리한 기록.
- 멀쩡한 코드를 고쳐서 깨뜨렸다 - 정규식 xlsx 파서의 self-closing 셀
대시보드에서 목표선이 전부 사라졌다. 범인은 며칠 전 내가 off-by-one 버그로 착각해 고친 커밋이었다. 정규식으로 xlsx를 파싱하던 리더가 self-closing 빈 셀을 여는 태그로 오인해 옆 칸 값을 흡수하고 있었고, 원래 코드는 그 동작에 맞아 있었다.
- 파워서플라이가 죽어 서버가 꺼졌다 - 복구 전에 데이터 손실 범위부터 따지기
실서비스 서버 PC의 파워가 죽어 사이트가 내려갔다. 급한 건 복구가 아니라 데이터였다. 라이브 볼륨·매일 백업·롤백용 클라우드 스냅샷의 최신도를 비교해, 파워만 교체하는 게 데이터 손실 0에 가장 덜 번거롭다는 결론에 이른 기록. 그리고 백업이 전부 같은 디스크에 있었다는 뒤늦은 깨달음.
- Vercel·Supabase에서 온프레미스로 - 학생 데이터를 교내 서버로 이전하기
실서비스 CMS를 클라우드(Vercel + Supabase)에서 교내 물리 서버로 옮겼다. DB 덤프의 @ 비밀번호 함정, 인증서가 안 나오던 진짜 이유(서버가 아니라 캠퍼스 방화벽), self-hosted Auth.js의 UntrustedHost, 엉뚱한 구글 프로젝트에 있던 OAuth 클라이언트까지 - 이전 과정에서 걸린 함정들의 기록.
- CI가 자기 레포에 커밋할 때의 레이스 컨디션 - concurrency 직렬화
PR을 연달아 머지하니 이미지 태그를 매니페스트에 자동 커밋하는 잡이 rebase 충돌로 줄줄이 실패했다. concurrency 직렬화와 merge 아닌 idempotent 재적용으로 해결한 기록.
- 운영 파드가 398번 재시작한 이유 - liveness probe와 이미지 릴리즈 스큐
멀쩡히 살아 있는데 재시작 398회. kubectl logs → describe → replicaset → git → exec로 계층을 좁혀, 헬스체크 경로를 그 경로가 없는 이미지에 먼저 배포한 릴리즈 스큐를 찾아낸 진단 기록.
- 마크다운 에디터와 미리보기를 양방향으로 잇기 - data-source-line과 postMessage
비전공자가 마크다운 문법을 몰라도 쓰게 하려면, 왼쪽에 쓴 글이 오른쪽에 바로 보이고 오른쪽을 보고도 고칠 수 있어야 했다. 위지윅을 양방향으로 만들며 부딪힌 벽과 해결 과정.
- git 커밋으로 만든 서버 없는 분산 편집 잠금(Soft Lock)
GitHub Contents API에는 파일 잠금이 없다. 백엔드도 DB도 없이 여러 명이 같은 브로슈어를 편집하다 서로 덮어쓰는 문제를, .locks 커밋과 heartbeat로 풀어낸 기록.
- WAL 폭주로 디스크가 찼다 - CNPG/Longhorn 클러스터 복구기
WAL이 디스크를 채워 PostgreSQL이 뜨지 않았다. 원인은 저용량 노드의 죽은 standby가 replication slot으로 WAL을 붙잡은 것. CNPG·Longhorn·노드 장치를 계층별로 나눠 replica 축소→dangling PVC→Pod 정리→multipathd 제거→물리 디스크 추가 순으로 복구한 기록.
- Ollama에서 vLLM으로 - AI 조교 서빙을 동접 30명까지 끌어올리기
codellama에서 Qwen3.6까지, Ollama에서 vLLM까지. Locust 부하 테스트로 매 단계를 실측하며 로컬 LLM AI 조교를 3초 안에 답하는 서비스로 만든 과정과, 그 사이 내린 모델 선택의 이유.
- 링크 하나가 곧 열쇠였다 - 7일 일기 요약을 안전하게 공유하기
부정 감정이 오래 이어진 사용자의 7일 일기를 상담사에게 넘겨야 했다. 상담사는 앱 계정이 없으니 링크만으로 열려야 했고, 그래서 링크가 곧 자격증명이 됐다. 토큰을 해시로만 저장하고 스냅샷으로 굳힌 이야기.
- 정원에 물고기가 가라앉았다 - 마음정원의 레이어 렌더링
흙 위에 꽃을 심고, 연못 안에 물고기를 넣는 정원. 평면 좌표만으로는 무엇이 무엇을 덮을지 정해지지 않았다. 각 아이템에 정수 레이어를 부여하고 정렬해 Stack으로 쌓은 이야기.
- GPT는 언젠가 실패한다 - 감정 분석에 폴백을 깐 이유
GPT-4o mini로 일기 감정을 분석하는 게 앱의 정중앙 기능이었다. 그런데 클라이언트가 안 뜨고, JSON을 달라 해도 JSON이 아닌 게 왔다. LLM 응답을 신뢰할 인프라로 취급하지 않기로 한 기록.