구조화 로깅, 장애 때 찾을 수 있는 로그 남기기
·
IT
장애가 났을 때 로그를 열었는데 원인을 못 찾은 경험이 있다면, 로그를 남기는 방식을 바꿀 때가 된 것이다. 로그는 많이 남긴다고 좋은 것이 아니라 찾을 수 있어야 쓸모가 있다. 이 글은 구조화 로깅으로 바꾸는 방법과, 무엇을 남기고 무엇을 남기지 말아야 하는지를 정리한다.문자열 로그는 검색할 수 없다흔한 로그는 이렇게 생겼다.2026-09-11 13:02:11 INFO 주문 처리 완료 - 주문번호: 10023, 사용자: 42, 금액: 35000원사람이 읽기에는 괜찮다. 문제는 기계가 읽을 수 없다는 것이다. "금액이 10만 원 넘는 주문 중 실패한 것"을 찾으려면 정규식을 짜야 하고, 로그 형식이 조금만 달라도 깨진다.구조화 로깅은 같은 내용을 이렇게 남긴다.{"ts":"2026-09-11T13:02:..
캐시 전략, 무효화와 스탬피드 대응
·
IT
캐시를 붙이면 빨라진다. 그런데 캐시를 붙이고 나면 새로운 문제가 생긴다. 데이터가 갱신됐는데 옛날 값이 보이고, 캐시가 만료되는 순간 데이터베이스가 몰려드는 요청에 쓰러진다. 이 글은 캐시를 도입할 때 반드시 결정해야 하는 무효화 전략, 만료 설계, 동시 만료 대응 세 가지를 정리한다.읽기 캐시의 세 가지 패턴먼저 어디에 캐시를 두고 누가 채우는지를 정해야 한다.Cache-Aside(Lazy Loading)가 가장 흔하다. 애플리케이션이 캐시를 먼저 보고, 없으면 데이터베이스에서 읽어 캐시에 넣는다.def get_user(uid): v = cache.get(f"user:{uid}") if v is not None: return v v = db.query_user(uid) ..
N+1 쿼리 문제, 발견하고 고치는 법
·
IT
목록 화면을 여는데 쿼리 로그에 같은 모양의 SELECT가 수백 줄 찍힌다면 N+1 문제다. ORM을 쓰는 프로젝트에서 가장 흔하게 만나는 성능 문제이고, 원인을 알면 고치는 것은 대체로 한 줄이다. 이 글은 왜 생기는지, 어떻게 발견하는지, 어떻게 고치는지를 순서대로 다룬다.어떻게 생기는가주문 목록을 보여주면서 각 주문의 사용자 이름을 함께 출력한다고 하자.orders = Order.objects.all()[:100] # 쿼리 1번for o in orders: print(o.user.name) # 주문마다 1번씩, 총 100번첫 줄에서 주문 100건을 가져오는 쿼리가 한 번 나간다. 그다음 반복문에서 o.user에 접근할 때마다 사용자를 가져오는 쿼..
인덱스를 만들었는데 쿼리가 느린 이유
·
IT
데이터베이스에 인덱스를 만들어 뒀는데 쿼리가 여전히 느리다면, 인덱스가 있는 것과 인덱스를 타는 것이 다르기 때문이다. 이 글은 인덱스가 무시되는 흔한 패턴을 실제 쿼리와 함께 정리한다. PostgreSQL과 MySQL 기준으로 쓰지만 원리는 대부분의 관계형 데이터베이스에 공통이다.먼저 실행 계획을 보는 법추측하지 말고 확인해야 한다. 모든 판단은 실행 계획에서 시작한다.-- PostgreSQLEXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 42;-- MySQLEXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42;여기서 볼 것은 딱 하나다. Seq Scan(PostgreSQL)이나 type: ..
AI 코딩 에이전트 시대의 코드 리뷰
·
IT
AI 코딩 에이전트를 쓰기 시작하면 코드가 빠르게 쌓인다. 그런데 그 코드를 읽고 책임지는 사람은 여전히 사람이다. 리뷰해야 할 양은 늘었는데 리뷰하는 속도는 그대로다. 이 글은 에이전트가 코드를 쓰는 환경에서 코드 리뷰가 어떻게 달라져야 하는지를 다룬다. 결론부터 말하면 리뷰의 초점이 문법과 스타일에서 경계와 의도로 옮겨 가야 한다.역할이 연주자에서 지휘자로 바뀐다2026년 현장에서 관찰되는 변화는 뚜렷하다. 개발자가 에디터에 직접 코드를 치는 비중이 줄고, 여러 에이전트에게 일을 나눠 주고 결과를 조율하는 비중이 늘었다. 구현 세부사항, 반복적인 디버깅, 테스트 작성 같은 작업이 먼저 넘어갔다.사람에게 남는 것은 아키텍처 설계, 시스템 간 인터페이스 정의, 성능·보안·신뢰성에 관한 판단이다. 에이전트..
Git 브랜치 전략, rebase와 merge 중 무엇을 쓸까
·
IT
Git 브랜치 전략을 정하는 회의는 대개 rebase와 merge 중 무엇이 옳은지로 흘러간다. 그런데 이 논쟁에는 정답이 없고, 팀마다 다른 답이 맞는다. 이 글은 둘이 실제로 무엇을 다르게 하는지 짚고, 어떤 상황에서 어느 쪽을 골라야 하는지를 기준으로 정리한다. 그리고 이 논쟁보다 중요한 것이 무엇인지도 이야기한다.둘은 같은 문제를 다르게 푼다merge와 rebase는 한 브랜치의 변경을 다른 브랜치로 통합한다는 같은 목적을 가진다. 방법이 다르다.merge는 두 브랜치의 끝을 이어 붙이는 새 커밋(머지 커밋)을 만든다. 원래 커밋들은 그대로 남고, 히스토리에 갈라졌다 합쳐진 모양이 기록된다.rebase는 내 커밋들을 떼어내서 대상 브랜치의 최신 커밋 위에 하나씩 다시 얹는다. 결과적으로 히스토리가..
npm 공급망 공격 방어, 락파일부터 쿨다운까지
·
IT
npm install 한 번에 수백 개 패키지가 딸려 온다. 그중 하나가 탈취되면 그 코드는 내 빌드 서버에서 실행되고, 환경 변수와 토큰에 접근한다. 2026년에도 이런 사고가 반복해서 일어났다. 이 글은 실제로 벌어진 공격의 형태를 보고, 락파일·설치 명령·업데이트 정책 세 축으로 방어를 정리한다. 도구를 새로 사는 이야기가 아니라 지금 설정을 바꾸는 이야기다.2026년에 실제로 일어난 일들세 건만 봐도 공격의 성격이 드러난다.2026년 3월, 다운로드 수가 가장 많은 축에 드는 axios가 인증 정보 탈취를 통해 침해됐다. 5월 14일에는 주당 1,000만 회 넘게 내려받는 IPC 라이브러리 node-ipc의 악성 버전 세 개가 동시에 npm 레지스트리에 올라왔다. 8월 4일에는 keyv와 cach..
도커 이미지 크기 줄이기, 멀티스테이지와 distroless
·
IT
도커 이미지가 1GB를 넘어가면 배포할 때마다 기다리게 된다. 이미지를 올리고 내려받는 시간이 길어지고, 오토스케일링으로 새 노드가 뜰 때 서비스 투입이 늦어진다. 장애 상황에서 롤백이 느린 것도 같은 이유다. 이 글은 이미지 크기를 줄이는 방법을 효과가 큰 순서대로 정리한다. 멀티스테이지 빌드 하나로 대개 절반 이하가 되고, distroless까지 가면 수십 MB 단위가 된다.왜 이미지가 커지는가크기의 대부분은 세 곳에서 온다.베이스 이미지가 첫 번째다. node:20은 1GB 가까이 되지만 node:20-slim은 200MB 안팎, node:20-alpine은 더 작다. 차이는 안에 들어 있는 것이다. 전체 이미지에는 컴파일러, 빌드 도구, 각종 유틸리티가 다 들어 있다.빌드 도구와 중간 산출물이 두..
Node vs Deno vs Bun, 2026년 런타임 선택 기준
·
IT
자바스크립트 런타임을 고르는 일이 몇 년 전까지는 고민거리가 아니었다. Node.js 말고 선택지가 없었기 때문이다. 지금은 Node, Deno, Bun 셋이 각자 다른 이유로 쓰인다. 이 글은 2026년 기준으로 셋이 어디가 어떻게 다른지, 그리고 무엇을 기준으로 골라야 하는지를 정리한다. 결론부터 말하면 성능 숫자만 보고 고르면 대개 후회한다.메모리와 속도에서 차이가 난다먼저 자주 인용되는 수치를 보자. 유휴 상태의 프로세스 메모리다.부하가 걸리면 격차가 더 벌어진다. 웹소켓 5,000개 동시 연결 기준으로 Bun이 620MB, Node가 890MB라는 측정이 있다.패키지 설치 속도 차이는 더 극적이다. bun install이 npm install보다 10배에서 30배 빠르다는 수치가 돌고, 스크립트..
PostgreSQL 19 REPACK, 새벽 점검이 줄어든다
·
IT
PostgreSQL을 운영하면서 테이블이 비대해졌을 때 쓸 수 있는 수단은 두 가지였다. VACUUM FULL은 디스크를 회수하지만 테이블 전체에 배타 잠금을 건다. CLUSTER는 인덱스 순서로 재정렬하지만 역시 잠근다. 둘 다 운영 중에는 쓰기 어려워서, 결국 새벽 점검 시간에 몰아서 했다. 2026년 9~10월에 나올 PostgreSQL 19의 REPACK 명령이 이 상황을 바꾼다. 이 글은 19의 주요 변화와, 운영자 관점에서 무엇을 먼저 볼지를 정리한다.REPACK 이 무엇을 합치나REPACK은 기존 두 명령의 기능을 합친 것이다. 디스크 공간을 회수하면서 테이블 내용을 재구성한다. 그리고 CONCURRENTLY 옵션을 주면 읽기와 쓰기를 막지 않고 수행한다.이 기능이 반가운 이유는, 지금까지 ..
쿠버네티스 1.35, 파드 재시작 없이 자원 조정
·
IT
쿠버네티스에서 파드의 CPU나 메모리를 바꾸려면 파드를 다시 띄워야 했다. 요청량이 늘어 메모리를 올리고 싶으면 재시작을 감수해야 했고, 그래서 처음부터 넉넉하게 잡아두는 것이 관행이 됐다. 2025년 12월 17일에 나온 쿠버네티스 1.35에서 In-Place Pod Resize가 정식(stable)이 됐다. 파드를 죽이지 않고 자원을 조정할 수 있다는 뜻이다. 이 글은 그 변화가 실제로 무엇을 바꾸는지와, 함께 들어온 기능들을 정리한다.1.35에 무엇이 들어왔나이번 릴리스는 60개의 개선을 담았고, 성숙도별로 나뉜다.정식으로 승격된 17개 중 현장에 가장 크게 와닿는 것이 In-Place Pod Resize와 OCI Image Volume이다.릴리스 이름은 "Timbernetes"다. 쿠버네티스는 릴..
React 20이 없는 이유와 React Compiler
·
IT
리액트 버전을 확인하려고 들어가 보면 의외의 사실을 마주한다. 2026년 9월 현재 최신은 19.3이고, React 20은 발표된 적이 없다. 19.0이 나온 뒤로 메이저 버전이 올라가지 않고 있다. 이 글은 왜 그런지, 그리고 그 사이 리액트에서 실제로 바뀐 것이 무엇인지를 정리한다. 결론부터 말하면 변화의 무게 중심이 런타임에서 컴파일러로 옮겨 갔다.버전 기록이 말해주는 것공식 버전 페이지의 최근 기록은 이렇다.버전날짜19.3.02026-09-0919.2.72026-06-0119.2.62026-05-0619.2.52026-03-1819.2.42026-01-2619.2.02025-10-011년 가까이 19.x 안에서만 움직였다. 마이너와 패치가 꾸준히 나오지만 메이저는 없다.이걸 "정체"로 읽을 수도 ..