주요글: 도커 시작하기
반응형

2020년 4월 21일 화요일 오전 8시 20분. 어제 이 시간에는 이미 서버 응답 시간이 증가하기 시작했다. 간헐적으로 됐다 안 됐다를 반복하다 8시 40분 정도부터 서비스를 사용하기 힘든 수준으로 서버 상태가 나빠졌다. 온라인 개학이 시작한 4월 17일부터 여러 온라인 서비스가 먹통 증상을 보이고 있다지만 오늘도 서비스에 문제가 발생하면 안 된다. 고객 이탈이 심해질 것이다.

 

8시 40분, 9시, 10시, 11시 .... 오후 5시. 평온하다. 간헐적인 오류도 있긴 했지만 비교적 하루가 무사히 지나갔다. 고생한 J 개발자에게 수고했다고 슬랙 메시지를 보냈다. 긴장이 풀리면서 피로가 밀려온다.

시작

2020년 3월 5일 오후. 관계사인 M사의 서비스에 성능 문제가 있으니 같이 보라는 지시가 내려왔다. JPA를 이용해서 서버를 개발했는데 내가 JPA 경험이 있다는 이유로 나한테까지 연락이 왔다. 대충 들어보니 사용자가 증가하면서 서비스가 먹통이 되었다고 한다.

 

M사 서버 개발자 J에게 연락해서 VPN, 스카우터, DB 정보, 소스 리포지토리 주소를 받았다. 스카우터로 확인해보니 XLog의 많은 점이 폭포처럼 찍혀 있다. 나이아가라 폭포 같다. XLog에서 느린 쿼리를 몇 개 찾아 실행 계획을 확인했다. 풀스캔이다. 이런 쿼리 몇 개를 찾아 인덱스 추가를 요청했다.

 

다음날 점심을 먹고 있는데 전화가 왔다. M사에 직접 가서 지원하라는 지시였다. 식사를 마치고 바로 M사로 이동했다. 사무실에 도착해서 현 상태를 들었다. 클라우드 DB의 CPU와 IO 성능을 높였는데 일시적인 효과는 있었지만 여전히 응답 시간이 느린 상태라고 한다. 상황이 나빠서인지 서버 개발자 근처에 이사람 저사람 우루루 몰려와 각자 떠들고 있다. 개중에는 윗사람에 잘 보이려고 온 인간도 보인다. 별 도움 안 되는 소리만 하면서 시간을 뺏는다.

 

한바탕 소란이 지나고 다들 돌아갔다. 중간 중간 서비스 상태를 물어보는 사람만 있을 뿐 집중할 수 있는 환경이 되었다. 서버 개발자 J와 해결안을 찾기 시작했다. 응답 시간이 느린 요청부터 확인하기 시작했다. 두 가지 정도가 눈에 들어왔다. 첫 번째는 느린 쿼리다. 인덱스 추가로 일부 해결할 수 있을 것 같다. 어떤 기능은 like 검색을 하는데 페이징 처리를 위해 count 쿼리도 날린다. 이건 다른 해결안을 찾아야 할 것 같다. 두 번째는 불필요한 쿼리를 너무 많이 실행하는 기능이다. JPA를 잘못 사용한 것으로 보인다.

코드

성능 개선안을 도출하기 위해 코드를 보다 자세히 보기 시작했다. 에휴..... 한숨이 절로 나온다. 코드가 기능 추가/변경, 성능 개선 등은 내 알 바 아니라고 말하고 있다. JPA를 사용했지만 JPA가 제공하는 매퍼 기능을 제외하면 맵을 사용하는 것과 별 차이가 없을 정도다. 족보를 알 수 없는 자신만의 모듈을 만들어 사용하고 있어 성능 향상을 위한 운신의 폭도 좁다.

왜 이렇게 했을까 사정을 들어보니 오픈전까지 같이 개발한 프리랜서가 구현 기술을 선택하는 등 일종의 표준을 잡았다고 한다. 그런 개발자에게 중요 결정을 맡겼으니 지금 M사의 고생은 어찌보면 자업자득이다. 단지 나도 같이 빨려서 고생을 하고 있으니 그게 싫을 뿐이다.

코드에서 발견한 근본적인 문제는 엔티티 연관을 아주 마음껏 사용했다는 거다. 일대일, 일대다, 다대일 가릴 것 없이 엔티티 간 연관을 거미줄처럼 설정했다. 이로 인해 목록 조회시 정말 많은 쿼리를 불필요하게 실행하고 있다.

API도 문제다. 스프링을 사용했지만 전형적인 구조가 아니다. 스프링 MVC를 확장해서 JPA 리포지토리를 바로 API에 연결하도록 구현했는데 조회한 엔티티를 그대로 API 응답으로 보낸다. 이 자체도 문제지만 거미줄처럼 연관된 모든 데이터를 함께 전송하고 있는 것도 문제다. 수정은 조회한 엔티티 데이터에서 일부만 변경해서 그대로 다시 보내는 방식을 사용했다. 연관된 데이터도 모두 포함해서 말이다.

엔티티 처리 로직도 흩어져 있다. 생성 전, 생성 후에 불리는 메서드가 있고 이 메서드에 생성 관련 로직이 흩어져 있다. 조회도 비슷하다.

최근에 본 코드 중에 가장 나쁘다.

그래도

 

코드가 이 모양이어도 문제를 해결해야 한다. 서비스는 해야 하니까. 해결을 시도해 보자.

 

[2부]에서 계속...

 

+ Recent posts