노력과 삽질 퇴적물

리눅스: grep 함정과 임기응변 본문

프로그래밍note/미분류.

리눅스: grep 함정과 임기응변

MTG 2022. 5. 21. 23:09
 오늘은 튜토리얼이나 샘플 코드가 아닌 실무에서 겪은 '괴담'에 가깝습니다.
요약본을 말하자면, 'grep 명령어가 파일 용량에 따라 결과가 상이하다.'입니다.
읽고도 '무슨 헛소리냐'싶어지죠?
저도 잘못 본 거였으면 좋겠지만, 이 이슈로 금요일 오전부터 오후까지 진땀 뺀터라.
 





당시 환경
 

> 우분투 16.04LTS, AWS ec2

> 톰캣 8.5
> 1.2~1.3GB정도 되는 톰캣 로그 3개.
> mongoDB v4.2.12

 테이블 일부를 초기화 시키다 그만 누적을 유지해야 하는 컬렉션까지 날려버린겁니다. 자동 백업본이나 수동 백업본이 아예 없던건 아니지만 시간상 몇 시간 공백이 있다 보니 대체 불가인 자료여서 어떻게든 복원을 시켜야 하는거였죠.
 그런데 어떤 방법으로?



구명 보트를 찾아라.

 noSQL인 몽고DB툴로 Robo 3T를 쓰고 있는데, 툴에 나오는 로그로는 그냥 제 멍청한 실수가 몇 시쯤 시행됐다만 재확인 시켜줄뿐 다른게 없습니다.
 
 그런데 잠깐!
 
 컬렉션에 데이터 입력시 JSON 형식으로 입력해야하는데, 디버깅용 로그가 활성중이라 톰캣 로그에는 온갖 입출력이 다 나와있고 로그 추적을 용이하게 하려고 DB에 입력된 값도 확인할 로그를 심은게 있어요.
 몽고DB건 다이나모DB건 테이블에 입력하는 자체 Item클래스는 map이지만 정규식과 문자열 바꾸기로 JSON형식에 맞게 가공이 가능하니 이제 할 일은 뭐다?

 확인겸 로그 파일에서 해당 자료 유형에만 존재하는 컬럼명을 검색해보니,
jsonPretty로 찍히긴 했어도 영 써먹지 못할 형태까지는 아닌게 확인됐습니다. 혹시 싶어 1 줄 짜리로 출력 되게 심어둔건 없는지 위아래로 찾아보니 다행히 있었습니다.

 입출력 값 로그는 사람이 파악하기 편하게 jsonPretty로 로그를 심는 것도 좋지만,
1줄 짜리 출력을 보조격으로 넣은게 구명 보트가 된거였습니다.



그런데... 보트가 움직이질 않는다?
 
 로그 파일이 다 있지만,
전부 합치면 3.5GB에 육박하는 문자열에서 내가 원하는걸 추려내야 합니다.

1) 특정 컬럼명이 있는 JSON을 한 줄내로 찍은줄만 추출하는 코드를 Junit등으로 작성?
-> 기각!
 아무리 단순 반복 기능이라도 용량상 유니티부터 MOS들이 띄워진 업무PC는 기다리면서 다른걸 한다 해도 과부하 가능성을 무시 못함. 
2) 학부 리눅스 수업에서 뭔가 비슷한 기능을 소개한거 같다.
-> 찾아보자!
 
 제가 찾은 방법은 'grep'입니다.
학부에서는 디스크내 파일 검색만 해봤지, 파일내에서 검색은 처음이라 은근히 헤매게 되더군요. (자료 복구가 걸린 일인것도 있지만...)
 
grep '도큐먼트_컬럼명' tomcat_A.2022-05-XX.log
 원하던 형태로 추려져서 검색이 동작한다!
 
 그런데 내가 필요한건 추출본...
검색 결과 그대로 파일에 저장 하는게 뭐였더라로 잠시 또 구글링.
 
grep '도큐먼트_컬럼명' tomcat_A.2022-05-XX.log > tomcat_crop.txt
난 이제 살았다! 자유야!
...
...
로 저기서 해결됐으면 굳이 괴담이라 운을 띄운 글을 남기지도 않았겠죠?
tomcat_crop.txt 용량은 고작 2KB였습니다.
너무 이상한거에요.
 
 분명 테이블을 마지막으로 백업하고 나서 몇 시간 지나고 초기화할 때 누적된 입력 값은 어림짐작으로 잡아도 그 정도 분량이 아닌데 어째서?
tomcat_crop.txt마지막 줄에 찍힌 시간=(UTC.0) 02:XX
tomcat_A.2022-05-XX.log마지막 줄에 찍힌 시간=(UTC.0) 23:XX
 인스턴스가 여러개였으니 특정 인스턴스에만 연속으로 호출이 걸려 한 동안 로그가 뜸한 타이밍이 가능하긴 하겠죠. 그런데 21시간 연속으로 이 인스턴스가 놀았다고?
이상하잖아요?
 
 
(한정된 자원에서)
가능성이 극도로 낮은건 발생치 않는 걸로 간주하는 것도 방법이다.
 
 
그렇다면 설마 이쪽 명령어에도 용량상 처리 가능한 상한선같은게 있는거였나?
 
 
split -b 500m tomcat_A.2022-05-XX.log tomcat_Apart_
 
 그래서 노트패드++로 열어볼려고 용량 상한선에 맞게 500메가바이트씩 잘랐습니다.(8.3.3 기준)
분할된 파일중 하나를 열어 '현재에서 모두찾기'를 하니깐...
아니 대체 왜?
 tomcat_crop.txt는 비교도 안 될 검색 결과 갯수를 보고 어느 단계에서 오류가 있던것인가로 머리속이 멈출... 뻔했는데 다행히 멈추지는 않고 감속정도?
"검색 결과가 이상해, 리눅스 명령어와 노트패드++중 하나가 나를 속이는거 아닌가?
설마?"
 
grep '도큐먼트_컬럼명' tomcat_Apart_* > tomcat_Agrep.txt
약 10KB 2개, 7KB 1개.
이게 무슨 현상이지?
 
 

뻥쟁이가 누군지는 상관없고, 추출 좀 하게 해줘.
 
 일단 로그파일 원본으로 grep를 해서는 정상적인 추출이 안 되는거 같으니 조금 번거롭더라도 파일 분할과 grep 결과 저장을 해결해봐야겠군요. 그래도 굳이 임시 코드 안 짜도 되는거 어디입니까?
 그리고 파일 분할시 용량 기준으로 자르는건 한줄내로 찍힌 JSON가 중간에 잘릴수도 있어 다른 옵션을 써야겠죠?
 
 
wc -l tomcat_A.2022-05-XX.log
wc -l tomcat_B.2022-05-XX.log
wc -l tomcat_C.2022-05-XX.log
전체 용량이랑 노트패드 용량 제한상 일단 약 3등분이 될 라인수로 해봤습니다.
 
 
split -l 100000 tomcat_A.2022-05-XX.log tomcat_Apart_
grep '도큐먼트_컬럼명' tomcat_Apart_* > tomcat_Agrep.txt
 
그리고 '현재에서 모두찾기'로 나오는 결과 갯수들... 아까보다 늘었났어?
 
 설마? [split -l]에서 라인수를 줄일수록 노트패드에 열어둔 파일들에서 검색되는 결과 갯수가 늘어나서 10만에서 시작한 값은 결국 200까지 가고 100으로 시도해본 결과 더는 늘어나지 않더군요.
 
로그 파일 원본으로 직접 grep = 50개 미만
split&grep로 추출 = 약 5천개
 
???
 무슨 작용인지는 모르겠지만, 입력가능한 JSON입력값이니 일단 텍스트 파일 3개를 합쳐서 정규식으로 불필요한 부분 삭제후 DB에 마저 입력하는걸로 이슈 해결.
 
 

위기는 탈출했다. 그런데 그건 뭐였을까?
 
 
이슈는 해결됐으니 다행이죠.
그런데 말입니다. 그건 대체 무슨 원리였을까요?
 
아무튼 기초들은 언제나 사람을 살리는 치트키이자, 구명 보트입니다.
그리고 테이블에서 수동으로 빼거나 넣을때는 무조건 백업스크립트 실행하는거 잊지마세요.