Linux 環境における Oracle Database サービス化の検証

こんにちは、YDCのしんじです。
今回のトピックは、Linux 環境における Oracle Database の自動起動/停止についてです。

init から systemd に

Oracle Database 12c を導入するにあたり、Red Hat Enterprise Linux 7 や Oracle Linux 7 に構築する機会が増えているのではないでしょうか。

Red Hat Enterprise Linux 7 や Oracle Linux 7 では、init の代替として systemd が採用されています。
プロセスID 1番は、init から systemd に変わりました。

Oracle Database の自動起動/停止といえば、/etc/init.d/dbora スクリプトでしたが、systemd の採用に伴い、これまで慣れ親しんだ方法は過去のものとなってしまいました。

/etc/init.d/dbora スクリプトのサンプル

#!/bin/bash
#
# chkconfig: 35 99 10

ORA_HOME=/u01/app/oracle/product/12.2.0/dbhome_1
ORA_OWNER=oracle

case "$1" in
'start')
su - $ORA_OWNER -c "$ORA_HOME/bin/dbstart $ORA_HOME"
touch /var/lock/subsys/dbora
;;

'stop')
su - $ORA_OWNER -c "$ORA_HOME/bin/dbshut $ORA_HOME"
rm -f /var/lock/subsys/dbora
;;
esac

ここからは、systemd のユニットファイルを用いた自動起動/停止の設定を検証していきたいと思います。

環境
OS Oracle Database ORACLE_HOME ORACLE_SID
Red Hat Enterprise Linux 7.3 Oracle Database 12c Release 2 /u01/app/oracle/product/12.2.0/dbhome_1 orcl

systemd ユニットファイルを作ってみよう

ユニットファイルのパス

ユニットファイルは、/usr/lib/systemd/system/ ではなく /etc/systemd/system/ に作成します。
Local configuration 向けのユニットファイルの場所となります。

ユニットタイプですが、Oracle Database の場合はもちろん"サービス"です。
ユニットファイルの拡張子は、.service となります。
詳しくは、systemd.unit(5) の man ページを参照してください。

ユニットファイルのパスは、/etc/systemd/system/dbora.service としました。
なお、ユニットファイルに実行権限は必要ありません

$ ls -l /etc/systemd/system/dbora.service
-rw-r--r--. 1 root root 350 6月 12 09:20 /etc/systemd/system/dbora.service

ユニットファイルのオプション

サービスユニットファイルは 3 つのセクションで構成されます。
Oracle Database 自動起動/停止のために必要そうな各セクションのオプションを紹介します。
詳しくは、systemd.service(5) および systemd.exec(5) の man ページを参照してください。

[Unit] セクション
オプション 内容
Description ユニットの説明文です。
Before, After ユニット開始順序の定義です。
[Service] セクション
オプション 内容
Type ユニットプロセスの起動タイプです。
ExecStart ユニットを起動するコマンドです。
ExecStop ユニットを停止するコマンドです。
拡張オプション 内容
User, Group コマンドを実行するユーザおよびグループです。
[Install] セクション
オプション 内容
RequiredBy, WantedBy 依存するユニットの一覧です。

これらのオプションを使って、ユニットファイルを作ってみましょう。

ユニットファイルのドラフト

[Unit]
Description=Oracle Database Service
After=network.target

[Service]
Type=forking
User=oracle
Group=dba
ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1
ExecStop=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.2.0/dbhome_1

[Install]
WantedBy=multi-user.target

上のようにユニットファイルを作ってみました。 ※後述しますが、上記の設定は危険ですので転用しないで下さい!
オプションの設定値について解説します。紙面の都合上、読みづらくなってしまい申し訳ありません (´・ω・`)

オプション 設定値 解説
Description Oracle Database Service Oracle Database のサービス名です。
After network.target ネットワークが開始された後に起動するように定義しました。
Type forking デフォルト値の simple だとユニットを起動するコマンドがサービスのメインプロセスになります。
子プロセスをバックグラウンドにまわして、起動するコマンドは終了するタイプなので forking にしました。
forking だとユニットを起動するコマンドが終了しても子プロセスがメインプロセスになります。
User
Group
oracle
dba
これだけでコマンドを実行するユーザおよびグループを指定できます。
/etc/init.d/dbora スクリプトのように、su させる必要はありません。
いい感じですね。
ExecStart /u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 ユニットを起動するコマンドです。
dbstart の引数に ORACLE_HOME を指定すると、Listener の起動もしてくれます。
ExecStop /u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.2.0/dbhome_1 ユニットを停止するコマンドです。
dbshut の引数に ORACLE_HOME を指定すると、Listener の停止もしてくれます。
WantedBy multi-user.target マルチユーザモードで使用するサービスとして定義しました。
シングルユーザモードでは起動させないということになります。

自動起動/停止を試してみよう

サービスの有効化

新規のユニットファイルを作成した後には systemctl daemon-reload を実行します。
ユニットファイルを変更した後も同様です。

# systemctl daemon-reload

作成した dbora サービスを有効にしましょう。

# systemctl enable dbora
Created symlink from /etc/systemd/system/multi-user.target.wants/dbora.service to /etc/systemd/system/dbora.service.

WantedBy=multi-user.target の設定に従って、/etc/systemd/system/multi-user.target.wants にシンボリックリンクが作成されました。

自動起動の確認

いよいよ OS を再起動して Oracle Database の自動起動を確認します。
おっと、その前に /etc/oratab の設定を確認しておきましょう。

orcl:/u01/app/oracle/product/12.2.0/dbhome_1:Y

3フィールド目が Y と設定されていますね。
これで orcl は、dbstart, dbshut で起動/停止されるインスタンスということになります。

それでは OS を再起動!

# systemctl reboot

dbora サービスの起動状態を確認しましょう。

$ systemctl -l status dbora
dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: active (running) since 火 2018-06-12 09:55:07 JST; 1min 27s ago
Process: 1160 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/dbora.service
├2458 /u01/app/oracle/product/12.2.0/dbhome_1/bin/tnslsnr LISTENER -inherit
├2911 ora_pmon_orcl
├2913 ora_clmn_orcl
├2918 ora_psp0_orcl
├2924 ora_vktm_orcl
├2934 ora_gen0_orcl
├2964 ora_mman_orcl
├2970 ora_gen1_orcl
├2975 ora_diag_orcl
├2977 ora_ofsd_orcl
├2981 ora_dbrm_orcl
├2983 ora_vkrm_orcl
├2985 ora_svcb_orcl
├2987 ora_pman_orcl
├2990 ora_dia0_orcl
├2994 ora_dbw0_orcl
├2999 ora_lgwr_orcl
├3004 ora_ckpt_orcl
├3006 ora_smon_orcl
├3008 ora_smco_orcl
├3010 ora_reco_orcl
├3015 ora_w000_orcl
├3017 ora_lreg_orcl
├3019 ora_w001_orcl
├3022 ora_pxmn_orcl
├3026 ora_mmon_orcl
├3028 ora_mmnl_orcl
├3030 ora_d000_orcl
├3032 ora_s000_orcl
├3034 ora_tmon_orcl
├3042 ora_tt00_orcl
├3044 ora_tt01_orcl
├3046 ora_tt02_orcl
├3048 ora_aqpc_orcl
├3058 ora_cjq0_orcl
├3146 ora_qm02_orcl
├3150 ora_q002_orcl
├3152 ora_q003_orcl
└3362 ora_w002_orcl

期待通り、Oracle インスタンスのバックグラウンドプロセスと Listener プロセスが、サービスのメインプロセスになっています。

$ORACLE_HOME の startup.log を確認します。

$ cat $ORACLE_HOME/startup.log
/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart: Starting up database "orcl"
2018年 6月 12日 火曜日 09:54:13 JST

SQL*Plus: Release 12.2.0.1.0 Production on Tue Jun 12 09:54:17 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

SQL> Connected to an idle instance.
SQL> ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size 8628936 bytes
Variable Size 675284280 bytes
Database Buffers 385875968 bytes
Redo Buffers 3952640 bytes
?????????????????
?????????????????
SQL> Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production?????????????

/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart: Database instance "orcl" warm started.

ログに文字化けがありますが、インスタンスの自動起動は成功しています。

$ORACLE_HOME の listener.log を確認します。

$ cat $ORACLE_HOME/listener.log
/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart: Starting Oracle Net Listener

LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 12-JUN-2018 09:54:12

Copyright (c) 1991, 2016, Oracle. All rights reserved.

Starting /u01/app/oracle/product/12.2.0/dbhome_1/bin/tnslsnr: please wait...

TNSLSNR for Linux: Version 12.2.0.1.0 - Production
System parameter file is /u01/app/oracle/product/12.2.0/dbhome_1/network/admin/listener.ora
Log messages written to /u01/app/oracle/diag/tnslsnr/rhel7/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=rhel7)(PORT=1521)))
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rhel7)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias LISTENER
Version TNSLSNR for Linux: Version 12.2.0.1.0 - Production
Start Date 12-JUN-2018 09:54:16
Uptime 0 days 0 hr. 0 min. 4 sec
Trace Level off
Security ON: Local OS Authentication
SNMP OFF
Listener Parameter File /u01/app/oracle/product/12.2.0/dbhome_1/network/admin/listener.ora
Listener Log File /u01/app/oracle/diag/tnslsnr/rhel7/listener/alert/log.xml
Listening Endpoints Summary...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=rhel7)(PORT=1521)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
The listener supports no services
The command completed successfully

Listener の自動起動も成功しています。

自動停止の確認

次は、自動停止を確認してみましょう。
OS を再起動!

# systemctl reboot

OS起動後、$ORACLE_HOME の shutdown.log を確認します。

$ cat $ORACLE_HOME/shutdown.log
SQL*Plus: Release 12.2.0.1.0 Production on Tue Jun 12 10:11:22 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

SQL> ????????
SQL> ?????????????????
????????????????????
ORACLE????????????????????
SQL> Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production?????????????
Database instance "orcl" shut down.

ログに文字化けがありますが、インスタンスの自動停止は成功しています。

$ORACLE_HOME の listener.log を確認します。

$ cat $ORACLE_HOME/listener.log
/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut: Stoping Oracle Net Listener

LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 12-JUN-2018 10:11:22

Copyright (c) 1991, 2016, Oracle. All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rhel7)(PORT=1521)))
The command completed successfully

Listener の自動停止も成功しています。

ちょっと実験してみよう

メインプロセスを停止するとサービスはどうなる?

ここで、Oracle インスタンスのバックグラウンドプロセスと Listener プロセスがサービスのメインプロセスになっていることに着目してみます。

Oracle のバックグラウンドプロセスを停止したらどうなるのでしょう?
インスタンスを sqlplus を使って停止してみます。

$ sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on 火 6月 12 10:25:06 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
に接続されました。
SQL> shutdown immediate
データベースがクローズされました。
データベースがディスマウントされました。
ORACLEインスタンスがシャットダウンされました。
SQL>

サービスの状態を確認します。

$ systemctl -l status dbora
dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: active (running) since 火 2018-06-12 10:13:38 JST; 12min ago
Process: 1143 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/dbora.service
└2405 /u01/app/oracle/product/12.2.0/dbhome_1/bin/tnslsnr LISTENER -inherit

Oracle インスタンスのバックグラウンドプロセスが、サービスのメインプロセスから消えました。

インスタンスを sqlplus を使って起動してみます。

$ sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on 火 6月 12 10:29:29 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

アイドル・インスタンスに接続しました。

SQL> startup
ORACLEインスタンスが起動しました。

Total System Global Area 1073741824 bytes
Fixed Size 8628936 bytes
Variable Size 675284280 bytes
Database Buffers 385875968 bytes
Redo Buffers 3952640 bytes
データベースがマウントされました。
データベースがオープンされました。
SQL>

サービスの状態を確認します。

$ systemctl -l status dbora
dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: active (running) since 火 2018-06-12 10:13:38 JST; 17min ago
Process: 1143 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/dbora.service
└2405 /u01/app/oracle/product/12.2.0/dbhome_1/bin/tnslsnr LISTENER -inherit

Oracle インスタンスのバックグラウンドプロセスが、サービスのメインプロセスに戻ることはないようです。

Oracle インスタンスが意図せず停止してしまった!

Listener プロセスも停止したらどうなるのでしょう?

$ lsnrctl stop

LSNRCTL for Linux: Version 12.2.0.1.0 - Production on 12-6月 -2018 10:34:00

Copyright (c) 1991, 2016, Oracle. All rights reserved.

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rhel7)(PORT=1521)))に接続中
コマンドは正常に終了しました。

サービスの状態を確認します。

$ systemctl -l status dbora
● dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: inactive (dead) since 火 2018-06-12 10:34:22 JST; 4s ago
Process: 4031 ExecStop=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.2.0/dbhome_1 (code=exited, status=0/SUCCESS)
Process: 1143 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 (code=exited, status=0/SUCCESS)

サービスのメインプロセスがいなくなりました。
Active: inactive (dead) だそうです。
あれれ? よく見ると ExecStop に定義した dbshut が実行された形跡があります!

sqlplus を使ってインスタンスの状態を確認ます。

$ sqlplus / as sysdba

SQL*Plus: Release 12.2.0.1.0 Production on 火 6月 12 10:41:46 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

アイドル・インスタンスに接続しました。

SQL>

Listener プロセスだけ停止したはずなのに、ExecStop に定義した dbshut が実行され Oracle インスタンスが意図せず停止してしまいました! これは大変...

ユニットファイルを調整しよう

systemd.service(5) の man ページを参照すると、全てのメインプロセスが終了してもサービスが active と見なされるようにする RemainAfterExit というオプションがありました。

また、TimeoutStopSec オプションでサービス停止のタイムアウト値を設定できるそうです。
シャットダウン時のハングアップに備えるのに良いですね。

これらを踏まえて、下のようにユニットファイルを調整しました。

ユニットファイルのサンプル

[Unit]
Description=Oracle Database Service
After=network.target

[Service]
Type=forking
RemainAfterExit=yes
TimeoutStopSec=5min
Restart=no
User=oracle
Group=dba
EnvironmentFile=/etc/sysconfig/dbora
ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 &
ExecStop=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.2.0/dbhome_1
KillMode=none

[Install]
WantedBy=multi-user.target

ユニットファイルから参照するようにした /etc/sysconfig/dbora の内容です。

NLS_LANG=American_America.AL32UTF8

再実験の結果

再度実験してみます。

# systemctl daemon-reload
# systemctl reboot

$ systemctl -l status dbora
dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: active (running) since 火 2018-06-12 12:55:49 JST; 53s ago
Process: 1152 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 & (code=exited, status=0/SUCCESS)
CGroup: /system.slice/dbora.service
├2367 /u01/app/oracle/product/12.2.0/dbhome_1/bin/tnslsnr LISTENER -inherit
├2704 ora_pmon_orcl
├2706 ora_clmn_orcl
├2708 ora_psp0_orcl
├2723 ora_vktm_orcl
├2728 ora_gen0_orcl
├2739 ora_mman_orcl
├2743 ora_gen1_orcl
├2771 ora_diag_orcl
├2773 ora_ofsd_orcl
├2777 ora_dbrm_orcl
├2779 ora_vkrm_orcl
├2781 ora_svcb_orcl
├2783 ora_pman_orcl
├2785 ora_dia0_orcl
├2787 ora_dbw0_orcl
├2789 ora_lgwr_orcl
├2791 ora_ckpt_orcl
├2793 ora_smon_orcl
├2795 ora_smco_orcl
├2797 ora_reco_orcl
├2799 ora_w000_orcl
├2801 ora_lreg_orcl
├2803 ora_w001_orcl
├2805 ora_pxmn_orcl
├2809 ora_mmon_orcl
├2811 ora_mmnl_orcl
├2813 ora_d000_orcl
├2815 ora_s000_orcl
├2817 ora_tmon_orcl
├2963 ora_tt00_orcl
├2965 ora_tt01_orcl
├2978 ora_tt02_orcl
├3033 ora_aqpc_orcl
├3037 ora_cjq0_orcl
├3123 ora_s001_orcl
├3188 ora_qm02_orcl
├3192 ora_q002_orcl
├3194 ora_q003_orcl
└3373 ora_w002_orcl

調整後も、期待通り Oracle インスタンスのバックグラウンドプロセスと Listener プロセスが、サービスのメインプロセスになっています。

念のため $ORACLE_HOME の startup.log を確認します。

$ cat $ORACLE_HOME/startup.log
/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart: Starting up database "orcl"
2018年 6月 12日 火曜日 12:55:06 JST

SQL*Plus: Release 12.2.0.1.0 Production on Tue Jun 12 12:55:09 2018

Copyright (c) 1982, 2016, Oracle. All rights reserved.

SQL> Connected to an idle instance.
SQL> ORACLE instance started.

Total System Global Area 1073741824 bytes
Fixed Size 8628936 bytes
Variable Size 675284280 bytes
Database Buffers 385875968 bytes
Redo Buffers 3952640 bytes
Database mounted.
Database opened.
SQL> Disconnected from Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production

/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart: Database instance "orcl" warm started.

EnvironmentFile オプションを使って、NLS_LANG 環境変数を設定したので、ログファイルの文字化けは起きないようになりました。

同じ手順を実施し、Oracle インスタンスのバックグラウンドプロセスと Listener プロセスを停止した後のサービスの状態を確認します。

$ systemctl -l status dbora
dbora.service - Oracle Database Service
Loaded: loaded (/etc/systemd/system/dbora.service; enabled; vendor preset: disabled)
Active: active (exited) since 火 2018-06-12 12:55:49 JST; 10min ago
Process: 1152 ExecStart=/u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1 & (code=exited, status=0/SUCCESS)

期待通り、全てのメインプロセスが終了してもサービスが active と見なされており、ExecStop に定義した dbshut が実行された形跡はありません。
Oracle インスタンスが意図せず停止することはなくなりました!

追加したユニットファイルのオプション

[Service] セクションに追加したオプションを紹介します。
詳しくは、systemd.service(5)、systemd.exec(5)、systemd.kill(5)の man ページを参照してください。

オプション 内容
RemainAfterExit yesに設定すると、全てのメインプロセスが終了してもサービスを active と見なします。
TimeoutStopSec サービス停止を待つ時間を設定します。
Restart noに設定すると、タイムアウト発生時にサービスを再起動しません。
拡張オプション 内容
EnvironmentFile 環境変数の設定ファイルを指定します。
KillMode noneに設定すると、プロセスは強制終了されません。ユニット停止時には停止コマンドのみが実行されます。

まとめ

systemd による Oracle Database のサービス化を検証すると、色んな発見がありました。
サービスユニットの挙動について、イメージが掴めましたでしょうか。
ユニットファイルには沢山のオプションが揃っていますので、今回紹介したサンプルも工夫の余地がありそうです。
Oracle Database に限らず、別のデータベースでも systemd のユニットファイルで簡単に自動起動/停止の設定が可能ですので、是非試してみてください。
長くなりましたので、今回はここまで!

Standby Expressに関するお問合わせ

  • TEL 042-333-6217
  • FAX 042-352-6101
  • LINE
  • Mail