웹 서버 프로젝트를 pm2 로 관리하던 중 생긴 문제.

 

프로젝트 요구 사항 중, 사용자가 업로드 한 유튜브 영상의 조회수를 하루마다 갱신하여 DB에 저장해야하는 기능이 필요했다.

따라서 DB에 저장된 영상의 고유 id값을 가져와 YouTube API를 통해 조회수를 수집 후, 이를 다시 DB에 Insert 하는 API를 개발 하였다.

 

key_value는 영상 id, runtime은 해당 영상의 조회수.

따로 크롤러는 만들지 않고, 해당 프로젝트는 pm2 프로세스로 관리 되던 터라 직접 cron 라이브러리를 통하여 함수를 작성하였다.

  1.  DB에 저장된 비디오의 정보를 가져와 해당 비디오의 id값만을 따로 리스트로 만들어 valuesOfContentList에 저장해준다.
  2. valuesOfContentList getVideoViewsCount 함수를 통해 유튜브에서 해당 영상의 조회수를 가져온다.
  3. 1에서 가져온 id값과, 조회수를 각각 key, value형태로 만들어 DB에 새롭게 Insert 한다.
  4. 해당 함수를 node-cron 라이브러리를 통해 주기적으로 실행할 수 있도록 설정하였다.

해당 함수를 로컬에서 테스트 후, 잘 실행되는 걸 확인하였고 이에 안심하고 배포를 하게 된다...

그러나, 예상과는 다르게 영상별로 조회수가 22시에 한번씩만 Insert 돼야 했지만 한 영상마다 수집한 조회수가 15건이 되어버렸다..

중복으로 수집된 데이터로 인해, 영상별 조회수 통계를 보여주는 페이지에서 대혼돈이 찾아왔다...(눈물)

 

왜 로컬에선 딱 한번만 수집되고, 배포 환경에선 안 되는 걸까..라는 원인 모를 상황에 약 이틀 동안 머리를 싸맸다..

처음엔 코드 문제인가 싶어 다시 찬찬히 훑어보았지만 매우 정상적으로 잘 작동 했다..

 

그러자, 불현듯 스치는 생각

https://yunja.tistory.com/12 

 

[ Jenkins + pm2 ] 트러블 슈팅

사내 프로젝트를 젠킨스를 통해 배포 자동화를 구축 후, 문제가 발생하게 된다. 상기의 이미지처럼, Jenkins Build Step을 쉘 스크립트로 비교적 간단하게 작성했다. NestJS로 프로젝트를 구성했던 터

yunja.tistory.com

해당 포스팅에서 잠깐 언급이 되었는데, 잠깐 설명하자면 배포할 프로젝트는 pm2로 관리되며 이 pm2는 프로젝트 루트 경로의 ecosystem.config.js 파일을 토대로 인스턴스 갯수를 정하여 그에 맞게 프로세스가 실행된다.

 

module.exports = {
  apps: [
    {
      name: 'app',
      script: './dist/app.js',
      instances: 15,
      exec_mode: 'cluster',
    },
  ],
};

배포 환경에선 서버 인스턴스가 15개나 되어, 위에서 작성한 영상 조회수 수집 함수가 무려 15번이나 실행되었던 것이다 !!

 

따라서 나는 한 인스턴스에서만 조회수 수집 함수가 실행 되게 하고 싶었으며, 해당 방법을 모색해보았다.

module.exports = {
  apps: [
    {
      name: 'primary',
      script: './dist/app.js',
      instances: 1,
      exec_mode: 'cluster',
    },
    {
      name: 'replica',
      script: './dist/app.js',
      instances: 13,
      exec_mode: 'cluster',
    },
  ],
};

기존에는 동일한 이름의 인스턴스로 15개를 실행하였지만, 수정한 config.js는 

하나의 인스턴스에는 primary라고 이름을 지정해주고, 다른 인스턴스에는 replica라고 이름을 명시해주었다.

이렇게 되면, 배포 서버의 노드 프로세스는 primary 이름의 프로세스 1개, replica이름의 프로세스 13개가 실행되어 진다.

 

이에 맞게, node-cron 에서 실행되어지는 getVideoViewsCount 함수에도 현재 실행되는 프로세스 인스턴스의 이름이 primary 일 경우에만, 함수를 실행하도록 하였다.

 

함수 처음 부분에 process.env.name을 가져와 primary인지 검사하여 , 맞을 경우에만 함수를 실행하도록 변경하였다.

 

해당 함수까지 변경 후 ,처음 원했던 대로 정상적으로 22시에 함수가 정상적으로 primary 인스턴스에서만 실행되었다 !!!

'Trouble Shooting' 카테고리의 다른 글

GitActions 러너 환경을 arm64 EC2로 변경하기  (0) 2023.08.04
[ Jenkins + pm2 ] 트러블 슈팅  (0) 2023.07.15

+ Recent posts