Show GN: 액션베이스(Actionbase) – 좋아요, 최근 본, 팔로우를 위한 데이터베이스
(github.com/kakao)좋아요, 최근 본 상품, 팔로우 기능을 위한 데이터베이스 액션베이스(Actionbase)를 오픈소스로 공개했습니다.
안녕하세요, 카카오에서 액션베이스를 함께 만들고 있는 개발자입니다.
어제 저녁 8시 (27일) Hacker News(Show HN)에 액션베이스를 올렸고, 게시 약 1시간 30분 만에 첫 페이지 1위에 올랐습니다. 사실 목표는 첫 페이지에 살아남는 거였는데, 예상보다 좋은 반응을 얻었습니다.
왜 만들었나요?
좋아요, 최근 본 상품, 팔로우 같은 기능은 서비스마다 형태는 조금씩 다르지만, 비슷한 데이터 구조와 처리 방식을 반복해서 만들게 됩니다.
문제는 팀마다 정방향/역방향 리스트, 카운트, 인덱스를 조금씩 다르게 구현한다는 점입니다. 재시도나 이벤트 순서 처리 방식도 제각각이다 보니 데이터가 미묘하게 어긋나는 경우가 생겼고, 좋아요 수 같은 집계 데이터를 만드는 방식도 서로 달라 운영이 까다로웠습니다.
어떻게 동작하나요?
액션베이스는 이를 누가(actor) 무엇을(target) 어떻게 했다(action) 라는 관계 모델로 정의하고, 쓰기 시점에 모든 걸 미리 계산합니다. 읽기는 단순 조회뿐이라 빠르고 예측 가능합니다.
프로덕션 적용
첫 프로덕션 적용은 카카오톡 선물하기 위시였습니다. 당시에는 부족한 점이 많았지만, 그 기대에 부응하기 위해 많은 것을 고쳐나갔고, 그 경험이 프로젝트를 성장시키는 계기가 되었습니다.
👉 스토리 보기
현재는 여러 카카오 서비스에서 분당 100만 건 넘는 요청을 몇 년간 처리하고 있습니다. 저장소는 HBase 기반이며, 다양한 규모에 대응할 수 있도록 경량 저장소(SlateDB 기반)도 준비 중입니다.
시작하기
Docker로 바로 실행해볼 수 있습니다:
docker run -it ghcr.io/kakao/actionbase:standalone
- 📦 GitHub: https://github.com/kakao/actionbase
- 🚀 빠른 시작: https://actionbase.io/quick-start/
질문, 피드백, 스타 모두 감사히 받겠습니다.
Q&A
Q: Redis로도 되지 않나요?
됩니다. 저희도 핫 데이터용으로 Redis를 캐시로 씁니다. 다만 규모가 커지면서 팀마다 중복 구현하고, 이벤트 순서가 꼬이면서 데이터가 틀어지는 문제를 겪었습니다.
Q: PostgreSQL/MySQL 샤딩하면 되지 않나요?
많은 팀이 그렇게 합니다. 저희가 겪은 문제는 핫 엔티티, 크로스 샤드 조회, 서비스마다 다른 캐시 전략이었습니다. 매번 샤딩 전략을 설계하지 않아도 수평 확장되는 모델이 필요했습니다.
Q: Write-time precompute가 어떻게 동작하나요?
쓰기 시점에 WAL 기록 → 락 → 상태 전이 → 카운트/인덱스 계산 → 저장 → CDC 발행. 읽기는 단일 GET이나 SCAN만 하면 됩니다.
Q: 이벤트 순서가 꼬이면?
각 mutation에 version(보통 타임스탬프)을 붙입니다. 이벤트가 like(t=100) → like(t=300) → unlike(t=200) 순서로 도착해도, version 기준으로 최종 상태가 올바르게 수렴합니다. 같은 이벤트를 리플레이해도 동일한 상태로 수렴하는 게 목표입니다.
Q: 실제 성능은?
카카오톡 선물하기 프로덕션에서 분당 100만 건 이상 지속, 피크 약 200만 건을 처리하고 있습니다. 읽기 지연은 p50 약 2~3ms, p99 약 10ms입니다. 핵심은 절대적인 숫자보다 지연이 bounded라는 점입니다. 읽기가 집계가 아닌 미리 계산된 룩업이라 데이터가 커져도 성능이 저하되지 않습니다.
Q: 어떤 유즈케이스에 적합한가요?
좋아요/리액션, 팔로우/팔로워, 최근 본 상품은 핵심 유즈케이스입니다. 추천/ML 피처는 CDC를 통해 트레이닝 데이터를 제공할 수 있지만, 추천을 직접 서빙하는 건 아닙니다. 채팅 메시지는 아마 최선의 선택은 아닙니다—페이지네이션, 검색, 스레딩 같은 다른 접근 패턴이 필요해서요. 이커머스 카트도 트랜잭션이 필요한데, 액션베이스는 크로스 엣지 트랜잭션을 지원하지 않습니다.
Q: 오버엔지니어링 아닌가요? / 큰 회사만 필요한 거 아닌가요?
맞을 수도 있습니다. 솔직히 작은 규모라면 잘 튜닝된 PostgreSQL + Redis가 맞는 답입니다. 액션베이스가 해결하는 문제들—샤딩 복잡성, 캐시 무효화, 팀 간 중복—은 상당한 규모가 되거나 여러 팀이 비슷한 기능을 만들 때 나타납니다. 저희는 그 벽에 여러 번 부딪혔기 때문에 만들었습니다. 그래서 작은 배포에서도 쓸 수 있도록 경량 백엔드(SlateDB)도 준비하고 있습니다.
감사합니다! Show HN에서 받아보지 못한 관심의 한을 여기서 풀고 있습니다.
혹시 어떤 부분이 실용적이라고 느끼셨는지 궁금합니다. 비슷한 문제 겪으신 적 있으신가요? 아니면 해당 기능 구현이 필요하신 상황인가요?
그리고 댓글 달 기회가 생겨서 말하고 싶었던 게 있는데요. 문서에는 unbounded traversal 안 한다고 적어뒀지만, bounded multi-hop은 올해 계획에 있습니다. "친구가 좋아한 상품" 같은 2-hop 쿼리요. https://actionbase.io/ko/stories/unified-graph/
어떤 점이 실용적이라고 느꼈냐면,
저 또한 비슷한 고민을 했던 경험이 있고, Redis 같은 KV 스토어를 기반으로 코드 레벨에서 추상화 레이어를 구현 해본 바가 있어, 문서가 말하고자 하는 목표와 방향성, 그리고 전체적인 구성까지 모두 매우 실용적이라고 생각했습니다.
그리고 여러 팀의 니즈와 고민을 반영해 엮어내 회사의 인터널 제품을 만들고, 오픈소스로 공개 했다는 게 멋있다고 생각합니다. ㅎㅎ
마지막으로 굳이 굳이 첨언하자면 사용하실 분들은 지금 문서로도 충분 하시겠지만, 복사-붙여넣기 수준으로 따라할 수 있는 배포 예제, 권장하는 용례나 인프라 레퍼런스를 example로 녹여내면 더 매력적일거라고 생각해요.
화이팅!
오 같은 고민을 하셨다니 진심으로 반갑습니다. 그리고, 멋있다 표현해주셔서 진심으로 고맙습니다.
말씀하신 부분 공감합니다. 저도 도구로 사용할 부분은 편하게 세팅하고, 제가 풀어야 할 문제에 집중하고 싶으니까요.
다만, 현재는 오픈소스 초기 단계고, 제한된 시간에 어떻게 이 핵심 가치를 전달할까에 초점을 맞췄습니다. 전달이 안 되면 실제 문제를 풀 수 있는 분들도 그렇지 못하게 될 테니까요. 이제 말씀하신 방향으로 진행하려고 합니다. 다만, 내부 스택인 HBase + Kafka로 갈지, 신규 개발 공수가 들어도 SlateDB + S2로 갈지는 피드백을 받아보고 싶습니다. 저희는 HBase 엔지니어들이 운영을 해주셔서 편하게 사용하고 있는데, 그렇지 못한 곳이 많을 테니까요. 의견 남겨주시면 감사하겠습니다(보팅만이라도요):
저는 말씀주신 2-hop 쿼리 같은 로드맵도 너무 매력적이라 생각하지만
지금 있는 문서에서 말하고자 하는 바를 코드같은 예제로 잘 녹여내면 훨씬 폭발적인 반응이 있을거라고 생각해요.
동의합니다. "예제로 잘 녹여내는 거요". 근데 이게 보이는 것만큼 쉽지 않더라고요 ㅠ 여러 방면으로 고민해보겠습니다. 감사합니다!
혹시 저희 동료가 열심히 준비한 https://actionbase.io/guides/build-your-social-media-app/ 인터랙티브 가이드 보셨는지 궁금합니다. 이게 그런 시도였는데요. 말씀하신 방향에 부합하는지 돌아보게 됩니다. 계속 노력해보겠습니다.
앗 그리고 새로 달면서 놓친 부분인데, 가이드뿐만이 아니라 전반적으로 문서 구성에 노력이 느껴집니다.
다만 예제로 준비된 구성을 앞서 말씀드렸던 것 처럼 git clone을 통해 쉽게 따라하게 만들 수 있다면 더 좋을 것 같아요.
이거 댓글을 달았다고 생각했는데 안 보여서 처음부터 다시 씁니다...(흑흑)
가벼운 마음으로 단 댓글에 비해 성심성의껏 응답해주시니 고맙습니다.. ㅎㅎ;;
아무튼 제가 말하고 싶었던 바는 이걸 도입해보고 싶은 작은 팀, 혹은 큰 팀 각각 환경이 굉장히 상이할 거라고 생각하고, 가벼운 마음으로 이거 한번 도입해볼까? 했을때 설득하기 제일 쉬운 형태는 팀에서 사용하는 언어로 짜여진 예제용 프로젝트라고 생각해요.
먼저 메이저한 언어들로 예제용 프로젝트를 만들고 이를 바탕으로 빠르게 시작하기를 구성한다면 훨씬 가벼운 마음으로 읽어볼 수 있고, git clone 으로 딸-깍해서 해보는게 매력이라고 생각하거든요.
그리고 이 방식이 베스트 프랙티스를 설명하기도 제일 좋다고 생각하구요.
물론 프로젝트 특성상 그러는 것이 간단치 않으리라는것은 알고 있지만, 그럼에도 불구하고 그게 제일 매력적이라고 생각합니다.
더불어서 가능하다면 pulumi나 terraform 같은 도구와 같이 예제를 구성한다면 더 좋을 것 같아요.
비슷한 use case를 가진 곳에서 잘 쓸 수 있을 거 같습니다. 공개해주셔서 감사합니다!
다만 ingestion에서 Lock을 쓰는 부분에서 문제가 없었는지 궁금한데요. 데이터 Write의 경우 트래픽이 어느 정도 됐었나요? Lock 경합 등으로 인해 문제가 되는 경우는 없었는지 궁금합니다.
소중한 질문 감사합니다!
Lock은 edge (source, target) pair 단위로 잡습니다 (예: Alice→Phone). 같은 edge에 동시에 쓰는 경우만 경합이 생기는데, 실제로 한 사용자가 같은 대상에 동시에 좋아요 누르는 경우는 거의 없어서 경합이 낮습니다. 이게 저희 데이터베이스 유즈케이스의 특징입니다.
Write 트래픽은 피크 기준 분당 수십만 건 정도입니다. 읽기가 100만+이고 쓰기는 그보다 낮아요.
벤치마크 참고 (읽기 85%, 쓰기 15%) - https://actionbase.io/ko/operations/benchmarks/
핫 엔티티(인기 상품 등)는 lock 경합이 생길 수 있는데, 이건 count 업데이트 때문이에요(HBase Increment). 이 부분은 별도로 최적화해서 처리하고 있습니다. 고빈도 쓰기 관련: https://actionbase.io/ko/stories/kakaotalk-gift-recent-views/
감사합니다! 관심 있으시면 다음 방향에 대한 의견도 남겨주세요: https://github.com/kakao/actionbase/discussions/144
개발자 문서가 정말 잘 작성되어있네요. stories로 보여주시는 use case나 빠른 시작, faq가 기술블로그 정도일만큼 알찼습니다.
감사합니다! 혹시 비슷한 기능 구현하시면서 겪으신 문제가 있으셨는지 궁금하네요. 저희가 다음에 뭘 먼저 할지 커뮤니티 의견 받고 있습니다: https://github.com/kakao/actionbase/discussions/144
의심할 만합니다. 근데 주작 아니에요.
첫 댓글에 링크 4개 넣었더니 30분간 shadowban 당했어요. 그동안 맥락 설명이 안 보이니까 사람들이 그냥 지나갔고요. 그 때 진짜 불안했어요. 묻힐까봐요. 링크 빼고 다시 달았더니 그제서야 1위로 올라가고, 그 댓글도 달리더라고요.
말씀하신 그 댓글러, 저도 확인했어요. 가입한 지 얼마 안 됐다는 거요. 그래도 고맙더라고요. 반응이라도 있으니까요. 그래서 정성껏 답 달았습니다. "why not redis?" 이거 미리 준비했어요. DB 관련이면 무조건 나온다는 질문이요. 설마 이렇게 진지하게 준비했는데 그런 질문이 달리겠어? 생각했어요. 근데 전날 s2-streamstore 때 알아봤어요. "TCP로 하지" 라는 답이 달려서. 준비했습니다.
참고로 팀원들한테 절대 업보트/댓글 달지 말라고 부탁했고요. 혹시 실수할까 봐 로그인도 풀어놓으라고 했습니다. HN이 그거에 민감한 거 미리 알고 있어서요.
어쨌든 설명해도 안 믿으실 수 있으니... 저희 레포 한번만 봐주세요. 살아남은 코드입니다. 같이 일한 동료들이 이 글 보고 마음 상할까 봐 자세히 적습니다. https://github.com/kakao/actionbase/discussions/32 한번만 봐주세요. 감사합니다.
그리고,
https://actionbase.io/ko/stories/kakaotalk-gift-wish/ 도요. 대규모 시스템을 고민하신 적 있으시다면 도움이 될 만한 내용 성심성의껏 적어봤습니다.
아 그리고 아래 제 X 보시면 아시겠지만, 1위는 그 댓글 달리기 전이에요. 그 댓글은 아마 2~3위로 떨어졌을 때 달렸을 거예요. 간식 먹는 공간에서 두쫀쿠 케이스에서 꺼내는 순간 댓글이 달려서, 달려가서 댓글 달았습니다. 그 뒤로 12시간 동안 30위까지 밀리다가 지금은 2번째 페이지에 있습니다 ㅠ