게시글의 view count 를 구현하기 위한 과정을 적어보았다.

처음 게시글의 view count를 구현하기 위해 고민이 있었다.

Redis, ElasticSearch, RDB중 어디서 view count를 관리할 것 인가?

처음 생각했던 방식으로는 게시글의 상세정보를 불러올 때 redis에서 게시물의 id 값으로 view count를 관리하는 것을 구상했었다.

하지만 위의 방식으로 구현하였을 떄 문제가 있었다.

view count는 게시글의 리스트를 가져올 때 출력해주어야 하는데 위의 방식으로 구성하게 된다면 게시글 검색기능을 통해 얻은 게시글 리스트 만큼 redis에서 view count를 가져오는 로직을 호출해야하는 상황이 되어버린다.

이미 게시글 목록을 불러오는 과정에서의 성능을 위해서 RDB에 접근하는 부분을 전부 버리고 Elastic Search에서만 데이터를 가져오는 상황을 구성한 입장에서, 위와 같은 방식은 사용할 수 없다고 느꼈다.

그렇다면 Elastic Search에서 view count를 관리하면 게시글 목록을 가져올 때 view count도 함께 가져올테니 1석 2조 아니겠는가?

라고 생각할 수 있겠지만. Elastic Search 를 처음 써보는 입장에서, Elastic Search 의 Update 는 비용이 크다는 정보를 들은적이 있어서, 무의식적으로 Elastic Search 에서 view count를 관리하려 하지 않았다.

그런데, 생각을 해보니 Elastic Search에서 Update 의 비용이 높은 이유는 데이터의 역 색인을 위한 처리과정 때문에 비용이 크다는게 머리를 스쳐지나갔고 그렇다면 색인을 하지 않는 필드에 대해선 어떨지 궁금해졌다.

당연히 view count 의 필드는 색인이 필요 없으니 위의 Mapping 데이터를 토대로 Elastic Search에서 view count를 구성해보기로 했다.

아래는 게시글의 상세정보를 불러오는 로직이다.

// ...

// 게시글의 상세 정보를 담을 변수
let board_detail_data = new BoardDetailDto();
// 게시글의 상세정보가 redis에 캐싱되어있는지 체크
if (await this.redis.hExists('board_detail_list', board_id.toString())) {
	// 만약 캐싱된 데이터가 있을 경우, redis에서 상세정보를 가져와서 return
  board_detail_data = {
    ...JSON.parse(
      await this.redis.hGet('board_detail_list', board_id.toString()),
    ),
  };
} else {
	// redis에 캐싱된 상세정보가 없을경우 RDB에 접근하여 게시글의 상세정보를 가져옴
  board_detail_data = {
    ...(await this.boardRepository
      .createQueryBuilder('board')
      .leftJoinAndSelect(User, 'user', 'board.user_uuid = user.user_uuid')
      .select([
        'board.board_id AS board_id',
        'board.board_type AS board_type',
        'board.board_title AS board_title',
        'board.board_contents AS board_contents',
        'board.user_uuid AS user_uuid',
        'user.user_name AS user_name',
        'board.update_date AS update_date',
      ])
      .where('board.board_id = :board_id', { board_id: board_id })
      .getRawOne()),
  };
}

if (isEmpty(board_detail_data)) {
  throw new HttpException('Not Found', HttpStatus.INTERNAL_SERVER_ERROR);
}

// RDB에서 가져온 상세정보를 redis에 캐싱
await this.redis.hSet(
  'board_detail_list',
  board_id.toString(),
  JSON.stringify(board_detail_data),
);

// ...

게시글의 상세정보를 불러왔다는 것은 게시글에 접근하였다고 판단하여 게시물의 view count 를 올려주기로 하였다.