Skip to content
Merged

fix #66

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
# Comeet_BE
[프로그래머스 풀스택 데브코스 7기] 게살버거팀 사이드 프로젝트_위치기반 개발자 커뮤니티

# 트러블 슈팅 경험

## 새로 빌드할 수록 서버 성능 저하

## 문제상황
코드를 새로 배포할 수록, 빌드시간이 증가하여 종국에는 이미지 빌드에 23분이나 걸리게 됨 \
또한 api 응답에 걸리는 시간도 10배 이상 증가함

### 관찰 1
image를 새로 빌드할 때마다, CPU & Network 사용량이 급격하게 증가하는 것을 발견

### 해결 1
github action을 이용하여 별도 서버에서 이미지를 빌드하여, docker hub에 올리고 \
프로덕션 서버에서 빌드된 이미지를 pull 해서 쓰는 것으로 변경
-> 빌드시간 3분 이내로 안정화됨, 그러나 api 성능 저하는 해결하지 못함

### 관찰2

``` shell
docker stats
```
명령어를 통해 container의 자원 사용량을 발견
-> 순간 Net/IO, Block/IO 항목이 할당량 보다 많은 자원을 소비하는 것을 알게 됨

### 해결2
t2 micro 크래딧의 한계로 인한 성능저하로 판단하여, unlimited 모드로 설정함 \
unlimited 모드: 자원 사용량이 limit을 초고할 경우 credit을 초과분 만큼 늘리고 후에 초과 사용량 만큼의 금액을 청구하는 방식 \
응답시간 다시 이전과 같은 수준으로 감소함

### 결론
docker를 통해 안정적인 배포를 하려면 t2 micro 보다 높은 사양 서버가 필요 \
규모가 작은 프로젝트라먄 도커를 사용하지 않고 t2 micro에 배포하는 것도 합리적이어 보임
Comment on lines +9 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

안녕하세요, 추가해주신 트러블슈팅 경험 공유 감사합니다. 내용 중 몇 가지 오타와 마크다운 서식에 대한 제안이 있습니다.

  • 오타 수정

    • 30행: 초고할 -> 초과할
    • 35행: 프로젝트라먄 -> 프로젝트라면
  • 마크다운 서식

    • 여러 줄 끝에 있는 \ 문자는 일부 마크다운 렌더러에서 의도치 않게 표시될 수 있습니다. 줄바꿈을 원하신다면 줄 끝에 공백 두 개를 사용하시거나, 문단 구분을 위해 빈 줄을 사용하시는 것이 더 일반적입니다. 가독성을 위해 \를 제거하는 것을 고려해보세요. (해당 라인: 9, 16, 29, 30, 34)



13 changes: 10 additions & 3 deletions src/users/api/search.adjacent.users.query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { SearchAdjacentUsersDTO } from "../dto";
import { OmitType } from "@nestjs/swagger";
import { ApiProperty, OmitType } from "@nestjs/swagger";
import { IsRange } from "../../utils";
import { IsOptional } from "class-validator";

export class SearchAdjacentUsersQuery extends OmitType(
SearchAdjacentUsersDTO, ["id", "origin"]
) {}
SearchAdjacentUsersDTO, ["id", "origin", "birthyear"]
) {
@IsRange()
@IsOptional()
@ApiProperty({ name: "age", type: "string", pattern: "^(\\d)-(\\d)$", required: false })
age?: [number, number];
}
14 changes: 1 addition & 13 deletions src/users/dto/search.users.filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,9 @@ import { ArrayMinSize, IsInt, IsOptional } from "class-validator";
import { ApiProperty } from "@nestjs/swagger";
import { IsRange } from "../../utils";
import { RangeObject } from "../../utils/range";
import { Expose, Transform } from "class-transformer";
import { Transform } from "class-transformer";

export class SearchUsersFilters {

@Transform(({ value }) =>
value && RangeObject.fromRange(
value.map((age: number) =>
new Date().getFullYear() - age + 1
).reverse()
)
)
@IsRange()
@IsOptional()
@Expose({ name: "age" })
@ApiProperty({ name: "age", type: "string", pattern: "^(\\d)-(\\d)$", required: false })
birthyear?: RangeObject;

@Transform(({ value }) => value && RangeObject.fromRange(value))
Expand Down
19 changes: 1 addition & 18 deletions src/users/interceptor/search.users.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nes
import { from, map, mergeMap, Observable, toArray } from "rxjs";
import { SearchUserResult } from "../dto";
import { transformBirthyearToAge } from "./interceptor.internal";
import type { Request } from "express";

type __ResponseT = { results: object[] };

Expand All @@ -14,25 +13,9 @@ export class SearchUsersInterceptor
> {

intercept(
ctx: ExecutionContext,
_: ExecutionContext,
next: CallHandler<SearchUserResult[]>
): Observable<__ResponseT> {
const req: Request = ctx.switchToHttp().getRequest();

if (req.query) {
const { age, ...rest } = req.query;

if (age && typeof age === "string") {

const birthyear = age
.split('-')
.reverse()
.join('-');

req.query = { birthyear, ...rest };
}
}

return next.handle().pipe(
mergeMap(data => from(data)),
map(transformBirthyearToAge),
Expand Down
13 changes: 11 additions & 2 deletions src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
UpdateUserBody
} from "./api";
import { Coordinates } from "../common/geo";
import { RangeObject } from "../utils/range";

@ApiTags("Users")
@Controller('/api/users')
Expand Down Expand Up @@ -87,8 +88,16 @@ export class UsersController {
@Query()
query: SearchAdjacentUsersQuery,
): Promise<SearchAdjacentUserResult[]> {
const { age, ...rest } = query;

const birthyear = age && RangeObject.fromRange(
age.map(x =>
new Date().getFullYear() - x + 1
) as [number, number]
);
Comment on lines +93 to +97

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

연령 범위를 출생 연도 범위로 변환하는 로직에서 .reverse() 호출이 누락되었습니다.

현재 로직은 age[20, 30]과 같을 때 출생 연도 범위를 [2004, 1994]와 같이 잘못된 순서로 생성합니다. 이로 인해 데이터베이스 쿼리가 의도한 대로 동작하지 않아 검색 결과가 비어있게 될 수 있습니다.

기존 search.users.filters.ts 파일에 있던 것처럼 map 호출 후에 .reverse()를 추가하여 [1994, 2004]와 같이 올바른 순서의 배열을 생성해야 합니다.

Suggested change
const birthyear = age && RangeObject.fromRange(
age.map(x =>
new Date().getFullYear() - x + 1
) as [number, number]
);
const birthyear = age && RangeObject.fromRange(
age.map(x =>
new Date().getFullYear() - x + 1
).reverse() as [number, number]
);


return this._searchUsersService
.searchAdjacentUsers({ id, origin, ...query });
.searchAdjacentUsers({ id, origin, birthyear, ...rest });
}

@Get("/search/hot")
Expand All @@ -102,7 +111,7 @@ export class UsersController {
.searchHotUsers();
}

@Get("/subscriptions")
@Get("/search/subscriptions")
@ApiOperation({ summary: "구독중인 유저 검색" })
@ApiBearerAuth()
@ApiOkResponse({ type: SearchUsersResponse })
Expand Down