<feed xmlns="http://www.w3.org/2005/Atom"> <id>https://riverfrot.github.io/</id><title>RiverFront</title><subtitle>개발에 대한 생각하고 글을 작성합니다.</subtitle> <updated>2026-05-08T10:31:40+00:00</updated> <author> <name>riverfrot</name> <uri>https://riverfrot.github.io/</uri> </author><link rel="self" type="application/atom+xml" href="https://riverfrot.github.io/feed.xml"/><link rel="alternate" type="text/html" hreflang="en" href="https://riverfrot.github.io/"/> <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator> <rights> © 2026 riverfrot </rights> <icon>/assets/img/favicons/favicon.ico</icon> <logo>/assets/img/favicons/favicon-96x96.png</logo> <entry><title>[LLM Serving] TurboQuant란 무엇이며, 어떻게 KV Cache 양자화로 메모리를 5배 줄일 수 있을까?</title><link href="https://riverfrot.github.io/posts/Turbo-Quant-Research/" rel="alternate" type="text/html" title="[LLM Serving] TurboQuant란 무엇이며, 어떻게 KV Cache 양자화로 메모리를 5배 줄일 수 있을까?" /><published>2026-04-04T00:00:00+00:00</published> <updated>2026-05-08T10:30:44+00:00</updated> <id>https://riverfrot.github.io/posts/Turbo-Quant-Research/</id> <content type="text/html" src="https://riverfrot.github.io/posts/Turbo-Quant-Research/" /> <author> <name>riverfrot</name> </author> <category term="AI" /> <category term="LLM" /> <summary>들어가며 이전 글에서 우리는 vLLM 위에서 FP16 vs AWQ 벤치마크, Continuous Batching 성능, KV Cache 부족 시 Preemption까지 직접 확인했다. 그 과정에서 반복적으로 등장한 병목이 있었다. KV Cache 크기 = 2 × layers × kv_heads × head_dim × seq_len × dtype_bytes 예시: Qwen2.5-7B (GQA: 28 attention heads, 4 kv heads), seq_len=4096, FP16 = 2 × 28 × 4 × 128 × 4096 × 2bytes ≈ 224MB (요청 1건) GQA 덕분에 짧은 context에서는 KV Cache가 작지만, seq_len이 길어지면 선형 증가한다. 동시 50명 ×...</summary> </entry> <entry><title>[LLM Serving] LLM 토큰 스트리밍에 SSE를 선택한 이유: 프로토콜 비교부터 HTTP/3까지</title><link href="https://riverfrot.github.io/posts/why-using-llm-sse/" rel="alternate" type="text/html" title="[LLM Serving] LLM 토큰 스트리밍에 SSE를 선택한 이유: 프로토콜 비교부터 HTTP/3까지" /><published>2026-04-02T00:00:00+00:00</published> <updated>2026-04-04T07:19:37+00:00</updated> <id>https://riverfrot.github.io/posts/why-using-llm-sse/</id> <content type="text/html" src="https://riverfrot.github.io/posts/why-using-llm-sse/" /> <author> <name>riverfrot</name> </author> <category term="AI" /> <category term="LLM" /> <summary>들어가며 많은 사람들이 요새는 AI 도구를 많이 사용해 봐서 알겠지만 AI 채팅에 대한 요청은 한번에 모든 응답값을 받지 않는다. 마치 채팅 하는것 처럼 느껴지게 하나씩 응답이 오는데 이전 글에서 테스트 했던 내용도 마찬가지였다. curl http://localhost:8000/v1/chat/completions \ -H "Accept: text/event-stream" \ -d '{"model": "Qwen2.5-7B", "messages": [{"role": "user", "content": "장애 로그를 분석해줘"}], "stream": true}' LLM은 토큰을 하나씩 생성(Autoregressive)하기 때문에, 첫 토큰이 나오는 순간부터 클라이언트에게 스트리밍해야 자연스럽...</summary> </entry> <entry><title>[LLM Serving] vLLM 인퍼런스 서버 구축과 벤치마크: Continuous Batching은 얼마나 빠른가?</title><link href="https://riverfrot.github.io/posts/vllm-benchmark/" rel="alternate" type="text/html" title="[LLM Serving] vLLM 인퍼런스 서버 구축과 벤치마크: Continuous Batching은 얼마나 빠른가?" /><published>2026-03-21T00:00:00+00:00</published> <updated>2026-05-08T10:30:44+00:00</updated> <id>https://riverfrot.github.io/posts/vllm-benchmark/</id> <content type="text/html" src="https://riverfrot.github.io/posts/vllm-benchmark/" /> <author> <name>riverfrot</name> </author> <category term="AI" /> <category term="LLM" /> <summary>들어가며 curl http://localhost:8000/v1/chat/completions \ -d '{"model": "Qwen2.5-7B", "messages": [{"role": "user", "content": "한국의 수도는?"}]}' 위 요청 하나는 57ms 만에 첫 토큰을 반환한다. 그런데 동시에 50명이 같은 요청을 보내면 어떻게 될까? 일반적인 API 서버와 달리, LLM 인퍼런스 서버는 요청 하나당 수 GB의 GPU 메모리를 소모한다. 이 글에서는 vLLM을 직접 구축하고, Continuous Batching이 실제로 throughput을 얼마나 개선하는지, 양자화(Quantization)는 항상 좋은 선택인지를 실측 데이터로 확인한다. 특히 “FP16과 AWQ 중 뭐가...</summary> </entry> <entry><title>MySQL 아키텍처 및 상세 설명 2편 - 인덱스</title><link href="https://riverfrot.github.io/posts/rdbms-index/" rel="alternate" type="text/html" title="MySQL 아키텍처 및 상세 설명 2편 - 인덱스" /><published>2026-02-03T00:00:00+00:00</published> <updated>2026-02-03T00:00:00+00:00</updated> <id>https://riverfrot.github.io/posts/rdbms-index/</id> <content type="text/html" src="https://riverfrot.github.io/posts/rdbms-index/" /> <author> <name>riverfrot</name> </author> <category term="Database" /> <category term="MySQL" /> <summary>들어가며 SELECT * FROM wallet WHERE user_id = 1; 지난 편에서는 “쿼리 한 줄이 실행될 때 MySQL 내부에서 벌어지는 일”을 전체 아키텍처 관점에서 살펴봤다. 우리는 데이터가 디스크에서 메모리(Buffer Pool)로 올라오고, Executor가 그것을 퍼올리는 과정을 확인했다. 하지만 여전히 풀리지 않은 의문이 있다. “똑같은 SELECT 문인데, 왜 어떤 건 0.01초 만에 나오고, 어떤 건 10초나 걸릴까?” 이 질문에 답하려면 인덱스(Index)의 실체를 파헤쳐야 한다. 단순히 “책의 목차” 정도로만 알고 있었다면, 오늘은 그 내부인 B+Tree와, 어떤 방식으로 검색 비용을 최적화 하는지에 대해 옵티마이저를 살펴보자. 특히 “PK가 없어도 내부는 B+...</summary> </entry> <entry><title>MySQL 아키텍처 및 상세 설명 1편 - 아키텍처 및 데이터 플로우</title><link href="https://riverfrot.github.io/posts/rdbms-deep-dive-and-data-flow/" rel="alternate" type="text/html" title="MySQL 아키텍처 및 상세 설명 1편 - 아키텍처 및 데이터 플로우" /><published>2026-01-22T00:00:00+00:00</published> <updated>2026-01-26T22:35:03+00:00</updated> <id>https://riverfrot.github.io/posts/rdbms-deep-dive-and-data-flow/</id> <content type="text/html" src="https://riverfrot.github.io/posts/rdbms-deep-dive-and-data-flow/" /> <author> <name>riverfrot</name> </author> <category term="Database" /> <category term="MySQL" /> <summary>들어가며 SELECT * FROM wallet WHERE user_id = 1; 이 한 줄의 쿼리가 실행되고 결과가 돌아오기까지, 내부에서는 어떤 일이 벌어질까? 백엔드 개발을 하면서 수많은 쿼리를 작성했지만, 정작 그 쿼리가 어떤 경로를 거쳐 데이터를 가져오는지 깊이 고민해본 적은 많지 않았다. “인덱스 걸면 빨라진다”, “트랜잭션으로 묶어야 안전하다”는 건 알지만, 왜 그런지를 설명하려면 결국 MySQL의 내부 구조를 이해해야 한다. 이 글에서는 MySQL의 전체 아키텍처를 확인하고, 쿼리 한 줄이 어떻게 데이터가 되어 돌아오는지 그 과정을 확인해본다. 이 흐름을 이해하면 다음과 같은 질문에 답할 수 있게 된다. 왜 같은 쿼리인데 어떤 건 빠르고 어떤 건 느릴까? Buffer P...</summary> </entry> </feed>
