이전글:
https://lemontia.tistory.com/910
올 한 해를 한 단어로 표현하면 '내실 다지기'라 할 수 있겠다. 그동안 제대로 동작하지 않았던 것들을 수정하고, 사람이 손이 덜 들어가게 자동화하는 등 최대한 내부적인 문제점을 해결하는 데 중점을 두었다.
나 역시 이전 것을 수정하는 것보다는 새로운 것을 만드는 게 편하다. 하지만 시스템이라는 것이 계속 원활하게 수행되려면 지속적인 유지 보수를 해주어야 한다. 집에 불이 났는데 외출할 수 없는 것처럼, 내재적인 위험성을 최대한 제거해두어야 앞으로 해야 할 것들을 할 수 있는 시간을 확보하고 발전할 수 있기 때문이다. 그래서 자동화, 관리 포인트를 줄이는데 특히 신경을 많이 썼으며, 그러다 보니 자연스레 새로 만든 것보다는 기존 시스템을 개선하는 것들이 훨씬 많았다.
# 내 시간을 뺏는 것을 찾아 리팩토링하기
우선적으로 했던 것은 정산 데이터의 안정화였다. 서버가 한 번씩 문제가 생기면 정산에 반드시 문제가 생겼다. 어느 날에는 20분 정도 장애가 생겼었는데 그 여파로 100만 원의 비용이 발생했다. 시스템 상 결제가 취소되어야 하는데 한쪽은 취소되고 한쪽은 유효한 상태로 남아있는 문제. 비용 문제뿐만은 아니었다. 그것을 수습하기 위해 인력이 붙어야 했고, 짧게는 3시간에서 길게는 며칠을 온전히 쏟아부어야 했다. 늦게 처리할수록 비용이 늘어나기 때문에 최대한 빠르게, 그리고 정확하게 해야 하는데 그 과정에서 오는 스트레스가 엄청났다. 그래서 우선 시스템 안정화를 하는데 중점을 두고, 이후 정산 데이터를 감시하도록 하였다. 데이터베이스에 인덱스를 개선하여 성능을 올렸고, SpringBatch-Jenkins를 이용해 1시간에 한 번씩 대사하도록 했다. 익숙하지 않은 SpringBatch에 JPA까지 쓰려니 좀 애먹었지만, 덕분에 JPA 문법에 익숙해질 수 있는 기회가 되었다. 현재는 정산 관련해서 한 달에 0~2시간 내외로 검수해도 충분할 정도로 고도화했다.
# 늘어나는 데이터 요청에 빠르게 대응하기
요청하는 항목에 따라 소요되는 시간이 들쑥날쑥하지만 많은 데이터를 기반으로 요구 사항을 추출할 때는 특히 시간이 오래 걸렸다. 적게는 3개월치, 길게는 2~3년 치의 데이터를 요청할 때가 있는데, 데이터가 많다 보니 서버에 부담이 되는 것은 물론이고 속도가 매우 더뎠다. 마침 관심이 있던 파이썬을 보고 있었는데 데이터를 처리하는데 가장 빠르다고 해서 도입해본 결과 압도적인 성능을 자랑했다. 이거다 싶어 좀 더 시간을 투자하였고 덕분에 이전에는 2~3일, 길게는 1주일 정도 걸릴만한 요청 건을 단 하루 만에 해결할 수 있었다. 가장 극적으로 효과를 본 것은 일주일 동안 매달리며 뽑았던 데이터를 단 20분 만에 해결할 수 있게 한 것이다. 당시 일주일 동안 매달리면서 삽질했던 당사자의 표정은 잊지 못할 기억이 됐다.
하는 동안 우여곡절이 많았다. 익숙지 않은 python과 padnas를 다룬다는 것은 꽤 곤욕이었다. 주말을 꼬박 학습하는데 쓴 적도 적지 않고, 때로는 SQL로 해버릴까 하는 충동도 많이 느꼈다. 그럼에도 꾸준히 필요한 것을 찾아가면서 학습했고 점점 속도가 붙었다. 최근에는 자주 뽑는 요청 건에 대해서는 Java(Spring boot) + Python(pandas)을 연계해 웹페이지로 만들었다. 버튼 하나로 데이터가 추출될 수 있도록 만들었는데, 덕분에 매월 반드시 할애해야만 했던 시간을 꽤 줄일 수 있었다. 간혹 커스텀이 필요하면 많은 시간을 요구하게 되지만.
똑같은 일을 줄이겠다고 마음먹지 않으면 무의식적, 습관적으로 일을 하게 된다. 만약 내가 '이 정도로도 적당히 나오는데'라고 생각했다면 프로그램으로 만들 생각을 하지 않고 여전히 수동으로 수행했을 것이다. 당연한 말이지만 프로그램을 만드는 시간이 꽤 걸렸다. 그럼에도 만들어두고 나니 유용하게 활용함은 물론이고, 앞으로의 시간도 세이브 될 것을 생각하니 뿌듯했다. 추후 데이터웨어하우스가 본격 구축이 된다면 이 프로그램도 더는 안 쓸 거 같지만, 그게 언제가 될지 명확히 알 수 없기에 만들길 잘했단 생각을 한다. '어차피 화장실 갈 건데 밥을 왜 먹어요' 같은 질문을 할 사람은 없으니까.
# 하반기 최고의 이벤트, 서버 이전
서버 이전을 단 한 번이라도 해본 사람은 알 것이다. 얼마나 피곤하고 신경 쓸 일이 많은지. 시스템 아키텍처, 네트워크 구성은 물론이고 DBMS 데이터를 모두 가져와야 했다. 현재 회사 내 DBMS의 백업은 약 500G, 라이브에서는 700G 정도의 물리적 용량을 사용하고 있으며 매일 백만 단위의 데이터가 적재되고 있었다.
서비스의 성격은 B2C, 24시간 서비스이기 때문에 다운타임을 길게 잡으면 안 됐다. 그리고 당연한 말이지만 오픈하고 나서 에러가 나면 안 되기에 꼼꼼히 살펴봐야 했다. 코드 쪽보다는 방화벽, 외부 통신 등 인프라 쪽을 중요하게 봤으며, 변경되는 DBMS에서 이전과 같은 퍼포먼스가 나오는지 확인할 필요가 있었다. 기껏 옮겼는데 이전 유저를 소화하지 못할 정도의 스펙이라면 분명 큰일 날 것이기 때문이다. 그리고 서버 이전이 실행되기 전날까지 새롭게 개발되는 건, 기존 것 유지 보수 등 코드가 계속 변했기 때문에 이에 대한 문제점도 최소화할 필요가 있었다.(서버 이전 이슈는 IT 부서의 이슈지 타부서에는 사실상 관계없는 이슈이기 때문에 새로운 요청 사안을 조절하고 최소한으로 줄이긴 했지만 그럼에도 불구하고 급하게 돌아가는 것들에 대해서는 처리해줄 수밖에 없었다.)
2개월 전부터 외부 방화벽 문제를 우선 체크했다. 그리고 라이브와 동일한 환경을 새로 이관할 서비스에 구축해두어야 했다. 그래야 서비스가 원활히 수행되는지 점검할 수 있기 때문이다. 똑같은 환경을 구성하는데 가장 큰 문제점은 서비스 작동 여부보다 라이브 서비스에서 작동하는 것이 중복 작동할까 봐 조심스레 진행했다. 스케줄을 수행하면서 특정 조건에 맞는 고객들에게 푸시-문자발송하는 기능이 있었는데, 데이터를 라이브에서 복제한 것이기에 라이브 서버와 가상으로 구축한 서버 양쪽에서 푸시-문자를 중복되게 보내면 절대 안 되기 때문에(그럴 경우 CS 팀에서 고생할 것이기에...) 특별히 신경 써야 할 부분이었다.
처음 이 프로젝트를 맡게 되면서 가장 중점에 둔 것은 많이 수행해 보는 것이었다. 그래서 아키텍처를 구성하고 삭제하기를 5번, 데이터베이스를 복제하고 삭제하기를 3번 정도 수행했다. 미들웨어 6개, 로드밸런서, 네트워크, 방화벽을 구성해야 했고, DBMS는 구축 및 DBMS 설정 확인, 데이터 복사 및 지속적 복사 기능을 점검해야 했기에 적지 않은 양이긴 했다. 진행하면서 부족한 부분은 추가 스크립트를 만들거나 자동으로 점검할 수 있도록 모듈을 개발해 수행시켰다. 데이터는 적절하게 잘 복사되는지 점검하는 모듈도 추가했다. 결과적으로 이번 프로젝트를 성공적으로 수행하기 위해 돌았던 백그라운드 모듈이 총 5개 정도 개발-운영되었다.
데이터베이스 성능점검은 반드시 해야 할 과정이었는데, 가장 오래 걸리는 API 몇 개를 nGrinder를 이용해 테스트했다. 이 테스트가 정말 도움이 된 것이, 현재 구성한 것이 어느 유저까지 커버할 수 있는지를 측정하는 척도가 되었다. 수행 결과, 지금 유저의 2~3배까지 동접자수가 늘어도 커버가 가능한 것을 확인했다. 덕분에 좀 더 자신 있게 진행할 수 있었다.
다운타임을 길게 잡지 말아야 할 것, 그리고 에러가 나지 않도록 꼼꼼히 점검해야 할 것이 이번 목표였다. 수행 시간은 0시부터 6시까지로 잡았지만 실질적으로 작업할 수 있는 시간은 0~3시까지였다. 점검 시간을 최소한으로 해야 이전하는 당일에 실점검 테스트할 시간을 확보할 수 있기 때문이다. 하지만 실제 수행된 시간은 총 90분이었다 이미 필요한 것들은 미리 복사를 마친 상태였으며, 수시로 수행되고 있는 모듈들이 신뢰를 더해주었기 때문이다. 오히려 너무 일찍 끝난 탓에 '정말 다 끝났어?'라는 대답을 들었다. 사전에 충분히 수행한 테스트가 신뢰를 갖게 했고, 그 결과 현 서비스의 피크시간인 8~9시, 11~1시에 서비스 자원 사용률이 10%가 넘지 않는 매우 깨끗한 상태를 유지할 수 있었다.
이번 작업을 하면서 가장 많이 느낀 것은, 기술의 축적과 신뢰에 대한 것이었다. 이전까지 서버 점검이라 하면 데이터를 제외한 나머지 것들을 미리 구축해놓고, 데이터베이스를 dump 형태로 밀어 넣어 마무리하는 형태였다. 그럼에도 불구하고 사전에 테스트 되지 않아 방화벽 문제가 발생해 서비스가 원활하지 않은 문제가 생겼었고, 데이터베이스의 용량이 클수록 복구하는 대기시간을 길어질 수밖에 없었다. 하지만 이번에는 데이터를 수시로 복사, 점검하였고 사전에 테스트 및 수행 작업을 몇 차례나 시뮬레이션 하면서 사고하나 없이 완벽하게 프로젝트를 마무리할 수 있었다. '어떻게 하면 잘할까?'라고 고민할 시간에 한 번이라도 더 수행해보고 부족한 것을 보충하면서 하나하나 쌓아갔고, 그것이 결과를 이끌어냈다.
이번 한 해는 이렇게 마무리되었다. 그리고 다가오는 2020년에는 무엇을 하고 집중해야 하는지를 간단하게 정리해봤다.
1) 모든 테스트 자동화
시스템이 제법 커지다 보니 새로 개발하거나 기존 것을 수정하는데 알게 모르게 부담이 된다. 이 부분을 해소하기 위해 테스트 자동화를 구축하도록 했다. 이전까지 작성되어 있지 않은 테스트는 새롭게 작성하고, 신규 개발은 무조건 테스트를 작성하도록 했다. 처음이라 테스트 작성이 어설프고 완벽하진 않지만, 어느 정도 지나면 분명 충분히 제 역할을 해주리라 믿고 있다. 또한 사람이 직접 해주는 테스트를 벗어나는 부수적 효과도 노릴 수 있으니 반드시 수행되어야 할 과제다.
2) 데이터웨어하우스 구축, 본격 데이터분석 시작
회사에 입사할 때 갖던 목표 중 하나는 개인화 서비스를 위한 인프라 구축 및 활용이었다. 그리고 1년이 지난 이제서야 첫삽을 뜰 수 있게 되었다. 진작부터 하고 싶었지만 내실이 튼튼하지 않은 상황이라 섣불리 할 수 없었다. 그러나 이제는 시스템이 어느 정도 안정권에 진입하게 되어 시작할 수 있을 것 같다. 빠르게는 1월, 늦어도 2월부터 시작할 예정이다. 파이썬을 공부했던 방법처럼 하나씩 구축해 볼 생각이다. 처음부터 완벽하게 할 생각은 없다. 몇 번의 시행착오를 겪어야 할지 감도 안 잡힌다. 그러나 하나씩 하다 보면 언젠가 구축되겠지라는 희망으로 시작할 예정이다.
3) 객체지향으로의 회귀
앞으로 유지 보수를 원활하게 하기 위해서 어떻게 노력하면 좋을지 많이 고민하다가 내린 결론이다. 최근 인상 깊게 읽은 책인 <오브젝트> 그리고 JPA 관련 인강을 보면서 어떻게 해야 유지 보수가 쉽지만 과감하게 업데이트를 할 수 있을지 많이 고민했고, 그런 일환으로 언어를 가장 언어답게 쓰자는 생각에 닿았다. 그래서 앞으로는 시스템 내부의 많은 부분을 리팩토링할 예정이다. 이 목표는 테스트 자동화와 연결되어 있다. 한 번에 모든 것을 바꿀 수는 없겠지만 일주일에 2개만 하자라는 목표로 해볼 생각이다.
이 모든 목표의 지향점은 단 하나, 바로 사람을 위해서다. 엉망인 소스, 복잡한 테스트는 그만큼 많은 인력을 요구하게 되고 수정하는 사람을 피곤하게 한다. 잦은 에러는 사람을 주눅 들게 하고 위축시키며 시스템이 두려워지게 만들고 더 좋은 방향으로 수정하려는 노력보다는 '이건 이러이러해서 안돼요'라는 이유를 대게 만든다. 잘 만들어진 서비스는 앞으로 새롭게 추가할 시스템을 적용하기 유연해질 것이며 이는 장기적으로 모두의 이익에 부합될 것이다. 분명 지향하는 목표는 매우 클지 몰라도 하루에, 일주일에 1~2개씩 꾸준히 해낸다면 언젠간 생각했던 좋은 시스템으로 도달할 수 있으리라 믿는다.
'공부 > 프로그래밍' 카테고리의 다른 글
[java] builder 패턴, 객체를 안전하게 생성하기 (0) | 2020.01.29 |
---|---|
[react, springboot] react 와 spring boot 로 구성하기, 묶어 build 하기 (21) | 2020.01.19 |
[개발] 2019년 상반기 회고록 (0) | 2019.12.29 |
[gitlab-telegram] gitlab 의 메세지를 telegram으로 받기 (0) | 2019.12.20 |
[docker] 로그 logrotate 로 관리하기(주기적으로 삭제하기) (0) | 2019.12.18 |
댓글