본문 바로가기

분류 전체보기

(26)
Github Action + NestJS e2e 테스트 환경 구성 개요인턴십 기간 동안, 사내 프로젝트 개발에 참여하며 서비스 안정화를 위해 테스트 코드를 작성했습니다. 특히 애플리케이션의 비즈니스 로직을 담당하는 서비스 레이어에 대해서는 시스템 간 상호작용을 직접 확인하기 위해 통합 테스트를 작성했습니다. 보다 더 안정화된 서비스를 위해, main 브랜치에 push 될 때 자동으로 테스트를 실행하는 워크플로우를 추가해 보겠습니다.   Continuous Integration(CI) 파이프라인name: Run Testson:  push:    branches:      - mainjobs:  container-job:    runs-on: ubuntu-latest    container: node:20    services:      postgres:        im..
가상 메모리를 통한 EC2 t2.micro 서버 다운 현상 해결 서론인턴십 온보딩 기간 동안 간단한 사내 프로젝트를 수행했습니다. 프로젝트의 배포는 EC2 t2.micro 위에 Docker Compose로 next.js, NestJS, PostgreSQL을 하나의 서비스로 정의해 컨테이너 묶음으로 관리했습니다. 컨테이너를 올리는 것까지는 정상적으로 동작했지만 컨테이너를 올린 뒤, 몇초가 지나면 EC2 서버가 다운되는 현상이 지속되었기에 이를 해결해보겠습니다.   Scouter 적용보통 EC2의 t2.micro는 일반 컴퓨터에 비해서 사양이 매우 낮기 때문에 과도한 CPU 버스트가 일어나거나, 할당할 수 있는 메모리가 없는 경우에 다운됩니다. 이를 확인해보기 위해 두가지 방법을 생각했습니다. 1. SSH로 EC2에 접근한 뒤, 명령어를 통해 CPU와 메모리 사용률을 측..
S3 presigned Url 적용을 통한 영상 업로드 성능 향상 서론숏츠 업로드 플랫폼을 개발하던 중, 업로드 기능의 성능을 테스트 해 보았습니다. 20MB 데이터를 가진 업로드 요청에 평균적으로 1초가 소요되었기 때문에, 동시 요청이 발생하면 가용 가능한 스레드가 존재하지 않아 에러가 발생할 것으로 예상했습니다.   테스트 (presigned URL 적용 전) 초기 서비스 대상은 교내 학생들이었기 때문에, 숏츠 업로드 API의 동시 요청을 10명으로 잡고 테스트했습니다.  초당 트랜잭션 처리량은 9.1 이었고, MTT는 979ms로 측정되었습니다. 눈여겨 봐야할 부분은 Errors 인데, 694개의 요청에 대해 201개로 34.5%의 에러 발생률을 기록했습니다.  10명이 동시에 비디오 업로드 API를 호출하면 최소 세명 이상은 에러를 반환받는다는 것 이기 때문에 ..
InnoDB FullText-Index를 이용한 검색 성능 향상 개요스터디 그룹 매칭 서비스 StudyHub를 진행하며 아쉬웠던 점을 하나 꼽자면 검색 기능입니다. 사용자 입장에서 생각했을 때 '정보처리기사' 모집 게시글을 업로드한다면 동일한 스터디에서도 아래와 같이 많은 게시글이 생성될 수 있습니다.  '정보처리기사 스터디원 구합니다.' '꾸준히 진행할 스터디 구합니다. (정보처리기사)' 프로젝트에서 조회 시 성능을 위해 인덱스를 사용했기 때문에 '정보처리기사' 라고 검색했을 시 첫 번째 게시글만 검색되고 두번째 게시글은 검색이 안된다는 단점이 있었습니다. 물론 아직 데이터가 적기 때문에 '%검색문자열%' 과 같이 양쪽에 와일드카드를 삽입하는 방법이 있습니다.  하지만 추후 데이터가 많아졌을때를 대비하여 N-gram 파서를 이용해 검색 기능을 향상시켜보겠습니다.  ..
MySQL InnoDB B-Tree Index 탐색 과정 분석 개요 MySQL 인덱스는 인덱스 키 값의 시작값을 기준으로만 탐색이 가능합니다. 예를들어 Aamer라는 key 값을 기준으로 'A%'는 탐색이 가능하지만 '%A', '%A%'는 탐색이 불가능합니다. InnoDB에서 인덱스의 동작방식을 살펴보며 불가능한 이유를 알아보겠습니다. 본론 B-Tree는 트리 구조의 최상위에 하나의 루트 노드가 존재하고 그 하위에 자식 노드가 붙어 있는 형태입니다. 트리 구조 가장 하위에 있는 노드를 리프 노드라 하고, 트리 구조에서 루트 노드도 아니고 리프 노드도 아닌 노드를 브랜치 노드라고 표현합니다. 실제 DB의 인덱싱은 B-Tree와 비슷한 구조를 가진 B+Tree를 사용합니다. B+Tree는 아래와 같은 조건을 만족합니다. 1. 모든 리프 노드들이 같은 레벨을 가집니다. ..
SpringDoc Swagger Https 설정법 문제 상황 기존 프로젝트를 멀티모듈로 전환하면서 Spring Boot 버전도 2 -> 3으로 올리게되었다. 스프링부트 3에서는 springfox swagger를 지원하지 않기 때문에 springdoc swagger로 전환하게 되었지만 해당 라이브러리는 springfox에서 사용하던 방식으로 https 세팅이 불가능했다. 해결 @OpenAPIDefinition의 위와 같이 url을 넣으면 스웨거 화면에서 기본 url이 세팅된다. servers 안에 여러개의 url 적용이 가능하기 때문에 로컬 환경을 위한 url도 삽입하면 테스트 시 용이하게 사용할 수 있을 것이다. reference https://stackoverflow.com/questions/70843940/springdoc-openapi-ui-how..
네이티브 쿼리문 + @SqlResultSetmapping 을 이용한 조회 문제 상황 최범균님의 도메인 주도 개발 시작하기 책을 읽으며 기존 프로젝트를 리팩토링 하던 중 문제에 직면했습니다. StudyEntity (study) 는 StudyApply 벨류 타입을 컬렉션으로 가지고 있으며 해당 벨류 타입을 별도 테이블로 (apply) 생성했습니다. 문제는 기능 요구사항 중 apply 테이블과 study 테이블을 조인해 값을 가져와야 하는 것이었습니다 JPQL에서는 컬렉션으로 지정된 StudyApply의 필드값에 접근할 수 없기 때문에 네이티브 쿼리문 + @SqlResultSetmapping을 이용해 문제를 해결했습니다. StudyEntity @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(name..
Hash 조인, NL 조인 서론 프로젝트 성능 향상을 위해 JOIN 관련해서 공부하던 중 의문점이 생겼습니다. 문제 상황은 아래와 같습니다. 1. 10^4건의 데이터를 가진 테이블 A와 B가 있다. 2. 두 테이블을 인덱스가 없는 칼럼을 기준으로 JOIN 할 경우 10^4 * 10^4 의 시간복잡도를 가지기 때문에 최소 1초는 걸릴 것이라 생각했다. 3. 실행 결과 15ms가 나왔다. 쿼리문은 아래와 같습니다. SELECT p.content FROM post AS p JOIN study AS s ON p.posted_user_id = s.master_user_id; 쿼리 실행계획을 통해 왜 예상과 다른 결과가 나왔는지 확인해보겠습니다. 본론 EXPLAIN ANALYZE 키워드로 확인한 결과 Inner hash join을 사용해 j..
[StudyHub] 성능 관점에서 확인해본 조회 쿼리문 서론 RealMySQL 8.0을 읽으면서 프로젝트에서 작성한 대부분의 쿼리문들이 성능을 염두해두지 않고 작성했다는 것을 알았다. 지금은 데이터 수가 적기 때문에 괜찮지만 추후 데이터 수가 많아졌을 때를 대비해 성능도 올릴겸, 책도 복습할겸 해서 성능 개선 여지가 있는 쿼리문을 확인해보겠다. LIKE @Override public List findByInquiry(final InquiryRequest inquiryRequest, final Pageable pageable, Long userId) { JPAQuery data = jpaQueryFactory .select(Projections.constructor(PostDataByInquiry.class, studyPostEntity.id.as("postI..
[StudyHub] 다중 칼럼 인덱스를 이용한 조회 성능 개선 서론 8만건의 데이터를 조회할 때 평균 95ms의 성능이 나왔기때문에 개선해보고자 한다. 개선하려는 쿼리문은 아래와 같다. SELECT p.post_id, p.major, p.study_start_date, p.study_end_date, u.email, u.image_url FROM post as p LEFT JOIN users as u on p.posted_user_id = u.user_id ORDER BY p.remaining_seat asc, p.created_date desc LIMIT 10 offset 5; 검색 조건은 로그인을 하지 않은 상태로 인기순, 생성날짜(나중에 생성한 날짜가 우선)로 정렬한 전체 데이터를 5 페이지 기준 상위 10개의 데이터를 가져오는 조건이다. 성능 테스트 테이블마..