하드 링크 (Hard Link) 와 심볼릭 링크 (Symbolic Link) 는 운영체제 파일시스템을 이해하는데 기초적인 개념이다.

아마 윈도우를 많이 사용한다면, 원본 - 바로 가기 개념이 떠오를 수 있지만 다소 차이가 있다.

 

  • Hard Link
    • 원본 파일과 동일한 inode 를 가지며 원본 파일이 삭제되더라도 링크 파일을 여전히 사용 가능하다
    • ln [Source] [Target] 명령어로 생성 가능
    • 위치 정보를 가지고 있는 이름을 여러 개 생성하는 개념이다. 그렇기 때문에 한 파일을 지워도 하드에서 해당 위치를 찾아갈 수 있다
  • Symbolic Link
    • 원본 파일의 이름을 가리키는 링크로 원본 파일이 삭제되면 사용 불가능하다
    • 전혀 다른 파일이라도 가리키는 원본 파일 이름이 같으면 계속 사용 가능하다
    • ln -s [Source] [Target] 명령어로 생성 가능. Source 를 가리키는 심볼릭 링크 Target 을 만든다
    • Source 파일을 수정하면 심볼릭 링크인 Target 파일도 수정된다
      • Target 파일을 수정해도 Source 파일이 같이 수정된다
    • 위치 정보를 갖고 있는 파일명을 또 다른 이름으로 가리키는 포인터의 개념이다
      • 하드링크는 한 위치 정보를 또 다른 이름으로 가리키는 개념

 

특히 리눅스 환경에서는 개발 환경 구성 시, 심볼릭 링크를 사용해서 파일 경로를 간편하게 관리하기도 한다

(루트 디렉토리 내에 심볼릭 링크를 구성해서 마운트한 파일 시스템을 연결시킨다던지)

 

잘 알아두면 유용하게 사용할 수 있다. :)

 



프로세스 제어블록(Process Control Block)의 약어로 프로세스를 관리하는데 사용하는 OS의 자료구조이다.

운영체제는 프로세스를 PCB 단위로 관리하며 프로세스 스케줄링을 위한 정보를 PCB 를 통해 관리한다.


프로세스가 생성될 때마다 고유의 PCB 가 생성되며, 프로세스가 완료되면 PCB 는 제거된다.

프로세스 간 Switching 이 발생할 때, 운영체제는 PCB 를 이용해서 상태를 전이시킨다. (State Transition)


프로세스는 CPU가 처리하던 작업 내용들을 PCB에 저장하고, 

다음에 다시 CPU 를 점유하여 작업할 때 PCB로부터 해당 정보들을 CPU 에 넘겨와서 하던 작업을 진행한다.


PCB는 다음과 같은 데이터 구성을 갖고 있다.


- Process Identification Data

- Process State Data

- Process Control Data


PCB 는 다음과 같은 정보들을 저장하고 있다.


(1) Process ID : 프로세스를 구분하는 ID


(2) Process State : 각 State 들의 상태를 저장한다.


(3) Program Counter : 다음 Instruction 의 주소를 저장하는 카운터. CPU는 이 값을 통해 Process 의 Instruction 을 수행한다.


(4) Register : Accumulator, CPU Register, General Register 등을 포함한다.


(5) CPU Scheduling Information : 우선 순위, 최종 실행시간, CPU 점유시간 등이 포함된다.


(6) Memory Information : 해당 프로세스 주소공간(lower bound ~ upper bound) 정보를 저장.


(7) Process Information(페이지 테이블, 스케줄링 큐 포인터, 소유자, 부모 등)


(8) Device I/O Status(프로세스에 할당된 입출력 장치 목록, 열린 팔린 목록 등)


(9) Pointer : 부모/자식 프로세스에 대한 포인터, 자원에 대한 포인터 등


(10) Open File List : 프로세스를 위해 열려있는 파일의 리스트






 가상메모리(Virtual Memory)는 컴퓨터가 사용하는 메모리 관리 테크닉이다.

실제메모리를 추상화하여 가상 메모리에 올림으로써 프로세스들이 연속된 물리적 메모리 공간처럼 여기게 만들 수 있을 뿐만 아니라 실제 메모리보다 많은 크기의 메모리도 운용이 가능하다.


가상메모리 기술이 동작하기 위해서는 2가지 이슈가 있다.

하나는 가상 메모리를 물리 메모리에 매핑시키는 Address Translation이고, 다른 하나는 이 가상 공간에 대한 관리 이슈이다.


이러한 Virtual Memory 와 Physical Memory 의 매핑을 위한 기술로 Paging 기법이 사용된다.


페이징 기법은 컴퓨터가 메인 메모리에서 사용하기 위해 데이터를 저장하고 검색하는 메모리 관리 기법이다.

페이징 기법을 통해 컴퓨터의 물리적 메모리는 연속적으로 할당되어 존재할 필요가 없으며, 반대로 연속적으로 존재하지 않는 물리적 메모리라도 페이징 기법을 통해 연속적으로 존재하는 것처럼 이용될 수 있다.


페이징 방식에서는 가상 메모리 상의 주소 공간을 일정한 크기로 분할한다. 

주소공간은 페이지 단위로 나뉘어져있으며 실제 기억공간은 페이지 크기와 같은 프레임으로 나누어 사용한다.


 - Frame : 물리 메모리를 일정된 한 크기로 나눈 블록

 - Page : 가상 메모리를 일정된 한 크기로 나눈 블록


이 때 Frame 과 Page 의 크기는 동일하게 관리된다.

페이지의 크기는 크기는 시스템에 따라 다르며 크기가 작으면 메모리를 단편화하기 쉬워지지만 페이지의 갯수가 많아지기 때문에 페이지 단위의 입출력이 자주 발생하게 된다.


페이지가 하나의 프레임을 할당받으면, 물리 메모리에 위치하게 된다.

프레임을 할당받지 못한 페이지들은 외부저장장치에 저장되며, 마찬가지로 프레임과 같은 크기 단위로 관리된다.


페이징 기법에서 페이지는 페이지테이블(Page Table) 이라는 자료구조 형태로 관리된다.

Page Table 은 프로세스의 페이지 정보를 저장하고 있으며, 하나의 프로세스는 하나의 페이지 테이블을 가진다.

Page table 은 Index 를 키로 해당 페이지에 할당된 메모리(Frame)의 시작 주소를 Value 로 저장하고 있다.


페이지 테이블 엔트리(Page Table Entry)는 페이지 테이블의 레코드를 말한다.

PTE 의 각 필드에는 다음 내용들이 기록된다.


 - 페이지 기본 주소(Page base address)


 - 플래그 비트(Flag bit)

  - Accessed bit : 페이지에 대한 접근이 있었는지를 나타낸다.

  - Dirty bit : 페이지의 내용에 변경이 있었는지를 나타낸다.

  - Present bit : 현재 페이지에 할당된 프레임이 있는지를 나타낸다.

  - Read/Write bit : 읽기/쓰기에 대한 권한을 표시한다.


페이지의 크기는 하드웨어에 의해 정의되며 대게 2의 제곱으로 증가한다.



페이징 기법에서 동적 주소 변환 과정은 다음과 같다.


(1) 수행 중인 프로세스가 가상주소를 참조한다.


(2) 페이징 기법을 통해 페이지 p가 페이지 프레임 f에 있음을 알아낸다.


(3) 실주소 r = f(페이지 프레임) + d(오프셋) 를 구해낸다.


위와 같은 방식으로 페이지 테이블은 Virtual Memory 에서 Physical Memory 를 참조가능하도록 지원한다.



페이지 테이블은 사용을 위해서 메모리에 존재해야 하지만, 그렇게 되면 메모리 접근에 있어서 중복 호출이 일어나므로(페이지 테이블에 한번, 페이지테이블을 통한 실제 메모리에 한번), 대게 MMU 의 지원을 받아 매핑시키게 된다. 



(참고 : https://www.geeksforgeeks.org/operating-system-paging/

https://gabrieletolomei.wordpress.com/miscellanea/operating-systems/virtual-memory-paging-and-swapping/)



좀비 프로세스(Zombie Process)와 고아 프로세스(Orphan Process) 는 흔히 볼 수 있는 프로그래밍 퀴즈 테마의 하나이다.


Unix / Linux 계열의 운영체제에서 프로세스 들을 관리하는 특징적인 방법으로 인해 나타나는 특이한 형태의 프로세스를 말한다.


부모 프로세스가 자식 프로세스보다 먼저 종료되면 자식 프로세스는 고아 프로세스가 되며, 자식 프로세스가 먼저 종료되었지만 부모 프로세스가 자식 프로세스의 종료 상태를 회수하지 못했을 경우에 자식 프로세스를 좀비 프로세스라고 한다.


리눅스의 코딩 시 fork()를 통해 자식 프로세스를 만들면 fork의 리턴값이 되는 pid로 부모와 자식을 구분할 수 있다. (pid>0 이면 부모, pid == 0 이면 자식) 

 

자식 프로세스가 작업을 종료하면 고아 프로세스의 경우 리눅스 시스템 상의 init 프로세스가 wait을 통해 자원을 회수하여 PID 가 1로 변한다. (대부분의 Linux 에서 init 프로세스의 PID 는 1이기 때문이다.)

반면 좀비 프로세스의 경우 부모 프로세스에서 wait 시스템콜을 사용해줘야 리소스 유출을 방지할 수 있다.



#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
// Create a child process
int pid = fork();

if (pid > 0)
printf("in parent process");
// Note that pid is 0 in child process
// and negative if fork() fails
else if (pid == 0)
{
sleep(30);
printf("in child process");
}
return 0;
}




참조 : https://www.geeksforgeeks.org/zombie-and-orphan-processes-in-c/

(너무 좋은 예제라 참조하였다.)





단일 프로세스 & 쓰레드를 갖는 프로그램을 개발할 경우에는 신경쓸 일이 거의 없지만 여러 작업루틴이 동시에 수행되며, 공유 리소스에 접근하게 되는 동시성 프로그래밍을 할 경우에는 반드시 신경써주어야 할 부분이 바로


Mutual Exclusion (상호배제) 문제이다. 이는 공유 불가능한 자원을 동시에 사용하게 될 경우 발생할 수 있는 충돌을 방지하기 위해서 Critical Section 을 만들고, 해당 영역에서 데이터를 사용하게끔 하는 방법을 사용한다.


(1) 세마포어(Semaphore)


이렇게 공유자원에 대한 동시성 문제가 발생하였을 때, 즉 여러 개의 프로세스 또는 쓰레드가 동시접근하는 문제를 방지하기 위해 고안된 것이 바로 세마포어이다. 


세마포어란 리소스의 상태를 나타내는 카운터를 지정하여 다중 프로세스에서 행동을 조정 및 동기화 시킬 수 있는 기술이다. 

여러 프로세스가 접근 시 여러 개의 Lock 을 할당하여 동시에 허용 가능한 Counter 의 제한을 둔다. 카운터가 1개로 0 / 1의 값을 가질 때 Binary Semaphore 라하고 이는 Mutex와 동작이 같다.


(2) 뮤텍스(Mutex)


뮤텍스는 Lock 을 가지고 있을 때에만 공유자원에 접근이 가능하게끔 하는 로직이다. 

즉, 세마포어가 여러 개의 락을 두어 제한된 리소스 접근을 허용하는데 반해 뮤텍스는 오로지 한 개의 쓰레드/프로세스만 할당한다.



* 세마포어(Semaphore) 와 뮤텍스(Mutex) 의 차이점


- 세마포어는 주로 시스템적 범위에 적용이 되며 뮤텍스는 프로세스 내에서 적용이 된다. 

(물론 세마포어와 뮤텍스는 매커니즘의 개념이기 때문에 국한된다고 할 수는 없다.) 주로 뮤텍스는 프로세스 내 쓰레드간 자원 접근에 대하여 적용이 되며 Lock 한 쓰레드가 Unlock 도 해주어야 한다. 

반면 세마포어는 Lock 을 건 소유주가 아니더라도 Unlock 이 가능하다.


- 세마포어는 동기화 대상이 하나 이상일 때, 뮤텍스는 하나일 때 사용된다.


동기화 처리 로직은 Lock 을 수반하며 이 Lock 이 여러 개의 작업 큐 내에서 걸릴 때 DeadLock 이 생길 우려가 있다.


데드락은 임계 영역 내의 전역 리소스에 대해 복수 개의 Lock에 의해 처리가 지연되는 현상이다. 

대표적으로 Critical Section 에 접근하여 공유 자원을 처리하는 여러개의 로직이 서로에 대한 의존도(Dependency)를 가질 때 발생한다.


다음과 같은 상황을 가정해보자.




위의 그림에서 프로세스1 은 Resource 1을 선점하고 있으며, Resource 2에 대한 작업처리를 요구한다.

Resource 2에 대한 처리를 완료하면 Resource 1을 사용할 수 있도록 Critical Section 바깥으로 반환할 것이다.

반대로 프로세스2 는 Resouce 2를 선점하고 있으며 Resource 1에 대한 작업 처리를 마친 후 Resource 2를 반환할 것이다.


위의 상황에서 두 프로세스는 서로 선점하는 Resource가 다르므로 동시에 Critical Section 진입이 가능하지만, 서로의 자원을 요구하는 탓에 탈출은 불가능하다. 이 상황을 Deadlock이라고 한다.


Deadlock 이 발생하면 자원의 누수 및 동작의 교착상태가 계속되기 때문에 어플리케이션 또는 시스템에 치명적이며 따라서 문제 해결을 위해 다음과 같이 관리 한다.


- 교착 상태의 예방

(1) Mutual Exclusion 조건 제거

(2) 사용할 때에만 해당 자원을 점유하고 사용하지 않을 때에는 해당 자원을 다른 프로세스가 사용할 수 있도록 양도

(3) 선점 가능한 프로토콜 제작

(4) 자원 접근에 대한 순차적 처리 


- 교착 상태의 회피

 : 자원 요청에 대해 Circular Wait를 방지하기 위한 할당 상태를 검사한다.


- 교착 상태의 무시

 : 확률이 낮은 경우 별도의 처리를 하지 않는다.





정리하기에 앞서 알아두어야할 점은 Synchronous, Asynchronous 와 Blocking, Non-Blocking 은 서로 비교 가능한 개념들이 아니다. 많이들 기술 먼저 습득하다보니(특히 NodeJS), 개념을 먼저 습득하기보다는, 특징을 먼저 배우는 터라 개념이 혼용되어서 쓰이는 경우가 많을 뿐이다.


동기(Sync) 와 비동기(Async)


<Synchronous I/O Model>


Sync와 Async 를 구분하는 기준은 작업 순서이다.

동기식 모델은 모든 작업들이 일련의 순서를 따르며 그 순서에 맞게 동작한다. 즉, A,B,C 순서대로 작업이 시작되었다면 A,B,C 순서로 작업이 끝나야 한다. 설령 여러 작업이 동시에 처리되고 있다고 해도, 작업이 처리되는 모델의 순서가 보장된다면 이는 동기식 처리 모델이라고 할 수 있다. 

많은 자료들이 동기식 처리 모델을 설명할 때, 작업이 실행되는 동안 다음 처리를 기다리는 것이(Wait) Sync 모델이라고 하지만, 이는 잘 알려진 오해이다. 이 Wait Process 때문에 Blocking 과 개념의 혼동이 생기는 경우가 흔하다. 동기 처리 모델에서 알아두어야할 점은 작업의 순서가 보장된다는 점 뿐이다.

동기식 처리 모델은 우리가 만드는 대부분의 프로세스의 로직이며, 특히 Pipeline 을 준수하는 Working Process 에서 매우 훌륭한 모델이다.


<Asynchronous I/O Model>


반면 비동기식 모델은 작업의 순서가 보장되지 않는다. 말그대로 비동기(Asynchronous) 처리 모델로, A,B,C 순서로 작업이 시작되어도 A,B,C 순서로 작업이 끝난다고 보장할 수 없다.

비동기식 처리 모델이 이득을 보는 경우는 각 작업이 분리될 수 있으며, Latency 가 큰 경우이다. 예를들어 각 클라이언트 또는 작업 별로 Latency 가 발생하는 네트워크 처리나 File I/O 등이 훌륭한 적용 예시이다.



블로킹(Blocking) 과 넌블로킹(Non-Blocking)


Blocking 과 Non-Blocking 을 구분하는 기준은 통지 이다.

Blocking 이란 말그대로 작업의 멈춤, 대기(Wait) 을 말한다. 즉, 작업을 시작하고 작업이 끝날때까지 대기하다가 즉석에서 완료 통지를 받는다.

이 때 작업이 멈추는 동안 다른작업이 끼어들수 있는지 없는지는 다른 얘기이다. 이부분이 중요하면서도 헷갈린데, 많은 Blocking 방식의 사례에서 다른 작업의 Interrupt 를 방지하기 때문에, Blocking 은 곧 "순차처리" 로 생각하는 오류가 생긴다. (이렇게 생각해버리면 Blocking 과 Synchronous 모델은 같은 개념이 된다.)

단순히 생각해서 Blocking 은 그저 작업을 수행하는 데 있어서 대기 시간을 갖는다는 의미일 뿐이다.


Non Blocking 이란 작업의 완료를 나중에 통지받는 개념이다. 작업의 시작 이후 완료시까지 대기하지 않고, 완료시킨다. 

즉, 내부 동작에 무관하게 작업에 대한 완료를 처리받는 걸 말한다.

(작업의 예약 부분이 오히려 비동기 설명과 오해를 불러오는 듯 하여 수정했습니다.)

효과적인 작업 상태의 처리를 위해 Non-blocking 에서는 성공, 실패, 일부 성공(partial success) 라는 3가지 패턴이 존재한다.

한 작업에 대해 대기 Queue 와 무관하게 다른 작업을 처리하는 효율적인 알고리즘 처리 시, 각 작업의 완료들의 순서가 보장되지 않는 경우가 많기 때문에 Async 와 헷갈릴 수 있지만, 이들은 앞서 언급했듯이 비교할 수 없는 다른 개념이다.



오해


많은 종류의 소프트웨어에서 동기 처리 방식이 Blocking 이고, 비동기 처리 방식이 Non-Blocking 인 이유는 익숙한 구조이기 때문이다.

일련의 작업들에 대해 순차적으로 하나씩 처리하고 완료하는 방식은 매 작업의 수행마다 Blocking 하는게 작업의 순서를 보장하기 쉬우며,

여러 작업들이 동시에 일어나는 구조에서는 한 작업을 수행하는 동시에 Non-Blocking으로 다른 작업을 받아와서 처리하는 구조가 효율적이다.

그렇기 때문에 같은 개념으로 혼동하기 쉽지만, 동기/비동기와 블로킹/논블로킹은 서로 양립할 수 있는 개념이란걸 기억하자.



정리한 개념을 통해 System I/O 의 모델들에 대해 이해해보자.


- Synchronous Blocking I/O : Application layer 의 계층이 Block을 일으키는 System Call을 호출하고, 이에 따라 User Layer와 Kernel Layer 간의 Context Switching 이 발생한다. 

이 때, Application 은 CPU 를 사용하지 않고 Kernel 의 응답을 기다리게 된다.


- Synchronous Non-blocking I/O : Nonblock Kernel Systemcall 을 사용하기 때문에 더 향상된 것처럼 보이지만, 

User Layer 가 Synchronous 이므로 응답을 기다리는 동안 Kernel 의 System Call을 Polling 하게 된다. 당연히 Context Switching 빈도수가 늘어나기 때문에 더 I/O에 지연이 발생하게 된다.


- Asynchronous Blocking I/O : User Layer의 I/O 가 Non-blocking 이고 Kernel 에서 알림이 블로킹 방식이다. Select System call 이 이 방식의 대표적이며 여러 I/O 를 한번에 수행할 수 있는 모델이다.


- Asynchronous Non-blocking I/O : Kernel I/O 의 개시와 알림 두 차례만 Context Switching 이 발생하고, Kernel 작업이 Non-block 이므로 select() 와 같은 멀티플렉싱 뿐 아니라 다른 프로세싱 자체가 가능하다. 

Kernel level 에서의 응답은 Signal 이나 Thread 기반 Callback 을 통해 user level 로 마치 이벤트처럼 전달된다.


OS 레벨에서 프로세스들의 동작 처리는 비동기 처리 모델 방식으로 진행된다. 각 프로세스 내에서 처리는 작업의 순서가 보장되는 동기 처리 방식이지만, 커널 레벨의 관점에서는 커널의 리소스를 사용하는 모든 작업들의

순서를 지켜줄 수 없으며, 커널 동작의 관점에서 보면 비동기 처리 모델을 사용한다. 

즉, 시스템 프로그래밍 윗 레벨에서의 대부분의 작업 모델은 동기 처리이지만, 커널 레벨에서 프로세스의 운용은 비동기 처리로 볼 수 있다.

물론 각 프로그램들이 동기 / 비동기 중 어떤 방식으로 내부 로직을 처리하는 가는 별도의 문제이다.



추가로 NodeJS 포스팅에서 언급할 예정이지만, NodeJS 는 Async I/O 처리를 위해 libuv 를 사용하는데, 이 엔진은 default thread를 4개 사용하여 Async I/O 를 구현한다. 결국 Async 라 해도 마법은 아니며, 구현의 레벨로 보자면 Scheduling 과 Loop 의 문제이다.


참조 : https://docs.microsoft.com/en-us/windows/desktop/FileIO/synchronous-and-asynchronous-i-o





서버 인스턴스를 관리하면서 자주 사용하게 되는 몇가지 시스템 모니터링을 위한 유틸리티 들을 정리해보았다



- Top : 시스템의 전반적인 운용상황을 확인할 수 있다. CPU / 메모리 / 부하율 등을 한번에 확인할 수 있다. Top –d 2 와 같이 하면 초단위로 refresh 한다. –q로 하면 실시간으로 반영된다. 윈도우의 작업 관리자와 같은 역할을 수행한다.


- Uptime : 서버의 전체적인 부하율을 확인하고자 할 때 사용한다

그냥 uptime 만 치면 한줄로 출력이 되며 현재시간, 부팅 후 꺼지지않고 운용된 시간, 현재 시스템에 로그인한 사용자 수(/var/run/utmp참조), 1분, 5분, 15분 간 서버 시스템 부하율 을 표기한다.


- Vmstat : 현재 리눅스 자원사용률 모니터링 도구로, 이름은 Virtual Memory Statistics 이지만 가상 메모리 이외에 실행 대기 중인 프로세스 수(r), 가상 메모리 사용량(swpd), 입출력 IO, 유휴 메모리(free), 버퍼 메모리(buff), 캐시 메모리(cache), 초당 인터럽트 수(in), 초당 컨텍스트 스위칭 수(cs), 유휴시간(id), 커널모드 소비 시간(sy), 입출력대기시간(wa) 등 다양한 내용 조회 가능하다.


- Iostat : 부팅 이후 Block IO 상태를 나타낸다.


- Free : 메인 메모리 사용량을 보여준다.


- Strace : System call tracer. 리눅스 최강의 디버깅 도구. 리눅스 시스템콜 추적 도구. 프로세스 대상을 선택하면 대상에 대한 시스템콜을 추적할 수 있고 프로세스가 받는 Signal에 대한 정보도 얻을 수 있다. 

간단하게 strace ./helloWorld 와 같이 사용하면 helloWorld 프로그램을 추적하게 되고 –o trace.log 와 같이 매개변수를 넘겨주면 trace.log 파일에 추적 로그가 남게 된다. 또한 –c 옵션을 이용해 통계도 낼 수 있다. –p 옵션을 사용하면 실행중인 프로세스에 대한 추적 또한 가능하다. 


- Tcpdump : 커맨드라인 네트워크 트래픽 모니터링 툴이자 패킷 분석 툴. 

Tcpdump –I eth0 과 같이 사용하면 지정된 eth0이더넷에 대해 패킷을 뜨게 되고 –w test.log 와 같이 test.log 에 로그를 기록할 수 있다. 확인은 –r test.log 와 같은 방식으로 해야 한다. 혹은 당연히 tcpdump –I eth0 > testout.log 와 같이 리다이렉트해줘도 된다.


- Netstat : 시스템의 네트워크 연결 목록(tcp, u에, 소켓)을 보여준다. 

Tcp (t), udp(u), DNS 질의끄기(n), Listen(l), 프로세스 명 표시(p), 라우팅정보(r) 과 같은 파라미터를 –뒤에 붙여 사용한다. 

(ex) netstat -nltp


- lsb_release -a : 리눅스의 버전을 확인하는 명령어. 특히 Dependency 관리를 위해 알아볼 때 종종 사용한다.

cat /etc/issue : 리눅스의 버전을 확인하는 명령어. 몇몇 버전의 경우 /etc/issue 에 버전 정보가 포함되어 있다.

- stat : 파일 또는 파일 시스템 상태를 조회한다. 파일크기, Inode 번호, 링크 갯수, Permission, UID, GID, 접근/수정/변경 일시 확인 가능하다.

(예시)

> stat xxx.log
File: ‘xxx.log’
Size: 11008296 Blocks: 21512 IO Block: 4096 regular file
Device: -----/----- Inode: 269769074 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 500/ user) Gid: ( 500/ user)
Access: 2018-10-04 00:00:03.158986433 +0900
Modify: 2018-10-04 15:02:18.999757886 +0900
Change: 2018-10-04 15:02:18.999757886 +0900
Birth: -

> stat -f xxx.log

File: ‘xxx.log’
ID: -----------        Namelen: 255 Type: xfs
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 25677313 Free: 23658809 Available: 23658809
Inodes: Total: 102759424 Free: 102490423


- du(disk usage) : directory 용량 확인. 현재 폴더 내 파일들의 용량을 확인할 수 있다.

- df : 리눅스 파일시스템 사용량 확인. 디스크 사용량 / 용량 포함.


- find : 파일 이름으로 시스템을 검색하는 명령어

 (1) find -name "파일이름"     > 파일이름에 해당하는 파일 검색

 (2) find -name "*.txt"     > 파일 확장자가 txt인 모든 파일 검색

 (3) find / -name "*.txt"     > 루트에서부터 txt 확장자를 가진 모든 파일 탐색

 (4) find / -name "code" -type d  > 디렉터리 이름이 code 인 모든 디렉토리 검색






 

도커(Docker)란 리눅스(Linux) 기반의 컨테이너 런타임 오픈소스로 가상화 기술을 이용한 경량화된 컨테이너를 통해 환경을 격리시켜주고 관리해주는 솔루션이다.




 VM처럼 Docker Engine이 Host 위에서 Container들을 가상화 시켜 관리해주며 이런 환경을 Image 화 함으로써 격리된 환경에서의 모든 어플리케이션들과 리소스들, 그 Dependencies를 전부 포함한 격리된 환경을 구성하고 구조할 수 있다.

(여기서 Host 라 함은 대부분의 OS를 말하고, 그 위에 새로운 환경을 만들어낸다고 생각하면 처음에 이해하기 쉽다. 쉽게 이해해서 OS 안에서 새로운 OS를 구축하는데 그 방법이 VM 보다 훨씬 더 가볍게 이루어진다는 뜻이다.)


여기서 운영체제의 가상화에 대해 간단히 언급하자면 기존의 하드웨어 Machine 에 OS를 탑제하는 것을 가장 간단한 형태의 가상화(Virtualization) 이라고 한다. 


조금 더 경량화된 방식이자, OS 위에서 가상 머신을 돌리기 위한 방법이 반가상화(Paravirtualization) 라 하여, Host OS 위에 Guest OS 형태로 OS 를 별도의 소프트웨어 처럼 동작시키는 방안이 있다. 대부분의 VM Software 들... Virtual Machine 이나 VM Ware 는 반가상화 방식이다.


Docker 는 반가상화 방식보다 경량화된 Container 를 이용하며, 이는 Guest OS 조차 필요없는 운영체제 레벨의 가상화를 구현한다. 그대신 OS 레벨에서의 지원이 필요하기 때문에 아직은 Linux 만 제공되고 있다.



 도커는 Linux 커널이 제공하는 컨테이너 기술(LXC)을 이용하며, 격리된 Container 에서 독립적 작업을 할 수 있게 추상화해준는데, 이 Container 들을 관리해주는 것이 바로 Docker Engine 이다.

(Docker 의 자세한 기술 스택은 추가로 포스팅 하겠다.)


 이렇게 이미지화 한 Container Image들은 Git의 VCS(Version Control System) 처럼 관리 및 배포할 수 있다.(Docker Hub) 이렇듯 설치 및 이용이 빠르고 협업에 있어 손쉬운 패키징이 가능한 장점이 있다. 

이러한 장점들 때문에 Cloud 환경에서 여러대의 서버를 대상으로 환경을 구축하는 것이 매우 편리하며, 각 Instance 에 대한 환경의 일관성이 보장되기 때문에 서버 인스턴스들에 대한 효율적인 모니터링이 가능하다.


 컨테이너들의 효율적인 배포 및 관리와 모니터링 등을 할 수 있게 해주는 것을 Container Orchestration 이라 하며, 이들은 컨테이너의 배치 및 복제, 컨테이너 그룹에 대한 로드밸런싱,  장애 복구(Fail Over), Scaling, Access Control 등의 기능을 갖는다. 다음과 같은 툴들이 대표적이다.





- Kubernetes : 구글에서 만들었으며 최근 각광 받고 있는 Orchestration Tool 이다. VM 환경, Public Cloud 등 다양한 환경에서 작동이 가능하며 손쉽게 접할 수 있도록 지원한다.


- Docker Swarm : 여러개의 Docker 호스트를 클러스터링 하여 단일 Docker Host 를 운영하는 방식이며, 설정 및 운용이 간편하다. 하지만 Kubernetes 만큼 다양한 기능을 제공하진 않는 것으로 보인다.


- Apache Mesos : 확장성이 뛰어나며 다른 아파치 재단의 Hadoop, Hypertable, Spark 와 같은 시스템과 연동하여 쓰기 좋게 되어있다. 



요즘 정말 많이 볼 수 있고, 많은 IT 트렌드 기술들이 Docker 를 응용하여 나은 성능과 효율성을 가져가고 있다. 이미 자리잡은 핵심 기술인 만큼 심도 있게 공부해둘 필요가 있다.




 실무를 하다보면 프로젝트에 따라 배치 스크립트를 작성할 일이 종종 있다.

그럴 때 듣게 되는 Daemon Process 라는 단어가 있는데, Background Process와 유사하면서도 의미가 조금 달라 헷갈리기 쉽다.


 Daemon Process 와 Background Process 모두 사용자와 상호작용하는 Foreground가 아닌 Background에서 동작하지만 둘 사이에는 차이가 있다. 


 일반적인 데몬은 터미널을 갖지 않는다. (유저와 상호작용하지 않는다.) 정확히는 데몬은 그 자체로 Process Group Leader로 부모가 1번 pid를 갖는 init으로 세팅된다. 즉, 독자적인 Session 을 갖고있으며 Linux System 자체가 아닌 별도의 독립된 Parent process를 갖지 않는다. 리눅스의 cron, smartd 와 같은 스케줄링 & 모니터링 프로세스들은 바로 이 Daemon Process 의 형태를 갖는다.


 백그라운드 프로세스는 이와 다르게 터미널을 통해 상호작용이 가능하다. 별도의 Parent process를 가질 수 있으며 Parent process와 세션이 공유되기 때문에 Parent process가 받는 Signal 의 영향을 받는다. (부모 프로세스가 종료되면 같이 종료된다.)



 Daemon Process의 조건 3가지는 다음과 같다.

(1) Fork로 자식 프로세스 생성 후 부모 프로세스를 종료 – 자식 프로세스의 ppid(소유 프로세스)를 pid 가 1인 init으로 양도


(2) Setsid를 이용하여 새로운 세션을 만들고 생성된 자식의 pid가 세션의 제어권을 가지도록 한다. – 세션이란 프로그램 그룹의 모음인데 세션 생성시 ttv를 부여하지 않게 되면 터미널을 갖지 않는 세션이 생겨나며 세션의 리더가 된다.


(3) 프로세스의 위치를 루트로 옮겨주면 경로 작업 수행에 유리하다(선택)


 * 또한 윈도우에서는 데몬을 서비스라고 부른다.



+ Recent posts