내 손에 직접 흙을 묻혀야 한다.
·
회고
'악마는 디테일에 있다(The devil is in the detail)'는 격언이 있습니다. 어떤 일이 겉보기에는 쉽고 좋아 보이지만, 세부 사항에 예상치 못한 문제나 함정이 숨어 있다는 뜻입니다. 저는 이 격언을 긍정적으로 해석해서 이렇게 말하고 싶습니다. '뛰어난 성과는 디테일까지 꼼꼼하게 챙길 때 나온다.'그리고 이렇게 디테일을 챙기는 과정을 저는 '손에 흙을 묻힌다'고 표현합니다. 개발자로서 직접 코드를 만지는 일이 많았을 때는 손에 흙을 묻히는 일을 참 많이 했습니다. 문제를 해결하기 위해 프레임워크의 코드를 파헤치거나 오픈소스 코드를 뜯어보는 등의 일을 했죠. 일하는 분야에서 깊어지는 기분을 느낄 수 있어서 좋았고, 제 손에 직접 흙을 묻혔기 때문에 성능과 안정성이 뛰어난 제품을 만들 수 있..
데이터베이스 Lock, MGL(Multiple Granularity Locking)
·
탐구 생활/데이터베이스
데이터베이스 Lock에 대한 기본과 더 나아가서 Lock을 효율적으로 획득, 해지하는 알고리즘인 Two-Phase Locking 에 대해서도 알아봤습니다. 이 글에서는 Lock 단위 세분화가 갖는 Trade-off 와 Trade-off 에서 장점을 극대화하기 위한 장치인 의도 락과 MGL에 대해서 알아보겠습니다. 이 글을 상당 부분은 Jim Gray의Granularity of Locks and Degrees of Consistency in a Shared Data Base에 기반합니다.락을 세분화하라(Lock Granularity)2PL은 "어떻게" 락을 획득하고 해제할 것인가에 대한 답을 주었습니다. 이제는 "어디에" Lock을 걸것이냐를 생각해야합니다.Lock 단위그런데 Lock을 어디에 것이냐라..
데이터베이스 Lock, 2PL(Two-Phase Locking)
·
탐구 생활/데이터베이스
이 글에서는 이전에 다뤘던 S-Lock, X-Lock 을 개별 트랜잭션이 "어떻게" 획득하고 해제하는게 좋을지 그 방법을 다루는 Two-Phase Locking을 소개합니다.트랜잭션의 충돌 이전 글에서 데이터베이스 Lock의 목적은 직렬성(Serializability)이라고 했습니다. 그런데 직렬성을 확보하기 위해 무분별하게 Lock을 걸면 트랜잭션들간에 충돌이 발생하기 마련입니다. 트랜잭션간 충돌이 일나는 시나리오는 제한적입니다. 락의 성격에 따라서 S-Lock끼리는 충돌이 일어나지 않구요, 오로지 S-Lock이 걸린 데이터에 대해서 X-Lock이 추가로 요구될때 혹은 X-Lock에 대해서 X-Lock이 추가로 요구될 때이죠. 조금 더 일반적으로 이야기하면 두 트랜잭션에 속한 두 개의 연산이 동일한 ..
데이터베이스 Lock, 기본개념
·
탐구 생활/데이터베이스
백엔드 개발을 하면서 RDBMS(MySQL, PostgreSQL)를 다루다 보면 DeadLock현상을 직접 마주하거나 혹은 코드리뷰 과정에서 DeadLock을 우려하는 리뷰를 받을 때가 있습니다. 그리고 DeadLock이라는 용어는 동시성을 다루는 소프트웨어를 개발자들에게 일상적인 용어입니다. 이 글을 쓰기로 마음먹은 날에 코드리뷰를 하면서 "이 테이블의 이 필드를 갱신하는게 DeadLock이 발생할지 한번 파악해보자"라는 이야기를 하고 있었습니다. 그러다 문득 깨달았습니다. 나는 RDBMS에서 DeadLock이 발생하는 매커니즘을 얼마나 이해하고 있을까? 그래서 RDBMS에서 Lock 에 대해 더 알아보았고, 데이터베이스 Lock에 대한 시리즈 글을 쓰기로 마음 먹었습니다.데이터베이스 Lock에 대한 ..
왜 Qwen 모델이 더 저렴할까? Tokenizer 에 대하여
·
탐구 생활/AI
회사에서 실험적으로 LLM을 이용한 기능을 PoC하고 상용화까지 이끈 경험이 있습니다. PoC 단계의 결과가 나쁘지 않다면, 다음 스텝은 명확합니다. 정확도 지표를 만들어 품질을 관리하는 동시에 일반 고객들도 부담 없이 접근할 수 있는 수준으로 서비스 운영 비용을 낮추는 것입니다.이 글은 그중에서도 백엔드와 인프라 관점에서 가장 중요한 '비용을 낮추는 작업'에 초점을 맞추고 있습니다.LLM API의 과금 기준: '토큰(Token)'이란 무엇인가?대규모 언어 모델은 우리가 입력하는 인간의 자연어를 텍스트 그대로 인식하지 않습니다. 컴퓨터가 이해할 수 있도록 텍스트를 고유한 정수 ID로 변환하여 처리하는데, 이때 모델이 정보를 처리하고 생성하는 가장 최소의 단위가 바로 '토큰(Token)'입니다.토큰을 만드..
JOIN을 지웠더니 편안해졌다, Application-Level Join 실전 도입기
·
탐구 생활/데이터베이스
이전 글에서는 RDBMS 조인이 '넓은 테이블(Wide Table)'과 '깊은 페이지네이션(Deep Pagination)'을 만났을 때 겪게 되는 수학적, 아키텍처적 한계와 디스크 스필(Disk Spill) 현상을 다루었습니다. 이 글에서는 디스크 스필이 실제 프로덕션 환경에서 어떻게 시스템 장애를 유발했는지, 그리고 이를 어플리케이션 레벨 조인(Application-Level Join)이라는 설계 패턴으로 어떻게 타파했는지 공유합니다.장애의 발단제가 맡은 서비스는 간혹 데이터베이스 CPU사용률이 80~90%까지 치솟는 문제가 발생하고 있었습니다. 이때마다 Read Instance가 수평확장되어서 결국 서비스가 안정화 되었지만, Read Instance가 확장되고 안정화되고 백엔드 어플리케이션과 연결될때..
MySQL vs PostgreSQL, 조인의 불확실성과 엔진별 한계
·
탐구 생활/데이터베이스
ORM이 보편화되면서 백엔드 개발자들은 select_related나 joinedload(JPA에서는 JOIN FETCH)를 통해 손쉽게 두 테이블을 INNER JOIN으로 엮어냅니다. 그리고 "옵티마이저가 알아서 쿼리를 최적화하여 필요한 데이터만 조인하겠지"라고 기대합니다. 하지만 데이터베이스가 감당해야 할 데이터가 수백만 건을 넘어가고, 넓은(Wide) 테이블에 깊은 페이지네이션(Deep Pagination)이 결합하는 순간 이 기대는 처참히 무너집니다. 이 글에서는 PostgreSQL과 MySQL(InnoDB)의 내부 아키텍처를 바탕으로, RDBMS 조인이 태생적으로 안고 있는 구조적 한계와 알고리즘의 맹점을 이론적으로 분석해 봅니다.관계 대수의 제약과 의미론적 장벽(Semantic Barrier)P..
Python GIL과 캐시 스래싱, 그리고 ARM64(Graviton)의 물리적 시너지
·
탐구 생활/Python
Python WSGI Django 환경에 Rust 를 받아들여서 하루 1.8억건의 요청을 견디는 백엔드 서버를 만든 글에서 자세히 보면 한가지 중요한 사항이 빠져있습니다. 바로 AWS 환경에서 ARM64(Graviton) CPU를 사용함으로써 Error Rate와 RPS가 모두 안정화 됐다는 점입니다.해당 글에서는 Rust를 이용함으로써 Accept Queue 에서 accept() 을 호출하는 과정에 안정화되어 Error Rate이 줄어든건 설명이 되지만 RPS가 개선된건 주로 CPU교체 때문이었습니다. 개인적으로 Python GIL 제약하에 CPU구조의 차이로 인해 X86_64(AMD64)와 Graviton(ARM64)에서 차이가 발생했다고 알고 있었지만 그 내용을 깊이 파보진 않았습니다. 이 글을 통..