← 모든 글

엔지니어링 철학: Salvatore Sanfilippo (antirez)

Redis를 만든 Salvatore Sanfilippo (antirez)

핵심 요약

  • 그를 규정하는 원칙은 더 적게 하라는 것입니다 — 머릿속에 통째로 담아둘 수 있는 작고 단순한 시스템이, 크고 기능을 다 갖춘 시스템을 이깁니다. 온라인에서 antirez로 알려진 Salvatore Sanfilippo는 Redis를 의도적으로 작은 저장소로 만들었습니다. 단일 스레드로 동작하고, 인메모리이며, 깔끔한 C로 작성되었고, 이해하기 어렵게 만들 기능이라면 가차 없이 밀어냈습니다. 그의 글들은 늘 같은 표적으로 돌아옵니다 — 비용을 따져보지도 않고 우리가 더해버리는 복잡성입니다.15
  • 그는 2009년에 Redis를 만들었고, 그것은 세계에서 가장 많이 쓰이는 데이터베이스 중 하나가 되었습니다. 인메모리 데이터 구조 저장소인 Redis는 2009년 2월 26일에 처음 공개되었습니다. 실시간 웹 로그 분석기였던 자신의 이탈리아 스타트업 LLOOGG를 확장하려던 시도에서 탄생한 것입니다. 그는 11년 동안 Redis의 단독 메인테이너이자 “자비로운 종신 독재자(Benevolent Dictator for Life)”로 일했습니다.12
  • Redis는 설계상 단일 스레드이며, 그것은 단점이 아니라 특징입니다. 멀티코어 처리량을 좇는 대신, Redis는 단일 스레드 위에서 한 번에 하나씩 명령을 실행합니다 — 이로써 경쟁 상태(race condition)와 락(lock) 부담이 사라지고, 모델이 단순하게 유지되며, 충분히 빠릅니다. Redis FAQ가 말하듯 “Redis에서 CPU가 병목이 되는 경우는 그리 흔하지 않습니다. 보통 Redis는 메모리나 네트워크에 묶이기 때문입니다.”7
  • 그는 코드를 사람이 다른 사람을 위해 쓰는 것으로 대합니다. “시스템 소프트웨어 작성하기” 연작 글에서 그는 소스 코드란 “실행되기보다는 읽히기 위한 것이며, 사람이 다른 사람을 위해 쓴 것”이라고 주장하고, 읽기 좋은 코드의 목표는 “읽는 사람이 머릿속에 떠안아야 하는 수고의 양과 세부 사항의 개수를 낮추는 것”이라고 말합니다.4

핵심 원칙

“우리는 기능을 추가하거나 어떤 차원을 최적화할 때 더 이상 복잡성을 셈에 넣지 않음으로써 소프트웨어를 망가뜨리고 있습니다… 우리는 터무니없는 의존성의 사슬로 모든 것을 비대하고 부서지기 쉽게 만들면서 소프트웨어를 망가뜨리고 있습니다… 우리는 더 이상 작게 줄어들지 않는 시스템을 만들면서 소프트웨어를 망가뜨리고 있습니다. 어떤 시스템에서든 단순한 일은 단순하게 해낼 수 있어야 합니다.” – Salvatore Sanfilippo, “We are destroying software”5

엔지니어링은 대부분 더하기입니다. 기능이 요청되니 더합니다. 어떤 의존성이 일주일을 아껴주니 끌어옵니다. 어떤 최적화가 사용자 한 명에게 도움이 되니 핵심에 박아 넣습니다. 한 걸음 한 걸음은 그 자리에서 보면 합리적으로 보입니다 — 그리고 그 합은 이제 어느 한 사람도 머릿속에 통째로 담을 수 없는 시스템입니다. Sanfilippo의 본능은 반대 방향으로 흐릅니다. 그의 철학에서 가장 위험한 한 줄의 코드는, 애초에 그것을 안 쓸 수 있는지부터 묻지 않고 쓴 줄입니다. 더 적게 하라. 질문은 결코 “이게 또 무엇을 할 수 있는가”가 아니라 “이게 무엇을 그만두고도 여전히 쓸 가치가 있는가”입니다.5

이 원칙이 가장 또렷하게 드러난 것이 Redis 자체입니다. Redis는 명령 실행에 있어 단일 스레드입니다 — 2009년, 업계가 다중 코어를 활용하려고 앞다투던 시절에는 거의 비뚤어진 선택처럼 보였던 결정입니다.17 그러나 그 근거는 원칙을 아키텍처로 빚어낸 것입니다. 한 번에 하나씩 명령을 실행하는 단일 스레드에는 경쟁 상태가 없고, 락이 없으며, 찢어진 읽기(torn read)가 없고, 두 스레드가 같은 키를 동시에 변경하는 버그가 없습니다. 머릿속 모델은 사람이 실제로 추론할 수 있는 무언가로 줄어듭니다. 명령은 순서대로, 차례차례, 원자적으로 일어납니다. 그리고 실제로 잃는 것은 거의 없습니다. CPU가 한계에 닿기 한참 전에 Redis는 “메모리나 네트워크에 묶이기” 때문입니다.7 동시성의 복잡성은 대부분의 워크로드가 결코 필요로 하지 않는 이득을 위해 antirez가 치르기를 거부한 비용이었습니다.

그 거부는 비용을 감당할 만하게 만들어 주는 두 동반자와 함께 갑니다. 첫째는 풍부한 기본 구성 요소(primitive)입니다. 모든 문제를 단일 키-값 모델로 밀어 넣는 대신, Redis는 문자열, 해시, 리스트, 셋, 정렬된 셋, 스트림을 네이티브 데이터 구조로 제공합니다. 그래서 적합한 도구는 대개 이미 상자 안에 들어 있습니다.1 둘째는 사람을 위해 쓴 코드입니다. 그는 소스가 “사람이 다른 사람을 위해 쓴 것”이며, 좋은 코드는 “읽는 사람이 머릿속에 떠안아야 하는 세부 사항의 개수”를 낮춘다고 역설합니다.4 사람들에게 강력한 기본 구성 요소 몇 개를 주고, 그들이 요청한 것보다 더 적게 하고, 전체를 한 사람이 여전히 이해할 수 있도록 쓰라. 그것이 원칙이며, Redis가 그 증명입니다.

배경

Salvatore Sanfilippo는 1977년 3월 7일 이탈리아 시칠리아의 Campobello di Licata에서 태어났습니다.1 그는 Gela 인근, 남부 시칠리아의 소외된 지역에서 자랐고, 열일곱 살에 건축을 공부하러 Palermo로 옮겼습니다 — 끝내 마치지 못한 학위로, 이후 관심을 컴퓨터 과학으로 돌려 거의 독학으로 프로그래밍을 익혔습니다.1 기억해 둘 만한 사실은 그가 독학파이며, 완료한 대학 컴퓨터 과학 학위가 없다는 점입니다. 그 기예는 자격증이 아니라 일을 직접 해내는 데서 왔습니다. 이 연작에서 거듭 나타나는 형태입니다 — 권위가 배운 것이 아니라 만든 것에 기대고 있는 깊은 실무자 말입니다.

그가 이 분야에 처음 남긴 자취는 데이터베이스가 아니라 보안이었습니다. 그는 보안 테스트에 쓰이는 TCP/IP 프로토콜용 오픈소스 패킷 생성·분석 도구 hping을 작성했습니다.1 더 결정적으로, 1998년에 그는 idle scan을 발표했습니다 — 원래 “dumb scan”이라 불린 은밀한 포트 스캔 기법으로, “자신에게 흔적이 되돌아오게 남기지 않고” 대상에 어떤 서비스가 열려 있는지를 알아냅니다.6 이 기법은 부수 채널을 이용해 동작합니다. 예측 가능한 IP ID 카운터를 가진, 유휴 상태의 제3자 “좀비” 호스트를 공격자가 눈먼 프록시로 삼아 대상의 응답을 추론하는 것입니다.6 이 기법은 nmap과 hping에 통합될 만큼 영리했고, 지금도 거기에 남아 있습니다.6 겉보기에 어려운 문제 밑에 숨은 우아한 메커니즘을 찾아낸다는, 훗날 Redis를 규정한 바로 그 본능입니다.

Redis 자체는 실용적인 확장 문제에서 나왔습니다. 2000년대 후반 Sanfilippo는 실시간 웹 로그 분석기를 만드는 이탈리아 스타트업 LLOOGG를 운영하고 있었는데, 기존 데이터베이스들이 그가 필요로 하는 쓰기 속도를 따라가지 못했습니다.1 그래서 2009년에 그는 자신만의 인메모리 저장소를 만들었고, 2009년 2월 26일에 Redis를 공개했습니다.12 그것은 빠르게 퍼져나갔고, 후원도 그 부상을 따라갔습니다. 2010년 3월 VMware가 그를 채용했고, (VMware에서 분사한) Pivotal Software2013년 5월에 후원을 넘겨받았으며, Redis Ltd.2015년 6월에 이를 떠맡았습니다.1 그는 11년 동안 이 프로젝트의 단독 메인테이너이자 BDFL로 일하다가 2020년 6월 30일에 물러났고, Yossi Gottlieb와 Oran Agra가 그 뒤를 이었습니다.1 2024년 12월 그는 Redis로 돌아왔습니다 — 에반젤리스트이자 활발한 기여자로서, 정점에서 떠났다가 다시 돌아온 보기 드문 창조자입니다.1

작업

Redis와 그 데이터 구조: 빈 키-값 저장소가 아닌, 강력한 기본 구성 요소

Redis를 다르게 만드는 것에서 시작합시다. 그것이 곧 제품으로 빚어낸 원칙이기 때문입니다. 대부분의 키-값 저장소는 정확히 그것만 줍니다 — 키 하나, 값이라는 불투명한 덩어리 하나, 그리고 나머지 전부를 직접 만들어야 하는 짐. Redis는 그 대신 풍부한 데이터 구조를 기본 구성 요소로 제공합니다. 문자열, 해시, 리스트, 셋, 정렬된 셋, 그리고 Redis 5.0부터는 스트림입니다.1 각각은 자체 명령을 가진 네이티브 서버측 타입이라서, 여러분이 애플리케이션 코드에서 손수 만들었을 데이터 구조가 이미 데이터베이스 안에 살아 있으며, 그 단일 스레드에 의해 원자적으로 다뤄집니다.17 그 대가는, 적합한 기본 구성 요소가 이미 거기 있기에 어려운 애플리케이션 기능이 명령 몇 개로 줄어든다는 것입니다.

가장 날카로운 예가 정렬된 셋(sorted set, ZSET)입니다. 이것은 고유한 멤버들의 집합이며, 각 멤버는 부동소수점 점수(score)를 지니고, Redis는 멤버들을 “순서대로 취해” 둡니다 — 정렬은 요청 시 계산되는 것이 아니라 데이터 구조 자체의 속성입니다.3 내부적으로는 스킵 리스트와 해시 테이블을 짝지은 이중 포트 구조여서, O(log(N)) 삽입과, 결과를 정렬된 순서로 읽어 오는 데 추가 작업이 전혀 없음을 제공합니다.3 멤버의 점수는 ZADD로 추가하거나 갱신하고, 멤버의 순위는 ZRANK(낮은 순)나 ZREVRANK(높은 순)로 읽습니다.3 대표적인 용례는 모든 게임이 필요로 하면서 모든 전통적 데이터베이스가 두려워하는 것입니다. 바로 리더보드입니다. Redis 문서가 말하듯, “정렬된 셋을 사용하면 거대한 온라인 게임에서 최고 점수의 순위 목록을 손쉽게 유지할 수 있습니다.”3

엔지니어링으로서 왜 중요한가: 관계형 데이터베이스에서 리더보드는 진짜 골칫거리입니다. 점수가 바뀔 때마다 UPDATE가 필요하고, “이 플레이어의 순위가 몇 위인가”라는 질의마다 테이블 전체에 걸친 ORDER BY나 유지 관리되는 인덱스가 필요합니다 — 플레이어 수에 따라 늘어나고 부하가 걸리면 경합하는 작업입니다. Redis에서 순위는 구조에 내재되어 있습니다. ZADD는 O(log(N))이 들고 ZREVRANK는 O(log(N))이 들며, 셋은 이미 정렬되어 있으므로 상위 열 개를 읽는 것은 사소한 일입니다.3 그 기능이 쉬워진 것은 Redis가 같은 작업을 더 빨리 해서가 아닙니다 — Sanfilippo가 그 형태 자체가 해답인 기본 구성 요소를 제공하기로 선택했기에 쉬워진 것입니다. 그것이 사용자 쪽에서 본 “더 적게 하라”입니다. 데이터베이스가 어려운 부분을 한 번 해두었기에, 수천 개의 애플리케이션이 그것을 두 번 다시 할 필요가 없는 것입니다.

단일 스레드와 인메모리: 설계의 중심에 둔 단순함

Redis는 제약처럼 보이지만 실은 그 힘의 원천인 두 가지 선택을 합니다. 그것은 인메모리입니다 — 작업 데이터 집합이 RAM에 살고, 내구성은 스냅숏과 추가 전용 파일(append-only file)을 통해 덧입혀집니다 — 그리고 명령 실행에 있어 단일 스레드여서, 단일 코어 위에서 요청을 한 번에 하나씩 처리합니다.17 두 선택 모두 변장한 “더 적게 하라”입니다.

단일 스레드 결정이 더 반직관적이며, 그 근거를 따라가 볼 가치가 있습니다. 멀티스레드 저장소는 공유 데이터에 대한 동시 접근을 조율해야 합니다 — 락, 원자적 연산, 락-프리 구조, 메모리 배리어 — 그리고 그 기계 장치야말로 데이터베이스 버그와 예측 불가능한 지연의 무서운 몫이 자리 잡는 곳입니다. 한 번에 하나씩 명령을 실행함으로써 Redis는 모든 명령을 구성에 의해 원자적으로 만듭니다. 추론해야 할 끼어듦(interleaving)이 없고, 잊어버릴 락이 없으며, 디버깅할 경쟁이 없습니다.7 공식 FAQ는 왜 그 비용이 거의 들지 않는지 단도직입적으로 말합니다. “Redis에서 CPU가 병목이 되는 경우는 그리 흔하지 않습니다. 보통 Redis는 메모리나 네트워크에 묶이기 때문입니다.” 그리고 단일 스레드는 “경쟁 상태와, 스레드에 따르는 CPU 부담이 큰 컨텍스트 전환을 피합니다.”7 이 설계가 포기하는 처리량은 대부분의 워크로드가 애초에 쓸 일이 없던 처리량이고, 그것이 사들이는 단순함은 모든 코드 한 줄에서, 그리고 새벽 3시의 모든 디버깅에서 되갚아집니다.

이것은 그의 글들에서 보이는, 복잡성을 더하기를 거부하는 기질과 똑같은 것입니다. 그는 그 실패 양식을 정확히 짚습니다. “우리는 기능을 추가하거나 어떤 차원을 최적화할 때 더 이상 복잡성을 셈에 넣지 않음으로써 소프트웨어를 망가뜨리고 있습니다.”5 멀티스레딩은 바로 그런 종류의 최적화입니다 — 하나의 차원, 즉 순수 CPU 처리량을 위한 것이며, 대부분의 사용자가 결코 필요로 하지 않은 이득을 위해 시스템의 복잡성을 곱절로 늘렸을 것입니다. 거기에 아니라고 말함으로써 Redis는 한 사람이 머릿속에 통째로 담을 수 있는 시스템으로 남았고, 그 속성이야말로 한 사람이 11년 동안 그것을 유지할 수 있게 한 것입니다.1

시칠리아에서 혁신상을 받는 Salvatore Sanfilippo

기예: 사람을 위해 쓴 C, 그리고 주석을 옹호하는 논거

세 번째 작업의 몸체는 기능이 아니라 코드를 어떻게 써야 하는가에 대한 태도입니다. Sanfilippo는 Redis를 C로 씁니다 — 안전장치가 없어 프로그래머가 모든 바이트에 책임을 지는 언어입니다 — 그리고 그는 그 C의 가독성을 나중에 덧붙일 것이 아니라 일차적인 관심사로 대합니다. 그의 글 “시스템 소프트웨어 작성하기: 코드 주석”은 소스가 일차적으로 소통으로서 존재한다는, 보기 드물게 직접적인 논증입니다. 코드는 “실행되기보다는 읽히기 위한 것이며, 사람이 다른 사람을 위해 쓴 것”이라고 그는 씁니다.4 실행 가능한 동작은 일의 절반일 뿐입니다. 나머지 절반은 그것을 이해해야 하는 다음 사람 — 흔히 미래의 여러분 — 입니다.

그 전제로부터 그는 주석과 명료함에 대한 실용적 이론을 끌어냅니다. 읽기 좋은 코드의 목표는 “코드를 읽는 동안 읽는 사람이 머릿속에 떠안아야 하는 수고의 양과 세부 사항의 개수를 낮추는 것”이라고 그는 주장합니다.4 주석은, 읽는 사람이 아니었다면 직접 재구성해야 했을 세부 사항을 없애줄 때 그 자리를 얻습니다 — 뻔하지 않은 선택 뒤의 이유, 함수가 가정하는 불변식, 빠른 경로(fast path)가 존재하는 까닭. 이것은 가장 깊은 의미의 기예입니다. 영리함이 아니라, 뒤에 오는 사람에 대한 보살핌입니다. 이것은 “더 적게 하라” 원칙과 정확히 짝을 이룹니다. 시스템이 작고 단순할수록 짊어질 세부 사항이 적어지고, 남은 세부 사항에 대해 코드가 더 정직해질 수 있기 때문입니다.

2025년 무대에서 발언하는 Salvatore Sanfilippo

같은 신념이 소프트웨어가 향하는 방향에 대한 그의 더 넓은 비판을 이끕니다. 그는 “모든 것을 비대하고 부서지기 쉽게 만드는 터무니없는 의존성의 사슬”을 경계하고, “더 이상 작게 줄어들지 않는 시스템: 어떤 시스템에서든 단순한 일은 단순하게 해낼 수 있어야 한다”고 경계합니다.5 Redis는 실행 가능하게 빚어낸 그의 반론입니다 — 의존성이 거의 없고, 작고 이해 가능한 핵심을 지녔으며, 단순한 일이 단순하게 남는 설계입니다. 기예는 엔지니어링 위에 얹은 장식이 아닙니다. 그것이 엔지니어링입니다.

방법

Redis, idle scan, 주석과 복잡성에 관한 글들, 그리고 단일 스레드를 가로질러 읽으면 같은 신조들이 반복됩니다. Sanfilippo의 방법은 표어라기보다 일관되게 지켜온 습관들의 묶음입니다.

더 적게 하라 — 가장 위험한 코드는 쓸 필요가 없었던 코드다. 그를 규정하는 습관은 덜어내기입니다. 기능이나 의존성이나 최적화를 더하기 전에, 시스템이 그것 없이도 살아남을 수 있는지부터 묻습니다. 그는 그 실패 양식을 직접 이름 붙입니다 — “셈에 넣지 않고” 더해진 복잡성이라고요.5 그 교훈은 데이터베이스를 한참 넘어서까지 옮겨갑니다. 여러분이 쓰지 않은 모든 줄은, 망가질 수 없고, 다음 독자를 헷갈리게 할 수 없으며, 십 년간 유지 관리될 필요가 없는 줄입니다. 이것은 시스템 핵심의 차원에서 본 최소한의 가치 있는 제품입니다 — 진정으로 쓸 가치가 있는 가장 작은 것을 내놓고, 끊임없이 커지라는 압력으로부터 그 작음을 지키는 것입니다.

미리 만들어진 정책이 아니라, 강력한 기본 구성 요소를 내놓아라. Redis는 정렬된 셋, 스트림, 해시를 건넵니다 — 리더보드, 큐, 속도 제한기를 만들어 낼 수 있는 범용 구조들입니다 — 각각을 위한 맞춤 기능을 주는 대신에 말입니다.3 일관된 습관은 한 부류의 문제 전체를 해결하는 밑바탕 메커니즘을 찾아 바로 그것을 내놓는 것이고, 그래서 데이터베이스가 어려운 부분을 한 번에 해냅니다. 이것은 Roberto Ierusalimschy가 Lua의 테이블과 메타테이블로 건 것과 똑같은 베팅입니다 — 사람들에게 날카롭고 범용적인 지렛대를 주고 나머지는 그들이 만들게 하는 것 — 그리고 그 친연성은 우연이 아닙니다. Redis가 바로 그것을 하려고 Lua를 내장하고 있기 때문입니다.

처리량을 치르더라도 단순함을 택하라. 단일 스레드 설계가 가장 또렷한 사례입니다. Redis는 명령 실행에 멀티코어 병렬성을 마다합니다. 단순함 — 경쟁 없음, 락 없음, 구성에 의한 원자성 — 이 코어보다 더 값지고, 어차피 CPU가 병목인 경우는 드물었기 때문입니다.7 규율은 어느 차원이 실제로 여러분을 옭아매는지 알고, 그렇지 않은 차원을 최적화하느라 복잡성을 치르기를 거부하는 것입니다. 이것은 성능에 적용한 증거 관문입니다 — 빨라 보인다는 이유로 동시성을 더하지 말고, 병목이 정말 어디인지 측정하라. 대개 그것은 CPU가 아닙니다.

다음에 읽을 사람을 위해 코드를 써라. 소스는 “사람이 다른 사람을 위해 쓴 것”이고, 주석의 임무는 읽는 사람이 짊어져야 할 세부 사항을 낮추는 것입니다.4 습관은 가독성과 설명하는 주석을 나중에 더할 곁가지가 아니라 정확성의 일부로 대하는 것입니다 — 아무도 이해할 수 없는 시스템은 아무도 안전하게 바꿀 수 없는 시스템이기 때문입니다. 이것은 Donald Knuth가 문예적 프로그래밍(literate programming)으로 극한까지 밀어붙인, 사람을 중심에 둔 바로 그 기예입니다. 프로그램은 사람을 겨냥한 한 편의 글입니다.

시스템 전체를 한 사람의 머릿속에 담아라. Redis가 11년 동안 한 사람에 의해 유지 관리될 수 있었던 것은, 한 사람이 이해할 수 있을 만큼 작게 유지되었기 때문입니다.1 일관된 다짐은 한 개인이 이해할 수 있음을 엄격한 설계 제약으로 대하는 것입니다 — 시스템이 한 사람의 머리가 담을 수 있는 것을 넘어 커지면, 그것을 신뢰할 만하게 만들었던 바로 그것을 잃은 셈입니다. 이것은 Linus Torvalds와 Unix 전통이 공유하는 단독 기예의 본능입니다 — 또렷하고 경계가 분명한 임무를 가진 도구를, 흩뜨려 위임하는 대신 깊이 소유하고 이해하는 것입니다.

영향의 사슬

그를 빚은 것들

Unix와 C 전통. Sanfilippo는 시스템 소프트웨어를 C로, 손수, 모든 바이트를 보살피며 씁니다 — 작은 도구들이 한 가지 일을 잘 해내고, 언어가 완전한 통제권과 완전한 책임을 함께 주는 Thompson과 Ritchie의 혈통입니다.4 코드는 사람이 읽으라고 쓰인 것이라는 그의 고집은, 그 전통의 읽기 좋은 C 윤리를 데이터베이스 시대로 이어온 것입니다. (형성적 영향)

1990년대 후반의 보안·네트워킹 해커 문화. Redis 이전에 hping과 idle scan이 있었습니다 — TCP/IP에 대한 정밀한 머릿속 모델과, 프로토콜에 숨어 있는 우아한 부수 채널을 알아보는 해커의 눈을 요구한 저수준 패킷 작업입니다.16 겉보기에 어려운 문제 밑에 깔린 영리한 메커니즘을 찾아내는 그 습관이, Redis의 데이터 구조를 낳은 바로 그것입니다. (직접적 영향)

실제 제품이라는 제약. Redis는 추상적으로 설계된 것이 아닙니다. 기존 데이터베이스들이 허용한 것보다 더 빠르게 웹 로그를 받아들여야 했던 LLOOGG의 필요가 그것을 억지로 태어나게 했습니다.1 구체적이고 다급한 문제의 압력 — 데이터베이스 그 자체를 만들려는 욕망이 아니라 — 이, 필요한 것을 정확히 하고 그 이상은 거의 하지 않는 쪽으로 Redis를 빚었습니다. (형성적 영향)

그가 빚은 것들

한 세대의 애플리케이션 아키텍처. Redis는 캐싱, 세션 저장, 속도 제한, 실시간 리더보드, 발행/구독(pub/sub)의 기본 선택지가 되었습니다 — “그 앞에 Redis를 둬”가 반사적인 엔지니어링 조언이 될 만큼 어디에나 있고, 그 데이터 구조는 데이터베이스가 무엇을 제공할 수 있는지에 대한 개발자들의 생각을 다시 빚었습니다.13

“풍부한 기본 구성 요소” 학파의 데이터 저장소들. 저장소가 정렬된 셋과 스트림을 불투명한 값이 아니라 일급 타입으로 제공할 수 있음을 증명함으로써, Redis는 분야 전체를 더 풍부한 서버측 데이터 구조 쪽으로, 빈 키-값 모델에서 멀어지는 쪽으로 밀었습니다. (분야를 규정하는 영향)

작고, 주관이 뚜렷하며, 단독 저자가 만든 시스템을 옹호하는 논거. Redis는 의도적으로 작은 시스템이, 안목을 지닌 한 사람에 의해 유지 관리되면서도 전 세계의 인프라가 될 수 있다는 살아 있는 증명으로 서 있습니다 — 그 이후의 모든 “더 적게 하라”, 최소 의존성, 이해 가능한 핵심 설계에 메아리치는 논거입니다.5

관통하는 줄기

Sanfilippo는 이 연작의 미니멀리스트들과 나란히 앉습니다 — 엔지니어링의 가장 높은 형태가 덜어내기라고 믿는 만든 이들입니다. Rich Hickey는 “Simple Made Easy”에서 선을 그었습니다. 단순하다는 것은 엮이지 않았다는 것, 한 겹, 하나의 관심사라는 것이고, 복잡성은 우리가 편의를 위해 더하고 영영 그 대가를 치르는 뒤얽힘이라고요. Redis는 그 논거를 C로 컴파일한 것입니다 — 동시성의 엮임이 아니라 하나의 관심사가 되도록 단일 스레드를 쓰고, 데이터 구조가 애플리케이션 코드와 얽히지 않도록 풍부한 기본 구성 요소를 내놓았습니다.57 그리고 Roberto Ierusalimschy는 한 사람이 이해할 수 있을 만큼 Lua를 작게 지어, 정책이 아니라 메커니즘을 내놓았습니다 — Redis가 그 기본 구성 요소로 거는 것과 똑같은 베팅이며, 그래서 Redis는 사용자가 그 위에서 원자적으로 스크립트를 짤 수 있도록 Lua를 내장합니다. 둘 다 Thompson과 Ritchie의 Unix 경제성에서 내려옵니다 — 또렷한 임무 하나를 가진 도구를, 읽기 좋은 C로, 통째로 이해할 만큼 작게 쓴 것입니다. Hickey가 그저 쉽게가 아니라 단순하게 유지하라고 말하고 Ierusalimschy가 규칙이 아니라 지렛대를 내놓아라라고 말하는 곳에서, Sanfilippo는 이렇게 말합니다. 더 적게 하라 — 사람들에게 강력한 기본 구성 요소를 주고, 모델이 머릿속에 남도록 한 번에 하나씩 실행하고, 다음에 읽을 사람을 위해 모든 줄을 써라. (연작의 다리)

내가 여기서 얻는 것

antirez에게서 내가 간직하는 교훈은, 내가 쓰지 않은 코드가 시스템에서 가장 가치 있는 코드라는 것입니다. 대부분의 만든 이들처럼 내 본능도 문제를 더하기로 해결하려 합니다 — 기능 하나, 의존성 하나, 스레드 하나, 영리한 최적화 하나. Redis는 그 더하기가 대개 실수라는, 11년에 걸친 논증입니다. 내가 가장 자주 생각하는 것은 단일 스레드 설계입니다. 그는 모두가 반드시 해야 한다고 말한 것 — 코어를 활용하기 — 을 마다했습니다. 그것이 가져오는 복잡성이, 그의 워크로드가 결코 필요로 하지 않은 이득에 비할 만한 가치가 없었기 때문입니다.7 이제 무언가를 만들 때 내가 빌려 오는 질문은 “쓸 가치가 있는 것을 내놓으면서도 내가 더하기를 거부할 수 있는 것은 무엇인가”입니다. 내가 건너뛴 모든 줄은, 망가질 수 없고, 헷갈리게 할 수 없으며, 다음 십 년간 유지 관리를 요구할 수 없는 줄이기 때문입니다. 더 적게 하기는 더 많이 하기보다 어렵고, 훨씬 오래갑니다.

두 번째 교훈은, 코드는 글이며, 읽는 이는 사람이라는 것입니다. 소스를 기계를 위한 명령으로 대하고 테스트가 통과하는 순간 멈추기는 쉽습니다. Sanfilippo는 그것을 소통으로 대합니다 — “사람이 다른 사람을 위해 쓴 것” — 그리고 다음 독자가 머릿속에 짊어져야 하는 세부 사항이 얼마나 적은가로 그것을 가늠합니다.4 그것이 내게 주석을 다시 보게 했습니다. 최소화해야 할 잡음도, 불분명한 코드에 대한 사과도 아니라, 무엇에서는 결코 재구성할 수 없는 이유를 다음 사람에게 건네주는 자리라고요. 읽는 이를 위해 쓰는 규율은 더 적게 하는 규율과 떼어놓을 수 없습니다. 시스템이 작고 단순할수록 그 코드는 더 정직해질 수 있고 — 지금부터 몇 년 뒤, 한 사람이 여전히 그 전체를 머릿속에 담을 가능성이 더 커지기 때문입니다. 이것이 절제로 읽은 품질이 유일한 변수입니다 — 사람을 위해 쓰이고 비대함에 맞서 지켜진, 올바르게 작은 것이, 세상이 그 위에 설 수 있는 인프라가 됩니다.

자주 묻는 질문

Redis란 무엇인가요?

Redis는 Salvatore Sanfilippo(antirez)가 만들어 2009년 2월 26일에 처음 공개한 오픈소스 인메모리 데이터 구조 저장소입니다.12 평범한 키-값 캐시처럼 불투명한 값을 저장하는 대신, 풍부한 네이티브 데이터 구조 — 문자열, 해시, 리스트, 셋, 정렬된 셋, 스트림 — 를 제공하며, 서버가 이를 원자적으로 다룹니다.1 작업 데이터 집합이 RAM에 살기 때문에(내구성은 스냅숏과 추가 전용 파일을 통해 확보) 대단히 빠르며, 그래서 캐싱, 세션 저장, 큐, 속도 제한, 실시간 리더보드, 발행/구독에 쓰이는, 세계에서 가장 널리 쓰이는 데이터베이스 중 하나가 되었습니다.17

antirez는 누구인가요?

antirez는 Salvatore Sanfilippo의 온라인 핸들로, 1977년 3월 7일 시칠리아의 Campobello di Licata에서 태어난 이탈리아(시칠리아) 독학파 프로그래머입니다.1 그는 Redis(2009)를 만든 사람으로 가장 잘 알려져 있으며, 11년 동안 단독 개발자이자 BDFL로 그것을 유지하다가 2020년 6월 30일에 물러났고 2024년 12월 프로젝트로 돌아왔습니다.1 Redis 이전에는 주목할 만한 보안 작업을 했습니다 — hping 패킷 도구를 작성하고, 1998년에 idle scan을 고안했는데, 이는 훗날 nmap에 통합된 은밀한 포트 스캔 기법입니다.16 그는 자신의 블로그 antirez.com에서 단순함, 코드 주석, 시스템 소프트웨어의 기예에 대해 사려 깊게 씁니다.45

Redis는 왜 단일 스레드인가요?

Redis는 단일 스레드 위에서 명령을 한 번에 하나씩 실행합니다. 그 워크로드에서는 단순함이 멀티코어 처리량보다 더 값지기 때문입니다. 단일 스레드는 모든 명령을 구성에 의해 원자적으로 만듭니다 — 추론해야 할 경쟁 상태도, 락도, 찢어진 읽기도 없습니다.7 그리고 실제로 드는 비용은 적습니다. Redis FAQ가 설명하듯, “Redis에서 CPU가 병목이 되는 경우는 그리 흔하지 않습니다. 보통 Redis는 메모리나 네트워크에 묶이기 때문입니다.” 그리고 단일 스레드는 “경쟁 상태와, 스레드에 따르는 CPU 부담이 큰 컨텍스트 전환을 피합니다.”7 이것은 Sanfilippo의 “더 적게 하라” 원칙을 아키텍처로 옮긴 것입니다 — 좀처럼 제약이 아니었던 차원(CPU)을 최적화하는 복잡성을 마다하는 것입니다.57

Redis 정렬된 셋이란 무엇인가요?

Redis 정렬된 셋(ZSET)은 고유한 문자열 멤버들의 집합으로, 각 멤버는 부동소수점 점수와 연결되며, 멤버들은 점수 순서로 자동 유지됩니다.3 멤버의 점수는 ZADD 명령으로 설정하거나 갱신하고, 그 위치는 ZRANK(낮은 점수 순)나 ZREVRANK(높은 점수 순)로 읽습니다. 구조는 항상 정렬된 상태로 유지되므로, 순위가 매겨진 결과를 읽는 데 추가 정렬 작업이 필요 없습니다.3 내부적으로는 스킵 리스트와 해시 테이블을 짝지어 사용하여, O(log(N)) 삽입과 O(log(N)) 순위 조회를 제공합니다.3 고전적인 용례는 실시간 리더보드입니다 — 관계형 데이터베이스에서는 고통스럽지만, 적합한 기본 구성 요소가 이미 존재하기에 Redis에서는 명령 몇 개로 줄어드는 기능입니다.3


출처


  1. “Salvatore Sanfilippo,” Wikipedia. 1977년 3월 7일 이탈리아 시칠리아 Campobello di Licata 출생. 남부 시칠리아 Gela 인근에서 성장했고, 17세에 건축을 공부하러 Palermo로 이주했으나 대학 학업을 마치지 못하고 컴퓨터 과학으로 전향한 독학파 프로그래머. 보안 테스트에 쓰이는 TCP/IP용 오픈소스 패킷 생성·분석 도구 hping 개발. 1998년 idle scan 포트 스캔 기법을 처음 발표. 실시간 웹 로그 분석기인 이탈리아 스타트업 LLOOGG의 확장을 동기로 2009년 Redis 개발을 시작; 오픈소스로 공개하고 11년간 주 개발자이자 자비로운 종신 독재자(BDFL)로 활동. 2020년 6월 30일 Redis 메인테이너에서 물러남을 발표(Yossi Gottlieb와 Oran Agra가 승계); 2024년 12월 에반젤리스트로 Redis(회사)에 복귀. 2010년 3월 VMware에 채용; 후원이 Pivotal Software(2013년 5월)로, 이어 Redis Ltd.(2015년 6월)로 이동. 

  2. “Redis,” Wikipedia. Redis는 Salvatore Sanfilippo(“antirez”)가 만든 인메모리 키-값 데이터베이스; 프로젝트는 2009년에 시작되었고 첫 공개는 2009년 2월 26일. Redis는 “단일 프로세스로 실행되며 단일 스레드이거나, AOF(추가 전용 파일)를 재작성할 때는 이중 스레드”이다. 문자열, JSON 문서, 해시, 리스트, 셋, 벡터 셋, 스트림을 포함한 데이터 구조 지원(스트림은 Redis 5.0에서 도입). 조직 연혁: Sanfilippo가 VMware에 채용(2010년 3월), Pivotal Software 후원(2013년 5월), Redis Ltd. 후원(2015년 6월), Sanfilippo가 단독 메인테이너에서 물러남(2020년 6월), 2024년 12월 복귀. 라이선스 연혁: 원래 BSD-3; 2024년 Redis Source Available License와 SSPL로 이중 라이선스; 8.0 버전(2025년 5월)부터 AGPL을 더해 삼중 라이선스. 

  3. “Redis sorted sets,” Redis 문서. Redis 정렬된 셋은 연결된 부동소수점 점수로 정렬된 고유 문자열(멤버)들의 집합이며, 점수가 같은 멤버는 사전순으로 정렬된다. “요소들은 순서대로 취해진다” — 정렬은 요청 시 계산되는 것이 아니라 데이터 구조의 속성이다. ZADD는 멤버를 점수와 함께 추가하거나 기존 멤버의 점수를 갱신한다(항목당 O(log(N))); ZRANGE/ZREVRANGE는 멤버를 오름차순/내림차순으로 반환한다; ZRANK/ZREVRANK는 멤버의 위치를 반환한다(O(log(N))). 스킵 리스트와 해시 테이블을 모두 담은 이중 포트 데이터 구조로 구현되어, O(log(N)) 삽입과 정렬된 결과를 가져오는 데 “추가 작업 제로”를 제공한다. 리더보드를 주요 용례로 문서화: “정렬된 셋을 사용하면 거대한 온라인 게임에서 최고 점수의 순위 목록을 손쉽게 유지할 수 있습니다.” 

  4. Salvatore Sanfilippo, “Writing system software: code comments,” antirez.com. 소스 코드는 “실행되기보다는 읽히기 위한 것이며, 사람이 다른 사람을 위해 쓴 것”이고, “읽기 좋은 코드를 쓰는 핵심 목표는 코드를 읽는 동안 읽는 사람이 머릿속에 떠안아야 하는 수고의 양과 세부 사항의 개수를 낮추는 것”이라고 주장. “시스템 소프트웨어 작성하기” 연작의 일부; 유지 관리 가능하고 이해 가능한 코드를 만드는 데 주석이 왜 핵심인지를 보이기 위해 Redis 주석을 분석한다. 

  5. Salvatore Sanfilippo, “We are destroying software,” antirez.com. 늘어나는 소프트웨어 복잡성에 대한 비판. “우리는 기능을 추가하거나 어떤 차원을 최적화할 때 더 이상 복잡성을 셈에 넣지 않음으로써 소프트웨어를 망가뜨리고 있습니다.” “우리는 모든 것을 비대하고 부서지기 쉽게 만드는 터무니없는 의존성의 사슬로 소프트웨어를 망가뜨리고 있습니다.” “우리는 더 이상 작게 줄어들지 않는 시스템을 만들면서 소프트웨어를 망가뜨리고 있습니다. 어떤 시스템에서든 단순한 일은 단순하게 해낼 수 있어야 합니다.” 그의 “더 적게 하라” / 반복잡성 철학을 직접 표현한 글. 

  6. “Idle scan,” Wikipedia. idle scan은 “자신에게 흔적이 되돌아오게 남기지 않고 대상 컴퓨터에 어떤 서비스가 열려 있는지를 알아내는 TCP 포트 스캔 방법”으로, 중개 “좀비” 호스트를 사칭하도록 패킷을 위조하고 좀비의 예측 가능한 IP 식별(IPID) 카운터로부터 포트 상태를 추론하여 수행된다. Salvatore Sanfilippo(별명 “antirez”)가 1998년에 이 기법을 발견했고(원래 “dumb scan”이라 불림); “idle scan”이라는 용어는 1999년에 만들어졌다. 이 기법은 “nmap과 hping 같은 흔한 소프트웨어 네트워크 유틸리티를 통해 수행할 수 있다.” 많은 현대 운영체제는 IPID 필드를 무작위화하여 이에 면역이다. 

  7. “Redis FAQ,” Redis 문서. Redis의 단일 스레드 설계를 설명: “Redis에서 CPU가 병목이 되는 경우는 그리 흔하지 않습니다. 보통 Redis는 메모리나 네트워크에 묶이기 때문입니다.” 오픈소스 Redis는 명령 실행에 “여러 CPU 코어의 처리 능력을 활용할 수 없”지만, CPU가 병목인 경우는 드물다 — 메모리나 네트워크 한계에 먼저 닿는다; 파이프라이닝을 쓰면 평균적인 Linux 시스템의 Redis 인스턴스 하나가 초당 약 100만 건의 요청을 처리할 수 있다. 단일 스레드는 “경쟁 상태와, 스레드에 따르는 CPU 부담이 큰 컨텍스트 전환을 피하”여, 멀티스레드 부담 없이 명령을 효율적으로 처리한다. 

관련 게시물

엔지니어링 철학: Rich Hickey, 단순함은 쉬움이 아니다

Rich Hickey는 하나의 구분 위에 Clojure와 Datomic을 세웠습니다. 단순함은 쉬움이 아닙니다. 단순함이란 엮이지 않은 상태, 한 가지에 하나의 관심사만 담긴 상태이고, 쉬움이란 그저 익숙하다는 뜻일…

13 분 소요

엔지니어링 철학: 얀 르쿤, 세상을 배우다, 공개적으로

얀 르쿤은 합성곱 위에 딥 비전을 세웠고, 이후 진짜 지능은 더 큰 LLM이 아니라 세상을 비지도 방식으로 학습하고 그것을 공개적으로 발표하는 데서 나온다는 데 베팅했습니다.

13 분 소요

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 분 소요