갑진년 맞이 연초 회고록을 작성해 보려고 한다.

2023년 1월, 모바일 게임 회사에 지원을 하였다.
공고에는 php, golang, node.js, c, c++, docker, kubernetes, helm, redis, memcached, mysql 등과 같은 기술들이 적혀있었다.
공고를 보고 게임회사에서 서버 개발자는 어떤일을 하는지 몰랐어서, 검색을 해본 결과,, 두종류의 서버로 나뉘었다.
1. 실시간 기능이 필요한 소켓 서버
2. 일반적인 웹 서버
1번의 경우에는 예를 들자면, MMORPG인 리니지와 같이 수만명의 연결을 유지해 상호작용이 필요한 서버이고,
2번의 경우를 예를 들자면, 턴제게임인 세븐나이츠와 같이 혼자 플레이 하는 서버이다. (pvp와 같이 실시간 대전 서버의 기능이 필요하다면 웹 서버 뿐만 아니라 실시간 서버가 추가로 들어갈 수 있다.)
서류지원 -> 필기 테스트 -> 1차 면접 -> 2차 면접 -> 입사의 채용 프로세스를 거치면서
면접 과정에서 많은것들을 여쭤봤다. 웹 서버는 PHP, 실시간 서버는 Golang 혹은 node.js를 사용하며 내가 지원한 팀의 게임의 기능은 약 80%정도가 1번의 기능이 필요했고, 나머지 20%의 기능은 2번을 필요로 했다는 것을 알게 되었다.
즉, 우리 게임은 두가지 종류의 서버를 구축해야 했다.
운이 좋게도, 좋은 기회를 잡아 입사를 하게 되었다!
2024년 2월이 되며 1년이 지나면서 돌이켜보면 정말 많은 것들을 배울 수 있었다.
아래와 같은 기술스택으로
PHP(웹 서버), Go(실시간 소켓 서버), Linux, Nginx, Docker, Kubernetes, Helm, MySQL, Redis, Memcached, Gitlab, GCP, EFK, Prometheus, Grafana
내가 진행했던 업무는 다음과 같다.
1. 웹 서버 기반의 컨텐츠 개발 (2023.05.01 ~ )
2. 쿠버네티스 크론잡을 활용한 배치 프로세스 구성 (2023.08.01 ~ 2023.08.31)
3. 프로메테우스, 그라파나를 활용한 Nginx, php-fpm metrics 수집 및 시각화 (2023.09.01 ~ 2023.09.30)
4. 쿠버네티스 데몬셋, Fluentd를 활용한 로그 시스템 개선 (2023.10.01 ~ 2023.11.30)
1. 웹 서버 기반의 컨텐츠 개발
API들을 만드는 일이다. 우리 웹서버는 PHP이다. 학부생때 접했던 Java 웹 서버와 문법은 비슷하지만 많은 다른점들이 있다. PHP는 인터프리터 언어이기 때문에 개발생산성이 정말 뛰어나다. 가령, 개발환경을 구성할때 도커 컨테이너가 띄워진 상태에서 PHPStorm(인텔리제이를 만든 젯브레인 회사 IDE)을 이용해 SSH로 내 컴퓨터에서 도커 컨테이너 내부로 PHP코드들을 전달해주면, 어떤 부분을 개발했는지 바로 확인해 볼 수 있다는 장점이 있다. Java였다면 컴파일 언어이기 때문에 컴파일하는 과정을 거쳐야 하기 때문에 비교적 PHP가 개발생산성이 훨씬 빠르다고 느꼈다.
하지만 PHP의 단점도 있다. 컴파일 과정이 없기 때문에 데이터 타입 체크가 되지않아, 개발자가 실수한다면 에러로 직결된다는 단점이 있다.
난생 처음 겪어보는 PHP에 조금씩 익숙해지자 개발업무를 파트장님이 던져주셨다.
게임 회사의 개발 프로세스는 다음과 같이 진행되었다. PD님과 기획자들의 기획이 나오면 그 기획서를 바탕으로 우리 스튜디오의 클라이언트 개발자, 서버 개발자, 이펙트, 원화, 모델러 등등의 직무들이 개발을 하기 시작한다. 프로토타입이 나오면 PD님과 기획자들이 보고 판단해 더 고도화할것인지, 재미가 없으니 드랍할 것인지를 결정한다. 이런 개발 프로세스는 1년에 3~4번 정도 빌드기간이라는 이름을 가지고 진행된다. 빌드를 거쳐 나온 프로토타입을 가지고 PD님은 또 윗사람에게 보고해야 하니 빌드기간에는 모두가 완성된 결과물을 위해 바쁘고 새벽빌드까지 하는 것도 볼 수 있었다.
정말 많은 것들이 기획자들에 의해 바뀌고 좌지우지되는 만큼 예측해서 개발하는 일이 잦아졌고 그만큼 빠르게 우리 서버 개발에 적응되기 시작했다. 개발 주요 코드뿐만 아니라 우리 서버는 서비스단만 단위 테스트를 PHPUnit을 사용해 검증하고 있었는데, 이런 코드들도 기획이 바뀌면 수정하고,,, 특히나 마스터 데이터는 csv파일을 이용해 저장하고 있었는데, 이런 부분이 많이 바뀐다면 단위 테스트 코드의 예시들도 또 수정해야 했다. 처음에는 내가 만든 코드들을 만들고 수정하고 만들고 수정하고 하다보니 회의감이 많이 들었지만 하다보니 또 적응이 되어서 기획이 바뀌면 그러려니~ 하게됐다.
내가 주요 진행했던 개발들은 Quest, Mail, 유닛(특정명칭이 있지만 유닛이라고 가정)이다.
Quest 기능을 개발하면서 클라에서만 알 수 있는 퀘스트와 서버에서만 알 수 있는 퀘스트들을 분리해야 하며, 추후 대부분의 API들에서 사용될 수 있어서 확장성 있는 설계를 위해 노력해야 한다는 점을 배울 수 있었다.
Mail 기능을 개발하면서, 우편함은 보통 유저들이 우편함에서 우편들을 수령하는 일이 다시 조회하는 일보다 많을 거라고 생각해서 특별하게 캐시를 사용하지 않고 개발하였다.
유닛 기능을 개발하면서, 기획이 정말 많이 바뀌었다. 쿨타임을 갖는 상점을 개발할때 디비에서 어떻게 처리해야 할지 고민해보았고, 기본적인 PHP의 CRUD에 대해 전반적으로 이해할 수 있던 시간이였다.
2. 쿠버네티스 크론잡을 활용한 배치 프로세스 구성
게임의 랭킹을 매일 집계해야 한다거나, DB에 쌓인 데이터들을 정리해야 한다거나 - ex) 우편함 같은 경우에는 7일이 지나면 삭제되는 기능 등등 일괄적으로 처리해야 하는 기능들이 필요해지기 시작했다.
우리 게임 회사에서 레거시 시스템을 가진 팀들은 리눅스의 크론탭을 활용했고, 최신 게임들은 쿠버네티스의 크론잡을 활용하는 팀들이 있었기 때문에 리눅스의 크론탭을 활용할건지, 쿠버네티스 환경이라면 크론잡을 활용할건지에 대해 고민해 봤던 시간이였다.
파트장님이 고려하라고 던져주신건 서머타임들을 사용하는 서버들이다.
한국서버뿐만 아니라, 글로벌 서버나 중국 서버 등등 다양한 서버에서 돌아가야 하는데, 이때 서머타임(DST)을 사용하는 글로벌 서버는 서머타임을 고려해야 했다. 서머타임을 사용한다면 이 시기에 배치가 돌아가지 않아 랭킹이 집계가 안되면 안되기 때문이였다.
기존 게임 서버가 쿠버네티스 환경에서 돌아가고 있었기 때문에 먼저 크론잡으로 배치 프로세스를 구성해보았다. 크론잡에는 많은 기능들이 있었다. 쿠버네티스 docs를 찾아보고 공부해봤지만 나오지 않는 부분들이 많아 테스트를 여러 방면으로 진행해봤다.
Cronjob을 생성하고 Job이 돌아가고 있는 와중에 다시 한 번 helm upgrade를 진행하면 기존의 Job이 멈추고 진행되는지?
Cronjob을 지우게 되면 job들이 모두 삭제되는지?
스케쥴을 변경한다면 그게 언제부터 적용되는지?
서머타임이라면, 돌아가지 않는건지?
매번 10분마다 돌아가는 배치 / 매일 특정한 시간에 돌아가는 배치들을 고려했는지?
등등의 운영환경에서 발생 할 수 있는 많은 예외 상황들을 마주해보려고 노력했고 리눅스의 크론탭으로도 개발해보며 크론잡과 크론탭의 차이를 이해할 수 있었다.
기존의 배포 프로세스의 일관성을 맞추기 위해, 도커 컨테이너의 이점을 그대로 살리고, 크론잡만의 기능들을 활용하기 위해 쿠버네티스의 크론잡을 사용하기로 결정했다.
배치 개발 업무를 경험해보며, 정말 다양한 상황에서 발생할 수 있는 예외 상황들을 다 고려해야 하고, 하나하나 꼼꼼하게 docs를 찾아보고 이해하고 적용해야 한다는 생각이 들어서 많은 걸 배울 수 있었던 업무였다.
3. 프로메테우스, 그라파나를 활용한 Nginx, php-fpm metrics 수집 및 시각화
기존의 프로메테우스 그라파나는 쿠버네티스가 아닌 GCP VM에 도커 컨테이너로 띄워져 있는 상태였고 나는 Nginx, php-fpm의 exporter를 쿠버네티스 Pod안에 넣고 이를 수집해야 하는 상황이였다. 해당 웹서버가 잘 돌아가고 있는지, 모니터링 하기 위해 게임 오픈 전에 꼭 필요한 개발이였다. 이런 업무를 통해 전반적으로 게임 서버에 대해 이해하고, PromQL이 어떤건지, php-fpm exporter를 연결하며 유닉스 소켓 통신과 TCP/IP 소켓 통신의 차이를 알 수 있었다.
4. 쿠버네티스 데몬셋, Fluentd를 활용한 로그 시스템 개선
기존의 로그들은 각각의 Pod안에서 php가 파일로 쓰는 로그들을 fluentd가 수집해 GCP의 VM에 도커 컨테이너로 띄워져 있는 중앙 Fluentd로 쏘고 있던 상태였다. 과연 이런 구조가 좋은 상태일지 고민해보며, 서칭을 해본 결과 쿠버네티스의 데몬셋으로 fluentd를 띄운다면 리소스를 기존의 Pod안의 컨테이너보다 비교적 쉽게 조절할 수 있어서 데몬셋을 활용해보기로 결정했다.
즉, php에서 파일로그로 로그를 남기는 과정이 아니라, 로그를 출력한다면 쿠버네티스 마스터 노드의 특정 폴더에 쌓이고 이 폴더를 데몬셋과 바인드 마운트해서 중앙 fluentd로 쏘는 과정이다.
이 업무를 진행해보며 로그 수집기에 대한 이해와 로그 시스템, 쿠버네티스의 전반적인 환경까지 이해해 볼 수 있는 시간이였다.
게임회사에서 서버개발자로 1년 넘게 일하며 많은 것들을 배울 수 있었다.
운영하고 있는 게임이 아니라 개발 중인 게임이라서, 단순히 API를 개발하는 것 이외에도 시스템적으로 이것저것 바꿔보기도 했고, 대량의 트래픽을 받아본 경험이 있는 뛰어나신 파트장님과 서버 팀원들이 개발하고 리뷰하는 것들을 보면서 많이 배울 점이 있었다.
처음 입사했을 때는 PHP에 대한 편견이 있었고, 인터넷을 찾아보면 많이 안 좋은 글들이 많았지만, 적어도 나는 많은 것들을 배울 수 있었다.
PHP는 싱글 스레드 언어라 실시간 서버는 PHP로 개발이 어려워서 실시간 서버는 다른 언어를 사용한다는 점, 스프링 부트는 톰캣이 내장되어 있어 웹 서버를 붙이지 않아도 되지만, PHP는 내장이 되어 있지 않아 웹서버를 붙여야 해서 경험하는 이러한 차이점들, 인터프리터 언어의 장점과 단점.. 많은 것들을 배웠다. 특히나 자바를 사용한다고 했으면서 GC를 모른다거나 직렬화를 모른다거나 버퍼를 모른다거나 스레드를 모른다거나,, 하는데 과연 자바를 배웠다고 할 수 있었을까?라는 의문이 들기도 했다. 내가 위 개념들에 대해 모호하게 알고 있었던 것들이 많았기 때문이다.
예를 들어 Php - redis 간의 직렬화를 하는 과정에서 '직렬화'의 개념이 더 중요한 거지 단순히 Java커리어를 위한 Java - redis의 경험이 중요하지 않다고 생각한다.
즉, PHP 던 자바던 밑바닥 CS지식을 알고 있어야 트러블 슈팅이 되고 단단해지는 개발자가 되지 않을까 하는 생각이 들었다.
시스템을 개선하거나 신기술을 적용해볼때도, CS의 중요성을 느꼈다.
예를 들어, 쿠버네티스 환경에서 NetworkPolicy때문에 서버가 느려지는 경우가 생겼는데, 찾아보는 과정에서 정말 많은 CS용어들이 나온다. Dnat/Snat을 쿠버네티스 내부적으로 사용하는데 이게 무엇인지.. 쿠버네티스로 이중화하는 과정에서 쿠버네티스 객체를 배우기 전에 L7스위치가 뭐고 L4스위치가 무엇인지.. 동시성 이슈를 해결하기 위해 Redis로 분산락 하는 과정에서 스핀락, 임계구역이 무엇인지..
1년간 배우고 익혀야 하는 이유들을 깨달을 수 있었다.
따라서, 앞으로도 CS지식을 단단히 공부하고 기술을 적용하는 개발자가 되려 노력해야겠다.
갑진년에는 하지 못한 것들에 조금 더 집중해 보고 청룡처럼 날아올라보고자 한다!

'회고록' 카테고리의 다른 글
[Project] 연합동아리 잇타, 이삼이상 회고록 (0) | 2022.08.19 |
---|---|
[Project] 교내 팀 프로젝트, Tlover(트러버) 회고록 (0) | 2022.08.13 |
[Project] 연합동아리 큐시즘 24기, Hurry up HUP! 회고록 (4) | 2022.08.13 |
[Mentoring] 청년고민해결단 온라인 멘토링 회고록 (4) | 2022.04.02 |