Kkrap/기능 설계 문서화

팔로잉 활동 폴더 피드 기능 문서

재윤 2025. 7. 27. 19:28
반응형

kkrap 프로젝트 팔로잉 페이지에서 내가 팔로잉 하고 있는 사람들의 일주일 동안 생성한 폴더에 대해서 보여주어야했다. 이 기능의 과정을 기술한다.

 

기능 개요

팔로우 중인 사용자의 최근 활동 이력을 조회하는 기능으로, 사용자는 자신이 팔로잉한 유저들이 최근 7일 이내에 생성된 폴더를 조회한다.

 

기능 목적 및 배경

  • 사용자가 팔로우한 사람의 폴더 생성을 확인함으로써, 새로운 유용한 콘텐츠나 폴더를 발견할 수 있게 한다.
  • 커뮤니티적 상호작용 유도, 콘텐츠 확산, 플랫폼 체류 시간 증가 등의 효과를 기대한다.

 

설계 전략

  • 팔로잉 활동 피드 구현에 대한 방법은 3가지가 떠올랐다.
  • 행동을 저장하는 DB를 하나 만드는데 여기서도 2가지가 있다.
    • 사용자 행동 이력 DB → 사용자가 행동한 것만 넣어주고 SELECT에서는 전부 JOIN에서 보여주는 것
    • 폴더 이력 DB → SELECT를 먼저 해서 이 DB에 다 넣고 난중에 한 번에 보여주기

 

  1. 사용자 행동 이력 DB를 하나 만들어서 폴더 생성 API에 요청이 왔을 때 그 즉시 사용자 행동 이력 DB에 INSERT 하는 방법
  2. 사용자가 폴더 생성 API 요청 후 Redis에도 담아두고 스프링 부트의 시간 간격을 주어 사용자 행동 이력 DB를 업데이트 하는 방법
  3. 사용자가 폴더 생성 API 요청 후 폴더 이력 DB에 전부 JOIN 해서 값을 넣어놓는 방법

 

3가지 방법이 있지만 우리 서버의 가용성과 실질적으로 우리 서비스를 사용할 사용자수를 고려를 해야될 것 같다는 생각을 했다. 또한 구현 전략에서 따져봐야할 키워드는 다음과 같다.

  • 실시간 → 현재 단일 서버이기 때문에 실시간성을 보장하기가 힘들다라고 판단이 서며 비용도 문제라 생각이 들었기에 실시간 성을 조금 포기해야된다고 생각
  • 조회 성능 → 단일 서버에서 너무 많은 SELECT를 해버리면 엄청난 과부하가 될 것 같다고 생각
  • 장애 복원력 → 장애에 대해서 현재 복구할 수 있는 뭔가 대응책이 없기에 서버에서 문제가 생기더라도 복원할 수 있는 무언가가 필요

상황을 한 번 본다면

1번 같은 경우에는 실시간성 처리가 잘 될 것 같지만 조회 성능이나 장애 복원력이 따라가지 못할 것 같다.

3번 같은 경우에는 실시간성 처리와 조회 성능은 좋지만 만약 서버가 뻗는다고 했을 때 수많은 요청에 들어오는 부분에 대해서 복원할 무언가가 없다.

 

그래서 결론적으로 2번을 채택하는 게 제일 좋다고 생각했다.

하지만 단점도 생각해본다면

  1. 사용자 행동 이력 DB에서 SELECT 할 때 JOIN
  • 이 JOIN이 많은 성능에 고려할 부분이 많지만 지금 당장 사용자가 많이 없어서 괜찮다라는 결론을 내림
  • 나중에 만약 사용자가 많아지면 이 부분을 바꿔야겠다는 생각

 

아키텍처 순서

1. DB인 activity_feed

CREATE TABLE activity_feed (
    activity_feed_id BIGSERIAL PRIMARY KEY,
    actor_user_id BIGINT NOT NULL,
    folder_id BIGINT NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT now()
);

 

 

2. Redis 구조 설계

  • Redis Key: feed:{userId}
  • Redis Value: List of folder_id (or JSON)
  • 캐시 타임: 1시간 (예: EXPIRE feed:{userId} 3600)
    • 이 캐시 타임은 스프링 부트 스케줄링을 이용해서 진행
    • 시간은 좀 더 호율적인 방법을 찾는 게 좋을 것 같다 지금 당장은 1시간으로 설정

 

응답값은 이런 형태로 생각

[
  {
    "folderId": 55,
    "folderName": "AI 프로젝트 정리",
    "createdAt": "2025-07-28T10:00:00",
    "actor": {
      "userId": 123,
      "nickname": "지호",
      "profileUrl": "/images/profile/123.png"
    }
  },
  ...
]
반응형