[F-Lab 모각코 챌린지 46일차] IO Bound Application 띄우고 부하테스트하기

부추·2023년 7월 16일
0

F-Lab 모각코 챌린지

목록 보기
46/66

1) PostgreSQL 인스턴스 생성 및 연결

CentOS7이 싫어지려고 한다. 얘 때문에 고생을 너무 많이 하고있다. 지금 RabbitMQ 인스턴스 띄우고 있는데 또 삑나서 노트북 부술 뻔했다.

아무튼 CentOS7에서 도커의 postgresql 이미지를 받으면 삑난다. 이런저런 개삽질을 다 해봤는데 안돼서, 그냥 홧김에 우분투로 질러버렸다. GCP에 우분투 VM 서버를 만들자. 여기에 postgresql이미지를 땡겨오겠다. SSH 접속 ㄱㄱ!

일단 도커를 설치하자. 공식 문서를 참고했다. 아래 명령어들을 쭉~ 입력해주면 된다.

$ sudo apt-get update
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

도커가 정상적으로 설치되었으면, 도커의 postgres 이미지를 내려받고 컨테이너로 실행시키자.

$ docker run --name pgsql -d -p 5432:5432 -e POSTGRES_USER=postgresql -e POSTGRES_PASSWORD=postgrespassword postgres
  • --name pgsql : 실행하는 도커 컨테이너의 이름을 pgsql로 설정한다.
  • -d postgres : postgres이라는 이미지에서 분리하여 container를 생성한다.
  • -e : 컨테이너 내 변수를 설정한다. 접속자의 유저 아이디와 비밀번호를 POSTGRES_USER, POSTGRES_PASSWORD로 설정했다.
  • -p 5432:5432 : 호스트의 5432번 포트와 컨테이너의 5432번 포트를 연결하는 과정. 호스트 서버, 즉 현재 우분투 서버의 5432번 포트로 들어온 요청을 컨테이너의 5432번 포트로 포워딩하게 하는 설정이다.

내 경우 별다른 문제 없이 실행됐는데 아닐수도.. 하도 삽질 많이해서 기억이 안난걸수도..

postgresql은 기본적으로 5432번 포트를 사용한다. GCP에서 기본 설정된 방화벽 때문에 5432번 포트의 접근은 막혀있다. jenkins 인스턴스의 8080 포트를 허용했던 것처럼, "방화벽 규칙 설정"에 들어가 DB서버 인스턴스의 5432번 포트의 접근을 열어주자!
어쩌구저쩌구 해서(과정 생략) 잘 만들어졌다. 아래 사진처럼 tcp:5432 허용이 나면 된다.

마지막으로, JPA를 사용하는 프로젝트의 설정 파일인 application.yml을 통해 방금 만든 postgresql 서버를 연결할 차례다. 다음 코드를 작성한다.

spring:
  datasource:
    url: jdbc:postgresql://10.178.0.14:5432/postgresql
    username: postgresql
    password: postgrespassword
  jpa:
    show-sql: true
    hibernate:
      dialect: org.hibernate.dialect.PostgreSQLDialect
      ddl-auto: update

이 뒤 @Entity, @Repository 등의 어노테이션을 사용해서 기본 엔티티-테이블 구조 코드를 만들고 스프링 프로젝트를 구동하면.. 잘 된다.


2) github의 webhook 사용해보기

깃헙에 새로운 코드를 만들어 push만 하면 우리의 워커 노드에 자동으로 빌드 및 배포가 되도록 하고 싶다. 지금 배포를 위해 젠킨스를 사용하는 상황이므로, 젠킨스에 접속한다. 아이템을 추가하고, "소스 코드 관리"탭의 Repository URL에 프로젝트의 깃헙 주소를 복붙한다.
main 브랜치에 push된 코드만을 실제 서비스에 반영하고 싶으므로, Branches to build 탭에는*/main이라고 적는다. 그리고 "빌드 유발" 탭의 "GitHub hook trigger for GITScm polling"항목을 체크한다.

현재 패키지 빌드 툴로 maven을 사용중이다. 깃헙에 push된 소스코드를 maven으로 빌드하기 위한 작업을 커맨드로 지정해줘야 한다. ./mvnw를 직접 사용하기 위해 스크립트 파일 권한설정을 바꾸고 clean package 빌드 작업을 할 수 있도록 하자!

chmod 544 ./mvnw
./mvnw clean package

이제 빌드 후 조치 차례이다. 빌드 결과는 /target 디렉토리 아래 io-0.0.1-SNAPSHOT.jar 파일로 존재할 것이다. 연결된 워커노드 각각에 서버 프로그램 소스파일, 그리고 해당 파일을 실행하기 위한 커맨드를 작성해주자. 아래와 같다.
톰캣은 80번 포트로 요청을 받게 설정했는데, 80번 포트에 열린 다른 프로그램이 있다면 곤란하므로 sudo kill을 사용했다. nohup 관련한 것은 전날의 게시글에 설명했으니 패스..


방금 젠킨스에서 설정해 준 것들은 모두 github의 web hook이 있어야 동작하는 것들이다. 젠킨스에 설정한, 프로젝트 깃헙 사이트로 들어가 "Settings"탭에 들어간다.

그 뒤 webhooks 탭 gogo.그리고 post 요청을 날릴 젠킨스 인스턴스의 IP 주소에 "github-webhook/"문자열을 더해 Payload URL을 추가한다. Content type은 json, 트리거는 push만, Active 설정 후 저장.
이제 해당 깃 레포지터리 main 브랜치에 어떤 코드가 push되면 젠킨스 측에서 자동 deploy를 해줄 것이다. 한번 Push해보고, 젠킨스 빌드 결과물의 console을 확인해보자.
진짜로 내 push로 인해서, 내가 입력한 build 커맨드가 실행되었다.


3) artillery 이용한 부하 테스트

artillery는 nodejs 기반으로, 스크립트를 작성해서 서버에 요청을 보내 성능 테스트를 할 수 있게 해주는 툴이다.

현재 컨트롤러 코드는 대강 이렇다.

@RestController
public class PostController {
    @Autowired
    PostRepository postRepository;

    private static final Integer PAGE_SIZE = 10;

    // 1. 글을 작성한다.
    @PostMapping("/post")
    public Post createPost(@RequestBody Post post) throws JsonProcessingException {
        return postRepository.save(post);
    }

    // 2. 페이지 단위로 글 목록 받기 : default = 1
    @GetMapping("/posts")
    public Page<Post> getPostList(@RequestParam(defaultValue = "1") Integer page) {
        return postRepository.findAll(PageRequest.of(page-1,PAGE_SIZE, Sort.by("id").descending()));
    }
    
    // 3. 글 번호로 조회
    @GetMapping("/posts/{id}")
    public Post getPost(@PathVariable Long id) {
        return postRepository.findById(id).get();
    }
    
    // 4. 글 내용으로 검색 -> 해당 내용이 포함된 모든 글
    @GetMapping("/search")
    public List<Post> findPostByContent(@RequestParam String content) {
        return postRepository.findByContentContains(content);
    }
}

그냥.. 150자 미만의 짧은 글을 작성할 수 있게 하는 게시판 C-R 코드이다. 이 서버에 매 초 n개의 요청을 보내서 latency가 얼마나 나오는지, 혹시 서버가 죽거나 하진 않는지 테스트를 해보고 싶다.


이렇게 생긴 ratings_test_5k.csv 파일의 데이터를 토대로 POST요청을 날려보도록 하겠다. 테스트에 사용되는 데이터는 강의에 나온걸 참고했는데 구글에 간단하게 150자 미만의 korean 데이터라고 검색하면 구할 수 있다
artillery의 공식 가이드에 나와있는 안내 그대로, npm install을 통해 라이브러리를 내려받고 post-content.yml 파일을 만들었다. 부하 테스트에 사용할 설정 파일이다. 설정 파일을 쭉 작성하자!

config:
  target: "http://{Nginx path}"
  phases:
    - duration: 300
      arrivalRate: 8
  payload:
    skipHeader: true
    path: "ratings_test_5k.csv"
    fields:
      - "content"
scenarios:
  - name: post test
    flow:
      - post:
          url: "/post"
          json:
            content: "{{ content }}"
  • duration이 300이므로, 300초 동안 테스트를 진행한다.
  • arrivalRate이 8이므로, 초당 8번의 POST 요청이 간다.
  • payload.path : HTTP 요청 메세지의 payload의 구성으로 위에서 가져온 csv파일을 설정해줬다. 첫번째 컬럼이 content 항목이다.
  • scenarios.post : 안에 POST 요청을 날릴 url, 그리고 HTTP body를 담았다.

해당 스크립트를 돌리는 커맨드다.

$ artillery run --output io-report.json post-content.yml

--output io-report.json은, 지금 진행하는 테스트의 결과를 io-report.json파일에 저장하겠다는 뜻이다.

테스트가 끝나면 결과 파일을 한눈에 볼 수 있게 하기 위해 html로 만들어주는 과정이 필요하다. 터미널에 아래 커맨드를 입력하자!

$ artillery report io-report.json

결과로 io-report.json.html파일이 나온다. 해당 파일을 브라우저나 html을 읽는 다른 뷰어로 열면.. 진행한 부하 테스트의 latency, 응답 상태코드 등을 다이어그램으로 확인할 수 있다.

profile
부추튀김인지 부추전일지 모를 정도로 빠싹한 부추전을 먹을래

1개의 댓글

comment-user-thumbnail
2023년 7월 17일

저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!

답글 달기