[Linux] (shell) 스크립트 기초

 

l  Linux

 

스크립트(shell script) 셸이나 명령줄 인터프리터(Interpreter)에서 실행되도록 작성되었거나 운영 체제를 위해 쓰인 스크립트이다. 스크립트가 수행하는 일반 기능으로는 파일 이용, 프로그램 실행, 문자열 출력 등이 있다. 스크립트에서는 .sh라는 파일 확장자를 가진 파일이 특정 종류의 스크립트를 가리키는 것이 보통이지만, 대부분의 스크립트는 파일 확장자를 지니지 않는다. 스크립트는 인터프리터 방식이므로 라인별로 읽어 실행함으로 속도가 다소 느리다는 단점이 있다.

스크립트라는 말은 유닉스 쉘을 위해 쓰인 스크립트를 말하는 반면, command.com(도스) cmd.exe (윈도우) 명령 스크립트는 보통 배치 파일이라고 불린다.  최근엔 마이크로소프트가 개발한 CLI쉘인 파워쉘이 있다.

 

이번 포스트에서는 가장 널리 쓰이는 bash 쉘을 사용하는 스크립트를 설명한다.

 

문장의 시작 (#!/bin/bash)

스크립트의 번째줄에는 항상 #!/bin/bash 기입되어 있어야 한다. 내용은 쉘이 실행될 어떤 쉘로 스크립트를 실행할지 정의하는 곳이다. 쉘에는 다양한 버전이 있다. 아래 예시는 hello.sh 라는 스크립트를 생성하고 실행하는 방법을 설명한다. 아래 스크립트를 hello.sh라는 파일을 생성하고 입력한다.

#!/bin/bash
 
echo "Hello, Shell Script"

 

아래 명령을 사용하여 스크립트를 실행하면 Hello, Shell Script 출력한다. 스크립트 명령어에 대한 부분은 아래에서 자세히 설명하도록 한다. 만약 실행이 되지 않는다면 실행 권한이 없어 발생한것으로 chmod 777 hello.sh 실행하여 권한 변경 실행한다.

$sh hello.sh

 

 

 

주석 처리 (#)

스크립트에서 단일 주석은 (#) 사용한다.

#!/bin/bash
 
#여기는 주석입니다.
#주석은 실행되지 않습니다.
 
echo "Hello, Shell Script"

 

블록 주석은 : <<”END” ~ ~ END 사용한다.

#!/bin/bash
 
: << “END” #주석 시작
여기는 주석입니다.
주석은 실행되지 않습니다.
END #주석
 
echo "Hello, Shell Script"
 

 

 

입력(read), 출력(echo)

echo 출력, read 입력을 있다. 위에서 이미 echo 사용하였으므로 read 사용하여 입력한 값을 출력하도록 스크립트를 작성해 본다. 입력 받은 값을 변수로 사용하려면 $기호를 사용한다.

#!/bin/bash
read input_value
echo "Hello, $input_value!"

 

스크립트를 실행하면 입력값이 발생할 때까지 실행되지 않고 대기한다. hahaha라고 입력하면 입력 받은 값이 변수로 사용되어 결과가 출력된다.

$sh hello.sh
hahaha

 

 

 

변수 특징

l  변수의 타입에는 로컬변수와 전역변수, 환경변수, 예약변수, 매개변수 다양하다.

l  변수는 , 소문자를 구별한다.

l  변수명에는 영문자, 숫자, 언더바( _ ) 사용된다.

l  변수의 이름은 숫자를 포함할 있지만, 숫자로 시작할 없다.

l  변수에는 모든 값을 문자열로 저장된다.

l  변수에는 자료형을 기입하지 않기 때문에 어떠한 값도 입력할 있다. (변수에 타입을 지정할 수도 있다.)

l  값을 사용할 때는 변수명 앞에 특수문자 "$" 사용한다. (Ex. echo ${data})

l  값을 대입(삽입) 때는 특수문자 "$" 사용하지 않는다. (Ex. data=mac)

l  변수를 생성할 때는 "=" 대입문자 앞뒤로 공백이 없어야 한다. (Ex. data="abcd") 문자열인 경우 “ “ 감싼다.

l  하나의 변수에 개의 값만 보존된다.

l  변수 값이 덮어 쓰기되는 것을 방지하기 위해서는 readonly 사용한다.

l  변수를 unset으로 삭제할 있다. (readonly 선언된 것은 삭제가 불가능하다.)

 

스크립트에서 시스템이 사용하는 예약어가 있다. 가지 대표적인 예약어이다.

변수 설명
HOME 사용자 디렉토리 의미
PATH 실행 파일의 경로
LANG 프로그램 실행 지원되는 언어
UID 사용자의 UID
SHELL 사용자가 로그인시 실행되는
USER 사용자 계정 이름
FUNCNAME 현재 실행되고 있는 함수 이름
TERM 로그인 터미널
Set 변수를 출력하는 명령어
Env 환경 변수를 출력하는 명령어
Export 특정 변수의 범위를 환경 변수의 데이터 공간으로 전송하여 자식 프로세스에서도 특정 변수를 사용 가능하게 한다.
unset 선언된 변수를 제거

 

 

전역변수, 지역변수

쉘에서 선언된 변수는 기본적으로 전역변수(global variable)이며, 함수안에서 지역변수(local variable) 사용할 있는데, 이때에는 local 붙여서 사용한다. 함수안에서 local 사용하지 않으면 전역 변수의 값을 덮어쓰게 된다.

#!/bin/bash
 
# 전역 변수 지정
string="hello shell, global variable"
 
function string_test() {
    # local 붙여야 지역변수로 인식. 만약 local 빼면 전역변수에 덮어쓰기로 적용
    local string="hello shell, local variable"
    echo ${string}
}
 
# 함수 호출
string_test # > hello shell, local variable
echo ${string} # > hello shell, global variabl
 
# 변수 초기화
unset string

 

 

 

변수 타입 지정

기본적으로 Bash 문자열만 저장하지만 데이터 타입을 지정할 수도 있다.

변수타입 설명
declare -r 읽기 전용 타입
declare -i 정수형 타입
declare -a 배열 타입
declare -A 연관배열(MAP) 타입
declare -f 함수 타입
declare -x 환경변수(export) 지정으로 외부 환경에서도 변수를 사용할 있다.

 

 

읽기전용 변수 (readonly)

변수에 값을 덮어 쓸수 있지만 readonly 지정한 경우 변수를 덮어쓸수 없다. 아래 예시는 readonly에서 변수 덮어쓰기를 시도할 발생한 오류를 확인할 있다.

#!/bin/bash
 
var="변수1"
VaR_2="변수2"
echo "Var_2=$VaR_2"
 
VaR_2="VaR_2 변경합니다."
echo ${VaR_2}
 
readonly var
var="readonly var 변수를 변경해 봅니다."

 

 

 

변수 값의 치환

변수의 값을 치환할 사용하는 문법을 표로 정리하였다.

문법 설명
${var} 변수 값을 바꿔 넣는다.
${var:-word} 변수가 아직 세팅되지 않거나 공백 문자열의 경우 word 반환한다. var에는 저장되지 않는다.
${var:=word} 변수가 아직 세팅되지 않거나 공백 문자열의 word 반환한다. var 저장된다.
${var:?word} 변수가 아직 세팅되지 않거나 공백 문자열의 경우 치환에 실패하고, 스탠다드 에러에 에러가 표시된다.
${var:+word} 변수가 세팅되지 않은 경우 word 반환된다. var에는 저장되지 않는다.

 

#!/bin/sh
 
echo "1 - ${var:-wordSetInEcho1}"
echo "2 - var = ${var}"
echo "3 - ${var:=wordSetInEcho3}"
echo "4 - var = ${var}"
unset var
echo "5 - ${var:+wordSetInEcho5}"
echo "6 - var = $var"
var="newVarValue"
echo "7 - ${var:+wordSetInEcho7}"
echo "8 - var = $var"
echo "9 - ${var:?StandardErrorMessage}"
echo "10 - var = ${var}"

 

 

문자열 패턴 비교는 아래 조건을 사용할 있다.

문법 설명
${var%pattern} 끝에서 부터 word 패턴이 일치하는 var 최소 부분(첫번째 일치) 제거하고 나머지를 반환
${var%%pattern} 끝에서 부터 word 패턴이 일치하는 var 최대 부분(마지막 일치) 제거하고 나머지를 반환
${var#pattern} 처음 부터 word 패턴이 일치하는 var 최소 부분( 번째 일치) 제거하고 나머지 부분을 반환
${var##pattern} 처음 부터 word 패턴이 일치하는 var 최대 부분(마지막 일치) 제거하고 나머지 부분을 반환

 

 

환경 변수 (export)

스크립트에서 변수명 앞에 export 붙여 환경변수(environment variable) 사용할 있다. 다만 환경변수 사용시 시스템에 미리 정의된 예약변수와 겹치지 않게 주의한다. 실습을 위해 개의 파일을 준비한다.

shell1.sh
#!/bin/bash
 
echo ${export_variable}

 

shell2.sh
#!/bin/bash
 
#환경변수 선언
export export_variable="export test, hello shell"
 
#변수값을 받아서 사용할 스크립트 호출
/파일 경로/shell1.sh

 

shell2.sh 실행한다. Export 변수의 값은 shell1.sh 호출할 사용된다.

 

 

매개변수

프로그램에서 실행할 인자를 사용하듯 스크립트에서도 매개변수를 사용할 있다. 규칙이 있는데, 실행한 스크립트 이름은 ${0}, 이후 인자 값들은 ${1}. ${2}…으로 사용한다.

변수 기능
$0 스크립트명
$1 ~ $9 인수 1 번째부터 인수 9번째까지 사용
$# 스크립트에 전달될 인수의
$* 모든 인수를 모아 하나로 처리
$@ 모든 인수를 각각 처리
$? 직전에 실행한 커멘드의 종료 (0 성공, 1 실패)
$$ 스크립트의 프로세스ID
$! 마지막으로 실행한 백그라운드 프로세스 ID

 

아래 스크립트는 매개변수를 입력 받아 어떻게 사용되는지 알아보는 예시이다.

#!/bin/sh
 
echo "\$0script name: $0"
echo "\$11st param: $1"
echo "\$22nd param: $2"
echo "\$#number of param: $#"
echo "\"\$*\": \"$*\""
echo "\"\$@\": \"$@\""
VAR="exit code is  0 "
echo $?

 

실행 결과는 아래와 같이 나타난다.

 

 

배열 (Array)

스크립트에서 배열은 1차원 배열만 지원하며 중괄호를 사용해야 한다. 배열 원소는 소괄호안에 공백으로 구분하며, 배열 원소는 문자열이든 숫자형이던 상관없이 있다.

#!/bin/bash
 
arr=("hello" "shell" 1 2 3 4 5)
 
echo "배열 전체 : ${arr[@]}"
echo "배열 원소의 갯수 : ${#arr[@]}"
echo "배열 첫번째 : ${arr}, 혹은 ${arr[0]}"
echo "4 index 갖는 배열의 원소 : ${arr[4]}"
 
arr[5]="four"
 
echo "4번째 index 갖는 배열의 원소 : ${arr[4]}"
 
# 4번째 해제
unset arr[4]
echo "4 배열 삭제 완료"
echo "4 index 갖는 배열의 원소 : ${arr[4]}"
echo "5 index 갖는 배열의 원소 : ${arr[5]}"

 

 

 

함수(function)

스크립트에서도 함수를 사용할 있다. 함수의 정의 형식은 아래와 같다. 주의할 점은 함수가 호출되기 전에 함수가 정의되어 있어야 하며 호출할 때는 괄호를 사용하지 않고 호출한다.

#!/bin/bash
 
function func(){
        echo "func()"
}
 
#함수 호출
func

 

 

비교문(if..fi)

쉘에서는 비교문이 약간 특이하다. bash if문의 특이한 점은 fi 대괄호([ ]) 이다. 다른 언어와 달리 중괄호를 사용하지 않기 때문에 fi if문의 끝을 알려주어야 한다. 주의해야 점은 if 뒤에 나오는 대괄호 [ ] 조건식 사이에는 반드시 공백이 존재해야 한다.

 

비교문에는 다양한 연산자를 사용할 있다.

연산자 설명
1 -eq 2 # 값이 같음(equal)
1 -ne 2 # 값이 같지 않음(not equal)
1 -lt 2 # 1 2보다 작음(less than)
1 -le 2 # 1 2보다 작거나 같음(less or equal)
1 -gt 2 # 1 2보다 (greater than)
1 -ge 2 # 1 2보다 크거나 같음(greater or equal)

 

문자열 비교

연산자 설명
문자1 = 문자2 # 문자1 문자2 일치 (sql같이 = 하나만 써도 일치로 인식)
문자1 == 문자2 # 문자1 문자2 일치
문자1 != 문자2 # 문자1 문자2 일치하지 않음
-z 문자 # 문자가 null 이면
-n 문자 # 문자가 null 아니면
문자 == 패턴 # 문자열이 패턴과 일치
문자 != 패턴 # 문자열이 패턴과 일치하지 않음

 

논리 연산자

연산자 설명
조건1 -a 조건2 # AND
조건1 -o 조건2 # OR
조건1 && 조건2 # 양쪽 성립
조건1 || 조건2 # 한쪽 또는 양쪽다 성립
!조건 # 조건이 성립하지 않음
true # 조건이 언제나 성립
false # 조건이 언제나 성립하지 않음

 

산술연산자 (쉘에서는 expr 숫자 연산자 숫자형식으로 사용한다.)

연산자 의미 예시
+ 덧셈 echo `expr 10 + 20` => 30
- 뺄셈 echo `expr 20 - 10` => 10
\* 제곱 echo `expr 11 \* 11` => 121
/ 나눗셈 echo `expr 10 / 2` => 5
% 나머지 echo `expr 10 % 4` => 2
= 저장 a=$b b 값은 a 저장
== 동일 [ "$a" == "$b" ] $a $b 동일하는 경우 TRUE 반환
!= 다름 [ "$a" != "$b" ] $a $b 동일하지 않는 경우 TRUE 반환

 

 

예제로 살펴본다.

#!/bin/bash
 
function func(){
        a=10
        b=5
 
        if [ ${a} -eq ${b} ]; then
                echo "a b 같다."
        fi
 
        if [ ${a} -ne ${b} ]; then
                echo "a b 같지 않다."
        fi
 
        if [ ${a} -gt ${b} ]; then
                echo "a b보다 크다."
        fi
 
        if [ ${a} -ge ${b} ]; then
                echo "a b보다 크거나 같다."
        fi
 
        if [ ${a} -lt ${b} ]; then
                echo "a b보다 작다."
        fi
 
        if [ ${a} -le ${b} ]; then
                echo "a b보다 작거나 같다."
        fi
 
}
 
#함수 호출
func

 

 

 

여러 조건을 사용할때, 다른 언어에서는 else if역할을 하는 것을 스크립트에서는 elif라는 것을 사용하여 else if 동일한 역할을 있다. elif[ 조건 ]; then 형식으로 사용한다. 만약 반복문에서 사용하여 조건이 참일때 반복문을 멈추고 싶을때 break라는 키워드를 사용하여 반복문을 멈출 있다.

#!/bin/bash
 
case ${1} in
        "linux") echo "리눅스" ;;
        "unix") echo "유닉스" ;;
        "windows") echo "윈도우즈" ;;
        "MacOS") echo "OS" ;;
        *) echo "해당없음" ;;
esac

 

 

파일 관련 조건문

스크립트는 명령어를 다루는 스크립트이기 때문에 파일이 존재하는지, 디렉토리가 존재하는지 파일과 관련된 조건 여부도 조건문을 통해 있다. 아래 표는 조건을 정리한 것이다. , 거짓을 판단할 , 느낌표(!) 사용하면 반대로 결과를 출력한다.

조건 설명
if [ -d ${변수} ]; then ${변수} 디렉토리가 존재하면 true.
if [ ! -d ${변수} ]; then ${변수} 디렉토리가 존재하지 않으면 true.
if [ -e ${변수} ]; then ${변수}라는 파일이 존재하면 true.
if [ ! -e ${변수} ]; then ${변수}라는 파일이 존재하지 않으면 true.
if [ -L ${변수} ]; then 파일이 symbolic link이면 true.
if [ -s ${변수} ]; then 파일의 크기가 0보다 크면 true.
if [ -S ${변수} ]; then 파일 타입이 소켓이면 true.
if [ -r ${변수} ]; then 파일을 읽을 있으면 true.
if [ -w ${변수} ]; then 파일을 있으면 true.
if [ -x ${변수} ]; then 파일을 실행할 있으면 true.
if [ -f ${변수} ]; then 파일이 정규 파일이면 true.
if [ -c ${변수} ]; then 파일이 문자 장치이면 true.
if [ ${변수1} -nt ${변수2}]; then 변수1 파일이 변수2 파일보다 최신 파일이면 true.
if [ ${변수1} -ot ${변수2}]; then 변수1 파일이 변수2 파일보다 최신이 아니면 true.
if [ ${변수1} -ef ${변수2}]; then 변수1 파일과 변수2 파일이 동일하면 true.

 

 

CASE

일반적인 CASE 사용법과 비슷하지만 CASE 끝에 세미콜론을 2개씩 사용하는 특징이 있다. 그리고 CASE 끝은 ESAC 닫아준다.

#!/bin/bash
 
DRINK="coffee"
case "$DRINK" in
    "beer") echo "맥주입니다"
    ;;
    "juice") echo "주스입니다"
    ;;
    "coffee") echo "개발자에겐 카페인 필수!"
    ;;
esac

 

 

CASE에서 OR 연산도 가능하다.

COUNTRY=korea
 
case $COUNTRY in
  "korea"|"japan"|"china") # or 연산도 가능하다
    echo "$COUNTRY is Asia"
    ;;
  "USA"|"Canada"|"Mexico")
    echo "$COUNTRY is Ameria"
    ;;
  * )
    echo "I don't know where is $COUNTRY"
    ;;
esac

 

 

반복문(for)

반복문을 빠져나갈때에는 break 사용하고, 현재 반복분이나 조건을 건너뛸때에는 continue 사용한다.

#!/bin/bash
 
# 초기값; 조건값; 증가값을 사용한 정통적인 for
for ((i=1; i<=4; i++)); do
    echo $i
done

 

 

 

반복문(for in)

#!/bin/bash
 
function func(){
        echo "사용예1"
        for i in 1 2 3 4 5
        do
                echo "${i}"
        done
 
        echo "사용예2"
        list="1 2 3 4 5"
        for i in ${list}
        do
                echo "${i}"
        done
 
        echo "사용예3"
        for i in {1..5}
        do
                echo "${i}"
        done
 
        echo "사용예4: 크기를 2만큼 증가시키면서 출력"
        for i in {1..5..2}
        do
                echo "${i}"
        done
 
        echo "사용예5: 배열을 이용"
        arr=(1 2 3 4 5)
        for i in "${arr[@]}"
        do
                echo "${i}"
        done
 
 
        echo "사용예6: C 유사한 형식의 for"
        for ((i=0; i<5; i++)); do
                echo "${i}"
        done
}
 
#함수 호출
func

 

 

 

반복문 (while)

수행 조건이 true일때 실행되는 반복문이다.

count=0
while [ ${count} -le 5 ];
do
    echo ${count}
    count=$(( ${count}+1 ))
done

 

 

이중 괄호를 사용하면 논리 기호로도 사용 가능하다.

count=0
while (( ${count} <= 5 ));  # 이중괄호 사용하면 논리기호 사용 가능
do
    echo ${count}
    count=$(( ${count}+1 ))
done

 

 

반복문(until)

수행 조건이 false 일때 실행되는 반복문이다. 조건이 While 반대라고 생각하면 된다.

count2=10
 
until [ ${count2} -le 5 ]; do
    echo ${count2}
    count2=$(( ${count2}-1 ))
done

 

 

 

종료 상태 코드

명령어가 실패할 경우 리턴되는 결과에 따라 다른 동작을 하려면 명령어의 종료 코드를 반환 받아 사용하면 된다. 명령어의 종료 코드는 $? 사용하여 가장 최근 실행한 명령어의 종료 코드를 받을 있다. 정상적인 종료는 0 반환되며 0 아닌 값은 오류라고 판단할 있다. 아래 표는 종료 코드에 따른 설명을 정리한 것이다.

종료 코드 설명
0 성공 (Success)
1 일반적 오류 (Catchall for general errors)
2 내장 명령의 틀린 사용 (Misuse of shell builtins)
126 파일이 실행 가능하지 않음 (Command invoked cannot execute)
127 명령어를 찾을 없음 (Command not found)
128 종료할 잘못된 인수 적용 (Invalid argument to exit)
128+n 치명적인 시그널 n 에러 (Fatal error signal “n”)
130 [Ctrl + C] 조합에 의한 종료 (Script terminated by Control-C)

 

 

이스케이프 문자

명령어 설명
\f 문자열만큼 열을 밀어서 이동한다.
\n 새로운 줄로 바꾼다.
\r 문자열의 앞부분 부터 뒷문자열 만큼 대체하고 반환한다.
\t 만큼 띄운다.

 

 

외에도 다양한 명령이 있다. 명령을 활용하면 리눅스 환경에서 시스템 관련 다양한 정보들을 스크립트로 얻을 있다.

 

 

 

[참고자료]

l   https://ko.wikipedia.org/wiki/%EC%85%B8_%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8

l   https://reakwon.tistory.com/136

l   https://inpa.tistory.com/entry/LINUX-%EC%89%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%95%B5%EC%8B%AC-%EB%AC%B8%EB%B2%95-%EC%B4%9D%EC%A0%95%EB%A6%AC

l   https://engineer-mole.tistory.com/200

 

 

 

2023-09-05 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, 쉘스크립트, 쉘사용법, 쉘명령어, shell command, shell script

'Linux' 카테고리의 다른 글

[Linux] Alpine Linux (알파인 리눅스) 는 무엇일까?  (0) 2023.09.04
[Linux] OOM(Out of Memory)란?  (0) 2023.08.30
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22
CentOS 심볼 링크 설정  (0) 2015.07.22

[Linux] Alpine Linux (알파인 리눅스) 무엇일까?

 

l  Linux

 

컨테이너 환경으로 다양한 서비스를 빌드하다보니, DevOps 팀에서 베이스 이미지를 ubuntu centos 대신 alpine(알파인) 리눅스를 사용하는 것이 어떻겠냐는 제안을 받았다. 리눅스는 다양한 커널 기반으로 배포판을 가지고 있다. 이번 포스트에서는 Alpine Linux (이하 알파인 리눅스”) 대해서 알아본다.

 

[개요]

알파인 리눅스는 리눅스 커널 기반으로 리눅스 배포판 하나이며 MIT 라이선스 아래에 배포되었으며 LEAF 리눅스의 포크 버전이다. 알파인 리눅스는 다른 배포판과 다르게 Musl BusyBox 기반으로 한다. 알파인 리눅스의 컨셉은 LEAF 리눅스와 동일하게 작고”, “보안이 뛰어나고”, “간단함 기반으로 한다. 하지만 시간이 지나면서 다양한 사람들에 의해 알파인 리눅스만의 형태로 발전되고 있다.

 

[특징]

장점

l  가볍고, 간단하며 보안성을 목적으로 개발한 배포판

l  용량을 줄이기 위해 시스템의 기본 C runtime glibc 대신 musl libc 사용

l  다양한 명령어는 GNU util대신 busybox 탑재

l  초경량( 80MB) 배포판으로 임베디드나 네트워크 서버 특정 용도에 적합.

l  특히 도커(Docker) 공식 이미지로 채택되어 5MB 크기의 리눅스 이미지로 유명함

l  보안에 염두해두고 설계되어 모든 바이너리는 독립적인 실행 파일(PIE) 컴파일

 

단점

l   리눅스 표준인 GNU 도구가 없어가나 Busybox 대신 들어가 있어, 명령어를 실행할 주의가 필요

l   라이트한 대신 패키지가 설치되어 있지 않아 직접 설치해주어야 하는 것들이 많다.

l   이것저것 설치하다보면 표준 리눅스 배포판과 거의 비슷한 용량이 되기도 한다. (개인적인 생각)

 

 

BusyBox?
BusyBox 일종의 명령어 모음집으로 박스안에 필요한 응용 프로그램들을 담아 놓은 것이다. 리눅스에서 사용되는 명령어들만 모아 놓아도 상당한 크기를 차지할 있는데, BusyBox에서는 각각에 함수들을 최소 사이즈로 다시 구현하였다. 그렇기 때문에 Embbeded(임베디드), 네트웍 서버 특정 용도에 적합하며 도커 컨테이너의 OS 많이 사용한다.

 

 

[자주 사용되는 명령어]

알파인 리눅스에서는 패키지 인스톨러가, 전통적인 yum, apt 대신에 apk 사용한다. 그리고 기본 쉘이 배시가 아니라 애쉬(ash)이다.

 

명령 설명
apk update 패키지 저장소 목록을 업데이트
apk search <package> 패키지 저장소 목록에서 패키지를 검색. v 옵션으로 설명 확인 가능.
apk add <package[=version]> 패키지를 설치. 버전을 명시하여 설치 가능.
apk del <package> 특정 패키지를 제거
apk cache clean 패키지 캐시를 모두 제거
apk cache -v sync 패키지 캐시를 초기화하고 부족한 패키지를 자동으로 다운로드
apk stats 현재 패키지 저장소에서 사용가능한 패키지나 설치된 패키지 등의 정보를 출력
apk fix 복구가 필요한 패키지를 복구하거나 종속성을 제외하고 업그레이드 진행.
apk info 현재 설치된 모든 패키지 정보 나열. -L 옵션을 사용하면 패키지내 파일 정보 출력.

 

 

[ 컨테이너에서 알파인 리눅스를 사용할까?]

지극히 개인적인 생각이다. 컨테이너 이미지 파일을 만들 , 베이스 이미지 위에 필요한 다양한 패키지를 설치하게 된다. 당연히 베이스 이미지 + 기타 필요한 패키지 크기만큼 이미지 사이즈가 되므로 빌드 용량도 커지게 된다. 그리고 이를 보관 배포하기 위해 스토리지 비용 네트워크 비용이 증가할 있다. 사실 스토리지 비용은 컴퓨팅 비용중에 가장 저렴한 부분 하나이다. 그래서 요즘은 용량 고민은 많이 하지 않는 편이다. 특히 온프레미스 환경에서 직접적으로 모든 것을 운용할 때에는 더더욱 그렇다. 하지만 클라우드 환경에선, 모든것이 비용으로 청구되기 때문에 최소한의 사이즈로 운영하면 비용 최적화에 많은 도움이 있을 것이라 생각한다.

 

 

 

[참고자료]

l   Alpine Linux:Overview : https://wiki.alpinelinux.org/wiki/Alpine_Linux:Overview

l   Alpine Linux  : https://namu.wiki/w/Alpine%20Linux

 

 

 

2023-09-04 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, 알파인 리눅스, Apline Linux, APK 명령어, 리눅스 배포판

'Linux' 카테고리의 다른 글

[Linux] 쉘(shell) 스크립트 기초  (0) 2023.09.05
[Linux] OOM(Out of Memory)란?  (0) 2023.08.30
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22
CentOS 심볼 링크 설정  (0) 2015.07.22

[Linux] OOM(Out of Memory)?

 

l  Linux

 

몇일전부터 개발 환경에서 겪던 문제로 멀쩡하던 MySQL 서비스가 갑자기 연결이 되지 않는다. 처음엔 단순히 현상인줄 알고, MySQL 서비스를 재시작 하였다. 그런데 동일한 상황이 하루에도 여러 발생하고 있어서 원인을 살펴보기로 했다. 원인을 살펴보니, 아래와 같은 로그가 있었다.

Aug 30 01:35:08 xxxxx kernel: [7189052.423131] [18540]   111 18540  1930392  1535479 12935168        0             0 mysqld
Aug 30 01:35:08 xxxxx kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child
Aug 30 01:35:08 xxxxx kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

OOM으로 인한 OOM Killer(강제 서비스 종료)였다. OOM 무엇이고 발생하는 것일까? 그리고 로그는 어떻게 확인할 있을까?

 

OOM (Out of Memory)

Linux swap 메모리와 물리 메모리를 모두 사용 , 프로세스에서는 필요에 의해 추가적인 물리 메모리 할당을 요청하였는데, 이상 할당할 물리 메모리 공간이 없어 할당이 불가능한 상태를 의미한다. 메모리 Over Commit 상태일 발생하는 현상으로 물리적으로 메모리가 부족하다는 뜻이다. 이러한 문제는 물리 메모리만 증설하면 사실 간단히 해결된다. 하지만 이러한 현상이 발생하는지 원인을 찾지 못한 상태에서 무한정 메모리를 증설할 수도 없다.

 

OOM Killer

서버 메모리 부족으로 OOM 발생하였을 , 리눅스에서는 메모리를 확보하기 위해 OOM Score 기준으로 점수가 높은 프로세스를 강제로 Kill 하여 메모리를 확보하는 Kernel 기능이다. 이렇게 OOM Killer 프로세스가 종료되면 내부 시스템 로그에 기록되어 추후 확인할 있다.

 

OOM Killer Log 확인

OOM Killer 프로세스가 종료되었을 때에는 각종 시스템 로그에서 확인할 있다. 시스템 로그에는 OOM Killer외에도 다양한 로그가 있기 때문에 로그 양이 많을 경우 필터를 해서 검색을 해야 수도 있다. 일반적으로 특별히 로그 경로를 수정하지 않았다면 아래 경로에서 다양한 시스템 로그를 확인할 있다.

 /var/log/

 

Kern.log에서는 아래와 같은 OOM 로그를 확인할 있었다.

cat kern.log

 

Aug 30 01:35:08 XXXXX kernel: [7189052.423131] [18540]   111 18540  1930392  1535479 12935168        0             0 mysqld
Aug 30 01:35:08 XXXXX kernel: [7189052.423132] Out of memory: Kill process 18540 (mysqld) score 512 or sacrifice child
Aug 30 01:35:08 XXXXX kernel: [7189052.424065] Killed process 18540 (mysqld) total-vm:7721568kB, anon-rss:6141916kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

syslog에서는 다양한 로그가 많이 기록되어 OOM이라는 필터를 사용하여 확인하였다.

cat syslog | grep oom

 

Aug 29 23:45:33 xxxxx kernel: [7182478.018455]  oom_kill_process+0x21f/0x420
Aug 29 23:45:33 xxxxx kernel: [7182478.018529] [ pid ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
Aug 29 23:45:34 xxxxx kernel: [7182478.495925] oom_reaper: reaped process 22648 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Aug 30 01:35:08 xxxxx kernel: [7189052.422998] icinga2 invoked oom-killer: gfp_mask=0x14200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0
Aug 30 01:35:08 xxxxx kernel: [7189052.423021]  oom_kill_process+0x21f/0x420
Aug 30 01:35:08 xxxxx kernel: [7189052.423096] [ pid ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
Aug 30 01:35:08 xxxxx kernel: [7189052.749286] oom_reaper: reaped process 18540 (mysqld), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

 

message 로그 파일에서도 동일한 오류 내역을 확인할 있다. Message 로그 파일은 다양한 로그 파일의 미러 역할을 하기 때문에 정말 다양한 로그가 기록되어 있다.

 

 

OOM killer 우선순위

로그를 살펴보면 OOM 의해 mysqld kill 되었음을 확인할 있다. 그렇다면 프로세스를 종료시키는 우선순위는 어떻게 정해질까? 가지 방법이 있다.

1.          oom_badness() 메소드에서 프로세스별 점수를 계산하여 종료시킬 프로세스를 선택한다.

2.          사용자가 특별히 지정하여 순위를 변동시킬 있다.

 

oom_badness() 사용하는 우선순위 선정 방법은 아래와 같다.

1.          특정 프로세스를 함으로써 최소한의 프로세스만 잃을 있어야 한다.

2.          많은 메모리를 회수할 있는 프로세스 (메모리 사용량이 작으면 되지 않는다.)

3.          프로세스중 Leak 발생하지 않는 프로세스 (릭이 발생하면 프로세스 Kill 의미가 없다)

4.          사용자가 특별히 지정한 프로세스

 

외에도 nice score 기반으로 우선순위를 선정할 있다.

 

 

OOM Killer score 확인

OOM score 확인 방법은 /proc/${pid}/oom_score 파일을 통해 조회할 있다. PID 확인하는 방법은 ps 명령을 사용한다.

l  ps : shell에서 실행중인 프로세스만 출력

l  ps -e : 실행 중인 모든 프로세스 출력

l  ps -f : 실행중인 모든 프로세스의 상태 정보 출력

l  ps -ef | grep mysql : grep 사용하여 특정 프로세스(mysql) PID 확인 한다.

 

ps -e | grep mywql

 

 

cat /proc/15368/oom_score

 

 

 

OOM Killer 순위 설정 방법

1.          특정 프로세스의 PID 조회

2.          /proc/PID/oom_adj 파일에 -17 입력. oom_adj -17 ~ 15 값을 가지며, 낮은 일수록 후순위.

3.          /proc_PID/oom_scroe_adj 파일에 -1000 입력. oom_score_adj -1000 ~ 1000 값을 가지며 낮은 값일수록 후순위.

 

아래 예시는 oom_adj 파일에 -17 변경하는 것으로 PID 변경하여 사용할 있다.

sudo echo -17 > /proc/${pid}/oom_ajd

 

아래 예시는 oom_score_adj파일에 -1000 변경하는 것으로 PID 변경하여 사용할 있다.

sudo echo -1000 > /proc/${pid}/oom_score_adj

 

 

메모리 누수로 인한 System hang 현상을 방지하기 위해 리눅서 커널에서는 OOM killer 자체는 비활성화 없기 때문에 순위 설정을 참고하여 중요한 프로세스는 Kill 되지 않도록 한다.

 

 

 

 

2023-08-30 / Sungwook Kang / https://sungwookkang.com

 

 

리눅스, Linux, OOM, OutOfMemory, 메모리부족현상, 강제킬, 프로세스확인, 메모리압박, 아웃오브메모리, OOMKiller, oom_score

'Linux' 카테고리의 다른 글

[Linux] 쉘(shell) 스크립트 기초  (0) 2023.09.05
[Linux] Alpine Linux (알파인 리눅스) 는 무엇일까?  (0) 2023.09.04
CnetOS 방화벽 설정  (0) 2015.07.22
CentOS 파일 압축/풀기  (0) 2015.07.22
CentOS 심볼 링크 설정  (0) 2015.07.22

SQL Linux fsync 버퍼된 IO (버퍼된 쓰기중 오류가 발생하였을때 파일은 유효할까?)

 

·       Version : SQL Server Linux

 

 

PostgreSQL에서 fsync() 오류처리는 안전하지 않으며 XFS에서 데이터 손실이  발생할 있다는 내용이 있다.

·       PostgreSQL's handling of fsync() errors is unsafe and risks data loss at least on XFS : https://www.postgresql.org/message-id/flat/CAMsr%2BYE5Gs9iPqw2mQ6OHt1aC5Qk5EuBFCyG%2BvzHun1EqMxyQg%40mail.gmail.com#CAMsr+YE5Gs9iPqw2mQ6OHt1aC5Qk5EuBFCyG+vzHun1EqMxyQg@mail.gmail.com

 

이번 포스트는  SQL Server에서도 Linux 동일한 문제가 발생하는지 유효성을 검증하는 내용으로,  SQL Server 경우 O_DIRECT 사용하기 때문에 PostgreSQL 같은 문제가 발생하지 않는다.

·       Direct I/O : https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/5/html/global_file_system/s1-manage-direct-io

 

응용 프로그램이 버퍼된 쓰기를 수행하고 성공을 수신한다. (이는 안정된 미디어 파일 시스템 캐시에 데이터를 저장할 있음을 의미한다.) fsync/fdatasync 데이터가 안정적인 미디어에 저장되도록 하는데 사용된다. 안정적인 미디어 쓰기는 동기화 작업중에 발생하며 EIO 오류를 보고하는 여러가지 이유로 (디스크 공간부족, SAN 연결 끊김 ) 실패할 있다.

·       fsync/fdatasync : http://man7.org/linux/man-pages/man2/fdatasync.2.html

 

 

 

위의 PostgreSQL링크에 설명된 문제는 동기화에서 오류를 반환하지만 캐시된 페이지의 상태를 지울수 있다 것이다. 다음 동기화는 캐시된 쓰기가 안정적인 미디어로 플러시 되지 않지만 응용 프로그램에 알려졌다는 것을 의미하는 ESUCCESS 반환한다.

 

데이터베이스 응용프로그램이 백업 파일을 열어 파일 시스템 캐싱 (~_O_DIRECT) 허용한다고 가장헌다. SQL Server 작업을 수행하지 않으며  실제로 Linux SQL Server에서 작업을 수행할 없도록 했다.

1.       버퍼링된 I/O 사용하여 백업이 시작된다.

2.       백업이 진행되면서 파일 시스템 캐시에 쓰기가 발생한다.

3.       파일 시스템 캐시 쓰기가 발생하는 동안 동기화에 대한 외부 호출이 발생한다.

4.       백업에 속한 버퍼에서 동기화쓰기 오류가 발생한다. 데이터베이스 응용프로그램 외부의 응용 프로그램에서 동기화를 호출하여 데이터베이스 응용프로그램이 실패를 인식하지 못한다.

5.       백업이 끝나면 데이터베이스 응용 프로그램에서 fdatasync 실행하고 EIO 반호나하는 대신 ESUCCESS 반환된다.

6.       fdatasync 성공적으로 완료되면 미디어 백업이 안정적으로 강화되고 데이터베이스 응용 프로그램이 트랜잭션 로그의 비활성 부분을 자른다.

7.       데이터베이스에 이상 트랜잭션 조작 또는 복구를 수행 적절한 로그 레코드가 없고, 일단 유효하다고 생각된 백업파일이 유효하지 않는다.

 

문제는 SQL Server 데이터베이스, 로그 백업파일에 영향을 미치지 않는다. SQL Server 파일 시스템 캐시를 무시하기 위해 O_DIRECT 사용하여 이러한 파일 형식을 연다. Linux SQL Server 강제 플러시 모드에서 실행 중인 경우에도 파일은 O_Direct 열리므로 문제가 발생하지 않는다.

 

 

[참고자료]

·       SQL Server Linux: fsync and Buffered I/O : https://blogs.msdn.microsoft.com/bobsql/2018/12/18/sql-server-linux-fsync-and-buffered-i-o/

 

 

2019-09-16 / Sungwook Kang / http://sungwookkang.com

 

 

SQL Server, SQL Linux, File System, Windows, Linux, fsync, fdatasync, O_Direct

SQL Server SQL Linux에서 인스턴스 파일 초기화 차이점

 

·       Version : SQL Server, SQL Server Linux

 

SQL Server 로그 파일 또는 데이터 파일이 증가하거나 새로 작성될때, 인스턴트 파일 초기화 작업을 진행한다. 이번 포스트에서는 인스턴스 파일이 초기화 될때, 기본 파일 시스템 구현과 Windows Linux 간의 동작 차이를 알아본다.

·       Database File Initialization : https://docs.microsoft.com/en-us/sql/relational-databases/databases/database-instant-file-initialization?view=sql-server-2017

 

SQL Server 데이터 로그 파일을 만들거나 확장(증가)할때 아래 API 호출 한다.

·       CreateFile : 파일 작성 또는 열기

·       SetEndOfFile : 파일 크기를 설정하고 I/O 장치에서 공간을 확보

·       SetFileValidData : 유효한 데이터 크기 설정

 

파일이 로그 파일(LDF) 경우 SQL Server 알려진 패턴값을 할당된 공간에 쓴다. 데이터 파일 (MDF, NDF) 경우 SQL Server 인스턴스 파일 초기화 추적 플래그 1805 설정을 확인하여 할당된 공간에 패턴값을 쓸지 여부를 결정한다.

TF 1805 : 데이터 파일에 대한 인스턴스 파일 초기화를 비활성화 한다.

참고 : 스탬핑은 일반적으로 최적의 성능과 Windows Linux 파일 시스템 페이지 블록크기 정렬과 정렬을 위해 4MB 청크로 수행

 

[Windows]

Windows 파일 시스템(NTFS, RTFS)에는 파일을 즉시 초기화 하기 위한 개의 멤버키가 있다.

·       EOF : 파일 위치

·       VDL : 유효한 데이터 길이 위치

 

Empty File

파일이 처음 작성될  EOF VDL 모두 파일의 시작을 가리킨다.

·       EOF = 0

·       VLD = 0


     

 

SetEndOfFile

SetEndOfFile 파일을 확장하여 I/O 장치에서 공간을 확보하고 EOF 값을 조정한다. VLD 값은 변경되지 않은 상태로 유지된다.

·       EOF = 10G

·       VLD = 0

   

SetFileValidData

SetFileValidData VDL 이동하는데 사용된다. VDL 기록된 것으로 간주되는 경우(쓰기가 수행되지 않은 경우에도) VDL 오프셋 이전의 모든 데이터와 VDL 이전의 공간 읽기는 I/O 장치에서 오래된 데이터를 반환할  있다. VDL 이후의 데이터는 유효하지 않은 것으로 간주되며 읽기 요청에 대해 0 리턴된다.

·       EOF = 10GB

·       VDL = 1GB

참고 : 보안 고려사항과 관련된 내용은 위의Database File Initialization 문서를 참고한다.

 

Write beyond the current VDL (WriteFile*)

VDL 오프셋 이상으로 쓰기가 발생하면 WindowsVDL 이동하여 쓰기를 수용하고 이전 VDL 쓰기 요청 시작 사이의 오프셋에 0 쓴다.

·       EOF = 10GB

·       이전 VDL =1 GB

·       VDL = 5GB

 

Instant File Initialization (New File)

VDL 증분 변경 대신 SQL Server SetEndOfFile 빠른 할당 기능을 사용하고  동일한 오프셋으로 SetFileValidData 호출한다. VDL이전의 모든 데이터는 Windows 파일 시스템에 의해 쓰여진(유효한) 것으로 간주된다. 인스턴트 파일 초기화가 활성화  경우 Windows 0 쓰지 않으며 SQL Server 데이터 파일의 패턴을 스탬프 처리 하지 않는다. 내부 SQL Server 데이터베이스 할당 구조는 SQL Server 데이터 파일 할당  유효한 데이터 읽기 활동을 추적한다.

 

Instant File Initialization (Grow)

인스턴스 파일 초기화를 사용하여 파일을 확장하면  오프셋으로 SetEndOfFile  SetFileValidData 수행된다. Windows   오프셋과 이전 오프셋 사이의 데이터를 유요한 것으로 취급한다.

 

 

[Linux]

Fallocate(http://man7.org/linux/man-pages/man2/fallocate.2.html) 시스템 호출(ABI) 사용한 Linux 지원 파일 할당 Windows API호출은 아래와 같이 Linux ABI 호출에 매핑 된다.

·       CreateFile : Linux 사용

·       SetEndOfFile : Linux fallocate 사용

·       SetFileValidData : Linux Noop

 

Windows Linux 파일 시스템의 주요 차이점은 유효한 데이터 길이( VDL) 아닌 범위를 추적한다. Linux에서 범위에는 I/O 장치에 쓰여 졌는지 여부를 나타내는 플래그가 포함된다.

Empty File

파일이 처음 작성될   EOF= 0이고 포함 범위는 기록되지 않도록 (N)으로 설정된다. 쓰지 않은 범위의 읽기는 Linux에서 항상 0 반환한다. LinuxI/O 장치를 사용하지 않지만 단순히 쓰지 않는 범위로 추적된 공간에 대해 리턴 버퍼를 0으로 채운다.

 

힌트 : 익스텐트 크기  조정에 대해서는 Linux 파일 시스템 설명서를 확인한다. 기본 크기는 일반적으로 최적의 성능을 위해 SQL Server 페이지는8K  64K 범위 경계에  맞는 메모리 페이지 크기 경계(주로4K) 정렬된다.

 

SetEndOfFile

파일 크기 증가는 대체 호출로 발생한다. Linux I/O 장치에서 공간을 확보하고  EOF 추적 범위 메타 데이터를 설정하여 기록되지 않음을 나타낸다. Fallocate SetEndOfFile Windows 파일 시스템의 공간을 확보하는 것처럼 공간을 확보하여 대용량 파일을 빠르게 생성할  있다. 차이점은 SetFileValidData이다. Linux 실제 쓰기 없이 범위 추적을 쓰기 설정하는 기능을 제공하지 않는다.

 

 

성능 고려 사항 : 대상 파일 시스템에 대해 fallocate 지원되지 않으면 SQL Server ftruncate 사용한다. 이름과 달리 ftruncate ABI 파일을 늘리는데 사용될  있지만  프로비저닝된 조장이다.(공간은 메타데이터만 업데이트 되지 않는다.) ftruncate 필요한 경우 실제 공간을 확보하고 제공하기 위해 SQLPAL 파일에 0 쓴다. SQLPAL 프로세스에 대한 오류가 없고 읽기 동작이 없다.

 

Write

 번째 쓰기가 수행되면 범위에 대한 메타 데이터도 업데이트 된다. 쓰기  쓰기 되지 않은 데이터를 추적하기 위해 익스텐트를 분할하거나Linux 커널에 의해 확장된 쓰기는 디스크의 공간에 0 쓰므로 전체 익스텐트가 쓰기 된것으로 표시될  있다.

 

참고 : 대부분의 Linux 파일 시스템에서는  번의 쓰기 요청이 발생하지만 쓰기 크기  오프셋 정렬에 따라  커질수 있다. (데이터 파일 요청1개와 메타데이터 변경 요청 1)

 

 

Windows 에서 SetFileValidData 단일  메타 데이터 작업이다. VDL 설정되면 쓰기(순차 또는 임의) VDL == EOF 추가 메타 데이터 업데이트가 필요하지 않다. Linux에서 쓰기에는 데이터 쓰기 메타 데이터 쓰기가 필요한 익스텐트 업데이트가 필요하다. Linux 또는 Windows에서 가능한 빨리 파일을 쓰고 확장할 있다. 그러나 Linux에서 처음 쓰기를 수행하면 메타 데이터가 유지관리 된다.

·       데이터베이스에서 쓰기 속도가 중요한 경우 익스텐트 파일 초기화를 사용하고 번째 쓰기에 추가 오버헤드가 발생하도록 한다.

 

참고 : 대부분의 쓰기 작업은Checkpoint 또는 Lazy Write 같은 백그라운드 프로세스로 수행되므로 SQL Server에서 오버헤드를 숨기는 경우가 많다. 활성 SQL Server 세션에서 쓰기가 발생할 있으므로 대량 로드는 예외이다.

 

·        쓰기 속도를 늘릴수 있는 경우 -T1805 사용하면 데이터베이스가 쓰기 확장 중에 데이터파일 공간을 스탬핑 되도록 있다. 스탬핑은 청크로 최적화되어 있으며 번째 쓰기 데이터 메타 데이터 작업이 발생하는 쓰기 경로가 된다. 위치가 기록(스탬프) 되면 이상 추가 메타 데이터 쓰기가 필요하지 않다.

 

참고 : 파일 시스템이 fallocate 지원하지 않으면 SQLPAL 의해 파일에 0 기록된다. 로그 파일(LDF) 알려진 패턴(0으로 작성) 표시하며 SQLPAL 공간을 0으로 채울때 메타데이터가 이미 업데이트 되었으므로 데이터 파일에 대한 인스턴스 파일 초기화를 안전하게 유지할 있다.

 

[참고자료]

https://blogs.msdn.microsoft.com/bobsql/2018/12/10/sql-server-instant-file-initialization-setfilevaliddata-windows-vs-fallocate-linux/

 

 

2019-09-13 / Sungwook Kang / http://sungwookkang.com

 

 

SQL Server, SQL Linux, File System, Windows, Linux, SetFileValidData (Windows) vs fallocate (Linux), T1805, SetEndOfFile, SetFileValidData, VDL

 

SQL Linux 업그레이드

 

·         Version : SQL Linux, Ubuntu

 

SQL Linux 최신버전으로 업그레이드 하는 방법에 대해서 살펴본다. 필자는 Ubuntu SQL Linux 설치된 상태이다. SQL Linux 업그레이드 진행 하기전 전체 사용자 데이터베이스 백업을 진행한다. 만약 업그레이드가 잘못되어 데이터베이스를 복원해야 경우를 대비해서 백업본을 보관하는 것이 좋다.

 

서버 로컬 접속 또는  Putty등을 사용하여 Ubuntu 서버에 연결한다.필자의 경우 Putty 사용하여 Ubuntu 서버에 접속 하였다.

 

Ubuntu에서 기존에 실행되고 있는 SQL Linux 버전을 확인한다. Sqlcmd 유틸리티를 사용하여 SQL Linux 연결하여 정보를 확인 있다. (Sqlcmd외에도 다양한 연결방법이 있으니 sqlcmd 사용할 필요는 없다.)

sqlcmd -S localhost -U sa

 

SELECT @@VERSION

GO

 

 

“apt-get” 명령을 사용하여 설치된 패키지 mssql-server 세부 사항을 확인할 수도 있다. apt-get 유틸리티는 Ubuntu APT(Advanced Packaging Tool)라이브러리를 사용하여 소프트웨어 패키지 설치, 기존 소프트웨어 패지키 제거, 기존 소프트웨어 패키지 업그레이드 등에 사용되는 무료 패키지 관리 명령어 프로그램이다. 아래 명령을 사용하여 mssql-server 버전, 체크섬 크기, 설치된 크기, 카테고리 간단한 설명과 함께 패치지 정보를 확인할 있다.

apt-cache show mssql-server

 

 

SQL Server 업그레이드 있는 사용가능한 업데이트 파일이 있는지 확인한다. 필요한 작업은 아니지만 업그레이드 프로세스를 이해하는데 도움이 된기 때문에 간단히 살펴본다. 명령은 설치된 모든 패키지에 대해 사용가능한 업데이트를 표시한다.

apt-get --just-print upgrade

 

 

현재 mssql-server 보류중인 업데이트가 있으므로 apt-get update 실행하여 /etc/apt/sources.list 파일에 지정된 소스에서 패키지 인덱스 파일을 동기화 한다. Update 명령은 패키지 인덱스 파일을 최신 버전으로 업데이트 한다. 아래 명령을 사용하여 패키지를 업데이트 한다.

sudo apt-get update

 

패키지 인데스 업데이트가 완료 되었으면 아래 명령을다시 실행하여 사용가능한 업데이트를 확인한다. 아래 스크린샷에서는 개의 패키지가 있음을 수있다. 하나는 이전 버전이고 다른 하나는 mssql-server 업그레이드하기 위해 적용해야하는 새로운 업데이트이다.

apt-cache show mssql-server

 

 

사용가능한 최신버전으로 업레이드하기 위해 아래 명령을 실행한다. 아래 명령은 최신 패키지를 다운로드 하고 /opt/mssql 있는 바이너리를 교체한다. 작업은 SQL 엔진을 교체하는 작업으로  사용자 데이터베이스에는 영향을 미치지 않지만 혹시 발생할 오류를 대비해서 처음 언급 한것처럼 백업을 것을 권장한다.

sudo apt-get install mssql-server

 

 

작업이 완료되면 SQL Server 빈드 버전이 14.0.3026.27에서 14.0.3029.16 업그레이드 것을 확인할 있다.

 

 

[참고자료]

https://www.mssqltips.com/sqlservertip/4647/upgrading-sql-server-running-on-ubuntu-to-latest-update/

 

 

2018-06-21 / Sungwook Kang / http://sqlmvp.kr

 

SQL Server, SQL Linux, SQL Upgrade, apt-get, apt-get update, apt-get install, 리눅스, linux,

MySQL/MariaDB Memory 모니터링

 

·      Version : MySQL 5.7.21, Ubuntu 16.0.4

 

Memory 사용률은 모든 운영체제에서 중요한 모니터링 지표이다. 다양한 어플리케이션이 서버에서 실행되면서 실제 물리메모리를 초과하는 메모리 요구가 발생할 있기 때문에 메모리 모니터링도 중요하다. 실제 데이터베이스의 경우 메모리가 부족하여 성능저하가 크게 발생하는 경우가 많다.

 

아래 명령어는 Unbuntu Linux에서 5 간격으로 메모리 사용량을 확인하는 명령이다.

watch -n 5 free –m

 


 

리눅스는 메모리의 효율적인 운영을 위해 전체 메모리에서 미리  Buffers + Cached 값을 자동으로 할당해 놓는다. 만일 어플리케이션에서 메모리가 필요할 경우 Cached 할당된 메모리를 자동으로 반환해 어플리케이션에 할당한다.

 

MySQL 서버는 다양한 종류의 메모리 버퍼(메모리 캐시) 사용한다. 사용영역에 따라 크게 전역과 지역으로 나눌 있다.

·       MySQL/MariaDB 아키텍처 메모리 할당 사용 구조 : http://sqlmvp.kr/220404814981

전역 메모리 (모든 커넥션 또는 스레드에서 공유)

지역메모리 (세션별로 할당, 공유하지 않음)

·       InnoDB Buffer pool

·       MyISAM key cache

·       Join buffer

·       Sort buffer

·       Read buffer

 

전체 메모리 사용량을 예상하여 할당하려면 아래와 같은 공식을 사용한다.

전역 메모리 사용량 + (지역적 메모리 사용량 X 최대 동시 커넥션 )

 

만약 물리 메모리 대비 InnoDB 버퍼풀 크기 비율을 과도하게 높게 하였을때 활성 커넥션(Active DB Connections) 증가로 세션 단위의 메모리 사용량이 증가한다면 MySQL 서버가 사용하는 전체 메모리는 물리메모리를 초과할 있으며 서버의 성능저하로 이어질 있다. 따라서 아래와 같은 가이드를 제공하여 성능 저하를 예방할 있다.

·       운영체제가 사용하는 적정 메모리 용량을 제외한 Buffer pool 할당

·       MySQL 서버에서 제공하는 Max Connection 제한

·       Max Connection 만큼 세션이 증가할 있으므로 세션별로 사용해야 하는 메모리 사용량 제한

·       물리 메모리를 초과하지 않는 범위에서 MySQL 서버가 전역적으로 사용해야하는 메모리 영역에 대한 최대 사용랑 제한

 

메모리 관련 설정을 메모리 사용량에 영향을 있는 변수는 약간의 유휴 메모리를 유지될 있게 설정하는 것을 권장한다.

·       MySQL/MariaDB Memory 관련 설정 변수 : http://sqlmvp.kr/220365937569

 

Swap 메모리가 빈번한 경우 서버에서 실행되는 어플리케이션이 메모리를 적절하게 사용하지 못하거나 물리 메모리가 부족하다는 것을 의미하기 때문에 Swap 지수가 0보다 경우 어느 어플리케이션이 메모리를 많이 사용하는지 확인이 필요하다.

 

 

[참고자료]

·       How MySQL Uses Memory : https://dev.mysql.com/doc/refman/5.7/en/memory-use.html

 

 

2018-03-27 / 강성욱 / http://sqlmvp.kr / http://sqlangeles.com

 

MySQL, MariaDB, linux, Memory 모니터링, watch, InnoDB Buffer pool, MySQL 메모리 사용량, 전역 메모리, 지역 메모리, 세션 메모리, Max connection



MySQL/MariaDB CPU 모니터링

 

·      Version : MySQL 5.7.21, Ubuntu 17.4

 

CPU 사용률은 모든 운영체제에서 가장 중요한 모니터링 지표이다. 이번 포스트는 기본적인 CPU 모니터링 방법에 대해서 살펴본다. 리눅스에서는 다양한 명령어를 사용하여 CPU 사용률을 확인할 있다.

·       Top 명령을 사용한 CPU  모니터링 : http://sqlmvp.kr/221024130336

 

기본적으로 CPU 사용량을 확인하기 위해서는 mpstat명령을 사용할 있다. 일반적으로 데이터베이스의 경우 시스템을 독립해서 사용하기 때문에 대부분의 CPU 사용량은 CPU System, CPU User, CPU IOwait 차지한다.

mpstat

 


 

[IOwait 높은 경우]

CPU 사용량이 높으면서 상대적으로 IOwait 사용량이 높다면 디스크의 I/O 오퍼레이션에 의한 병목을 의심해야 한다. 위에서 언급했듯이 일반적으로 데이터베이스 서버의 경우 독립적으로 운영하기 때문에 항목이 높다면 MySQL 서버가 실행되는 서버의 디스크 성능이 쿼리 트래픽을 처리하지 못해서  발생할 있다. 이때 초당 쿼리 유입량을 함께 확인하여 실제 요청이 많은지 확인할 필요가 있다. 또한 최적화 되지 않은 쿼리로 인하여 요청량은 적지만 디스크에 많은 부하를 일으키는 경우 IOwait 높게 나타날 있다. 경우는 적절한 인덱스를 사용하도록 가이드하거나 불필요한 정렬이나 그룹핑을 하지 않도록 하는것도 방법이다. 또한 빈번한 서브쿼리의 경우 결과를 임시테이블에(메모리보다 결과가 클겅우) 적재하여 처리하기 때문에 디스크 사용이 높을 있다.

 

[CPU User 높은 경우]

CPU IOwait CPU System상태가 낮은대 반해 CPU User 비율이 높은것은 MySQL 서버가 CPU 안정적으로 사용하고 있는 것으로 판단할 있다. 하지만 전체 CPU 높은 상태에서 CPU User 높은 경우 헤비한 쿼리(악성쿼리) 발생하지 않는지 확인해볼 필요가 있다. 또한 단순하게 CPU 사용량만으로는 판단할 없으면 요청되는 쿼리량을 확인하여 쿼리량이 많으면서 CPU 높으면 당연하지만 쿼리 요청량이 적은반면에 높다면 헤비 쿼리를 의심할 있다.

 

[CPU System 높은 경우]

CPU System  사용률이 높은 경우는 리눅스의 Kernel 프로세스의 CPU 사용량이 높은것으로 판단할 있다. 경우는 MySQL 서버가 커널이 실행해야하는 명령을 많이 수행한다는 뜻으로 커널의 의존성을 낮추기 위한 최적화 방안이 필요하다. 특히 서버가 데이터베이스 전용으로 사용하지 않고 다양한 어플리케이션이 함께 동작한다면 다른 요인으로 인해서 커널 사용량이 높을 수도 있다.

 

2018-03-26 / 강성욱 / http://sqlmvp.kr / http://sqlangeles.com

 

MySQL, MariaDB, linux, CPU 모니터링, mpstat, IOwait, CPU User, CPU Sytem, CPU 병목



+ Recent posts