프로세스와 커널
프로세스(Process)는 운영체제의 커널의 관리하에 현재 시스템에서 동작중인 프로그램, 실행 중인 프로그램의 인스턴스 인데 시스템 리소스(예: CPU, 메모리, 파일 등)를 할당받아 작업을 수행합니다.
커널은 프로세스를 관리하기 위해 각 프로세스에게 PCB를 할당하고, init프로세스는 부팅 시 가장 먼저 실행되어 시스템에 설정을 하는 초기화 프로세스 입니다.
프로세스 종류
프로세스에도 종류가 있는데 아래의 표와 같습니다.
프로세스명 | 설명 |
데몬 프로스세스 | 사용자에게 특정기능이나 서비스를 제공하는 프로그램입니다. |
부모 프로세스 | 부모 프로세스는 다른 프로세스를 생성하며 init을 제외한 모든 프로세스는 부모 프로세스를 가지고 있습니다. |
고아 프로세스 | 자식 프로세스보다 부모 프로세스가 먼저 종료가 되었을 때 자식프로세스는 고아 프로세스가 되어 init 프로세스가 관리하게 됩니다. |
좀비 프로세스 | 자식 프로세스의 종료 신호를 부모 프로세스가 처리하지 못할 경우 자식 프로세스는 좀비 프로세스가 됩니다. |
프로세스의 주요 구성 요소
- 프로그램 코드 (Code)
- 프로세스가 실행할 명령어 집합.
- 데이터 (Data)
- 전역 변수, 정적 변수 등.
- 힙 (Heap)
- 동적 메모리 할당 영역.
- 스택 (Stack)
- 함수 호출 시 사용되는 지역 변수 및 매개변수.
- 프로세스 제어 블록 (PCB)
- 프로세스의 상태, 프로그램 카운터, CPU 레지스터, 메모리 관리 정보 등을 포함한 데이터 구조.
프로세스와 커널 간의 상호작용
- 시스템 콜 (System Call)
- 사용자 모드에서 실행 중인 프로세스가 커널 모드로 전환하여 커널 기능을 요청하는 메커니즘.
- 예: 파일 열기, 메모리 할당, 프로세스 생성 등.
- 인터럽트 (Interrupt)
- 하드웨어 또는 소프트웨어 이벤트가 발생하면, CPU는 현재 작업을 중단하고 커널의 인터럽트 핸들러를 실행합니다.
- 컨텍스트 스위칭 (Context Switching)
- 커널은 하나의 프로세스 상태를 저장하고, 다른 프로세스 상태를 복원하여 CPU를 다른 프로세스로 전환합니다.
프로세스 확인하기
시스템에서 실행 중인 프로세스를 확인하기 위해 ps 명령어를 사용할 수 있습니다. ps 명령어는 현재 시스템에서 동작 중인 프로세스를 확인하는 데 사용됩니다.
ps 명령어의 사용법
ps 명령어는 다양한 옵션을 제공하여 프로세스 정보를 출력할 수 있는데 주요 옵션은 다음과 같습니다.
- -e: 모든 프로세스에 대한 리스트를 출력합니다.
- -f: 풀 포맷(full format)으로 출력합니다.
- -a: 다른 사용자들의 프로세스도 출력합니다.
- -u: 사용자 이름과 시간 등 상세한 정보를 출력합니다.
- -x: 현재 실행되고 있는 모든 프로세스를 출력합니다.
보통 -e와 -f 옵션을 함께 사용하여 모든 프로세스를 풀 포맷으로 출력합니다.
예제
ps -ef
이 명령어를 입력하면 아래 스크린샷처럼 시스템에서 실행 중인 모든 프로세스가 풀 포맷으로 출력됩니다.
ps -ef 명령어의 출력 필드 설명
ps -ef 명령어를 입력하면 아래와 같이 여러 필드가 포함된 출력이 나타나는데 각 필드의 의미는 다음과 같습니다.
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:37 ? 00:00:01 init
root 234 1 0 10:37 ? 00:00:00 kthreadd
root 240 2 0 10:37 ? 00:00:00 kworker/0:1H
user 1300 1200 1 10:42 pts/0 00:00:00 bash
user 1345 1300 0 10:43 pts/0 00:00:00 ps -ef
- UID: 프로세스를 실행시킨 소유자의 사용자 ID입니다.
- PID: 프로세스 ID로, 실행된 프로세스에 부여된 고유 번호입니다.
- PPID: 부모 프로세스 ID로, 해당 프로세스를 생성한 부모 프로세스의 PID를 나타냅니다.
- C: 짧은 기간 동안의 CPU 사용률을 나타내는 스케줄링 관련 필드입니다.
- STIME: 프로세스가 시작된 시간입니다.
- TTY: 프로세스가 연결된 터미널을 나타냅니다.
- TIME: 프로세스가 사용한 총 CPU 시간을 나타냅니다.
- CMD: 실행된 프로세스의 이름 또는 실행한 명령입니다.
프로세스 다루기
프로세스에 대해 알아보았다면, 이제 프로세스를 다루는 방법 중 하나인 kill 명령어에 대해 설명하겠습니다.
kill 명령어
kill 명령어는 프로세스에게 SIGNAL(신호)을 전달하는 명령어입니다. 이를 통해 프로세스를 제어하거나 종료할 수 있습니다.
신호의 종류 확인
kill -l 명령어를 사용하여 kill 명령어로 보낼 수 있는 신호의 종류를 확인할 수 있습니다.
kill -l
kill 명령어의 사용 방법
kill -[번호/SIGNAL] [PID/작업번호]
- 번호/SIGNAL: 보낼 신호의 번호 또는 이름
- PID/작업번호: 프로세스 ID 또는 작업 번호
자주 사용하는 신호
- 2번 SIGINT: 인터럽트 신호로, 주로 프로그램을 종료할 때 사용됩니다. (Ctrl+C)
- 9번 SIGKILL: 강제 종료 신호로, 즉시 프로세스를 종료합니다.
- 15번 SIGTERM: 종료 요청 신호로, 프로그램이 종료될 수 있도록 요청합니다.
- 18번 SIGCONT: 정지된 프로세스를 재개합니다.
- 19번 SIGSTOP: 프로세스를 일시 정지합니다.
예제
예를 들어, PID 100번의 프로세스를 종료하고 싶다면 다음과 같이 사용할 수 있습니다.
kill -9 100
또는
kill -SIGKILL 100
sleep 명령어
sleep 명령어는 입력한 시간 동안 대기 상태에 있는 프로세스를 생성하는 명령어입니다.
주로 스크립트에서 특정 시간 동안 대기하도록 할 때 사용됩니다.
sleep [시간]
[시간] 부분에 대기할 시간(초 단위). 예를 들어, 5초 동안 대기하려면 sleep 5를 사용합니다.
예제
sleep 5
위 명령어는 5초 동안 대기하는 프로세스를 생성합니다.
프로세스의 동작형태
이제 프로세스를 다룰 수 있다면 프로세스의 동작형태에 대해 알아보겠습니다.
포어그라운드 프로세스 (Foreground Process)
- 포어그라운드 프로세스는 CLI(Command Line Interface) 환경에서 대부분의 명령어가 실행되는 방식입니다.
- 이러한 프로세스는 사용자와 직접 상호작용하며, 명령어의 실행 과정이나 결과를 화면에 출력합니다.
- 예를 들어, 터미널에서 ls 명령어를 입력하면, 해당 명령어가 포어그라운드 프로세스로 실행되어 디렉토리 목록이 화면에 출력됩니다.
백그라운드 프로세스 (Background Process)
- 백그라운드 프로세스는 프로세스가 종료되지 않은 상태에서도 즉시 명령 대기 상태로 돌아갈 수 있게 합니다. 즉, 다른 명령어를 사용하면서 동시에 실행될 수 있습니다.
- 백그라운드로 실행하기 위해서는 명령어 마지막에 &(Ampersand)를 붙여 사용합니다.
- 백그라운드는 주로 장시간 실행되는 작업에 사용됩니다.
- cp -r /usr/gsk/sr1 & 명령어를 사용하면 [1] 5020이라는 출력이 나타납니다.
백그라운드 프로세스 관리
jobs 명령어
현재 백그라운드에서 실행 중인 프로세스를 확인할 수 있습니다.
jobs
fg 명령어
백그라운드 작업을 포어그라운드로 전환할 때 사용합니다.
fg %[작업번호]
bg 명령어
포어그라운드 작업을 백그라운드로 전환할 때 사용합니다.
bg %[작업번호]
시스템 프로세스 확인
시스템에서 실행되고 있는 프로세스는 /proc 디렉토리 아래에서 확인할 수 있습니다.
/proc 디렉토리는 실제 하드디스크에 존재하지 않으며, 메모리에 저장된 내용을 확인할 수 있는 가상 디렉토리입니다.
메모리 정보 확인
cat /proc/meminfo
CPU 정보 확인
cat /proc/cpuinfo
커널 버전 확인
cat /proc/version
사용 하는 방법(Go)
Go 프로그램을 리눅스 환경에서 실행하기 위해 먼저 컴파일 해야 합니다 예를 들어서 myprogram.go라는 파일이 있다 가정하여 다음 명령어를 사용합니다.
go build -o myprogram myprogram.go
이제 myprogram이라는 실행 파일이 생성되었습니다.
그 후엔 생성된 실행 파일에 실행 권한을 부여해야 합니다.
chmod +x myprogram
이제 백그라운드에서 프로그램을 실행해보겠습니다.
./myprogram &
이렇게 하면 백그라운드로 실행시킬 수 있지만 터미널을 종료할 때 프로그램도 함께 종료됩니다.
nohup
그래서 터미널을 종료해도 프로그램이 계속 실행되도록 하기 위해 nohup을 사용해야 합니다.
nohup ./myprogram &
이렇게 하면 프로그램이 종료되는 시그널을 무시하게 하여, 터미널을 닫아도 프로그램이 계속 실행되게 합니다.
쉘 스크립트를 사용하는 방법
#!/bin/bash
# Go 프로그램 컴파일
go build -o myprogram myprogram.go
# 실행 파일에 실행 권한 부여
chmod +x myprogram
# nohup을 사용하여 백그라운드에서 실행
nohup ./myprogram &
echo "프로그램이 백그라운드에서 실행 중입니다. 로그는 nohup.out 파일에서 확인할 수 있습니다."
쉘 스크립트란?
쉘 스크립트는 쉘(명령어 해석기)에서 실행할 수 있는 명령어들을 모아 놓은 파일입니다. 이를 통해 여러 명령어를 자동으로 순차적으로 실행할 수 있습니다.
그 외
systemd 서비스로 SleepService 만들기
systemd 를 이용해서 서비스로 만들기 위해서는 “/lib/systemd/system/sleepservice.service”
아래에
다음과 같은 것을 만든다.
[Unit]
Description=Sleep service
ConditionPathExists=/home/ubuntu/work/src/sleepservice/sleepservice
After=network.target
[Service]
Type=simple
User=sleepservice
Group=sleepservice
LimitNOFILE=1024
Restart=on-failure
RestartSec=10
startLimitIntervalSec=60
WorkingDirectory=/home/ubuntu/work/src/sleepservice
ExecStart=/home/ubuntu/work/src/sleepservice/sleepservice --name=foo
# make sure log directory exists and owned by syslog
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/sleepservice
ExecStartPre=/bin/chown syslog:adm /var/log/sleepservice
ExecStartPre=/bin/chmod 755 /var/log/sleepservice
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=sleepservice
[Install]
WantedBy=multi-user.target
위의 파일에서 사용된 패스들은 여러분의 경로에 맞게 수정 하면 될 것 이다.
물론 sleepservice 라는 서비스 이름 자체도 말이다.
해당 프로그램 전용 사용자를 만들고 , 깃헙에서 만들어 둔것이 있으면 제대로 된 위치로 옮기고, 755 권한을 준다.
$ cd /tmp
$ sudo useradd sleepservice -s /sbin/nologin -M
$ wget https://raw.githubusercontent.com/fabianlee/blogcode/master/golang/sleepservice/systemd/sleepservice.service
$ sudo mv sleepservice.service /lib/systemd/system/.
$ sudo chmod 755 /lib/systemd/system/sleepservice.service
systemctl 를 이용해서 sleepservice.service 를 enable 시키고 시작시키고, journalctl 을 통해 제대로 시작되는지 확인한다.
$ sudo systemctl enable sleepservice.service
$ sudo systemctl start sleepservice
$ sudo journalctl -f -u sleepservice
May 21 16:20:43 xenial1 sleepservice[4037]: 2017/05/21 16:20:43 hello foo
May 21 16:20:43 xenial1 sleepservice[4037]: 2017/05/21 16:20:43 About to sleep 1526ms before looping again
May 21 16:20:45 xenial1 sleepservice[4037]: 2017/05/21 16:20:45 hello foo
May 21 16:20:45 xenial1 sleepservice[4037]: 2017/05/21 16:20:45 About to sleep 196ms before looping again
그 밖에도 기존의 etc/init.d 를 이용해서 할 수도 있다.
1) /etc/init.d 아래 스크립트 작성 (Golang 프로그램을 시작시키거나 멈추는 run 스크립트를 부팅시 호출 해준다.)
#! /bin/sh
# /etc/init.d/myservice
USERNAME=who??
COMMAND_MYSERVICE_SCRIPT="/home/$USERNAME/myservice/run"
case "$1" in
start)
echo "Starting myservice .."
sudo -u $USERNAME $COMMAND_MYSERVICE_SCRIPTstart
echo "Done!!"
;;
stop)
echo "Stopping myservice .."
sudo -u $USERNAME $COMMAND_MYSERVICE_SCRIPTstop
echo "Done!!"
;;
*)
echo "Usage: /etc/init.d/myservice {start|stop}"
exit 1
;;
esac
exit 0
권한설정
- sudo chmod 755 myservice
- update-rc.d 로 설정 ( sudo update-rc.d myservice defaults)
'Linux' 카테고리의 다른 글
[바미] 리눅스 특수 문자에 대해 알아봅시다. (0) | 2021.07.01 |
---|---|
[바미] 리눅스 크론탭(Linux Crontab)에 대해 알아 봅시다. (0) | 2021.07.01 |
[바미] 특정 시간마다 내 서버의 상황을 log로 남겨보자! (0) | 2021.06.24 |
[바미] watch 명령을 이용하여 linux 시스템 모니터링하기. (0) | 2021.06.15 |
[바미] PS에 대해 알아보자! (0) | 2021.01.18 |