
오랜만에 찾아왔습니다!!
빨리 접속하기: https://velog-dashboard.kro.kr/
Github repo: https://github.com/check-Data-Out/velog-dashboard-v2
이 서비스가 velog에 귀속된(?) 구조다 보니 알릴 수 있는 채널이 사실상 velog 밖에 없습니다. 하지만! 뉴스레터 이후로 유입도 계속 올라가고 어느 순간부터 MAU 1K+ 를 찍고 있더라구요...!
그리고 애초에 “우리나 편하게 쓰자”로 시작한 프로젝트라 막 공격적으로 알리자! 이런 마음은 애초에 크지 않았고요. 어떻게 알고 찾아오시나요?..!?
간간이 LinkedIn 이나 velog 글에서 통계 지표를 캡쳐해서 활용하시는 분들도 보이고, 그럴 때마다 저희 모두 조용히 뿌듯해하고 있었습니다ㅎㅎㅎ
사실 이 프로젝트는 같이 시작했던 취준생 분들을 위한 (나름의) 취업 장려 프로젝트이기도 했는데, 멤버 절반 이상이 취업을 했습니다! (하거나, 다시 돌아온..!! 상태) 프로젝트의 비공개 KPI는… 달성했습니다. 😎
혹시 이 글을 읽고 계시는 취준생 분이 계시다면! 개인적으로 나 혼자 쓰는 product 이라도 0 to 1 으로 세상에 공개하는 경험과 관리해보는 경험이 정말 큰 도움이 될 것이라고 생각합니다!
아무튼, 살아있다는 근황 겸 소소한 업데이트 공유해봅니다. 🙏🔥
① 직접 통계 새로고침!
② 완전 싱크 맞는 "마크다운 통계 뱃지" (사실 TBD이긴 한..)
③ 토큰 공격 방어!! Fail-fast JWT + Redis 기반 인증 실패 추적/차단 (rate limit)
그동안 통계를 “유저가 직접 업데이트” 하지 못하게 막아뒀습니다. 이유는 단 하나... 서버 비용이 0원이라 리소스가 절망적이기 때문 입니다 ㅎㅎ
그래서 통계를 어그리게이션 하는 가장 무거운 배치는 철저하게 GitHub Actions 로만 돌립니다. (무려 20개 배치를 30분마다 돌림 ㅋㅎㅋㅎㅋㅎ)
근데 문제가 있죠.
그래서 이번에 “어느 정도 cap” 을 두고, 유저가 직접 통계를 새로고침 할 수 있는 창구를 만들었습니다.
Redis 큐 적재 → Consumer 구독/처리

Consumer 는 가장 리소스가 널널한 백오피스 서버에서 가동하기로 했습니다!
15분 리미트가 걸려있습니다. 기준은 버튼 누른 시간이 아니라, “나의 가장 마지막 업데이트 시간”으로부터 15분 입니다 ㅎㅎ. 고로 신규로 오신분은 바로 클릭이 가능하실거에요!
첫 설계시 "비동기 task를 범용적으로 처리하는 consumer" 는 아니었는데, 만들다 보니 범용성을 목표로 하게 되었습니다.. (일 부분 만큼은 오히려 창업한 product 보다 완성도가 높은 기분) 그래서 핵심 아래 3가지 경우를 중요하게 다뤘습니다.
1) 셧다운 때 / 에러 발생 시
2) 메시지 수신 전용 큐 / 처리 전용 큐 / 실패 전용 큐 분리 + 비동기 작업 처리
3) 실패 시 retry + 완전 실패 시 일정 사이즈만큼 보관 (디버깅/추적)
플로우 차트는 아래와 같습니다.


코드가 궁금하다면 여기서 바로 보실 수 있습니다!!
https://github.com/Check-Data-Out/velog-dashboard-v2-back-office/tree/main/consumer
최적화 작업으로 인해,
사실, 아쉽게 26.01.23 이후에야 제대로된 기능으로 사용하실 수 있습니다.. 🙏🙇🏻♂️🙏🙇🏻♂️🙏🙇🏻♂️
통계 뱃지를 만들어 주신 분들이 이미 많이 있습니다. 근데 이미 기존 뱃지들은 어쩔 수 없이 제대로 된 통계 데이터를 한 번에 불러올 수 없는 구조 입니다.ㅠㅠ
근데 Velog Dashboard 에 등록한 분들은, 완벽한 마크다운 뱃지를 “직접 생성해서” 쓸 수 있습니다. 우측 상단 프로필에 "뱃지 생성기" 가 있습니다!



그래서 GitHub README.md / velog 소개 페이지 / 기타 마크다운/html 지원하는 곳 어디든 다 박을 수 있어요. 짜잔.


1) /badge?username=xxx 로 요청이 들어오면 파라미터 검증을 하고
2) Next(server-side)에서 백엔드 API 호출로 통계/최근글 조회 (클라에 노출 안 됨)
3) React 컴포넌트 → Satori → PNG 로 이미지 생성합니다.
4) img 태그 하나로 끝! 입니다.
5) 최적화 작업으로 이제 캐싱 layer 가 추가되어서 릴리즈 될거에요!
이 업데이트는 기능 추가라기보다, 보안을 위해 결국 해야만 했던 방어 작업이다..! 어느 날부터 “가끔” 서버가 트래픽이 피크를 찍는 구간이 있었는데, 역시 해외에서의 무작위 요청! 근데 이게 어떻게 특정 포인트를 알아버린건지 DB connection 을 써야만 하는 API 을 타겟을 제대로 했더라구요..
쓰레기 토큰이 대량으로 들어옴 → 인증 미들웨어가 매번 payload 파싱 시도 → 예외가 계속 남 → 방어 없이 계속 들어옴 → 연결 풀이 먼저 말라버림 → "Max client connections reached"
즉, 어차피 의미 없는 토큰인데도 미들웨어가 열심히 달려버리면서 (그리고 중간중간 DB/연결 리소스를 건드리면서) 커넥션 풀이 빠르게 고갈되는 구조였습니다. 사실 이게 구조적인 문제가 좀 있었죠. (애초에 지금 서비스가 직접 회원을 관리하는 구조가 아니기에...)
그래서 전략을 바꿨습니다.
1. Fail-fast: JWT “형식부터” 먼저 보고, 아니면 바로 컷 (DB까지 갈 자격 없음)
2. Rate limit: 계속 던지는 IP는 Redis 에 기록해서, 임계치 넘으면 잠깐 차단.
3. Fail-open: Redis 가 죽어도 서비스는 죽지 않게 (차단 기능만 비활성)
InvalidTokenError 발생 시 실패 추적(trackAuthFailure) 연결

템플릿도 있고, 이슈도 열려있고, 진짜로 “어? 이거 고치고 싶은데?” 하면 바로 들어오실 수 있게 해놨습니다!! https://github.com/Check-Data-Out/velog-dashboard-v2 여기서 관련 레포를 한 눈에 볼 수 있어요.
놀랍게도 대시보드 프로젝트는 벌써 1년이 넘었더라구요. 시간 진짜 너무 빠르네요. 이 프로젝트는 앞으로도 그냥 이런 “적당한 기술 놀이터” 같은 느낌으로 계속 이어갈 것 같습니다.
통계 데이터 개수만 벌써 곧 1천만개 입니다...! (무료로, 어떻게든, 살아남는 중)
안녕하세요. 인프라단에 fail2ban을 적용해보는 것도 도움이 될 수 있을 것 같아서 코멘트 남깁니다!