본문 바로가기
책상 노트 책상 노트
실무자가 실제로 굴려본 업무도구·업무 자동화 기록

살아 있는데 대답 없는 서버, 범인은 3개였다

읽는 시간 약 12분

죽은 게 아니라 멈춰 있었습니다

아침에 브라우저를 켰습니다. 늘 쓰던 사내 도구 화면을 열었는데 안 열렸습니다. 아무것도 없는 흰 화면이 전부였습니다. 확인해보니 서버 프로그램은 멀쩡히 살아 있었고 포트도 정상적으로 열려 있었고 연결까지 문제없이 맺어졌는데, 정작 요청을 보내면 아무것도 돌아오지 않았습니다. 종료된 게 아니라 걸린 것이었고, 이 둘은 다릅니다.

이 구분이 중요합니다. 죽은 것과 걸린 것은 겉으로 드러나는 증상만 비슷할 뿐, 원인을 좁혀 들어가는 순서도 실제로 손대야 할 자리도 처음부터 끝까지 완전히 다릅니다. 죽은 서버는 목록에서 사라집니다. 그러니 프로세스 목록을 한 번 뽑아보는 것만으로 누가 보든 그 자리에서 바로 눈에 띕니다. 걸린 서버는 다릅니다. 프로세스도 살아 있고 포트도 열려 있고 연결도 맺어지니, 하나씩 짚어보는 점검 항목이라는 게 처음부터 끝까지 전부 정상으로 보입니다. 그래서 방화벽이니 네트워크니 하는, 아무 상관도 없는 데를 한참 뒤지게 됩니다. 저도 그랬습니다.

저는 개발자가 아닙니다. 재무와 경영 실무를 보는 사람이고, 이 서버도 회사가 운영하는 시스템이 아니라 제가 제 일에 쓰려고 개인적으로 띄워둔 업무 도구일 뿐입니다. 이걸 고치고, 자동 감시를 붙였다가, 며칠 만에 결국 다시 걷어낸 과정을 순서대로 남깁니다.

죽은 게 아니라 걸린 것이었습니다
가능성이 낮은 것부터 지워가며 바깥에서 안쪽으로 좁혔습니다.

확인은 바깥에서 안쪽으로 들어갔습니다

증상은 하나인데 후보는 여럿이었습니다. 방화벽인지, 프로그램이 죽은 건지, 코드가 잘못된 건지, 아니면 포트가 겹친 건지. 어느 쪽인지 전혀 모르는 채로 가능성이 낮은 것부터 하나씩 지워가며 좁혔습니다.

연결은 되는데 응답이 없었습니다

먼저 명령줄로 두드렸습니다. 브라우저는 캐시나 확장 프로그램이 중간에 끼어들어 상황을 흐려놓을 수 있으니, 아예 도구를 통째로 바꿔서 같은 주소에 같은 요청을 보내보는 편이 판단하기에 훨씬 정확하기 때문입니다. 결과는 둘이었습니다. 연결 성립, 그리고 빈 응답.

이 조합이 절반을 알려줍니다. 꽤 큰 절반입니다. 연결이 맺어졌다는 건 방화벽에 막힌 것도 아니고 프로그램이 죽은 것도 아니며, 포트를 붙잡고 있는 무언가가 분명히 그 자리에 살아 있다는 뜻이 됩니다. 살아는 있는데 대답만 못 합니다.

같은 서버가 여러 개 떠 있었습니다

그다음. 그 포트를 대체 누가 잡고 있는지 확인했습니다. 하나가 아니었습니다. 셋. 시작 시각을 보니 며칠 전에 띄운 것, 그날 오전에 띄운 것, 새벽에 띄운 것이 아무도 안 치운 채로 나란히 쌓여 제각각 살아 있었습니다.

원인은 단순합니다. 제가 그랬습니다. 뭔가 잘 안 될 때마다 다시 실행했고, 그때마다 기존에 떠 있던 걸 안 껐습니다. 실행 파일을 두 번 눌러도 이미 떠 있다는 경고 한 줄이 안 뜨니, 겹쳤다는 사실 자체를 알 방법이 없었습니다.

프로그램마다 다르긴 합니다. 다만 같은 포트를 여러 프로세스가 동시에 물고 있으면, 들어온 요청이 그중 어느 쪽으로 갈지를 아무도 예측할 수 없게 됩니다. 어제는 되던 화면이 오늘은 안 열리는, 그런 오락가락하는 증상이 여기서 나옵니다. 셋 다 종료시키고 하나만 다시 띄웠습니다. 정상이었습니다.

왜 멈췄는지도 확인했습니다

증상이 사라졌다고 끝난 건 아닙니다. 같은 일이 또 날 확률이 궁금했습니다. 코드를 열었습니다. 이유가 있었고, 그게 구조에 박혀 있었습니다.

요청마다 처리 흐름이 따로 뜨는 구조인데 코드 안에 전역 잠금이 여러 개 걸려 있었고, 게다가 일부 요청 처리 과정에는 최대 15분까지 하염없이 기다리는 외부 프로그램 호출이 통째로 끼어 있었습니다. 그 호출이 한 번 늘어지기 시작하면, 그 요청을 처리하던 흐름이 잠금을 쥔 채로 안 놓습니다. 그러면 화면 한 장 불러오는 가벼운 요청까지 전부 그 잠금 앞에 줄을 서서 같이 멈춰 버립니다.

포트는 열려 있고 연결도 되는데 응답만 없는 상태. 딱 이겁니다. 같은 일이 또 일어날 확률이 결코 낮지 않다는 뜻이기도 했고, 그래서 뭐라도 붙여둬야겠다고 생각했습니다.

자동 감시를 붙였습니다

근본 수정은 코드 구조를 통째로 손봐야 합니다. 당장 붙기엔 무거웠습니다. 대신 1분마다 상태를 확인하고, 응답이 없으면 알아서 기존 것을 전부 정리한 뒤 새로 하나만 띄워주는 감시 프로그램을 붙여두기로 했습니다. 마침 다른 작업에 같은 방식을 쓰고 있던 참이라, 형태를 그대로 가져다 붙였습니다.

동작은 세 줄입니다. 확인해서 정상이면 아무것도 안 하고 끝낸다. 응답이 없으면 기존에 떠 있던 프로세스를 전부 정리하고 새로 하나만 다시 띄운다. 그리고 재시작이 실제로 일어났을 때만 메신저로 알린다.

정상일 때 로그를 아예 안 남기게 해둔 것도 일부러 그렇게 한 겁니다. 1분마다 정상이라고 꼬박꼬박 기록하면 로그가 아무 의미도 없는 줄로 가득 차 버리고, 정작 문제가 터진 날 찾아야 할 그 한 줄이 그 안에 파묻힙니다.

등록이 권한에서 막혔습니다

윈도우 작업 스케줄러에 등록하려니 거부됐습니다. 액세스 거부. 몇 번을 다시 해도 같았습니다. 확인해보니 지금 쓰는 계정이 관리자 그룹에 속해 있기는 한데, 정작 그 권한은 거부 전용으로 표시된 일반 토큰 상태였습니다. 관리자 그룹에 이름만 올라가 있을 뿐, 관리자 권한을 그대로 행사할 수 있는 상태는 아니었다는 뜻입니다.

여기서 한참 헤맸습니다. 그러다 방법을 바꿨습니다. 명령줄 옵션을 하나하나 붙여가며 만드는 대신, 작업 정의를 파일로 먼저 써두고 그 파일을 통째로 불러다 등록하는 방식으로 바꿨더니 아무 저항 없이 그냥 통과했습니다. 같은 계정, 같은 권한. 결과만 달랐습니다. 이유는 아직 모릅니다.

작업 하나 등록하는 데 이만큼 걸릴 줄은 몰랐습니다. 이런 게 시간을 먹습니다. 티도 안 납니다. 만드는 데 30분. 등록에는 그 이상.

고장을 일부러 내서 확인했습니다

등록이 됐다는 것과, 필요한 순간에 실제로 작동한다는 것은 전혀 다른 이야기입니다. 그래서 서버를 강제로 종료해놓고 감시 프로그램을 돌렸습니다. 멈춘 걸 감지하고, 기존 것을 정리하고, 새로 띄우고, 마지막에 정상 응답까지 제대로 돌아오는지를 처음부터 끝까지 눈으로 따라가며 지켜봤습니다.

이 과정에서 하나 걸렸습니다. 실행 중인 프로세스 목록을 읽어오는 부분에서, 한글이 섞인 줄을 처리하다가 인코딩 오류가 났습니다. 치명적이진 않았습니다. 그래도 고쳐뒀습니다. 다만 그냥 두면 언젠가 엉뚱한 순간에 조용히 실패할 자리라서, 결과를 문자로 바로 받지 않고 원본 그대로 받아둔 다음에 한국어 윈도우 인코딩으로 직접 풀도록 고쳐뒀습니다.

한 번 더 고장을 냈습니다. 고친 다음 한 번 더 고장을 내서, 같은 오류가 다시 재현되지는 않는지까지 눈으로 확인하고 나서야 손을 뗐습니다. 실제로 고장을 안 내봤으면 이 오류는 정작 복구가 필요한 순간에 처음 만났을 겁니다.

1분마다 검은 창이 떴습니다

작동은 합니다. 대신 다른 게 붙었습니다. 1분마다 검은 명령창이 화면 한가운데 떴다가 사라지기를 반복했습니다. 작업 스케줄러가 백그라운드가 아니라 대화형으로 실행되면서 창이 진짜로 열렸다 닫히기 때문입니다.

창을 숨긴 채로 실행해주는 작은 스크립트를 하나 만들어서, 스케줄러가 원래 프로그램 대신 그걸 부르게 하는 방식으로 없앴습니다. 로그는 그대로 남으니, 나중에 동작을 되짚어 확인하는 데는 아무 지장이 없었습니다.

실제로 고친 시간은 프로세스 세 개를 정리한 몇 분이었습니다
나머지는 전부 이걸 자동으로 할 것인가를 정하는 데 들어갔습니다.

붙인 것을 다시 걷어냈습니다

여기까지 오고 나서 방향이 두 번 바뀌었습니다. 두 번 다 뭔가를 더 붙이는 쪽이 아니라 이미 붙여둔 걸 걷어내는 쪽이었다는 게, 지나고 보니 이 작업의 요점이었습니다.

먼저, 자리에 없을 때도 메신저로 재시작 명령을 보낼 수 있으면 좋겠다는 생각이 들었습니다. 감시 프로그램이 어차피 1분마다 도니까, 같은 주기에 메신저 메시지도 같이 확인하게 하면 될 것 같았습니다. 그런데 붙이다 말았습니다. 쓰려던 봇 토큰을 다른 프로그램이 이미 물고 있었습니다. 그리고 이런 메시지 수신 방식은 한쪽이 먼저 읽어가 버리면 다른 쪽은 그 메시지를 영영 못 받습니다. 재시작 명령 하나 넣어보겠다고 하다가, 평소에 잘 오던 알림이 통째로 씹히는 구조를 만들어놓을 뻔했습니다. 이걸 피하려고 전용 봇을 새로 하나 파는 방법도 있긴 했습니다. 그런데 그럴 필요가 없었습니다. 메신저로 제 요청을 받아 처리하는 경로가 이미 따로 돌고 있었기 때문입니다. 그쪽에 “재시작해줘” 한 줄이면 끝납니다.

그다음이 더 컸습니다. 수동으로 언제든 재시작을 시킬 수 있다면, 자동 감시라는 게 대체 왜 필요한가. 이 질문이 남았습니다.

  • 자동 감시가 있으면 제가 전혀 모르는 사이에 서버가 멈춰도 그 상태를 알아서 감지하고 스스로 복구해둡니다. 열었는데 하필 멈춰 있는 일이 없어집니다.
  • 자동 감시가 없으면 제가 열어보기 전까지 멈춘 채로 방치됩니다. 대신 구조가 단순해집니다.

이건 기술 판단이 아니었습니다. 용도 판단이었습니다. 이 도구는 하루에 몇 번, 제가 필요할 때만 열었다 닫는 개인용 화면일 뿐입니다. 24시간 돌아야 하는 서비스가 아닙니다. 멈춰 있다가 열었을 때 그제야 재시작해도 되는 정도의 문제였습니다. 그래서 지웠습니다. 공들여 등록해둔 감시 작업을 스케줄러에서 삭제했고, 다만 감시 프로그램 파일 자체는 나중을 생각해서 그대로 남겨뒀습니다. 강제 재시작 옵션이 붙어 있어 필요할 때 한 줄로 부를 수 있고, 마음이 바뀌어 다시 자동으로 돌리고 싶어지면 그때 등록만 다시 하면 되니까요.

만들었다가 지운 셈입니다. 그래도 낭비는 아니었습니다. 그런데 직접 만들어 며칠 굴려보기 전이었다면, 이 판단은 절대 못 했을 겁니다. 검은 창이 1분마다 뜨는 걸 며칠 겪고 나서야 알았습니다. 자동화는 공짜가 아니라는 것.

걸린 서버를 겪고 남긴 여섯 가지

  • 서버가 안 열리면 죽었는지 걸렸는지부터 가릅니다. 브라우저 말고 명령줄에서 같은 주소로 직접 요청을 보내보면, 이 둘이 그 자리에서 갈립니다.
  • 다시 실행하기 전에 이미 떠 있는 게 없는지부터 봅니다. 겹쳐 뜬 프로세스는 아무 경고 없이 조용히 쌓이고, 나중에 원인 찾기를 훨씬 어렵게 만듭니다.
  • 증상이 사라졌어도 왜 그랬는지는 확인해둡니다. 재발 확률을 모르면 다음 조치를 못 정합니다.
  • 자동 복구는 반드시 고장을 내서 확인합니다. 등록 성공과 작동은 다릅니다.
  • 자동화를 붙이기 전에, 그 도구가 정말로 24시간 내내 돌아가고 있어야 하는 물건인지부터 스스로에게 한 번 묻습니다. 혼자 쓰는 도구에 감시까지 붙이면 얻는 것보다 신경 쓸 것이 늘어납니다.
  • 알림 채널은 한 프로그램만 씁니다. 편의 기능 하나 붙이겠다고 손대다가 잘 돌아가던 기존 알림 전체를 망가뜨릴 수 있습니다.

정리하면 이렇습니다. 이 작업에서 실제로 뭔가를 고친 시간은 겹쳐 뜬 프로세스 세 개를 정리한 몇 분이 전부였고, 나머지는 전부 “이걸 자동으로 할 것인가”를 결정하는 데 들어갔습니다. 그리고 결론은, 하지 않는 쪽이었습니다.

이어서 읽을 기록

책상 노트 운영자
함께 보면 좋은 글
error: Content is protected !!