쉘기능을 자유자재로 다루기_06 scp로 파일 전송할 때 CPU 이용률을 계산해서 압축 처리를 할 것인지 판단하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: time, scp, awk, bc
키워드: CPU 바운드, I/O 바운드, 처리 시간, 측정
사용처: 스크립트 실행 시간과 CPU 사용 시간을 측정해서 전체 실행 시간 대비 CPU 사용률을 알고 싶을 때


실행예제

$ ./time-scp.sh
transfer.dat	100%	18MB	9.0MB/s	00:02
scp 전송 CPU 사용률 : 66.98 (%)

스크립트

#!/bin/sh

# 테스트 전송 파일명, 전송할 곳 등 정의
username="user1"         # ssh 사용자명  --------------- 1
filename="transfer.dat"  # 전송 파일명  ---------------- 1
hostname="192.168.2.10"  # 전송 호스트  ---------------- 1
path="/var/tmp"          # 전송경로  ------------------- 1
tmpfile="timetmp.$$"     # 시간 측정을 위한 임시 파일  -- 1

# scp 명령어로 파일 전송
# time 명령어로 시간을 측정, 임시 파일에 출력
(time -p tcp scp -C "$filename" ${username}@${hostname}:"${path}" ) 2> "$tmpfile"  #--- 2

# time 명령어 출력 임시 파일에서 각 time 추출
realtime=$(awk '/^real / {print $2}' "$tmpfile")  #----- 3
usertime=$(awk '/^user / {print $2}' "$tmpfile")  #----- 3
systime=$(awk '/^sys / {print $2}' "$tmpfile")  #------- 3

# CPU 사용 시간에서  CPU 사용률 계산
cpu_percentage=$(echo "scale=2; 100 * ($usertime + $systime) / $realtime" | bc )  #--- 4
echo "scp 전송 CPU 사용률 : $cpu_percentage (%)"

# 임시 파일 삭제
rm -f "$tmpfile"

   

해설

이 스크립트는 scp 명령어로 파일을 전송할 때 파일을 압축하고, 그때 걸린 총 소요시간에 대한 CPU 사용 시간 비율을 표시합니다. 이 예제는 처리 시간을 측정하기 위해 암호를 입력하는 시간이 포함되지 않도록 ssh 공개키 인증을 한다고 가정합니다.

여기서 ssh 공개키 인증이란 비밀키공개키의 쌍으로 인증하는 방법입니다. 일반적으로 ssh로 암호 인증을 사용하면 로그인할 때 암호를 입력해야 하므로 셸 스크립트 자동화가 어렵습니다. 하지만 키 인증으로 로그인하는 방식은 암호 입력이 필요 없으므로 자동화가 간단합니다.

이런 키 인증 ssh 설정은 방대한 내용이므로 간단한 절차만 설명합니다.

1OpenSSL의 ssh-keygen 명령어 등을 사용해서 비밀키, 공개키 쌍을 생성합니다.
2작성한 키 중 공개키 파일 내용을 접속 대상 호스트의 ~/.ssh/authorized_keys 파일에 추가합니다.
3접속 대상 호스트의 ~/.ssh/config 파일을 편집해서 비밀키 파일과 로그인 사용자명을 지정합니다.

비밀키는 무척 중요한 파일입니다. 설치한 디렉터리는 다른 사람이 보지 못하도록 권한을 지정하는 등 엄중히 관리해야 합니다.

예제에서 파일 전송을 위해 사용한 scp 명령어-C 옵션으로 파일을 압축해서 전송할 수 있습니다. 하지만 네트워크 영역은 충분하지만 CPU 성능이 부족한 머신에서 이런 압축 처리를 하면 반대로 CPU 시간을 잡아먹어서 전체 전송 시간이 길어질 수도 있습니다. 한편, 네트워크가 극단적으로 느린 환경이라면 압축하는 쪽 효율이 좋을 수도 있습니다. 이 스크립트는 이런 상태를 판단하기 위한 툴로 사용한다고 생각하면 됩니다.

1에서 우선 전송에 사용할 파일과 서버명 등을 설정합니다. 셸 변수 tmpfile은 time 명령어 출력을 저장하는 임시 파일입니다.

2는 scp 명령어로 파일을 전송합니다. scp 명령어는 다음처럼 통신 상대를 지정해서 파일을 전송할 수 있습니다. 2에서 CPU 시간을 측정하기 위해 압축 옵션 -C도 사용합니다.

  • scp 명령어 서식

    # [파일 압축해서 전송]
    scp -C <파일명> <사용자명>@<서버명>:<전송경로>
    
    # [파일을 압축하지 않고 전송]
    scp <파일명> <사용자명>@<서버명>:<전송경로>
    

그리고 2에서 사용하는 time 명령어는 지정한 명령어 실행 시간과 CPU 사용 시간을 측정하는 용도입니다. 예를 들어 cp 명령어로 파일을 복사하는데 걸린 시간을 time 명령어로 측정하려면 다음과 같습니다. -p 옵션은 단순히 초만 표시할 때 사용합니다.

  • time 명령어로 실행 시간 측정

    $ time -p cp tmp.dat tmp2.dat
    real 3.92
    user 0.02
    sys 0.33
    

여기서 real은 명령어 시작부터 종료까지 경과한 실제 시간, user는 사용자 CPU 시간, sys는 시스템 CPU 시간을 나타냅니다. 즉, 대략적으로 user + sys가 CPU 시간이고 real 부터 CPU 시간을 뺀 시간이I/O대기 시간이라고 볼 수 있습니다.

  • CPU 처리 시간 : user + sys
  • I/O 대기 시간 : real - (user + sys)

일반적으로 CPU 처리 시간이 길면 ‘CPU 바운드 처리’, 디스크나 네트워크처럼 I/O 대기가 길면 ‘I/O 바운드 처리’라고 부릅니다. 예제에서는 time 명령어 출력 결과를 사용해서 CPU 사용률을 계산합니다. 따라서 CPU 바운드 처리였는지 I/O 바운드 처리였는지 판단할 수 있습니다.

2에서는 명령어 전체를 ( )로 싸서 서브셸로 실행합니다. 이것은 명령어 전체를 그룹핑해서 리다이렉트하기 위한 처리입니다. 서브셸을 사용하지 않으면 scp 명령어 결과만 리다이렉트되어서 time 명령어 결과를 얻을 수 없습니다. 또한 time 명령어는 결과를 표준 에러 출력으로 표시하므로 2에서는 2>로 표준 에러 출력을 파일로 리다이렉트합니다.

이렇게 scp 전송 시 CPU 사용 시간과 실시간을 측정해서 임시 파일 $tmpfile에 출력합니다. 그럼 CPU 처리 시간 비율을 계산해봅시다.

3은 임시 파일에서 time 명령어 출력 real, user, sys 값을 얻습니다. awk 명령어로 각각의 인수를 필터 지정하고, 두 번째 컬럼값을 얻어서 셸 변수에 각각 대입합니다. 이것으로 전송 시간 전체에 대한CPU 이용 시간 비율을 계산 가능합니다. 셸 스크립트에서 계산은 expr 명령어를 자주 사용하는데 expr 명령어는 소수를 계산하지 못합니다. 소수를 포함한 계산은 bc 명령어를 사용합니다.

bc 명령어는 다음처럼 계산식을 표준 입력에 전달하면 수치 계산이 가능한 명령어입니다. 소수점 이하 지정은 scale=으로 지정합니다.

  • 소수점 두 자리까지 출력하는 bc 명령어 계산 예

    $ echo "scale=2; (32.2 + 41.3) / 5.6" | bc
    13.12
    

앞에서 설명했듯 CPU처리 시간은 user+sys 이므로 전체 걸린 시간 real로 나누면 CPU 처리 시간 비율을 계산할 수 있습니다. 4에서 이 값을 계산해서 퍼센트를 표시합니다.

만약 예제에서 표시된 CPU 처리 시간 퍼센트가 무척 크면 scp 명령어 전송 시 압축하지 않아야(-C 옵션을 사용하지 않음) 전송이 더 빨라 끝난다는 뜻이 됩니다. 네트워크 영역과 CPU 성능에 따라 판단이 달라지는데 그 판단 지료포 이런 툴을 사용하면 됩니다.

   

주의사항

  • time 명령어는 셸 내장 명령어와 외부 명령어가 각각 환경에 따라 출력 형식이 달라집니다. 우분투라면 세 종류의 time 명령어가 있습니다.

    • sh 내장 time 명령어
    • bash 내장 time 명령어
    • 외부 명령어 /usr/bin/time

    셸 내장 명령어나 외부 명령어나 time 명령어에 -p 옵션을 사용할 수 있습니다. 표시 형식 통일을 위해 셸 스크립트에서는 기본적으로 -p 옵션을 사용하기 바랍니다.