중복이 발생해서 중복으로 처리되어버린 장애가 발생했다.. 그래서 대응 방안으로 모니터링을 구현해 빠른 조치가 가능하도록 하기로 했다.
작업 수행하게 되면, 로그를 남기는데 중복으로 수행됐다면 로그도 중복으로 남는다.
따라서, 이를 확인하기 위해서 구현을 하게 되었다.
리눅스는 대학교 방학 때 명령어를 따라서 몇 번 따라서 쳐본 것이 전부였다.. OMG..
그런데 쉘 스크립트를 작성하라니..
우선 해야 할 목록을 적어보았다.
- 해당 로그파일에서 중복된 행을 카운트 한다.
- 카운트가 있으면 중복이 발생, 없으면 정상
- 해당 로그파일의 중복된 행에서 key 값을 가져온다.
- key 값으로 빠른 조회 및 대처를 위해서
- 모니터링 창을 하루종일 켜두고 지켜볼 수 없으니, 중복이 발생하면 문자 메세지를 전송해준다.
1, 2번은 그래도 '검색하면 되겠지..' 였는데, 3번은 '그런게 가능해..? 이런 느낌이었다.'
먼저 어느정도 필요할 거라는 명령어를 팀장님이 알려주셨다.
- crontab
- chmod
- 쉘 스크립트 작성
- uniq
- sort
- >, >>
나머지 모르는 부분은 하면서 추가적으로 찾아봤다.
구현
우선 1번을 하기 위해 로그 파일을 보면(샘플이다. 실제로 이렇지는 않다.)
2019-08-01 12:00:20 |abc|20190801********|********|
날짜와 값들을 |
를 사용해 구분해놓았다.
가운데 2019~
가 key값이며 , 뒷 부분은 회원 고유 값이다.
만약, 중복 발송이 되었다면 로그에 찍힌 시간은 다르겠지만 |abc| 이하 값은 똑같을 것이다.
(같은 key 값을 가지고 발송을 하기 때문에)
cut -f 2 로그파일 경로.log | sort | uniq -dc
위 명령어는 공백, 탭을 기준으로 2번 cut 한 후 중복 된 행을 정렬, 카운트, 한 라인만 표시 해준다.
그렇지만 중복되는 라인이 많이 출력되어 보여지는 것은 의미가 없다.
- 중복이 되었다는 사실이 중요하다.
명령어를 하나 더 추가한다.
cut -f 2 로그파일 경로.log | sort | uniq -dc | wc -l
중복되어 출력된 행들의 라인 수를 출력한다.
- 중복이 없다면 ? -> 결과 값은 0
- 중복이 있다면 ? -> 중복 된 만큼 출력
이렇게 해서 1번이 끝났다.
다음 2번
빠른 대처를 하기 위해서는 중복 되어 발송 된 key 값을 알아야 조회가 가능하다.
2019-08-01 12:00:20 |abc|20190801********|********|
마찬가지로 앞의 날짜 뿐만 아니라 다른 로그데이터는 필요 없고 2019~
의 데이터만 있으면 된다.
중복 된 값들이 2개 이상이면 (key 값이 2개, 중복 발송된 건이 2건 이상)
각각 값들에서 key 값만 얻어와야한다.
//중복 된 key값만 출력하는데 중복 된 건이 있으면 다 출력
ex)20190801111이 한번만 출력되면 되는데
//20190801111
//20190801111
//20190801111
cut -f 3 -d'|' 로그파일 경로.log | uniq -d
//중복 된 값을 찾는 순간 종료되어버림
//첫 중복만 잡아서 여러 중복이 발생 할 경우 못 찾음
uniq -d 로그파일 경로.log | cut -f 3 -d'|'
//각각 다른 key값을 모두 출력
cut -f 3 -d'|' 로그파일 경로.log | sort -u
쉽지 않았다..
중복 된 경우를 제외한 결과에 대해서 한번 더 중복 체크를 해야한다.
어 그럼 혹시?
위의 3개의 명령어 중
cut -f 3 -d'|' 로그파일 경로.log | uniq -d
이 부분에 | uniq
하나를 더 추가 해봤다.
위의 결과에 대해 한번 더 중복 체크.
> 그랬더니 성공!!
3번 문자 발송
리눅스도 처음 접하는데 리눅스로 문자 발송을 한다고..?
비슷하게 짜여진 예제를 보았더니, 리눅스에서 웹 처럼 post 방식
으로 값을 던질 수 있었다.
wget -O- --post-data
을 사용하면 된다.
명령어 실행 시 진행 상황이 보기 싫다면 wget 바로 뒤에 -q
를 추가해 주자.
명령어 사용 방법은
wget -O- --post-data="post 방식으로 전달 할 데이터 ex)id=abc&password=def" "전송 할 url"
즉,
wget -O- --post-data="id=abc&password=def" "https://n1tjrgns.tistory.com"
이제 실제로 발송을 해보자.
문자 발송은 사내 서비스를 사용했다.
function send_sms {
msg="$my_ip $new_line $id"
for i in $phone3
do
wget -O- --post-data="$post_data&phone=$i&M1=$msg" $jsp_url
done
}
리눅스에서도 function을 사용해서 함수를 만들 수 있다는게 놀라웠다.
msg에 내가 문자에 보내고 싶은 내용을 저장하고
for i in $phone
에 문자를 받을 사람을 지정한다. 여러명에게 보내고 싶다면 여러명을 적어주면 된다.
for i in $phone1 $phone2 $phone3
물론 그 만큼 선언을 해놔야겠지?
가독성을 위해 파라미터와 url을 전부 변수로 선언했다.
- 발송 케이스
- 1번이 0이 아닌경우 발송 하는데 조회 한 2번의 id값을 메세지에 같이 보내준다.
이렇게 필요한 로직은 구현이 끝났다.
이렇게 하고나니 더 필요하다고 생각되는 부분이 있었다.
- 카운트 결과를 따로 로그파일로 떨어트린다.
- 로그파일 보관 주기는??
- 문자 발송을 몇 분 간격으로?
- 한 번 보냈으면 또 보낼 필요는 없지 않나?
- 새로운 중복이 생기면 그에 대한 발송은?
1번의 카운트 값을 가지고 중복 발생 여부를 판단해 그 값을 로그파일로 만들자.
>
와 >>
에 대해서 찾아보면 된다!
if [ $print_duplication_count -gt 0 ];
then
echo $sysdate" SMS_DUPLICATION_CHECKING :)" >> "로그 파일 생성 할 경로.log"
echo $sysdate" Duplication_Exception!!! : "$print_duplication_count" duplicated." >> "로그 파일 생성 할 경로.log"
elif [ $print_duplication_count -eq 0 ]
then
echo $sysdate" SMS_DUPLICATION_MONITORING_IS_RUNNING :)" >> "로그 파일 생성 할 경로.log"
echo $sysdate" Duplication_Nothing~~ : " $print_duplication_count " ^^ " >> "로그 파일 생성 할 경로.log"
fi
이렇게 했더니 간단하게 로그 파일이 생성되었다.
그럼 파일 보관 주기는??
리눅스에서 주기는 crontab
이라는 명령어로 관리한다.
crontab -l
등록 되어있는 crontab을 확인해 보니 삭제 주기가 +60이었다.
삭제하는 방법은
find "삭제 할 파일의 경로/*.log" -mtime +60 -exec rm -f {} \;
find 뒤의 -mtime이나 -ctime 등등을 검색해보고 원하는 경우에 맞게 사용하면 되겠다.
find로 찾은 결과는 {}
안에 하나씩 들어가게 되고 -exec
는 뒤에 나오는 명령어를 실행시킨다.
매일 하루 자정마다 2달이 지난 로그를 삭제!
00 00 * * * /bin/bash "find 명령어를 등록한 .sh 파일 경로"
4번이 해결되었다.
5번, 문자를 얼마나 보내줘야 할까?
중복이 발생했더라도 조치를 취해야 하는 입장에서는 장애가 발생했으므로 짜증(?) 이 날 수 있는데 문자가 1분 간격으로 계속 온다면?
이거 개발한 사람 누구야..
나에게 화살이 돌아올 수 있다. 마땅한 방법이 생각나지 않았다...
내가 생각 한 방법은
- 문자 메세지를 보내는 주기는 1시간이다.
- 1시간 안에 또 중복이 발생 할 수 있으므로, 중복이 발생 된 건에 대한 id 값을 비교해서 기존의 값과 다르면 새로운 중복이 발생한 것이기 때문에 다시 문자를 보내준다!
- 다르지 않다면 아무것도 수행하지 않고 flag를 +1 해준다.
- 10분간 sleep 한다.
이렇게 해서 중복이 발생되었을 때 while 문을 10분 간격으로 5번 돌려주어 매 정각 ~ 50분 까지 체크
다시 정각이 되면 새로 crontab에 맞게 실행되는 방식으로 구현을 했다.
그런데 반영하려고 실제 리눅스 서버에 넣었더니 값이 이상했다.
분명 id값이 나오면 안되는데 나오고 있었다.
id값을 얻어오는 명령어가 아무래도 잘못되었다..
다시 수 많은 검색과 실행을 통해
cut -f 2 로그파일 경로 | awk -F '[|]' '{print $3 " " $6}' | sort |uniq -d | awk '{print $1}' | uniq
라는 명령어로 id값을 정확히 얻어냈다. (이번엔 진짜다.)
awk -F 를 사용해 구분자는 |
를 주어 3번째 영역과 6번째 영역을 가져온 뒤 중복 체크 명령어로 줄인 뒤에
결과 값을 id값만 가져와 다시 중복을 제거했다.
말만 들어도 헷갈리지만 어쨌든 이걸로 되었다.
그런데 쉘 스크립트에서 사용하니까 안먹혔다.
왜?
cut -f 2 로그파일 경로 | awk -F '[|]' '{ print $3 " " $6 }' | sort | uniq -d | awk '{ print $1 }' | uniq
이렇게 print의 괄호를 띄어쓰기를 사용해 구분을 해주어야 했다.
awk 명령어를 사용하니까 출력된 결과물에 대해서 원하는 값만 추출하기가 상당히 편했다.
로그 파일 경로가 서버마다 다르기 때문에 바뀌는 부분에 대한 경로를
#디렉토리 경로
#server_dir=`pwd | awk -F [/] '{ print $4 }'`
#transfer_dir=`pwd | awk -F [/] '{ print $5 }'`
이런 식으로 잘라서 얻어냈다.
하지만 위 코드는 결국 사용하지 못했다.
왜냐하면 작성된 쉘을 crontab에서 주기마다 실행 시키는데, crontab에서 실행하면서 pwd가 해당하는 디렉토리를 제대로 읽지 못하고 crontab이 실행하는 곳의 경로를 읽는 것 같다.
그래서 값을 대입해줬다.
느낀점
위에 적은 내용 뿐만아니라 더 많은 삽질을 했다..
프로세스를 체크해서 프로세스가 죽은 경우 재구동을 시켜주고 등등의 방식을 생각해서
그렇게 하려했지만, 애초에 로그 파일만 읽기 때문에 그렇게 할 필요도 없고 자바에서 따로 구현을 해야했다.
하지만, 다음에 프로세스 방식으로 구현 할 일이 생긴다면 도움이 될 것이다.
이번 기회에 리눅스에 대해 친근감이 생긴 것 같다.
재밌었다.
ps. 추가적으로 발송 이력이 없어서 파일이 존재하지 않을 경우 아무런 작동이 안 된다고 생각할 수 있을 것 같아서 파일의 갯수를 카운트해서 if 문에 추가해줬다.
find 파일 디렉토리 경로 -type f -name [파일이름.log](파일이름.log) | wc -l
파일의 갯수를 카운트 하지 않더라도
if [ -f "$filename" ]; then
와 같이 사용하면 파일이 존재하는지의 유무를 반환해준다.
$filename은 파일의 경로.
'OS' 카테고리의 다른 글
[리눅스]쓰레드 덤프, 힙 덤프, 코어 덤프 분석 삽질과정 (0) | 2020.01.31 |
---|---|
[Linux] 리눅스에 톰캣 설치 & 서비스 등록 (0) | 2019.07.05 |
OS - 메모리 관리 (0) | 2019.06.18 |
댓글