Dotorian

Upstash Redis로 조회수와 공감을 나눈 방법

김민기금융 데이터를 읽고 제품을 만듭니다

글 아래에 숫자를 붙이는 일은 쉬워 보인다. 페이지가 열리면 숫자를 하나 올리고, 하트를 누르면 또 하나 올리면 된다. 하지만 조회수와 공감은 같은 데이터가 아니다. 중복을 막는 기준도, 사용자가 기대하는 동작도 다르다.

그래서 두 기능을 Upstash Redis 안에서도 다른 키와 다른 규칙으로 나눴다.

조회수는 24시간 단위로 중복을 막는다

조회수 API는 요청 헤더의 첫 IP를 서버 전용 비밀키가 있는 HMAC-SHA256 값으로 바꾼다. 비밀키가 없는 로컬 환경에서만 일반 SHA-256으로 대체한다. 원본 IP를 저장하지 않고, viewdedup:<slug>:<hash> 키를 24시간 TTL로 둔다.

Redis의 SET NX EX가 성공한 첫 방문만 views:<slug>를 증가시킨다. 같은 사람이 하루 안에 페이지를 다시 열어도 전체 조회수는 올라가지 않는다. 해시 값은 “이미 방문했는지”를 판단하는 데만 쓰이고, TTL이 지나면 사라진다.

완벽한 방문자 수 통계라고 주장하려는 장치는 아니다. 개인 블로그에서 새로고침으로 숫자가 계속 오르는 일을 줄이기 위한 현실적인 기준이다.

공감은 IP보다 브라우저 단위를 썼다

공감은 클릭한 사람이 다시 취소할 수 있어야 한다. IP를 기준으로 하면 회사·학교·모바일망처럼 IP를 공유하는 환경에서 서로의 선택이 섞일 수 있다.

그래서 브라우저의 localStorage에 UUID를 한 번 만들고, likes:<slug> Redis Set에 이 UUID를 넣거나 뺀다. Set의 크기가 공감 수가 되고, 같은 브라우저는 한 글에 한 번만 공감한 상태를 가진다. 서버에서는 IP당 시간당 60회로 토글을 제한하고, 글 하나의 Set도 1만 명에서 멈춰 자동화 요청이 저장공간을 무한히 늘리지 못하게 했다.

이 선택도 엄격한 인증 기반 투표는 아니다. 브라우저 저장소를 지우면 새 ID가 생긴다. 대신 로그인 강제 없이 “좋아요를 누르고 다시 취소한다”는 사용자의 기대를 지킨다.

UI는 서버 응답을 기다리되, 클릭은 즉시 보여준다

공감 버튼을 누르면 화면은 먼저 상태를 바꾼다. 이후 POST 요청이 성공하면 서버의 실제 숫자로 맞추고, 실패하면 이전 상태로 되돌린다. 이를 낙관적 업데이트라고 한다.

조회수와 공감 API가 아직 준비되지 않은 배포에서는 기능 플래그가 UI 전체를 숨긴다. NEXT_PUBLIC_FEATURE_REACTIONS=true와 Upstash 환경 변수가 있어야만 동작한다. 외부 서비스가 없는 상태에서 API 오류나 빈 숫자를 독자에게 보여주지 않기 위해서다.

숫자보다 중요한 것

조회수는 관심의 크기를 정확하게 증명하지 못하고, 공감도 사용자의 감정을 완전히 설명하지 못한다. 그래서 이 기능은 성과 지표를 만들기보다, 글을 읽은 뒤 남길 수 있는 작은 신호로만 취급한다.

그 신호가 믿을 만하려면 숫자를 크게 만드는 것보다 먼저 해야 할 일이 있었다. 조회수와 공감이 무엇을 세는지, 어떤 중복은 허용하고 어떤 중복은 막는지 정하는 일이었다.

  • #upstash
  • #redis
  • #analytics
  • #interaction