어느덧 본격적인 백엔드 엔지니어로서 일한지 1년이 넘어갑니다. 슬슬 시스템 아키텍쳐에 익숙해지면서 직접 칼질(설계 및 개발)을 하기도 합니다. 다만 그로 인해 문제가 생기는 상황 또한 종종 맞닥뜨리게 됩니다.
올해 초는 유독 그런 사례가 좀 많았습니다. 아무래도 회사가 갑자기 성장하면서 많은 기능들이 바뀌고 추가되다 보니 더욱 그러한 경우가 많은 듯 합니다. 그로부터 제가 배울 수 있는 것들은 어떤 것들이 있었을지 되짚어 보았습니다.
1. Scale matters
비록 제가 몸담고 있는 회사가 엄청난 동시접속자를 보유하고 있거나 하는 것은 아니지만… 그럼에도 불구하고 TPS 자체는 꽤 있는 편이라고 생각이 됩니다. 그렇기 때문에 들어오는 데이터의 scale이 중요합니다.
처음 시스템을 설계할때는 문제가 없었던 설계가, 이후 데이터 양이 급증하면서 문제가 생기는 경우가 있습니다. 이를테면 처음에는 TPM 1000 아래에서만 정상 동작하도록 만든 시스템이 있습니다. 초창기에 1000 이상으로 만들면 당연히 비용 문제 때문에 완!전! 손해죠. 유저수가 증가하면서 트래픽이 1000 이상으로 쌓이게 되고; 이를테면 1500씩 쌓이면, 500의 처리되지 않은 잔여 데이터가 남게 될 것입니다. 이는 계속해서 쌓이고 쌓여서, 나중에 timeout나 starvation과 같은 문제를 유발하게 되죠.
이러한 문제 상황에 맞닥뜨리는 것을 방지하기 위해서 어떤 것을 할 수 있을까요? 아마 design documentation을 쓸 때에 “Limitation” 혹은 “Risk”에 잘 정리해 놓아야 되지 않을까 생각이 됩니다. 그래야 CS나 엔지니어 측에서도 문제가 될 상황에 앞서 미리 대응이 가능하겠죠. 또한, 꾸준히 모니터링 할 수단 또한 미리 마련해 두어야겠죠. (바로 아래 섹션에서 다룹니다)
2. Monitoring matters
미리 이야기하자면, 이건 “Scale matters”와 궤를 같이 합니다. 크게 “정보의 종류”와 “정보의 비용”의 문제입니다.
먼저 정보의 종류 차원에서는, 당연하게도 유의미한 정보가 모니터링 될 수 있도록 하는 장치에 신경을 쓰는 것입니다. 이를 테면, 어떠한 숫자값이 있는데 이게 크게 변동하면 문제 상황이라고 합시다. 혹은, 단순한 경고성 로그가 있는데 해당 로그가 급증할 경우 문제의 전조라고 여겨진다고 합시다. 그렇다면 해당 메시지를 모니터링 하여, 그래프로 보여주면 훨씬 쉽게 파악이 가능하며, 동시에 분당 일정 횟수 이상 메시지 발생 시 알람을 줄 수도 있을 것입니다.(snitching)
그리고, 이 모든 작업을 하는 데 소요되는 비용(Cost)의 문제입니다. 모니터링으로 많은 유의미한 정보를 파악할 수 있는 것은 좋습니다. 다만, 그 정보들이 정말로 사용되는 것인지? metric이 생성하는 차원 수가 너무 많지는 않은지? 그리고 metric이 너무 많이 생산되지는 않는지? 등을 확인해 봐야 됩니다. 모니터링은 또다른 정보를 생산하기에 그만큼의 비용이 들 것이므로, 이를 최소화하면 도움이 되겠죠.
3. 슬며시 생글생글 웃으며 당신의 곁으로 기어오는 혼돈 (+Early return)
니알라토뎁… 은 아니고 버그입니다!
보통 버그라 함은 문제가 발생하면 그 즉시 퍼펑! 터지는 친구를 의미합니다. 그리고 경험상 문제의 근원지에서 가까울수록 찾기 쉽고, 재현하기 쉽고, 따라서 해결하기도 쉽습니다. (이를테면 nullptr 이라던가 … 덤으로 더 많이 무언의 압박을 받을 것이니…)
하지만 인생이 그렇게 호락호락하지 않습니다. 문제를 발생시킨 지점에서는 정상적으로 동작하다가, 이후에 해당 데이터가 다른 곳에서 본격적으로 문제를 일으키는(Dirty bit 같은 것 처럼, 처음에는 잘 돌다가 뒷부분 어디선가 프로그램 강종에서부터 — 정합성 깨먹기까지…) 경우에는 훨씬 더 골치가 아파집니다.
그보다 더 멀리에서 발생하는, 그러니까 재현이 아예 불가능한 수준의 버그 또한 존재합니다. 무려 한-두달 이상 서비스가 되어야 확인되는 문제 또한 존재한다는 것이죠. 이 섹션의 제목이 의미하는 바가 그것입니다. 정말 버그가 슬며시 당신의 곁으로 저며듭니다.
이러한 버그를 찾는 데 있어서 가장 좋은 것 중 하나는 모니터링 툴이 아닌가 싶습니다. 문제가 바로 발생하지는 않겠지만, 지속적으로 어떤 메트릭의 변화가 확인된다면 이를 통해 미리 상황을 확인할 수 있는 것이죠.
참고로 해당 문제는 “Early return”으로 인해 발생했습니다. 메서드를 일찍 리턴하여 불필요한 code nesting을 줄여서 가독성을 향상시키고자 많이 쓰이는데, 문제는 생각없이 이 방식을 쓰면 꼭 마지막에 수행되어야 하는 deferred method (e.g. cleanup) 등이 수행되지 않을 수 있다는 것입니다. 이번 문제도 그러한 연유로 인해 쓰레기 값이 쌓여서 발생한 문제였습니다🥲. 비싼 교훈이네요. 조심합시다.
4. False positive
거짓 양성(Type I Error)이라는 것이 있습니다. 실제로는 정상이 아닌데, 겉보기나 지표로는 정상처럼 보이는 것이죠.
그리고 작업 도중 실제로 그러한 일이 있었습니다. 세부 작업이 실패해서 프로세스의 최종 결과는 실패로 나와야 하지만, 모종의 이유로 해당 오류가 누락되어 정상으로 나오게 되는 문제가 있었던 것이죠.
다행히 다른 모니터링 지표에서 문제가 확인되기 때문에 대참사가 일어나지는 않았지만, 이러한 거짓 양성을 방지하기 위한 작업 또한 필요하지 않을까 고민할 필요가 있을 것 같습니다. 그래서 제가 좋아하는 건, 고의적으로 테스트를 실패하고 이를 검증하는 것입니다. 성공 케이스에만 너무 치중하면 이러한 문제를 놓칠 수 있다는 것이죠.
'개발 > Essay' 카테고리의 다른 글
Short note — win exe reversing (0) | 2023.04.17 |
---|---|
Filter iteration과 Low pass (0) | 2023.03.20 |
개발 관련하여 읽은 책과 글들 (2022년 하반기) (0) | 2022.12.26 |
웹 서비스 백엔드 바닥부터 개발한 후기 (0) | 2022.08.06 |
개발자로 살면서 겪은 것들에 대한 이야기 (0) | 2022.08.01 |