---
# System prepended metadata

title: Server 대본

---

# Server 대본

생각나는 내용
- mongoDB 설계방식
- Jest, RestAPI
    - 테스트 동기화 ( feat 하나씩 추가할 때 마다 )
- Swagger
    - API 문서 작성을 통한 개발 협업 증가
- 서버 자동배포
    - 빠른 배포를 위한 편의성 제공
- TypeScript
    - 타입지정을 통한 예측가능한 오류 방지
- Webpack
    - 백엔드에서 뭐가좋을까? 찾아보는중
- pm2 cluster
    - 싱글스레드 => 멀티스레드
- 아티랠리
    - 성능 테스트 및 코드 개선
    - 맨처음 실행한 테스트를 기준으로 성능을 점차 늘리자.
- NCP
    - AWS대신 NCP를 이용한 서버배포

목차 
- 



대본
-

저희의 서비스는 많은 에러를 받아야 하기 때문에 서버에서 SDK 에서 보내오는 많은 요청들을 처리하고 뿐만 아니라, Admin 페이지 에서도 많은 요청이 오기 때문에 성능이 좋을 필요가 있었습니다. 
그래서 저희는 평소에 쓰던 작은 크기에 서버 컴퓨터 보다 더욱 좋은 컴퓨터를 빌렸습니다. 하지만, 코어가 여러개라 하여도 Node 는 싱글 쓰레드에서 돌아가기 때문에 서버 컴퓨터의 리소스를 모두 활용할 수가 없었습니다. 
그래서 저희는 읽기쓰기에 강한 MongoDB 와 노드의 프로세서 매니저인 PM2에 클러스터링 모드를 이용해서 Node 를 여러개 만들어서 사용하려고 했습니다. Artillery 를 이용해서 얼마나 처리하는 지를 확인 했습니다.
```
1초에 1000개씩 10초 동안
```


```yaml=
PM2 프로세스 한개 일 때
Summary report @ 18:03:33(+0900) 2020-11-27
  Scenarios launched:  10000
  Scenarios completed: 10000
  Requests completed:  10000
  Mean response/sec: 359.84
  Response time (msec):
    min: 55.1
    max: 9550.5
    median: 8545.4
    p95: 9395.9
    p99: 9519.9
  Scenario counts:
    Message Throw Test: 10000 (100%)
  Codes:
    200: 10000
```

```yaml=
PM2 클러스터링 모드로 프로세스가 4개일 때
Summary report @ 18:06:38(+0900) 2020-11-27
  Scenarios launched:  10000
  Scenarios completed: 10000
  Requests completed:  10000
  Mean response/sec: 513.87
  Response time (msec):
    min: 3.7
    max: 187.5
    median: 6.7
    p95: 41.5
    p99: 98.5
  Scenario counts:
    Message Throw Test: 10000 (100%)
  Codes:
    200: 10000
```

보시는 것처럼 저희가 빌린 서버컴퓨터의 더 잘 사용하여서 더 빠른 처리를 할 수 있게 되었습니다. 서버에서 좋은 결과도 얻었엇습니다. 



또한 저희는 webhook 를 사용해서 master branch 변화가 있을 때, 배포 서버가 이를 감지해서, master branch 에 코드를 가져와서 PM2 reload 를 하게 됩니다. PM2 reload document 에서는 Zero-downtime rolling restart 라서, 코드가 업데이트 되어도 서비스가 중단되지 않고, 계속해서 서비스할 수 있게 하였습니다.

==== 여기 too much ====

restart 할 때에는 충분한 시간을 기다린 뒤에서 마스터 프로세스에 'ready' 를 보내주어야 하는데, 보통은 app 이 켜지자마자 ready 를 보내줍니다. 하지만, 저희 서비스가 구동될 때에는 app 이 켜진뒤 db 를 연결하는등 실제로 준비가 완료된 것은 아니라, ready 를 따로 보내주게 설정했어야 합니다.  


또한 old_app 이 종료되어야할 때 마스터에서는 SIGINT 를 보내고 일정시간 뒤에 SIGKILL 을 하는데 이때 app 이 제대로 close 되어있지 않으면 SIGKIL 를 기다리고 있는 app 이 데이터를 받아서 SIGKIL 당하면 서비스가 유실 되는 것이기 때문에 그런것들 막고 싶었습니다.

==== 여기 too much ====

앞에서 좋은 결과를 가지고 프로젝트를 하던중 sdk Error 를 잡는 부분에서 추후 다시 테스트를 하였는데, 저희는 넘어온 Error 에 ErrorTrace 에서 ErrorType 와 ErrorMessage , 그리고 ErrorStack 에 첫번째 줄로 비교하여 Error 가 이전과 같은 Error 가 있었는지를 비교하고 같은 에러가 있다면 그 에러를 Issue 로 그룹화 해주게 해놓았습니다.

그런데 Error 를 Issue 로써 그룹화할 때 우리는 4개의 app 이 돌아가고있는데 , 동시에 처음보는 4개에 Error 가 app에 도착하면 ,  app 은 기존에 해당 Error 에 대한 Issue 가 없었으니 새로운 Issue 를 만들어서 , 4개에 같은 Error 에대한 Issue 를 만들어주는 버그를 찾았다.

여기에서 우리는 해결법을 찾으려 노력했는데, Transction 을 이용하는 방법을 찾았었는데, 이 방법으로 하게 되면 우리의 처음 목표인 빠르게 하기위해 mongoDB를 사용했는데, 제대로 공부하지 않아서 스스로 느려지게 만든 것 같아서 너무 아쉽다.




대본

![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1747afa0-0401-4369-900a-138656da5037/Untitled_Diagram_(1).png](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/1747afa0-0401-4369-900a-138656da5037/Untitled_Diagram_%281%29.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20201215%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20201215T073221Z&X-Amz-Expires=86400&X-Amz-Signature=373391d7f1dbb092ad5db50bb5ddbbb8277803464b5167a89eea645869b870bf&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22Untitled_Diagram_%281%29.png%22)

그림에서 보시다시피 저희의 개발 과정은 SDK - Server - Client 로 구성되어 있습니다. 개발을 진행하면서 서버측에서는 양쪽의 오류를 검사하고 빠른 피드백이 중요하단 점을 인지하였습니다.

 따라서 서버에서 중요하게 생각한 점은 개발 협업을 위한 API Docs, 기존 코드의 오류를 방지하기 위한 테스트코드, 빠른 피드백과 배포를 위한 서버 자동배포기능 세가지를 소개하려 합니다.

- API DOCS

(Excels 문서로 된 DOCS와 Swagger를 비교하면 너무 저격같으려나?) 먼저 저희는 API DOCS로 Swagger를 채택하였습니다. Swagger는 Express와 함께 동작가능한 API 문서이며, 그림과 같이 API종류, path, query, body, response 등을 한눈에 확인 할 수 있습니다. ( 사진을 보며 좀 길게 설명? )

해당 Docs는 YAML 형식을 통해서 작성되었습니다. 다음은 YAML과 JSON 형식의 비교입니다. JSON의 경우 JavaScript Object와 비슷하고 YAML의 경우 Python의 문법과 유사합니다. 보시는 바와 같이 Docs를 작성할때는 가독성에서 yaml이 더 편한것을 알 수 있습니다. (왜 ? → )

- JEST와 RESTClient를 통한 테스트



- 서버 자동배포