Linux

init system (systemd)

Superkill 2016. 12. 27. 05:04
반응형

모든 Unix 시스템에는 pid가 1인 특별한 프로세스가  있다.

이 프로세스는 다른 프로세스들이 시작되기 이전에 커널에 의해 실행되며 

다른 모든 프로세스들의 부모 프로세스이며 누구의 자식 프로세스도 아니다.


다른 프로세스들이 할 수  없는 많은 일을 수행함과 동시에 그에 따른 의무도 있다.

(예를 들면 부팅하는 동안 userspace를 가져오고 유지하는 일 등)


예전부터 sysvinit이라는 패키지를 통해 init이라는 process가 리눅스의 1번 pid로 시스템의 booting과 shutdown를 컨트롤 하는 역할을 해왔다. 물론 그 동안 다른 대안 init system들이 여럿 제안되었다. (systemd, Upstart 등)


일단 init system의 가장 중요한 역할은 userspace를 띄우는 것이다.

그리고 좋은 init system이란 그 작업을 빠르게 하는 것이라고 할 수 있는데

전통적인 SysV의 init system은 특별히 빠르진 않았다.


빠르고 효율적인 init system은 두가지 요소를 통해 실현할 수 있다.

1) 최대한 적게 실행한다


2) 최대한 많은 것을 병렬적으로 실행한다


최대한 적게 실행한다는 것은 적은 수의 서비스를 실행하거나 당장 필요하지 않은 서비스의 실행을 나중으로 미루는 것이다. (예를 들어 네트워크에서 장치를 탐지해서 사용가능하게 해 주는 Avahi라는 시스템은 네트워크에 장치가 아무것도 연결되어있지 않고 어떤 application도 Avahi api를 필요로 하지 않는다면 당장 실행할 필요가 없을 것이다) sysvinit 같은 경우 여러 shell script들로 디자인 되었다. 하지만 많은 shell script들은 많은 process들의 생성, library탐색 등을 야기하는데 이는 결국 속도가 느려지게 만든다. 여담으로 부팅 후 로그인을 하고 터미널을 연 echo $$를 입력하면 PID가 나오는데 그 수가 작을 수록 init하는데 필요한 프로세스의 수가 적다는 의미로 그 수가 적을 수록 init system이 빠르다는 것을 의미한다.


최대한 많은 것을 병렬적으로 실행한다는 것은 sysvinit처럼 직렬로 실행하는 것이 아닌 많은 것을 동시에 실행한다는 것이다. 따라서 CPU와 IO 대역폭을 최대한으로 사용하고 전체적인 실행시간을 줄일 수 있게 된다.


하지만 대부분의 시스템은 병렬로 처리하려 해도 또 다른 연관된 시스템들 때문에 순서의 동기화가 필요해지고 결과적으로 직렬처리가 되어버린다. 예를들면 Avahi라는 시스템은 D-Bus라는 시스템이 먼저 실행되어서 준비가 되었다는 신호를 받아야 실행될 수 있다. 이런 식으로 시스템 간에 순서대로 실행되어야 해서 동시에 실행시키지 못하는 경우가 많다.


그래서 이런 동기화와 직렬성을 제거하기 위해 각 서비스(프로세스)들의 실행이 지연되는지 다른 프로세스로부터 무엇을 필요로 하는지 파악해야한다.


-Socket Service

Socket Service의 경우 어떤 daemon이 다른 daemon으로 부터 socket을 기다리느라 실행을 못하고 있다면 (Unix 계열 시스템 에서는) daemon들을 시작하기 전에 각 daemon들에 필요한 socket들을 모두 만들어 놓고 exec()가 진행되는 동안 socket을 넘겨주면 된다.

물론 여전히 서비스들은 다른 서비스와 연결이 되지않아 100% 실행완료는 되지 않을 것이다. 하지만 연결 request들이 각 서비스들의 소켓 버퍼에 큐로 저장되기 때문에 버퍼가 가득 차지만 않는다면 연결 수립 request를 보내기 위해 서비스가 중단(block)될 필요가 없고 계속 작업을 진행 할 수 있다. request를 받는 서비스가 준비완료 상태가 되면 큐에 있는 request들이 하나씩 처리 되어진다.


이런식으로 의존성 관리가 해결되거나 적어도 개선되어짐을 확인할 수 있다.



- Keep Track of Process (cqroups)

서비스를 시작하고 유지하는 시스템의 핵심은 process 돌보기다.

서비스를 감시하고 서비스가 죽을 경우 재시작을 해주며 서비스를 완정히 종료시키는 능력도 있어야 한다. 충돌했을 때는 관련 정보를 수집한 후 저장하고 있어야한다. 또한 crash dump 시스템과 로깅 시스템에 그 정보를 연동해야한다.


전통적으로 유닉스 시스템에서 double forking을 통해 실행되는 프로세스는 부모 프로세스의 감시를 벗어날 수 있다. 예를 들면 double-fork를 통해 시작된 CGI script[각주:1]가 잘못 동작하고 있는데 Apache[각주:2]를 꺼도 종료되지 않는다면 그 CGI script의 존재를 알고있지 않은 이상 Apache와의 관계를 알 수 없을 것이다.


그래서 여러번 fork를 통해 실행된 프로세스들을 관리하기 위해 ptrace나 netlink connector 같은 해결책들이 나왔지만 확장성이 떨어지고 불완전한 것으로 말이 많았다.


그래서 나온 것이 cgroups.

Control Groups(aka 'cgroups')은 기본적으로 process들의 그룹 계층을 만들도록 한다.

계층은 가상 파일시스템에 직접적으로 노출되고 쉽게 접근이 가능하다.

group name은 기본적으로 가상 파일시스템의 디렉토리 이름이다.

특정 cgroup의 process가 fork를 통해 만든 자식 process는 같은 그룹의 멤버가 된다.

자식 프로세스에게 특권이 주어지거나 cgroup file system에 접근권한이 있는 것이 아니라면 절대 group을 벗어날 수 없다.

원래 cgroup은 container를 위한 목적으로 kernel에 도입되었다. 이것을 이용해 몇몇 특정 kernel subsystem(자원 컨트롤러)들이 특정 group들에 할당되는 자원을 제한시키도록 할 수 있다.

기존에는 하나의 프로세스에 대해 자원을 제한 하는 반면 cgroup은 그룹 내의 여러 프로세스 전체에 대해 제한을 적용할 수 있다. 결과적으로 daemon(process)들을 트래킹하기 편하다.

cgroup내의 process는 /proc/$PID/cgroup에서 찾을 수 있다.


(후략)

http://0pointer.de/blog/projects/systemd.html




-systemd는 pid 1로 돌아가며 대부분의 시스템을 동작을 시작해주는 시스템이자 서비스 관리자이다. cgroup을 이용해 process들을 관리해주고 마운트와 자동마운트 포인트를 유지, 정교한 transactional dependency-based service control logic을 진행한다.

SysV와 LSB init script를 지원하며 sysvinit을 대체한다.

deamon 로깅, 기본 시스템 환경설정 등을 조정하는 유틸리티를 포함한다.


systemd 공식 홈페이지 : https://www.freedesktop.org/wiki/Software/systemd/

  1. 웹 서버와 외부 프로그램(database) 사이에서 정보를 주고받는데 사용됨. ex) php [본문으로]
  2. 웹 서버 [본문으로]

'Linux' 카테고리의 다른 글

CMake 시작하기  (0) 2019.06.16
명령어 옵션 - 더블대쉬(--)  (0) 2018.07.04
Alpine Linux 설치  (0) 2018.04.15
package 'openjdk-7-jdk' has no installation candidate  (0) 2017.08.19
자식 프로세스 / 부모 프로세스  (0) 2017.01.04