어느새 큰아이가 대학교 졸업반이 됩니다. 오랜만에 저녁 식사를 하다가 문득 아이에게 말했습니다.

 

"직장이란 너의 꿈, 너의 사업을 가지기 위한 시드 머니를 확보하는 곳 같아"

 

예전 블리자드를 다닐 때 일입니다. 블리자드에서는 팀 리더와 원-온-원을 주기적으로 하는데, 주로 캠퍼스 주변을 산책하면서 여러 이야기를 나눴습니다. 그때 받은 질문 중 하나가 꿈이 뭐냐는 것이었습니다. 꿈? 글쎄요. 저는 정말 그냥 멋진 중년의 개발자가 되는 것이 꿈이었습니다. 그런데 자신의 꿈은 로스앤젤레스 근처에 빵집을 차리는 것이라는 겁니다. 의외였죠. 그 팀 리더는 개발도 잘하는 멋진 친구였거든요. 제가 물었죠.

 

"그러면 왜 개발을 하고 있어?"

 

그 친구는 자신이 개발자로 근무하는 이유가 빵집을 차리기 위한 시드 머니를  마련하기 위한 것이라고 하더라구요. 약간의 놀라움과 함께 그날의 원-온-원은 그 렇게 지나갔습니다.

 

같은 팀 동료였던 Sam은 UX 기획자였습니다. 그의 책상에는 두꺼운 책들이 많이 있었습니다. 알고보니 항공기 조종사 교재더라구요. Sam은 기장이 되고 싶었지만, 워낙 교육과정이 비싸다 보니 그걸 벌기 위해서 직장을 다니는 것이었습니다. 결국 Sam은 몇년 더 근무하고 블리자드를 그만두고 기장이 되었습니다. 처음에는 화물기를 운행하다가 몇년전 드디어 여객기 기장이 되었습니다.

 

이제 자타공인 중년의 나이를 먹다보니 여러 생각이 듭니다. 특히 AI의 발전 속도를 몸으로 체감하는 산업분야에 일하다 보니 직장이라는 것, 현재의 직장 구조가 언제까지 유지될 것인가하는 의문이 들 때도 있습니다. 그러다가 예전 직장에서의 일이 생각나면서 진짜 나의 꿈은 무엇인가라는 생각을 해 봅니다.

 

제가 개인적으로 아쉬운 것은 중년의 개발자는 되었는데, 뭘 만들지 더 명확하게 했어야 하지 않았나 하는 것입니다. 동료들에게 개발은 진짜 꿈을 향한 수단이었는데, 저는 개발자가 되는 것 자체가 꿈이었습니다. 기술을 익히고 아키텍처를 설계하는 과정이 재미있고 즐거웠습니다. 하지만 막상 중년의 개발자가 되고 나니, 그 때 동료들이 빵집 사장님과 비행기 기장이라는 명확한 목적지를 가졌던 것처럼, 나 또한 소프트웨어 개발이라는 수단을 가지고 무엇을 향해 갔어야 할 지를 명확히 했었어야 하는건가 하는 아쉬움이 생깁니다.

 

AI의 등장으로 예전보다 훨씬 더 많은 것을 쉽게 할 수 있게 된 요즘, 다양한 언어와 여러가지 아키텍처를 배우는데 집중했던 제가 이따끔씩 멍해질 때가 있습니다. 소프트웨어 개발 기술로 무언가를 구현함에 있어 존재했던 여러 장벽은 AI 덕분에 낮아졌는데, 정작 이 기술로 무엇을 만들어야 할까라는 질문에 대한 답을 여전히 찾고 있기 때문입니다. How보다 What이 좀 더 중요한 시대가 된 것이죠. 제가  멍한 느낌이 들었던 이유도 이제는 '어떤 가치를 만들것인가'라는 본질적인 질문을 마주했기 때문일 것입니다.

 

그래서 요즘은 제가 뭘 만들고 싶은 것인지에 대해 예전보다 훨씬 많이 고민하는 시간을 가져봅니다. 

 

여러분의 꿈은 뭔가요?

반응형

제미나이로 정리한 기술 원고입니다.

긱뉴스에 올라온 글과 댓글, 지인들이 댓글에서 언급한 키워드를 중심으로 정리하라고 했더니 아래와 같은 글이 작성되었습니다. 정말 공부하기 좋은 세상입니다.!

 

리눅스 커널 변화와 PostgreSQL 성능 분석 보고서

1. 핵심 개념 상세 설명

SpinLock (스핀락)

스핀락은 임계 구역(Critical Section)에 진입하기 위해 대기하는 스레드가 잠들지 않고 루프를 돌며 권한을 획득할 때까지 계속 확인하는 동기화 기법

  • 동작 방식:
    1. 스레드가 자원 사용을 위해 락(Lock)을 요청합니다.
    2. 락이 이미 사용 중이라면, 스레드는 대기 큐로 들어가는 대신 CPU를 계속 사용하며(Spinning) 락의 해제 여부를 체크합니다.
    3. 락이 해제되는 순간 즉시 자원을 점유합니다.
  • 특징:
    • Context Switch 없음: 스레드가 잠들고 깨어나는 오버헤드가 없습니다.
    • 비결정적 대기: 대기 중에도 CPU를 100% 점유하므로, 대기가 길어지면 시스템 성능이 급락합니다.
  • 장단점:
    • 장점: 임계 구역이 매우 짧을 때, 잠들고 깨어나는 시간보다 그냥 기다리는 시간이 짧아 효율적입니다.
    • 단점: 락을 쥐고 있는 스레드가 지연되거나 선점(Preemption)당하면, 기다리는 모든 스레드가 CPU를 낭비하며 '미친 듯이 도는' 현상이 발생합니다.

rseq (Restartable Sequences)

리눅스 커널이 제공하는 최신 기술

유저스페이스 코드가 원자적(Atomic)으로 실행되어야 하는 구간에서 커널에 의해 중단(선점)되었는지를 감지

  • 도입 배경: 멀티 코어 환경에서 'CPU별 데이터(Per-CPU data)'에 접근할 때 락 없이 빠르게 처리하기 위해 고안되었습니다.
  • 동작 원리:
    1. 프로세스가 특정 코드 구간(rseq 구간)을 시작함을 커널에 알립니다.
    2. 만약 이 구간을 실행하다가 커널이 스레드를 중단시키고 다른 일을 시킨다면(Preemption), 커널은 이 사실을 기록합니다.
    3. 스레드가 다시 CPU를 잡았을 때, 구간 중간부터 이어서 하는 것이 아니라 구간의 처음으로 돌아가 다시 실행(Restart)합니다.
  • 효과: 락을 쓰지 않고도 데이터의 일관성을 유지할 수 있으며, 이번 PostgreSQL 사례처럼 "락을 쥐고 잠드는" 최악의 시나리오를 방지할 수 있는 대안으로 제시되었습니다.
비교 항목 SpinLock Mutex rseq / Lock-free
대기 방식 계속 회전 (CPU 소모) 잠듦 (CPU 반납) 재시도 또는 원자적 처리
권장 상황 매우 짧은 임계 구역 긴 대기 시간 예상 시 고성능 멀티코어 환경
오버헤드 낮음 (즉시 반응) 높음 (문맥 교환) 매우 낮음 (난이도 높음)

2. 커널 스케줄링 및 선점 (Preemption) 관련

리눅스 커널이 CPU 자원을 여러 프로세스에게 나누어 주는 방식에 대한 용어입니다.

  • 선점 (Preemption): 실행 중인 스레드의 의사와 상관없이 OS 스케줄러가 강제로 CPU 사용권을 뺏어 다른 스레드에게 주는 행위입니다.
  • PREEMPT_NONE: "나 건드리지 마" 모드입니다. 스레드가 스스로 I/O를 기다리거나 잠들기 전까지는 커널이 웬만해서는 실행을 중단시키지 않습니다. 서버 환경에서 처리량(Throughput)을 극대화할 때 유리합니다.
  • PREEMPT_FULL / LAZY: "언제든 비켜줄게" 모드입니다. 응답 속도(Latency)는 빨라지지만, 자주 흐름이 끊겨 전체적인 일 처리량은 줄어들 수 있습니다. 리눅스 7.0에서 NONE 모드가 사라지면서 이번 성능 저하의 도화선이 되었습니다.
  • Restartable Sequences (rseq): 커널이 유저스페이스(PostgreSQL 등)에 "방금 네 실행 흐름이 중간에 끊겼었어"라고 알려주는 기능입니다. 이를 통해 중단되었던 작업을 처음부터 다시 안전하게 실행할 수 있게 돕는 최신 기술입니다.

3. PostgreSQL 성능 회귀 사건 분석 (통합)

최근 리눅스 7.0(내부 커널 버전 기준)에서 발생한 이슈는 하드웨어와 OS, 소프트웨어의 설계 철학이 충돌한 대표적 사례입니다.

📍 사건의 발단: 커널 정책의 변화

  • PREEMPT_NONE 제거: 과거 서버용 리눅스의 기본값이었던 "자발적 양보 외엔 절대 끊지 않음" 모드가 사라졌습니다.
  • PREEMPT_LAZY 도입: 처리량을 고려하되 필요시 선점하는 절충안이 기본이 되었으나, PostgreSQL의 전역 스핀락 구조와 상극을 일으켰습니다.

📍 문제의 메커니즘 (Cascading Failure)

  1. 스핀락 점유: PostgreSQL의 백엔드 프로세스가 공유 버퍼 풀 접근을 위해 단일 전역 스핀락(s_lock)을 획득합니다.
  2. 마이너 페이지 폴트: 락을 쥔 상태에서 메모리에 접근했는데, 해당 페이지가 물리 램에 매핑되지 않아 커널이 개입합니다.
  3. 선점 발생: 페이지 폴트 처리 중, 커널이 스레드를 잠시 중단(Preemption)시킵니다.
  4. 폭주: 락을 쥐고 있는 놈이 자리를 비우자, 나머지 수백 개의 CPU 코어들이 락을 얻으려고 스핀락 루프를 돌며 CPU 점유율을 100%까지 끌어올립니다.

📍 해결책 및 트레이드오프

해결 방법 주요 내용 장점 단점
Huge Pages 메모리 페이지를 4KB → 2MB/1GB로 확대 페이지 폴트 발생 빈도 감소 메모리 사전 할당 필요
rseq 도입 선점 시 재시작 메커니즘 선점 병목 해소 대대적 코드 수정 필요
Direct I/O OS 캐시 우회 중복 캐싱 방지 성능이 케바케임

4. 용어 사전 요약

  • Direct IO
    • 운영체제(OS)의 페이지 캐시(Page Cache)를 거치지 않고 데이터베이스 엔진이 저장 장치(Disk)와 직접 데이터를 주고받는 방식
    • 보통 OS는 성능 향상을 위해 디스크에서 읽은 데이터를 메모리에 임시로 저장(캐싱)합니다. 하지만 DBMS는 자체적으로 더 정교한 버퍼 풀(Buffer Pool) 관리 시스템을 가짐
    • 중복 캐싱(OS와 DBMS가 같은 데이터를 이중으로 들고 있는 현상)을 방지하고 CPU 사용량을 줄일 수 있음. 다만 OD가 제공하는 최적화 기능을 사용하지 못하므로 DBMS가 데이터를 효율적으로 관리하지 못하면 성능이 떨어질 수 있음
  • 네할렘 (Nehalem):
    • 메모리 컨트롤러를 CPU 내부로 통합. 이로 인해 NUMA 구조를 확립한 아키텍처.
    • 2008년 말 인텔이 출시한 CPU 마이크로 아키텍처. 2009년 서버 시장에 보편화
  • SMP( ymmetric Multi-Processing, 대칭형 다중 처리):
    • 모든 CPU가 동일한 메모리 접근 권한을 갖는 대칭형 구조.
    • CPU 개수가 늘어날수록 메모리로 가는 통로(Bus)에 병목 현상이 생겨 성능 확장 어려움 -> NUMA 등장
  • NUMA( Non-Uniform Memory Access , 비균할 메모리 접근): 
    • CPU별 독립 메모리 구조. 멀티 소켓 서버의 표준. 네할렘 이후의 멀티 소켓 서버는 대부분 이 구조를 따름
    • 각 CPU(소켓)마다 자신만의 전용 메모리 영역을 가짐. 자기 옆 메모리 접근시에는 빠르지만, 다른 CPU에 붙은 메모리 접근하려면 버스로 주고 받아야 하므로 속도가 느려짐.
    • NUMA를 지원하지 않는 소프트웨어는 멀리 떨어진 메모리만 쓰다가 성능이 떨어질 수 있음.
  • CCIX(Cache Coherent Interconnect for Accelerators):
    • CPU와 가속기 (GPU, FPGA 등) 간 캐시 일관성을 유지하면서 아주 빠른 속도로 데이터를 주고받기 위한 차세대 인터페이스.
    • NUMA의 데이터 전송 속도 한계를 극복하고, 서로 다른 제조사의 칩들이 마치 하나의 메모리를 쓰는 것처럼(캐시 일관성) 통신
    • 최근에는 인텔이 주도하는 CXL(Compute Express Link) 기술이 이 분야의 대세가 되면서, NUMA가 가졌던 물리적 한계를 극복하는 메모리 풀링(Memory Pooling) 시대로 이행되고 있
  • TLB(Translation Lookaside Buffer):
    • 가상 주소를 실제 주소로 바꾸는 맵이 담긴 변환용 초고속 캐시. TLB가 작으면 자주 매핑 정보를 구성해야 해서 속도 느려짐. Huge Pages 사용 시 효율 급증.
  • Huge Page
    • 기본 메모리 페이지 크기를 4K에서 2M/1GB로 뻥튀기. 페이지 수가 줄어들어 페이지 폴트 발생횟수가 줄어들면서 TLB 효율이 높아짐.
  • 페이지 폴트(Page Fault)
    • 프로그램이 메모리 주소를 불렀는데, 실제 물리 램에 아직 준비가 안되었을 때 발생하는 이벤트
    • 커널은 급히 램을 할당해줘야 하므로 아주 미세한 지연이 발생.

5.  성능 분석 및 벤치마크 관련

  • TPS (Transactions Per Second): 초당 처리되는 트랜잭션 수로, DB의 심박수와 같습니다. 이번 사례에서는 9.8만에서 5만으로 반토막 났습니다.
  • pgbench: PostgreSQL의 성능을 측정하는 표준 도구입니다.
  • perf: 리눅스 커널의 성능 분석 도구입니다. CPU가 어떤 함수에서 시간을 가장 많이 쓰는지 초 단위로 쪼개서 보여줍니다. 이번 분석에서 s_lock(스핀락)이 CPU의 55%를 먹고 있다는 범인을 잡아냈습니다.

 

반응형

+ Recent posts