TIL 08.01 & 08.02 <트러블 슈팅& 아키텍쳐>

박선우·2022년 8월 1일
0

WIL

목록 보기
20/33
post-thumbnail

사용자 피드백을 받으면서 오류수정, 최종발표 준비로 트러블 슈팅 & 아키텍쳐 설명등을 작성하였다.

  • 사용자 피드백을 받아 반영하는 부분은 백 보다는 프론트 쪽에서 거의다 진행이 요구되는 상황이라 백은 하게 많이 없었다

  • 우리는 최종발표 자료를 조금더 준비를 많이하고, Github readme 파일을 작성하기로했다.

아키택쳐

  • 백엔드 웹 어플리케이션 서버는 Node.js와 Express로 구축

  • Nginx에 SSL인증을 도입해 WebRTC 실시간 화상 통화 구현 및 리버스 프록시 설정을 통해 백엔드 서버에 직접적인 접근을 차단하여 보안 강화

  • 깃허브 액션 CI-CD를 통해 Docker Image를 빌드하여 동일한 개발 환경으로 자동화 배포

  • 기본 데이터베이스는 데이터의 무결성을 보장하기 위해 RDS의 Mysql와 ORM인 Sequelize 사용

  • 인메모리 데이터 구조 저장소인 Redis에는 I/O이 빈번하거나 일회성인 데이터를 저장하여 데이터 처리 속도를 크게 개선

  • 이미지 데이터는 Multer 미들웨어를 통해 Multipart/form-data로 받아오고 S3 버킷에 저장, 삭제할 수 있도록 구현

  • 사용자의 간편한 로그인을 위해 passport를 이용해 카카오 로그인 구현

🔥 트러블 슈팅

✔️ 메인페이지 로딩 속도 개선

문제점

  1. 메인 페이지는 서비스를 이용하는 모든 유저들이 방문하기 때문에 API 사용량이 매우 많다.

  2. DB에서 모든 게시글을 조회하고 1주일간 좋아요를 많이 받은 순서로 정렬하는 로직을 매번 실행한다.

  3. 느린 로딩 속도로 유저가 느끼는 불편함을 개선하고 운영 측면에서도 서버 비용을 감축할 필요가 있다.

해결방안

  1. 레디스에 가공된 데이터를 미리 저장하고 API 호출 시 DB에 접근하지 않고 레디스에서 바로 해당 데이터를 전송한다.
  2. 10분 단위로 캐시에 저장된 데이터를 업데이트한다.

결과

Artillery로 테스트해본 결과, 기존 방식에 비해 레디스를 같이 활용했을 때 서버 응답 속도가 70% 가량 단축되었다.

아쉬운점

10분마다 인기 게시글을 업데이트 해주기 때문에 실시간으로 업데이트된 데이터를 제공할 수 없다는 한계점이 있다.

응용

  1. 일일 조회수를 레디스에 저장하고 오전 12시에 합산하여 DB에 업데이트한다. 레디스의 데이터 타입 set을 활용하여 중복 집계를 방지한다.
  2. 레디스를 세션 저장소로 활용하여 JWT 토큰을 저장하고 중복 로그인을 방지한다.

✔️ 상세페이지 로딩 속도 개선

문제점

  1. 1:N의 관계를 갖는 데이터(게시글 : 댓글, 좋아요, 태그 등) 조회에 Eager Loading을 활용한다.
  2. 여러 번의 테이블 Join으로 성능 저하된다.

해결방안

Lazy Loading을 활용하여 데이터를 각각 테이블에서 조회한다.

결과

  1. 코드 가독성이 좋아졌다.
    Eager Loading
const paper = await Paper.findOne({
    where: { postId },
    include: [
        {
            model: Comment,
            include: {
                model: User,
                as: 'Users',
                attributes: ['userId', 'blogId', 'nickname', 'profileImage'],
            },
        },
        { model: Tag, attributes: ['name'] },
        { model: User, as: 'Users', attributes: ['blogId', 'nickname', 'profileImage'] },
        { model: User, as: 'Likes', attributes: ['blogId'] },
    ],
});

// Lazy Loading

const paper = await Paper.findOne({ where: { postId } })
const comments = await Comment.findAll({
    where: { postId },
    include: {
        model: User,
        as: 'Users',
        attributes: ['userId', 'blogId', 'nickname', 'profileImage'],
    },
});
const tags = await paper.getTags({ attributes: ['name'] });
const user = await paper.getUsers({ attributes: ['blogId', 'nickname', 'profileImage'] });
const likes = await paper.getLikes({ attributes: ['blogId'] });
  1. 기존 방식에 비해 서버 응답 속도가 50% 가량 단축되었다.

변경 전후

✔️ 도커 도입

문제점

로컬에서 문제없이 돌아가던 서버가 배포 후 실행을 하면 reify fsevents 프리징 문제 발생

구글링을 통해 노드 버전 문제로 인한 에러라는 사실 발견

해결방안

  1. 노드 버전을 로컬환경과 맞춰주는 방법도 있지만 추가 인스턴스를 생성할 때마다 맞춰줘야하는 번거로움 발생

  2. 로컬환경의 도커 이미지를 생성해 인스턴스에서 실행

결과

로컬에 작업한 걸 이미지로 빌드해 실행하니 배포환경에서 버전 이슈 등으로 인한 에러를 걱정하지 않고 배포 가능

✔️ S3 미사용 이미지 관리 문제

문제점

이미지를 첨부(업로드)하고 게시글을 작성하다가 중간에 페이지를 벗어난다면 사용되지 않는 이미지가 S3에 남아있게 됨 게시글을 수정하면서 기존에 사용한 이미지를 삭제할 때도 똑같은 문제가 생김

해결방안

  1. image 테이블을 추가

  2. 이미지 업로드 시 image 테이블에 postId가 null인 상태로 추가

  3. 게시글 동록 시 본문에 정규식으로 이미지 url들을 필터링하고 배열에 저장 배열 내 값들과 일치하는 row들은 postId를 부여
    node-cron으로 postId가 null이고 updateAt이 하루 전 이상인 데이터를 주기적으로 삭제

profile
코린이 열심히 배우자!

0개의 댓글