SAP Service Startup 과정에 이어서, SAP HANA DB Startup 과정에 대해서도 정리한다.
여기까지는 기존 SAP Service Startup 과정과 동일하다.
OS 부팅 후, init 프로세스에 따라 sapinit 서비스가 수행되면서, /usr/sap/sapservices 파일을 읽어와 환경변수 세팅과 함께, sapstartsrv 프로세스가 시작된다.
이후 HANA DB 서비스 시작 명령어(HDB start, sapcontrol) 수행에 따라서 sapstart 프로그램이 수행된다.
sapstart 프로그램은 실제 SAP HANA 시스템을 구동하기 위해, HDB Daemon 프로세스(hdbdaemon) 를 수행한다.
HDB Daemon 프로세스는 daemon.ini 파일을 읽어와 정의된 SAP HANA Service 들을 runlevel 단계에 맞게 수행한다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000000 i Basis TraceStream.cpp(00000) : ==== Starting hdb.sap<SID>_HDB<InstNum>, version 2.00.XXX.00.0000000000 (fa/hana2spXX), build <OS Platform> <Hash Value> 2000-01-01 00:00:00 ...
...
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000001 i Daemon MainImpl.cpp(00000) : * hdbdaemon configuration file "/usr/sap/<SID>/HDB<InstNum>/<Hostname>/daemon.ini"
...
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000002 i Daemon Daemon.cpp(00000) : Line up current runlevel 0 to 5; next event "check" due in 10000 ms
...
기본적으로 위 순서의 Runlevel 이 daemon.ini 에 설정되어 있으며, 구성이나 설정에 따라 조금 차이가 있을 수 있다.
아래 설명은 위 단계를 따라 설명한다.
Runlevel 의 첫 단계는 Nameserver 다.
Nameserver 는 SYSTEMDB 의 핵심 서비스이며, 항상 첫번째로 시작하게 된다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
### Runlevel 0 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000003 i Daemon Daemon.cpp(00000) : Runlevel 0 started
...
### nameserver 서비스 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000004 i Daemon Program.cpp(00000) : Update runlevel of program 'nameserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000005 i Daemon Program.cpp(00000) : Instance 0 of program 'nameserver' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000005 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000006 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbnameserver' with args ''
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000007 i Daemon DaemonChild.cpp(00000) : Child program 'hdbnameserver', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000008 i Daemon RunningInstance.cpp(00000) : Start 'hdbnameserver' as process 00000, process group 00000, instance 0 of <HDB Nameserver>
...
### nameserver 서비스 시작 중...
...
### 내부 소켓통신으로 nameserver 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000009 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000010 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbnameserver'. Received message "started"
### nameserver 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000011 i Daemon DaemonHandle.cpp(00000) : Program 'hdbnameserver', pid 00000 is started
### Runlevel 수정 (0->1)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000012 i Daemon DaemonHandle.cpp(00000) : Last instance in runlevel 1 started
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000013 i Daemon Program.cpp(00000) : Update runlevel of program 'nameserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000014 i Daemon Daemon.cpp(00000) : Line up current runlevel 1 to 5; next event "check" due in 1000 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000015 i Daemon Daemon.cpp(00000) : Runlevel 1 started
...
두번째 단계는 Compileserver 와 Preprocessor 서비스이다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
### compileserver 서비스 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000016 i Daemon Program.cpp(00000) : Update runlevel of program 'compileserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000017 i Daemon Program.cpp(00000) : Instance 0 of program 'compileserver' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000018 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000019 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbcompileserver' with args ''
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000020 i Daemon DaemonChild.cpp(00000) : Child program 'hdbcompileserver', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000021 i Daemon RunningInstance.cpp(00000) : Start 'hdbcompileserver' as process 00000, process group 00000, instance 0 of <HDB Compileserver>
...
### preprocessor 서비스 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000022 i Daemon Program.cpp(00000) : Update runlevel of program 'preprocessor', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000023 i Daemon Program.cpp(00000) : Instance 0 of program 'preprocessor' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000024 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000024 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbpreprocessor' with args ''
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000025 i Daemon DaemonChild.cpp(00000) : Child program 'hdbpreprocessor', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000026 i Daemon RunningInstance.cpp(00000) : Start 'hdbpreprocessor' as process 00000, process group 00000, instance 0 of <HDB Preprocessor>
...
### compileserver, preprocessor 서비스 시작 중...
...
### 내부 소켓통신으로 compileserver 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000027 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000028 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbcompileserver'. Received message "started"
### compileserver 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000029 i Daemon DaemonHandle.cpp(00000) : Program 'hdbcompileserver', pid 00000 is started
### 내부 소켓통신으로 preprocessor 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000030 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000031 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbpreprocessor'. Received message "started"
### preprocessor 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000032 i Daemon DaemonHandle.cpp(00000) : Program 'hdbpreprocessor', pid 00000 is started
...
### Runlevel 수정 (1->2)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000033 i Daemon DaemonHandle.cpp(00000) : Last instance in runlevel 2 started
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000034 i Daemon Program.cpp(00000) : Update runlevel of program 'nameserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000035 i Daemon Program.cpp(00000) : Update runlevel of program 'compileserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000036 i Daemon Program.cpp(00000) : Update runlevel of program 'preprocessor', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000037 i Daemon Daemon.cpp(00000) : Line up current runlevel 2 to 5; next event "check" due in 1000 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000038 i Daemon Daemon.cpp(00000) : Runlevel 2 started
...
세번째 단계는 Indexserver 와 Xsengine 서비스이다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
### indexserver 서비스 시작 (각 Tenant DB 별)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000039 i Daemon Program.cpp(00000) : Update runlevel of program 'indexserver.<TENANTDB>', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000040 i Daemon Program.cpp(00000) : Instance X of program 'indexserver.<TENANTDB>' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000041 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000042 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbindexserver' with args '-port <TENANTDB_internal_port>'
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000043 i Daemon DaemonChild.cpp(00000) : Child program 'hdbindexserver', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000044 i Daemon RunningInstance.cpp(00000) : Start 'hdbindexserver -port <TENANTDB_internal_port>' as process 00000, process group 00000, instance X of <HDB Indexserver-<TENANTDB>>
### xsengine 서비스 시작 (각 Tenant DB 별)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000045 i Daemon Program.cpp(00000) : Update runlevel of program 'xsengine.<TENANTDB>', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000046 i Daemon Program.cpp(00000) : Instance X of program 'xsengine.<TENANTDB>' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000047 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000048 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbxsengine' with args '-port <TENANTDB_xsengine_port>'
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000049 i Daemon DaemonChild.cpp(00000) : Child program 'hdbxsengine', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000050 i Daemon RunningInstance.cpp(00000) : Start 'hdbxsengine -port <TENANTDB_xsengine_port>' as process 00000, process group 00000, instance X of <HDB XSEngine-<TENANTDB>>
...
### indexserver, xsengine 서비스 시작 중...
...
### 내부 소켓통신으로 indexserver 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000051 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000052 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbindexserver'. Received message "started"
### indexserver 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000053 i Daemon DaemonHandle.cpp(00000) : Program 'hdbindexserver', pid 00000 is started
### 내부 소켓통신으로 xsengine 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000054 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000055 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbxsengine'. Received message "started"
### xsengine 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000056 i Daemon DaemonHandle.cpp(00000) : Program 'hdbxsengine', pid 00000 is started
...
### Runlevel 수정 (2->3)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000057 i Daemon DaemonHandle.cpp(00000) : Last instance in runlevel 3 started
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000058 i Daemon Program.cpp(00000) : Update runlevel of program 'nameserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000059 i Daemon Program.cpp(00000) : Update runlevel of program 'compileserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000060 i Daemon Program.cpp(00000) : Update runlevel of program 'preprocessor', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000061 i Daemon Program.cpp(00000) : Update runlevel of program 'indexserver.<TENANTDB>', instance X
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000062 i Daemon Program.cpp(00000) : Update runlevel of program 'xsengine.<TENANTDB>', instance X
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000063 i Daemon Daemon.cpp(00000) : Line up current runlevel 3 to 5; next event "check" due in 1000 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000064 i Daemon Daemon.cpp(00000) : Runlevel 3 started
...
네번째 단계는 webdispatcher 서비스이다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
### webdispathcer 서비스 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000065 i Daemon Program.cpp(00000) : Update runlevel of program 'webdispatcher', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000066 i Daemon Program.cpp(00000) : Instance 0 of program 'webdispatcher' will be started in 0 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000067 i Daemon Program.cpp(00000) : Starting instance right now
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000068 i Daemon DaemonChild.cpp(00000) : Starting program 'hdbwebdispatcher' with args ''
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000069 i Daemon DaemonChild.cpp(00000) : Child program 'hdbwebdispatcher', pid 00000 started in its own process group
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000070 i Daemon RunningInstance.cpp(00000) : Start 'hdbwebdispatcher' as process 00000, process group 00000, instance 0 of <HDB Web Dispatcher>
...
### webdispatcher 서비스 시작 중...
...
### 내부 소켓통신으로 webdispatcher 상태 체크 -> Return msg "started"
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000071 i Daemon NetworkListener.cpp(00000) : New connection accepted from 127.0.0.1/00000_tcp over socket 13
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000072 i Daemon NetworkConnection.cpp(00000) : Connection from 127.0.0.1/00000_tcp socket 13 pid 00000 'hdbwebdispatcher'. Received message "started"
### webdispatcher 서비스 시작완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000073 i Daemon DaemonHandle.cpp(00000) : Program 'hdbwebdispatcher', pid 00000 is started
### Runlevel 수정 (3->4)
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000074 i Daemon DaemonHandle.cpp(00000) : Last instance in runlevel 4 started
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000075 i Daemon Program.cpp(00000) : Update runlevel of program 'nameserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000076 i Daemon Program.cpp(00000) : Update runlevel of program 'compileserver', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000077 i Daemon Program.cpp(00000) : Update runlevel of program 'preprocessor', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000078 i Daemon Program.cpp(00000) : Update runlevel of program 'indexserver.<TENANTDB>', instance X
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000079 i Daemon Program.cpp(00000) : Update runlevel of program 'xsengine.<TENANTDB>', instance X
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000080 i Daemon Program.cpp(00000) : Update runlevel of program 'webdispatcher', instance 0
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000081 i Daemon Daemon.cpp(00000) : Line up current runlevel 4 to 5; next event "check" due in 1000 ms
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000082 i Daemon Daemon.cpp(00000) : Runlevel 4 started
...
다섯번째 단계는 지금까지 시작한 서비스들을 다시 한번 체크한다.
daemon_<hostname>.3<Instance number>00.XXX.trc
...
### Runlevel 5 시작
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000083 i Daemon Daemon.cpp(00000) : Runlevel 5 started
### 서비스 전체 체크
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000084 i Daemon Daemon.cpp(00000) : Target runlevel lined up
### Runlevel 5 완료
[00000]{-0}[-0/-0] 2000-01-01 00:00:00.000085 i Daemon Daemon.cpp(00000) : Runlevel 5 is completed
...
SAP HANA 에는 여러 서버 구성요소(Server Components) 가 있으며, 각 구성요소마다 제공하는 서비스가 다르다.
SYSTEM DB 에서만 실행되는 Nameserver 는 SAP HANA 시스템의 토폴로지(topology) 정보를 가지고 있으며, 하위 TENANT DB 를 관리하는 역할을 한다.
indexserver 는 각 TENANT DB 에서만 실행되며, 실제 데이터 저장과 데이터 처리를 위한 엔진이 포함되어있다.
compileserver 는 프로시저(procedures) 및 프로그램의 컴파일을 수행하며, SYSTEM DB 에서만 실행된다.
Preprocessor 는 인덱스서버에서 텍스트 데이터를 분석하고, 검색에 필요한 정보를 추출하는데 사용된다. 마찬가지로 SYSTEM DB 에서만 실행된다.
webdispathcer 는 XS Classic 서비스에 대한 HTTP, HTTPS Inbound 연결을 처리한다.
옵션 서버의 서비스는 HANA DB 구성 시, 필요에 따라 수동으로 추가를 해야 한다.
scriptserver 는 C++ 로 작성된 애플리캐션 함수 라이브러리를 실행하는데 사용된다.
docstore 서비스는 이름에 맞게 문서 저장소에 대한 레파지토리가 별도로 필요하며, 문서 저장소 내 JSON 문서에 대한 Native 작업, 다른 테이블과의 Join 작업을 지원한다.
SAP HANA 에서 애플리케이션 개발을 위한 runtime 환경을 제공한다.
기존 XS Classic 의 강점을 기반으로 더 진화된 서비스이다.
SAP HANA Extended Application Server 라 불리는 XS Classic server 는 SAP HANA 기반의 웹 어플리케이션을 위한 서비스이다.