희우 위키

HOME ABOUT ME STUDY RSS

Implement Counting of Unique Vistor

  • IMPLEMENTATION

개요

이 포스팅은 최근 블룸 필터 포스팅에서 비트 마스킹을 다루며 이전 직장에서 조회수 기능을 구현하기 위해 고민했던 내용들이 떠올라서 누군가에게 아이디어를 제공하고 보완해나가기 위하여 작성한 글이다.

실무에서 사용하려면 조금 더 깊이 있게 고민이 필요하고 보완 해야 할 내용이 많다.

포스트나 댓글 등의 유니크 조회자 수를 집계하는 데에는 정말 다양한 방식이 존재한다.

예를테면 다음과 같은 방식이 있으며 각 방식에는 오류가 존재한다.

  • HTTP의 쿠키 기반으로 Unique Visitor를 카운팅 하는 방식
    • 이 방식은 HTTP의 쿠키를 제거하면 유니크 집계가 불가능하다.
  • 유저의 방문 기록을 저장해두고 그 방문기록을 검증하여 카운팅 하는 방식
    • 시스템의 확장이 불가능하다. (시스템이 오래 될수록 데이터 검증에 드는 비용이 증가하고 스토리지 공간의 효율성이 떨어진다.)

등등 여러가지가 있다.

일반적인 구현 방식에서 확장성과, 정확성을 보장하기 위하여 어떻게 구현하면 좋을까?

요구사항

기능적 요구사항

  • 고유한 유저에 대해 하루에 한 번 방문한 것을 기록해야한다. 중복 카운트는 집계처리 하지 않는다.
  • 하루에 총 방문자 수를 카운트 해야한다.
  • 미가입 된 유저에 대한 방문은 집계하지 않는다.

비기능적 요구사항

  • 유저 수는 급격하게 증가될 수 있음을 고려해야 한다.
    • 따라서, 유저 수가 급격하게 증가되는 상황에서의 처리를 위해 시스템의 공간 효율성을 신경써야하며, 응답 지연 또한 발생되면 안 된다.

비트 마스킹 (Bit Masking)을 통한 유니크 방문자 수 집계

레디스를 사용하고 있다고 가정하겠다. 나는 다음과 같은 전략을 세웠다.

전체 유저에 대해 1번부터 N번까지 줄세운다. 1번부터 N번까지 0과 1을 가지는 2진 비트 배열(bit array)를 사용하여 방문/미방문을 표시한다.

스크린샷 2023-09-03 오전 3 34 42

레디스에는 String 형태의 값을 저장할 수 있는데, 이 String은 일반적인 문자열이 아니라 바이트 시퀀스(Byte Sequnce)를 저장한다. (참고문서)

이러한 특징으로 인하여, 비트 단위의 연산도 지원하게 되는데 레디스 공식문서의 Redis bitMaps에 관련 정보들이 잘 나와있다.

하나의 키(Key)에 대해 String은 총 512MB 크기의 데이터를 저장할 수 있고, 이는 2의 32승만큼의 서로 다른 비트를 저장할 수 있는 것과 동일하다.

만약, 유저를 줄 세웠을 때 2의 32승이 되지 않는다면(되지 않을 것 같다면) 하나의 키로 모든 유저를 처리할 수 있겠으나 2의 32승이 넘어가는 상황에서는 키를 분할해주는 과정(키 파티셔닝)이 필요하다. (이는 큰 작업이 아니기에 본 포스팅에서는 하나의 키로 표현하겠다.)

위에서 표현한 bit array의 key의 값이 visitarray:20230902 라고 하였을 때, 만약 3번째 유저가 방문했다면 다음과 같은 비트 연산 오퍼레이션을 수행한다.

redis-cli > SETBIT visitarray:20230902 3 1

스크린샷 2023-09-03 오전 3 49 33

BITCOUNT 오퍼레이션을 통해 문자열 바이트 시퀀스에서 총 몇 개의 비트가 1로 설정되어있는지도 확인할 수 있다.

만약, 1억명이 방문하는 서비스라고 해보자. 1억명의 방문 데이터를 전체 로그를 쌓는다면 용량이 얼마가 될 것 같은가?

저장할 데이터의 사이즈마다 다르겠지만, 10MB보다는 클 것이라고 확신한다. 이 비트 어레이는 약 10MB로 1억명의 고유 방문자 수를 저장하고 집계할 수 있다.


보완할 점

1. 레디스의 용량 제한

본 포스팅에서는 유저수의 제한만 걸었다. 다만, 집계해야하는 케이스가 많아질 수록 그만큼 키의 양 자체가 늘어버린다. 현실적으로 레디스의 메모리 제한 때문에 천문학적인 숫자의 집계는 불가하므로, 이러한 경우에 대해서도 대비가 되어야 할 것이다.

2. 기능적 요구사항에 유저가 방문한 시간도 남겨야 한다면 ?

3. 등등..


정리하며

구현을 위해 고민했던, 혹은 구현 방식에 대한 간단한 기술에 대해서 처음 포스팅 해보았는데 생각보다 재밌는 것 같다. 이러한 주제를 가지고 앞으로 자주써야겠다.

읽어주셔서 감사합니다.


참고문서