Post

2025년 4월 회고

2025년 4월 회고

4월 한 달 동안에는 해오던 일을 차차 마무리 하고, 좀 더 넓고 높은 관점에서 내게 어떤 것이 정말 중요한 지 조망했다.

성격이 워낙 무던하고 꼼꼼하지 못한 탓에, 대충 대충 살아도 괜찮은 삶의 시스템을 만들고 싶다. 실수해도 괜찮고, 막 미친듯이 일하지 않아도 괜찮고, 외적인 위기에도 내성을 가진 그런…

내가 가진 꿈을 위해서는 스몰 비지니스나 창업을 해야한다고 생각했어서 지난 2년 반 동안 여러가지 도전을 해봤지만, 겪어보니 이젠 안다. 나는 뭐 대단한 사람이 되고 싶다기 보다, 그냥 설렁설렁 유유자적하게 머릿속에 떠오르는 거 만들어 보면서 살고 싶다. 그러다 운 좋으면 세상에 좋은 일도 해볼 수 있는 거고.

써오던 토막글들을 올리던 김에, 개인적으로 따로 남기고 있던 TIL(Today I Learned)도 함께 정리해보았다.

4월 동안 쓴 토막글들

오늘의 토막글 77

  • 책 ‘하드 씽’ 을 읽기 시작했습니다. 제가 별로 선호하지 않는 자서전 형식이긴 하나… 오히려 그렇기 때문에 가볍게 읽기에 나쁘지 않아 보였어요.
  • JVM 에서 static 한 객체들은 기본적으로 사용되는 시점에 lazy 하게 스테틱 메모리에 할당 되는데, Kotlin의 companion object 는 직접 참조/초기화 되지 않아도 해당 object 를 포함한 클래스가 인스턴스화 될 때 스테틱 메모리에 할당됩니다. 이 시점을 디버거로 잡으면 스택 트레이스가 갑자기 튀는데, 그 이유는 JVM 수준에서 클래스 로더가 monitor lock 을 잡기 때문입니다. 이것은 static 메모리 할당이 thread safe 한 이유이기도 해요. 오늘 companion object 객체를 사용하지도 않는데 계속 초기화가 실패하길래 파보다가 알게 되었습니다.
  • 사내에서 발표를 듣고 궁금해서 게임 이론과 관련한 동영상을 찾아 보았는데, 너무 감명 깊게 보았어요. 요약하자면 이렇습니다: ‘죄수의 딜레마’는 협력이 필요한 자연 상태계에서 어렵지 않게 발견할 수 있는 딜레마다. 협력/배신을 상호 선택할 수 있기 때문이다. 얼핏 보면 무조건 배신을 하는 게 합리적이나, 자연 상태에서는 서로 협력하는 생물들을 많이 보게 된다. 그 이유를 알기 위해 딜레마를 극복하기 위한 전략들 중 점수(자원)를 가장 많이 획득할 수 있는 전략을 연구했는데, 그 결과 처음엔 협력적이만 배신을 당하면 즉시 보복하는 ‘눈에는 눈, 이에는 이(tit-for-tat)’ 전략이 가장 성과가 좋았다. 이것은 자연 생태계에서 어떻게 이기적인/개인적인 행태만 발견되지 않고 (배신당할 리스크를 감수하면서 까지) 상호 협력하는 모습이 발견되는 지를 수학적으로 설명한다. 당신도 삶에서 많은 점수(자원)를 얻고 싶다면 tit-for-tat 전략을 취하라.

오늘의 토막글 78

  • 하드씽의 1장에서는 닷컴버블 당시 기술 기업의 처절한 사투를 적나라하게 보여줍니다. 기업 공모, 주식 합병, 로드쇼, 구조 조정까지. 그래서 제목이 그런가? 했습니다.
  • 스프레드 시트 단축키를 하나 배웠어요. Shift + Space 로 행 선택 후 Opt + Cmd +/- 로 아래 행 추가/삭제.
  • 오늘 하루는 소소한 재미는 있었으나 고됐습니다. 최근 했던 문제 파악이 제대로 되지 않아 일을 두 번 해야 했고, 서비스 출시가 곂쳐 정신이 없는 와중에 이리 저리 시달려야 했으며, 알 수 없는 이유로 기대한 대로 동작하지 않는 현상을 출시 직전에 발견, 심지어 새벽 2시가 넘어서까지 해결도 하지 못했습니다. 어떤 걸 해야 더 잘할 수 있었을지 감도 오지 않네요. 한 가지 해볼만한 건… 문제 파악을 할 때 조금 더 많이 의심하는 버릇을 들여야겠습니다. ‘아 이거구나’ 에서 한 걸음 더 나아갔어야 했어요.

오늘의 토막글 79

  • 3월의 회고를 혼자 해봤습니다. 여러가지로 헤맨것도 많고 해낸 것도 많았는데, 그래도 3월이 넘어가니 무거운 돌덩이를 하나 내려놓은 마음입니다. 하지만 돌덩이는 어디 가지 않죠. 어디다 내려놓았냐구요? 바로 4월의 제 머리 위에 올려 두었어요. ㅎㅎ수고해라.
  • 클로드 코드가 프리뷰로 공개가 되어서 써봤는데, 커서 수준으로 너무 만족스러워요. 파이썬 프로젝트를 생성하고 대시보드를 띄우기 까지 1시간도 걸리지 않았습니다. 세상이 변하는 게 참 빠릅니다. AI가 시니어급의 지식을 갖췄지만 맥락파악은 주니어 수준이어서 가지는 한계점을, 이제는 맥락 파악까지 시니어 급으로 잘하게 만드는 노력들로 극복하고자 하는 것 같네요. 심지어 오픈소스인데, 레포지토리 주소는 여기에요: https://github.com/anthropics/claude-code
  • 사회/경제/정치 등 여러 분야에 대해 너무 문외한인 것 같아서 어떻게 하면 이걸 극복할 수 있을지에 대한 고민을 요새 하고 있습니다. 위기는 대비가 안되었다면 ‘위험’이고 대비만 잘하면 ‘기회’ 라서 이름이 ‘위기’라던데, 객관적으로 스스로를 들여다 봤을 때 대비가 하나도 안되어 있다고 느끼거든요. 클로드 코드가 풀고자 하는 문제와 마찬가지로, 나의 모든 실시간 맥락 정보들을 정말 AI가 받아먹기 좋게 체계화/정규화하여 전달할 수 있다면 잘 대비할 수 있게 도와주는 친구를 하나 만들 수 있지 않을까 싶어요. 이 세상의 모든 분야를 섭렵하는 건 관심도 없거니와 불가능하다고 생각하지만, ‘대비’는 그냥 하라는 대로만 하면 되잖아요? 클로드 코드에서 맥락을 지식 베이스를 어떻게 관리하는지 찬찬히 뜯어봐야겠어요. 이런 게 오픈소스라니 고마우면서도 미친 세상 같습니다.

오늘의 토막글 80

  • 이야기를 해줘도 자꾸만 되돌아가서 대화가 답답하다는 피드백을 반복적으로 듣습니다. 슬프지만 제가 콱 막힌 답답한 사람이라는 사실을 인정할 수 밖에 없었어요. 정답이 정해져있다면 이해와 동시에 납득을 곧잘 하지만, 정답이 정해져 있지 않은 부분에 대해서는 납득을 잘 못한다는 사실을 깨달았거든요. 관점을 ‘이해함’ 과 ‘동의함’은 엄연히 다르나, 이해만 하고 넘겼다가 반례나 다른 관점을 찾으면 ‘들어봐, 우리가 틀렸을 수 있어’ 하며 좋아라 떠들어대는 거죠. 이해는 잘하지만 동의는 못하는 그런 걸림돌 같은 사람이었던 겁니다.
  • 의사결정을 내리는데 현실적인 도움이 되지 않는다면 그냥 묻어두고 다른 생산적인 논의를 하면 될텐데, 아쉽게도 저는 그것을 구분도 잘 하지 못하고 한 번 생각에 갇히면 잘 빠져나오지 못합니다. 올해 초부터 글로 많이 적었던 어디까지 동의가 되었는가? 에 대한 고민도 여기서 기인한 것 같아요. 저란 사람은 정답이 정해져 있는 곳, 의견 불일치가 일어나지 않는 곳에서만 있었던 걸까요. 맙소사. 너무나 오랜 시간을 그렇게 뇌 빼고 편하게 살았나 봅니다.
  • 깃헙 MCP 서버가 프리뷰로 공개되었습니다. 이걸로 뭘 할 수 있을까. 당장 생각나는 것만 떠올려봐도 워크플로우를 AI가 생성하고 LLM 학습에 포함되지 않았던 최신 best practice 같은 걸 더 잘 리트리브 할 수 있을 거 같아요.

오늘의 토막글 81

  • 예전에 글로 썼던 것처럼, 주장에는 대개 현상과 근거 그리고 처방이 따릅니다. (A는 어떤 상황이다. B하기 때문이다. 그러니 C 해야 한다)그런데 보통 이 3가지에 모두 동의하는 사람들은 곧잘 없어요. 현상과 근거를 정말 잘 짚어내더라도 처방에 동의되지 않으면 주장에 힘이 빠지는 거죠. 오늘 유진님과 이야기 하다 제가 스스로 처방을 내리는 부분에 문제가 있다는 걸 깨달았고, 앞으로는 팀을 리딩하는 입장이 아니라면 처방은 정말 조심히 내려야겠다는 생각을 하게 되었습니다. 꼭 처방을 내려주지 않아도 팀이 놓쳤거나 합의된 부분을 되짚는 것만으로 생산적인 논의는 충분히 가능하다고 생각했거든요. 유진님 덕분에 한결 가벼운 마음이 들었습니다.
  • 그럼 어떻게 해야 하는가? 결국엔 질문을 더 잘하자로 귀결되었어요. 이게 머리로만 아는 것과 실제로 적용하는 것은 사뭇 다르단 생각이 들어요. 대안도 없이 반대 의견을 내는 게 조심스러워서 저도 모르게 처방을 내렸거든요. 이제는 질문 레벨에서부터 사고의 흔적을 먼저 남기자고 다짐했습니다. 예를 들면 ‘A제품이 있는데도 우리 제품을 사람들이 쓰려면 이런 게 있어야 말이 되지 않을까?’ 보다는 ‘A 제품이 있는데 왜 굳이 우리 제품을 써야해?’ 를 먼저 던지는 거죠.
  • 저녁 약속으로 반 년동안 못 보았던 친구들을 만나 수다를 떨었습니다. 지난 날을 되돌아보며 웃을 수 있어 행복했어요.

오늘의 토막글 82

  • 러스트(Rust)는 상당히 신박하게 동작합니다. 우선 메모리에 대한 소유권 개념이 있어요. 변수가 할당되고, 함수 스코프가 종료되면 이 소유권도 함께 소멸되는 구조입니다. 게다가 소유권 이전도 할 수 있어요. 하지만 이 메모리를 변경할 수 있는 권리는 단 한 개의 참조 만이 행사 할 수 있죠. 물론, 난 너의 메모리에 손대지 않을게! 라고 맹세한 친구들은 얼마든지 메모리를 들여다 볼 수 있지만요. 이 친구들이 살아가는 세상은 굉장히 엄격하고 명확합니다.
  • 이를 통해서 프로그래밍 관점에서 발생하는 여러가지 문제들을 원천적으로 봉인하는 데요. 예를 들면 단 한개의 참조만이 메모리를 변경할 수 있기 때문에 동시성 이슈에서 자유롭습니다. 게다가 C/C++ 에서 발생하는 댕글링 포인터(dangling pointer) 문제도 발생하지 않아요. 요것은 변수의 라이프 사이클을 러스트 컴파일러가 추론한 다음에 원래 주인이 죽고 난 뒤에 다른 친구가 그 메모리를 가질 것 같다 싶으면 컴파일 시점에 에러를 띄워주기 때문이에요.
  • 보면 볼수록 매력적인 언어라는 생각이 듭니다. 그럼 이 러스트의 단점이 뭘까요? 어려운 건 둘째치고, 컴파일러가 하는 일이 많아서 컴파일이 매우 느리답니다.

오늘의 토막글 83

  • NATS 라는 분산 메시징 시스템을 알게 되었습니다. Go 언어로 만들어졌고, 아주 경량화된 분산 메시지 큐에요. Kafka 가 디스크에다 데이터를 영속화 한다면, NATS 는 인메모리 중심으로 데이터를 서빙합니다. 그 대신 브로커에서 중간 저장되지 않고 바로 전달되기 때문에 카프카보다 훨씬 빠르고요.
  • 이벤트 소싱 용으로도 좋을까 하고 봤었는데, 그 역할에는 아무래도 영속화되는 부분 때문에 카프카가 더 좋아보이긴 했습니다. 이벤트 소싱에서는 replay 가 또 장점 중에 하나니까요. NATS는 스트리밍 방식이지만 기본적으로 pub/sub 구조에 가까우므로 최신 정보 갱신이 중요한, 이를 테면 주식 가격, 현재 온/오프라인 접속 상태, 웹소켓 관리, 클라우드 컨피그 같은 곳에서  유용할 것 같습니다.
  • JetStream 이라는 확장 기능을 설치하면 디스크 영속화를 비롯해 메시징 큐에서 중요한 재시도, 순서 보장 같은 기능도 사용이 가능해서, 데이터 누락이 치명적이지 않은 일부 케이스를 제외하곤 거의 필수적으로 설치해야 한다고 봐야겠네요.

오늘의 토막글 84

  • 슬랙 단축키를 알게 되었습니다. Ctrl + Cmd + 좌우 화살표 로 슬랙 버티컬 패널을 오갈 수 있고, 패널 안에서 위아래 화살표로 어디든지 갈 수 있습니다. 또, Cmd + 숫자는 워크스페이스를 이동하지만, Ctrl + 숫자는 홈, DM, 내 활동 등을 선택해서 오갈 수 있어요. 더 정밀하게 타고 들어가고 싶으면 탭을 쓰면 되구요, 메시지 전달하고 싶거나 링크 따는 것은 각각 F, L 단축키로 가능합니다. 요 단축키들을 알게 된 뒤론 슬랙 쓸 때 마우스를 최대한 안써보려고 하고 있습니다.
  • 주말 동안 서점에 가서 경제 기초와 관련된 책들을 샀습니다. 머릿속에 떠오르는 궁금증들을 해결해주는 책들을 보면 되게 반갑더라구요. 원래 서점 거들떠도 안보던 사람이었는데 그 땐 아마 머릿속이 텅 비었어서 그랬던 것 같습니다.
  • 경제 지식이 짧아, 이제서야 M0(본원), M1(협의), M2(광의) 통화에 대해 알게 되었습니다. M뒤에 붙은 숫자가 커질 수록 의미하는 통화량을 더 포괄적으로 해석합니다. M0는 중앙은행이 찍어낸 실제 돈, M1은 시중에서 즉시 소비가 가능한 돈(현금 + 수시 입출금), M2는 거기에 더해 신용(수신 자산)까지 포함합니다. M0, M1, M2 의 변화량으로 시중에 돈이 얼마나 풀렸는지, 사람들이 돈을 어디다 묶는지 등을 파악할 수 있겠더라구요. 자본주의는 신용이 베이스가 된다는 것이 볼 수록 와닿습니다.

오늘의 토막글 85

  • 경제 지표들은 서로 복잡하게 상호 작용하기 때문에 어떤 경제 현상에 대해서 원인을 결정 짓거나 가장 큰 영향을 미치는 요소를 특정하긴 어렵습니다. 이렇게 여러가지 요소가 결합된 복합문제를 잘 푸는 기술이 있어요. 바로 인공신경망입니다. 미적분을 수도 없이 반복하면서 최적의 방정식을 구하는 것이죠. 아는 사람 중에 10년 전에 시도하던 친구가 있었는데, 지금 다시 시도하면 어떨까 싶긴 하네요. 하지만 제 수준에선 애당초 어떤 팩터들이 있는가를 정리하는 것이 우선이겠어요.
  • tfs 와 qos 간의 관계를 알게 되었습니다. qos 로 설정한 리소스가 어떻게 코어를 할당하는가? 하는 의문이 있었는데 코어 개수가 아니라 시간을 할당하는 거였어요. 그래서 CPU 설정이 0.5 일 때 이것은 코어를 절반만 사용하겠다는 것이 아니라 tfs가 설정한 CPU 할당 싸이클의 절반의 시간동안 CPU를 쓰도록 허락해준다는 뜻입니다. 그 이상을 쓰려고 하면 쓰로틀링에 걸리게 됩니다. 특정 시점에 CPU 메트릭을 조회했을 때 100%가 나오지 않는 이유는 바로 이 쓰로틀링 때문입니다.
  • 구글 파이낸스를 들어가보면 주가 정보, 환율 정보, 암호화폐, 선물 시장에 대한 준 실시간 데이터를 얻을 수 있습니다. yahoo 주가 데이터는 15분 딜레이가 있지만 이 친구는 그것보단 나은 것 같아요.

오늘의 토막글 86

  • 구현 전 글쓰기가 큰 도움이 되고 있습니다. SRS(요구사항), ADR(의사결정록), TSP(테스트 전략), MSP(모니터링 전략), KPT(회고) 이렇게 5가지 항목을 간략히 적는데요, 실수가 줄어듦을 실감하고 있어요. 아무리 익숙해져도 실수를 범하는 태생을 도저히 고칠 수가 없어서 좌절했었는데 빛이 보이는 것 같습니다. 시간이 조금 더 소요되긴 하지만요.
  • 기술 면접 시 면접관 입장에서 까다로운 부분은 면접자가 자신만의 생각을 고집할 때와 면접자가 아무런 대답도 하지 못할 때인 것 같습니다. 전자는 면접관이 면접자의 맥락을 제대로 이해하지 못했거나 면접관 부터 이미 생각이 갇혀있을 위험이 있고, 후자는 어디까지 힌트를 주어야 역량을 최대한 가늠할 수 있을까에 관한 딜레마가 있습니다. 후자는 글 쓰면서 생각해봤는데, 그냥 2-3분 정도 기다리다 답 없으면 힌트는 다 드리고 더 다양한 상황까지 유도해내는 게 더 좋은 것 같습니다.
  • 기축통화는 정말 개사기입니다. 미국채를 거의 디폴트 직전까지 발행하고 관세 정책이나 금리로 인플레를 유발하고 있는 걸 보면 미국채를 들고 있는 다른 나라들은 살살 녹아내리는 채권 가치에  피눈물을 쏟고 있을거에요. 다른 나라가 이런 짓을 벌이면 그 나라의 신뢰와 채권 가치가 떨어지겠지만 기축통화국인 미국채는 그러기 쉽지 않습니다. 과거 프랑스 재무장관이었던 지스카르는 이를 두고 ‘지나친 특권’이라 말하기도 했습니다

오늘의 토막글 87

  • 다른 사람에게 돈을 빌려준다는 것은 신용을 주는 것입니다. 너 나중에 갚을거지? 하고 믿는 거죠. 그래서 은행에서 여신(신용을 수여한다 = 돈 줄게), 수신(신용을 수신한다 = 돈 받을게) 하는 거고요. 하지만 경제 상황은 1:1 에서만 발생하는 게 아니니, 스파게티처럼 관계가 얽히고설키면서 신용이 팽창합니다. 돈 빌린 사람이 다른 사람에게 그 돈을 또 빌려주는 거죠. 이는 곧 현금보다 부채가 엄청나게 늘어남을 뜻합니다. 신용을 준 채권자는 돈을 잃을 위험을 감수하는 대가로 이자를 받아야 하는데요, 이 이자를 감당하는 것은 바로 생산성입니다. 내가 무언가를 생산해 가치를 창출하고 그 가치의 일부를 이자로 반납함으로써 상황 유지가 되는 거죠. 이것을 1:1을 M:N으로 관점을 바꿨던 것처럼 거시적으로 시야를 확장해보면 한 국가의 생산성이 부채를 감당할 만한가? 라는 질문을 떠올려 볼 수 있습니다. 국가 내부적으로 신용이 팽창되는 속도를 생산성이 받쳐준다면 모두가 행복합니다. 자산 시장에 활기가 찾아오고 더 큰 신용으로 더 많은 일을 해볼 수 있죠. 빌린 신용으로 그 이상의 생산성을 만든다는 거니까요. 그런데 지탱하지 못하게 되는 순간 모두에게 재앙이 찾아옵니다. 한국은 어떨까요? 초고령화를 비롯한 여러가지 이슈로 잠재성장률이 1%대에 진입하고 있고, 기업 실적 악화로 법인세수가 급감하고 있습니다. 이 상태로 언제까지 괜찮을지 잘 모르겠어요.
  • 예전엔 남들이 아는 무언가를 내가 모른다는 사실이 너무 두려웠습니다. 무엇이 그렇게 두려웠을까요. 남들의 부정적인 평가, 인정받지 못할 것 같은 두려움, 결코 따라잡지 못할 것 같은 좌절감… 극한의 궁지에 몰렸을 때 택했던 건 오늘의 허접한 나의 토막글이었고 결과적으론 두려움을 극복하는 데 도움을 많이 받게 된 것 같습니다. 모르는 걸 찾으면 적어도 글 쓸 거리가 생기니까요. 의외로 매일 새로 알게된 걸 쓰는 게 쉽지 않더라구요
  • 네트워크 효과를 이루어 내기 위해 노드를 늘리기 보단 링크를 늘리는 데 집중해야한다는 글을 보았습니다. 일리가 있었어요. 네트워크의 가치가 참여자 수의 제곱에 비례하는 건 참여자끼리 만들어 낼 수 있는 관계의 수를 계산한 데서 만들어진 논리거든요. 1-2개 짜리 연결을 가진 5천명 보다 10개 연결을 가진 1천명이 훨씬 더 가치 있다고 보는 거죠. 페이스북이 ‘친구 초대하고 혜택받기’ 가 아니라 ‘알 수도 있는 친구’ 기능을 런칭한 이유가 여기에 있다고 합니다.

오늘의 토막글 88

  • namecheap 이라는 서비스를 알게 되었습니다. 그런데 도메인 가격만 두고 보면 cloudflare 가 더 저렴한 느낌이에요. custom email address 을 만들고 싶어서 여러가지 비교해보는 중입니다.
  • 지원자에게 지나치게 구체적인 지식을 물어보거나, 시종일관 평가하는 자세로 일관하는 건 면접관으로서 별로 좋지 못한 것 같습니다. 지원자가 뇌정지가 온 것 같으면 그걸 잘 풀어주는 것은 면접자의 역량이기도 하지만 어찌보면 또 면접관의 역량에도 해당되는 것 같아요. 지금까지 보았던 좋은 뇌정지 해제 방법은 면접자가 머리를 굴릴 수 있도록 요구사항을 정돈하여 다시 알려주거나, 면접자의 말을 틀렸다고 지적하기 전에 너무 이상한 대답만 아니라면 일단 수긍하는 것을 보여주는 겁니다. 함께 일하고 싶은 사람을 뽑는 자리이니만큼, 지원자도 그 기운을 느낄 수 있어야 좋은 면접 경험으로 남게 될 것 같아요.
  • 비지니스 기회가 될 것 같은 아이디어들은 생각이 날 때마다 메모해두는데, 썩은 건 버리고 남은 걸 세워보니 12개 정도 됩니다. 그런데 오늘 하나를 또 잃어버릴 위기에 처했어요. 아이디어 중 하나가 ‘의료 관광을 오는 해외 방문객들을 위해 국내 병원 진료 예약을 해주는 서비스’ 가 있었거든요. 우연찮게 팀에서 새롭게 하려고 하는 방향성과 파이가 곂칩니다. 타깃을 완전 호화로운 슈퍼리치로 잡아 더 니치하게 파고들면 어떨까 싶기도 하네요. 뭐 지금 당장 해볼 건 아니지만… 타깃을 완전 호화로운 슈퍼리치로 잡아 더 니치하게 파고들면 어떨까 싶은 망상에 잠깐 젖어보았습니다.

오늘의 토막글 89

  • M2 통화량 증가 추세를 보고 시중의 자금 경색 현상을 일시적으로 완화시킬 수 있겠다고 기대하는 것은 얼핏 맞는 말 같지만, 경우에 따라 틀릴 수도 있습니다.
  • M2 통화는 은행채나 양도성 예금 증서를 포함하기 때문입니다. 은행이 돈이 모자라 채권을 발행하면, 실제로 시중에는 자금이 부족한데 M2 통화는 증가 추세로 집계되어 버립니다. 그래서 M1에 비해 M2가 너무 크게 증가 한 것은 아닌지, 은행의 채권 발행량이나 예금 증가율을 같이 따져볼 필요가 있습니다.
  • 사람들과 이야기 나누다 문득 제가 해결책이 정해져 있거나 이미 잘 정의된 문제보다 정의되지 않은 문제를 푸는 것을 더 좋아한다는 사실을 깨달았습니다. 그래서 비지니스 세계가 그렇게 멋져 보였나 봅니다.

오늘의 토막글 90

  • 최근에 개인적으로 해오던 일을 정리하는 중에 있습니다. 그러면서 마음 정리도 하고 이런 저런 상상들 하며 게으름을 피우고 있었어요. 조만간 다시 열심히 살아볼까 합니다.
  • 랭킹 정보가 필요하면 관성적으로 레디스의 zset을 떠올리고 있었는데, 유저 당 할당되는 내역에 대해 랭킹이 필요한 경우에는 그 방법을 쓰지 못한다는 것을 깨닫고는 아차 싶었습니다. zset 은 오버헤드가 너무 커서 백만 단위로 사용자가 늘어나면 메모리가 꽤나 곤란하거든요. 정합성이 크게 중요하지 않은 상황이라면 비동기로 DB에 업데이트 하고 캐시 어사이드로 처리하는 걸로 충분할 것 같습니다.
  • 책 ‘지금 당장 돈의 흐름 공부하라’를 다 읽고서 케인즈의 ‘고용 이자 및 화폐의 일반이론’ 과 폴 볼커의 ‘미스터 체어맨’을 주문했습니다. 하고 싶은 일도 많고 해야할 일도 많아 큰일이네요.

오늘의 토막글 91

  • 바꿀 수 없는 것은 받아들이는 평온을
  • 바꿀 수 있는 것을 바꾸는 용기를
  • 그리고 그 둘을 분별할 지혜를

오늘의 토막글 92

  • 앤캐리 청산은 쉽게 말해 투자자들이 저금리인 엔화를 빌려서 고금리 시장의 자산을 구매했다가, 이 포지션을 청산하고 빌린 엔화를 상환하는 과정을 의미합니다. 이 트레이드는 오랫동안 초저금리를 유지했던 일본 앤화로 자금을 조달하여 금리차익(두 시장 사이의 금리차에서 오는 이익)과 환차익(환전 시 환율 변동에서 오는 이익)을 동시에 노릴 수 있었기 때문에 매력적인 투자 전략이었습니다. 그런데 일본이 금리를 인상하려는 움직임을 보이거나 글로벌 경제가 불안해지면, 투자자들은 손실을 피하기 위해 고금리 시장의 자산을 매도하고 빌린 엔화를 상환하려는 움직임이 대규모로 발생합니다. 이 과정에서 엔화 가치는 급등(엔화를 구해야 상환이 가능하니 수요가 증가해서)하고 투자했던 고금리 통화와 자산 가치는 급락하게 됩니다. 여기서 문제는 조금이라도 더 늦게 파는 사람은 가치가 떨어져버린 자산을 팔아 비싸진 앤화를 갚아야 하니 누군가 팔기 시작하면 도미노처럼 매도에 관성이 붙어 규모가 더 빨리, 더 많이 커지게 된다는 겁니다.
  • 이 앤캐리 트레이드는 주로 글로벌 투자자들이 쓰는 전략인데, 그 가치가 무려 약 1200조원에 달한다고 합니다. 과거 금리가 높았던 한국 주식시장의 경우 예전부터 앤 캐리 청산이 있을 때마다 주가가 급락하는 사태를 보여왔구요. 작년 1월에 마이너스 금리에서 제로 금리로 전환되면서 앤캐리 청산이 대두되었고, 트럼프 관세 정책으로 글로벌 경제 전망이 불확실해 지면서 더더욱 서로 눈치를 보는 상황이 연출되고 있는 것 같습니다. 일본도 30년 침체를 벗어난 것만 같이 경제 신호가 여러가지로 좋아지고 있지만 금리를 쉽게 못올리고 있는 것도 이런 이유도 있을 거에요.
  • 변동성을 가지는 시장에서 매매 관성이 붙는 것은 일반적인 현상이지만, 앤 캐리 트레이드는 통화와 자산 시장이 동시에 영향을 받기 때문에 돈의 흐름이 이 시장 타고 그 다음 저 시장 타고 하는 게 아니라, 급격한 물살에 휘말려 여러 시장을 한 번에 타격할 가능성이 높습니다. 그래서 특히 더 위험하다고 해요.

오늘의 토막글 93

  • Godot 이라는 오픈 소스 게임 엔진에 대해 알게 되었습니다. Unity와의 큰 차이점 중 하나는 unity와 달리 일일이 gui에서 에셋을 연결해주지 않고 코드로 연결할 수 있다는 점입니다. 코드는 C#이 아니라 GDscript를 쓰는데 파이썬과 문법이 비슷하네요. 3D가 약하다는 평이 있어요.
  • TF-IDF 는 전통적인 문서 벡터화 기법입니다. 단어 빈도와 역빈도를 곱해 그 문서가 벡터 공간에 어디 쯤에 있다를 나타내는 행렬을 산출하는 방식인데요. BERT 가 딥러닝에서 더 많이 쓰이긴 하지만, 해야 하는 일이 그리 복잡하지 않다면 전통적인 기법을 사용하는 것도 방법이 될 수 있겠어요.
  • 기껏 비동기로 비싼 계산을 빼놨더니 또 다른 동기 요청과 경쟁 조건이 생겨서 결국 비관락을 잡게 되었습니다. 다른 서버들을 여러번 호출해서 가용성이 낮은 상황에 일관성까지 높이려 하다보니 어려운 문제가 되었네요.

오늘의 토막글 94

  • 잠자는 자세가 엉망이었다 싶었는데 목에 담이 쎄게 왔습니다. 거북목이 있으면 담에 더 잘 걸린다고 해요. (특히 거북목은) 목을 지탱해주는 신경과 근육들이 낮 동안 긴장해서 쉬어줘야 하는데, 밤까지 계속 고생 시키면 담이 오는 거죠. 담을 푸는 것은 찜질이나 마사지 이런 것도 좋지만 경험상 별로 효과적이지 않습니다. 빨리 벗어나려면 우선 고통을 주는 근육들과 연결된 신경(겨드랑이에 있대요)을 풀어줘야 해요, 그건 의외로 목이 아닌 팔과 연결되어 있습니다. 그래서 아픈 쪽 팔을 뒤쪽으로 넘겨 20초 정도씩 자세를 유지하며 신경을 이완시켜주는 것이 좋습니다. 뒤쪽으로 넘길 때는 팔꿈치 120도 각도를 유지한 채로 뒤로 넘기기, 허리 손바닥으로 짚고 최대한 뒤쪽으로 팔꿈치 보내기, 아래서부터 뒤쪽으로 팔 들어올린 채 유지하기 이렇게 3가지 방식으로 진행합니다.
  • 파티션이 리벨런싱 되는 시점에 랙이 있는 상황에서 순서 보장을 하는 방법이 무엇인지 고민하다가, 결국 데이터 유실이나 순서 파괴를 감수하는 게 더 저렴하다는 생각을 하게 되었습니다.
  • 경제 관련된 뉴스나 영상이 예전엔 무슨 말인지 하나도 모르겠고 재미도 없었는데, 이제는 조금은 알아 듣게 된 것 같습니다. 예를 들어 ‘장단기금리차 역전’ 이라는 단어를 보면 바로 국채를 떠올리게 되었습니다. 장단기 금리차 역전은 여러 가지 이유로 경기 침체가 올 것으로 예상되면 보다 안정적인 장기 국채의 가격이 오르고 금리가 하락하면서 장기채 금리가 단기채 금리보다 작아지는 경우를 의미합니다.

오늘의 토막글 95

  • 케인즈의 고용, 이자 및 화폐의 일반이론 1편(1장)까지 읽었습니다. 단어들이 어려워서 한 장 한 장 넘기기가 무겁습니다. 고작 각주 따위에서 ‘독자들은 내가 이러이러한 지점에서 사용자비용을 공제했다는 것을 눈치챘을 것이다’ 하는 데 억울하지만 전혀 눈치 못챘고, 사용자 비용이 뭔지도 몰랐습니다. ㅋㅋ 1편에서는 고전경제학파들의 이론적 뼈대가 되는 공준이 얼마나 순진한지 대차게 까내리는 한 편, 유효수요가 무엇인지 정의하며 앞으로 펴낼 논리의 토대를 다집니다. 그런데 여기서 정의하는 내용이 현대 거시경제의 기반이라 매우 당연하게 느껴지고, 고전경제학은 왜 그렇게 생각했던 거지? 하고 의구심을 갖게 하는 게 쏠쏠한 재미를 줍니다.
  • 구글 계정을 새로 만들 때 식상한 gmail.com이 아니라 커스텀 도메인을 쓰고 싶어서 예전부터 봐오던 도메인을 새로 구입하고 도메인 레코드를 연결했는데, 인증메일이 오지 않습니다. 테스트로 메일 주고받는 것 까지 다 해봤는데도요. 시간 날 때 원인을 좀 알아봐야겠어요.
  • 면접관 입장에서 내가할 시스템 디자인 질문에 답이 스스로 떠오르지 않으면 질문이 망설여지는데, 그래도 그냥 해버리는게 낫겠다는 생각이 드네요. 같이 문제를 풀어가면서 합의된 해결책을 도출하는 과정을 보는 거니까요.

4월 동안 쓴 TIL

Kotlin 에서 object 와 companion object 의 차이

  • object와 companion object 는 JVM 클래스 수준에서 static 처럼 동작함
  • JVM 은 기본적으로 실제로 사용되지 않으면 초기화하지 않는 lazy 전략을 택하기 때문에 해당 객체나 값이 실제로 사용되지 않으면 스태틱 메모리 영역에 할당(초기화)하지 않음
  • 또한 초기화 과정은 thread safe 하게 이루어져서 큰 문제 없이 싱글턴 객체로 관리됨
  • thread safe 한 이유는 monitor lock 을 사용하기 때문(JVM이 직접 관리하는 고수준 lock - synchronized)
  • 따라서 object의 경우 이것을 처음으로 사용되는 시점에 스태틱 메모리 영역에 할당됨
  • class 내부에 선언된 companion object는 해당 companion object가 쓰이지 않더라도 선언된 class 가 인스턴스화될 때도 초기화되는 차이가 있음

chacha20 암호화 알고리즘

  • 블록 암호가 아닌 스트림 암호로 설계됨
  • 블록 암호는 고정된 크기의 데이터 블록을 한 번에 처리하는 암호화 방식임. 평문을 일정한 크기의 블록으로 나누고, 각 블록을 동일한 키를 사용해 암호화함. AES, DES 가 대표적인 블록 암호.
  • 스트림 암호는 데이터를 비트 또는 바이트 단위로 연속적으로 처리함. 그래서 일반적으로 블록 암호보다 속도가 빠름
  • chacha20은 Nonce(12바이트), 카운터(4바이트), 키(32바이트)를 조합해 초기 상태를 만들고, 이를 변환(20번의 행렬 연산 라운드를 거침, 그래서 이름이 chacha20임)해 키스트림을 생성한 후 평문과 XOR 하여 암호화함.
  • 주요 특징으로는 길이가 보존된다는 점이 있음. 예를 들어 평문이 100바이트면 암호문도 100바이트가 됨. 단, 암호화만 제공하고 무결성은 제공되지 않아서 보통은 Poly1305와 같은 인증 알고리즘과 함께 사용됨. 그렇게 되면 인증 태그(16바이트)가 추가되어 전체 암호문 길이가 늘어날 수 있음.
  • 현대적인 프로토콜(TLS 1.3, SSH 등)에 널리 사용됨.

스택이 무한하다면 힙이 필요 없을까?

  • 결론은 그렇지 않음. 힙과 스택은 사용 목적이 다르기 때문
  • 스택은 함수 콜이 일어날 때마다 프래임이 쌓이고, 그 안에 할당된 지역 변수들은 프레임이 끝날 때 메모리에서 해제 됨
  • 그래서 함수 콜 라이프 사이클에서 벗어나 생명이 유지되어야 하는 메모리의 경우에는 별도 저장될 공간이 필요하고 그게 힙임
  • 멀티 스레딩 환경에서 어떻게 동작할지도 고민해봄직 함
  • 스레드마다 로컬 변수를 가지게 구현하긴 쉽겠지만 특정 객체를 동시에 업데이트 하는 경우 스택주소를 넘겨주어야할 텐데, 그 주소가 포함된 스택 프레임이 정리 되었는지 안되었는지를 계속 검사하는 로직이 필요함

업스트림이 아닌 다운스트림에서 응답 속도에 영향을 주는 경우

  • 대부분의 응답 속도와 관련한 부분은 업스트림에서 데이터 응답을 늦게 주었기 때문임
  • 그런데 다운스트림에서도 응답 속도에 영향을 줄 수 있음
  • TCP 에서는 네트워크 성능을 감안해 클라이언트가 얼만큼의 데이터 사이즈를 받을지에 대한 유량제어(flow control)을 하게 되는데, 네트워크 통신이 오감에 따라 이 슬라이딩 윈도우(Sliding window) 사이즈는 동적으로 조절될 수 있음
  • 이 슬라이딩 윈도우 사이즈가 작다면 업스트림이 빠르게 응답을 준다고 하더라도 다운스트림에서 이 응답을 받는 게 느려질 수 있음

istio 에서 timeout, rate limit, circuit break 설정을 쓸 수 없는 이유

  • Istio 에선 마이크로 서비스 옆에 사이드 카를 달아 네트워크 트래픽을 모니터링하고 관리할 수 있음
  • 이 사이드카를 통해 timeout 설정이나 rate limit, circuit break 설정도 지원하지만 실제로는 쓰기 힘듦
  • 그 이유는 결국 호스트 단위로 해당 설정들이 적용되기 때문임.
  • 예를 들어 특정 호스트의 특정 API 만 실패하는 경우일 때 서킷이 열리면서 해당 호스트의 정상적으로 응답 가능한 다른 API 응답을 못받게 될 수 있음
  • rate limit 이나 timeout 과 같은 경우에도 host 단 보다는 api 단에 적용하는 게 더 적절한 설정임.
  • 최신 버전에서는 api path 단위로 설정이 가능해졌으나 api path 가 추가되는 변경일 때는 결국 애플리케이션이 변경되었기 때문일 가능성이 높아 굳이 해당 설정을 쓸 필요가 없음. 인프라가 서비스에 대해 너무 깊이 알게 되기 때문임.
  • 모노레포이고, 이런 인프라 관련된 설정까지 한 번에 수정이 편리하다면 고려해봄직함.

Look aside 캐시가 Write through 캐시보다 더 좋은 경우

  • Look aside 캐시는 조회 시 값이 없다면 그 때 DB를 조회해 캐시에 값을 채움
  • Write through 는 변경이 있을 때 DB와 캐시를 동시에 갱신하고 조회시에는 캐시에서 먼저 읽음
  • 사실 상 조회 시 캐시를 먼저 읽는 것은 동일한 데 Look aside 가 write through 보다 나을 수 있을까?
  • Write through 는 쓰기가 발생할 때마다 캐시를 갱신하므로 보통 TTL을 설정하지 않음
    • 따라서 한 번 갱신되고 이후에 조회가 거의 되지 않는 데이터도 캐시에 계속해서 유지될 가능성이 있음
  • 또, Write through 는 모든 쓰기마다 캐시까지 갱신하므로 쓰기 부하가 많아지고, 캐싱에 실패하면 정합성이 깨짐
  • 그러나 Look aside 는 쓰기 실패하더라도 다음 시도 때 캐싱을 재시도 하므로 정합성을 확보하기 더 쉬움
  • 그래서 다음과 같은 경우에는 Look aside 방식이 더 좋음
    • 데이터를 stale 해도 되는 경우, 정합성이 크리티컬하지 않은 경우: 로그인한 유저 정보
  • 다음과 같은 경우에는 Write through 방식이 더 좋음
    • 항상 최신 데이터가 보장되어야 하고 정합성이 중요한 경우: 실시간 뱃지 상태

Kafka fetch 와 poll 의 차이

  • Kafka 클라이언트는 내부적으로 Fetcher 라는 컴포넌트를 가짐
  • fetch 는 백그라운드에서 내부적으로 브로커의 데이터를 미리 받아오는 것
  • fetch: Kafka -> Consumer 내부 버퍼
  • poll은 미리 받아온 내부 버퍼에서 실제 어플리케이션에 쓰기 위해 데이터를 가져가는 것
  • poll: Consumer 내부 버퍼 -> 사용자 어플리케이션
  • 컨슈머가 poll 을 일정 시간 호출하지 않으면 컨슈머가 죽은 것으로 간주하고 리벨런스를 발생시킴
  • 리벨런싱은 비용이 굉장히 크기 때문에 카프카 설정을 최적화해서 최대한 리벨런싱이 발생하지 않도록 해야 함

CFS(Completely Fair Scheduler)

  • 리눅스의 기본 CPU 스케줄러로, 모든 프로세스가 공평하게 CPU 자원을 나눠쓰도록 스케줄링함
  • 여기서 공평하다는 의미는 모든 프로세스/스레드가 동일한 실행 시간을 가지도록 CPU 시간을 분배한다는 뜻
  • 이를 위해 프로세스마다 Virtual runtime(가상 실행 시간)을 기록하고, 시간을 덜 쓴 프로세스가 우선 순위를 갖게 됨
  • k8s와 같은 멀티테넌시 환경에서 qos 설정은 바로 이 cpu.cfs_quota_us, cpu.cfs_period_us 설정을 내부적으로 사용함
  • 이를 통해 특정 프로세스가 과도하게 CPU를 점유하는 것을 막음

FluentBit

  • 로그 수집/가공/전송하는 경량 로그 파이프라인 도구임
  • 가볍고 빠르고 유연하기 때문에 K8s 환경에서 거의 표준처럼 쓰이고 있음
  • FluentBit은 보통 DaemonSet 형태로 설치되어 컨테이너 로그를 수집하고, pod 이름, namespace, 라벨 등 메타데이터를 붙여 elastic, loki, cloud watch 등으로 로그를 전송함
  • 즉, 컨테이너가 남긴 stdout 로그를 읽어들여 메타데이터를 붙여 로그 유실없이 메모리/디스크에 버퍼링해서 전송해주는 로그 전송기임

카프카 토픽 리텐션

  • 카프카 토픽을 얼마나 가지고 있을지에 관한 설정임
  • retention.ms 옵션으로 시간 설정이 가능함 /혹은 retention.bytes 로 용량 기준으로 설정도 가능함
  • 토픽마다 개별적으로 retention 을 설정할 수 있음. 혹은 브로커 단위로 설정도 가능함.
  • 카프카 클러스터를 운영하면서 사용하는 kafka-config.sh 을 통해 설정하게 됨
  • 리텐션을 줄이게 되면 디스크 공간이 절약되고, 브로커 성능이 안정 되나 장애 복구(offset rewind)가 그만큼 취약해진다는 단점이 있음.

X-B3-TraceId

  • 분산 트레이싱 시스템에서 사용되는 HTTP 헤더이고, 여러 서비스 간의 요청 흐름을 추적하기 위한 고유 식별자임
  • 이름이 B3인 이유는 Big Brother Bird (Zipkin의 원 프로젝트 이름)로 Twitter에서 만든 Zipkin 트레이싱 헤더 포멧 명세이기 때문
  • Zipkin 은 너무 예전에 만들어졌었고 대규모 서비스에서는 성능이 떨어져서 최근엔 OpenTelemetry가 더 많이 쓰임
  • B3 Trace Id 의 생성 주체는 UUID 같은 걸 사용하여 충돌 가능성을 해소함

redis의 BitField command

  • 메모리를 효율적으로 사용하기 위해 bitmap 형식으로 데이터를 관리함
  • 예를 들어, 이벤트 참여자수를 유니크하게 계산하기 위해 사용.
  • 만약 이벤트 참여자수 100만명을 boolean setnx 로 카운트 한다고 했을 때 set 을 이용해 boolean 값을 저장하게 되면, redis 내부적으로 String 처리되므로 약 56바이트 * 100만 = 56MB 를 차지하는 반면, (키도 100만개 생성하게 되어 전부 메모리를 차지)
  • hash table 을 사용한다고 했을 때는, 키는 단일키지만, 숫자가 전부 4바이트 씩 계산되어 저장되므로, 약 30MB를 사용하게 됨
  • bitmap key 로 연산하는 경우 100만 비트 = 122KB 정도만을 사용함. 유저 ID의 최대값(100만)이 크기를 결정하기 때문임. (+단일 키)
  • bitmap 중 특정 offset 으로도 연산을 진행할 수 있는데 이것이 BITFIELD 이고, SET과 마찬가지로 O(1)의 시간복잡도를 가진다.
  • bitfield 는 특정 offset으로부터 범위를 설정하여 정수로 읽어들일 수도 있음

AI 시대에 기술 쇠퇴를 피하는 방법

  • GPS 기술의 발달로 길찾기 능력이 약해진 현대 인류에 빗대어, AI에 의존하는 개발자들에게 경고함
  • 비판적 사고가 실제로 줄었다는 연구 결과도 있고, AI가 풀지 못하는 문제를 풀 수 없다면 어떻게 할 것인가에 관한 의구심이 듦.
  • 개발자가 AI에 너무 의존하게 되면, 디버깅 포기 현상, 이해없는 복붙, 문제 해결력 약화, 기억력/회상력 감소 현상을 보임
  • 따라서 때로는 고생도 필요함을 이해하고 기본기를 탄탄하게 쌓아야 함
  • 즉, 메타인지가 더욱 중요해짐. 내가 모르는 것을 AI 에게 시키지 말고, 학습의 기회로 삼을 줄 알아야 함

TF-IDF(Term Frequency-Inverse Document Frequency)

  • TF-IDF 는 정보 검색과 텍스트 마이닝에서 문서의 중요도를 평가하는 통계적 방법으로, 특정 단어가 문서 내에서 얼마나 중요한 지를 수치화하기 위해 사용됨.
  • 이 수치는 단어 빈도(TF) x 역문서 빈도(IDF) 로 구함
  • 역문서 빈도는 전체 문서 집합에서 얼마나 희소한지를 나타냄, 예를 들어 ‘그리고’는 여러 문서에 자주 등장해서 덜 중요하다고 가정함
  • 뉴스를 클러스터링할 때 이 기법이 쓰일 수 있음. 불용어 제거/어간 추출/ 토큰화 한 뒤 TF-IDF 행렬을 생성하고, 유사도를 계산 한 뒤 클러스터링(K-means) 하여 군집화 함
  • 이렇게 했을 때 구현은 쉽지만, 문서 길이에 따른 편향이 있는 점, 단어의 의미적 관계를 고려하지 않음(유사어, 동의 구분 못함) 등의 문제가 있음
  • 이 중 문서 길이에 따른 편향을 고려햐여 TF-IDF 를 구하는 방식은 BM25임

Zero payload vs Full payload

  • 이벤트 드리븐 아키택처에서 이벤트에 payload 를 id 만 붙이는 게 zero payload, 데이터를 fully 전달하는 게 full payload 방식임
  • zero payload 에서는 id 를 받으면 변경이 있었음을 알 수 있기 때문에, 사용자의 조회 시점에 업스트림을 조회해 최신 데이터를 보장할 수 있음
  • 그러나, 변경이 많이 일어나는 경우 시스템 간 통신으로 인해 지연이 발생하고, 이벤트를 사용하고 있음에도 시스템 간 결합이 있음
  • full payload 방식도 데이터가 너무 많이 쌓이면서 컨슈머 랙이 발생하게 되면 사용자는 예전 데이터를 보게 되므로 문제가 생길 수 있음
  • 즉, 이 둘 중 하나를 고르는 것은 일관성(C), 가용성(A) 둘 중 하나를 희생하는 분산 시스템의 전통적인 문제임
  • Hybrid payload 를 구성하는 방법도 있음. 변경이 자주 일어날 데이터는 payload 로 실어보내고, 자주 일어나지 않을 것 같은 데이터는 제외하는 방식임
  • 다만 이 경우 설계가 복잡해지고, 특정 컨슈머는 이 이벤트로 충분하지만 다른 컨슈머는 그렇지 않아서 일관성이 깨지는 문제가 생김
This post is licensed under CC BY 4.0 by the author.