网上和官方文档已经有不少介绍如何设置开机启动Oracle实例的文章(Linux平台),不过以sysvinit和service这种方式居多。最近遇到了UAT环境的服务器打补丁后需要重启服务器的情况,
需要DBA去手工启动Oracle实例的情形,和同事讨论,决定将UAT环境的Oracle实例启停设置成systemd服务,使其开机自启动,避免在服务器打补丁重启的情况下,
需要DBA去手工启动Oracle实例。这样可以大大减少工作量。 下面是设置Linux平台Oracle开机自启动的总结性文档,仅供参考。 实验环境: 操作系统版本: Red Hat Enterprise Linux release 8.10 (Ootpa) 数据库版本 : Oracle 19c 修改/etc/oratab的配置,找到如下这样的配置(不同环境,ORACLE_SID以及Oracle安装路径可能不一致,以实际情况为准) 原始值: 修改后: 在oratab文件中,ORACLE_SID:$ORACLE_HOME:<N|Y>,设置为Y时,表示允许Oracle实例开机自启动,当设置为N时,则不允许开机自启动。 这个文件里的配置仅仅起一个开关的作用,
其实它并不会具体的执行启动和关闭Oracle实例操作. 因为后面的脚本dbstart中会从oratab获取相关值,它类似一个参数配置文件。所以这一步至关重要。 简单方式,可以使用下面命令修改 dbstart文件的具体路径为:$ORACLE_HOME/bin/dbstart 上述脚本在启动监听时,只启动了默认监听服务(LISTENER),不会启动命名的监听服务,如果你配置的是命名监听的话,
那么需要修改脚本,如下所示,如果你使用的是默认的监听服务的话,那么直接跳过这一步。 --修改前 --修改后 此处监听名为gsp,那么我们调整为"$ORACLE_HOME/bin/lsnrctl start gsp" 另外,这里不需要修改其它配置,网上有些文章修改"ORACLE_HOME_LISTNER=$1",其实这个看你的方案与思路,至少这里无需修改其它任何代码。
因为调用dbstart脚本的时候,会传入参数。 dbshut文件的具体路径为:$ORACLE_HOME/bin/dbshut 这里跟步骤2一致,如果是默认的监听服务,那么也请跳过这一步。 修改前: 修改后: 在/etc/systemd/system/下创建一个新的systemd服务文件,命名为oracle.service 方式1: 注意:/opt/oracle19c/product/19.3.0/db_1为$ORACLE_HOME,根据实际情况进行调整。 配置完成,执行下面命名后,就可以使用systemctl启动或停止Oracle实例了。 在测试oracle服务的启停前,先确保oracle实例和监听服务已经关闭,如果手工启动的oracle实例,使用下面命令关闭时会异常。详情请见下文"问题1"。 此时,你通过命令"systemctl status oracle.service",可以知道查看oracle实例是否正常,你也可以通过$ORACLE_HOME/rdbms/log/startup.log日志查看
其实这个日志是在dbshut中生成的。当前测试环境为/opt/oracle19c/product/19.3.0/db_1/rdbms/log/startup.log 如下所示,我们可以在systemd中引入环境变量,如下所示 我们也可以使用EnvironmentFile来指定环境变量,如下所示,创建文件/home/oracle/dba_scripts/oracle.env,在文件中指定环境变量 做完上述操作后,执行下面命令重新加载systemd系统和服务管理器配置 上面的方案有一个问题,就是如果监听服务是命名监听,那么必须修改dbstart或dbshut脚本,如果是一台或两台数据库实例,这样修改倒也没有什么问题。
如果服务器多了的话,那么每一台都要修改,那么我们应该考虑不修改这些脚本,通过另外的形式来事项。这个就是方案3的出现的理由。 我们新建一个脚本oracle_start_stop.sh 新建一个oracle.service的systemd服务文件,如下所示,ExecStart和ExecStop中去调用执行oracle_start_stop.sh文件 配置完成,执行下面命名后,就可以使用systemctl启动或停止Oracle实例了。 systemctl是systemd系统和服务管理器的命令行工具,主要用于控制systemd管理的服务。对于那些不是通过 systemd 启动的服务或进程,
systemctl 默认情况下是无法直接控制的。例如,如果Oracle实例是通过sqlplus手工启动的话,脚本中不做一些特殊控制或修改,默认情况下,
systemctl将无法控制它(关闭它)。 这种情况下,无法获取系统变量$ORACLE_HOME的值。会报如下错误,如下所示: 分析如下: 其实出现这个问题,是因为在systemd中脚本必须使用绝对路径。这个归因于systemd的工作方式和路径解析机制,出于安全(避免路径遍历攻击、防止命令注入等)
等方面的原因。 但是可以在脚本后面使用环境变量,如下所示 关于有些版本的一些bug问题,systemd服务里面可能需要设置一些系统变量,如下所示。具体参考官方文档Automatic Stop of Database (dbshut) not working in OL 7 with systemd (Doc ID 2229679.1)。方案1
1. 修改oratab文件
gsp:/opt/oracle19c/product/19.3.0/db_1:N
gsp:/opt/oracle19c/product/19.3.0/db_1:Y
[root@OraPrefTest system]# more /etc/oratab
# This file is used by ORACLE utilities. It is created by root.sh
# and updated by either Database Configuration Assistant while creating
# a database or ASM Configuration Assistant while creating ASM instance.
# A colon, ':', is used as the field terminator. A new line terminates
# the entry. Lines beginning with a pound sign, '#', are comments.
#
# Entries are of the form:
# $ORACLE_SID:$ORACLE_HOME:<N|Y>:
#
# The first and second fields are the system identifier and home
# directory of the database respectively. The third field indicates
# to the dbstart utility that the database should , "Y", or should not,
# "N", be brought up at system boot time.
#
# Multiple entries with the same $ORACLE_SID are not allowed.
#
#
gsp:/opt/oracle19c/product/19.3.0/db_1:Ysed -i 's/:N/:Y/' /etc/oratab
2.修改dbstart
# Determine location of listener.log
mkdir -p -- $ORACLE_BASE_HOME/network/log
LOG=$ORACLE_BASE_HOME/network/log/listener.log
# Start Oracle Net Listener
if [ -x $ORACLE_HOME/bin/tnslsnr ] ; then
echo "$0: Starting Oracle Net Listener" >> $LOG 2>&1
$ORACLE_HOME/bin/lsnrctl start >> $LOG 2>&1 &
VER10LIST=`$ORACLE_HOME/bin/lsnrctl version | grep "LSNRCTL for " | cut -d' ' -f5 | cut -d'.' -f1`
export VER10LIST
else
echo "Failed to auto-start Oracle Net Listener using $ORACLE_HOME/bin/tnslsnr"
fi # Determine location of listener.log
mkdir -p -- $ORACLE_BASE_HOME/network/log
LOG=$ORACLE_BASE_HOME/network/log/listener.log
# Start Oracle Net Listener
if [ -x $ORACLE_HOME/bin/tnslsnr ] ; then
echo "$0: Starting Oracle Net Listener" >> $LOG 2>&1
$ORACLE_HOME/bin/lsnrctl start gsp >> $LOG 2>&1 &
VER10LIST=`$ORACLE_HOME/bin/lsnrctl version | grep "LSNRCTL for " | cut -d' ' -f5 | cut -d'.' -f1`
export VER10LIST
else
echo "Failed to auto-start Oracle Net Listener using $ORACLE_HOME/bin/tnslsnr"
fi3.设置dbshut
# Determine location of listener.log
mkdir -p -- $ORACLE_BASE_HOME/network/log
LOG=$ORACLE_BASE_HOME/network/log/listener.log
# Stop Oracle Net Listener
if [ -x $ORACLE_HOME/bin/tnslsnr ] ; then
echo "$0: Stopping Oracle Net Listener" >> $LOG 2>&1
$ORACLE_HOME/bin/lsnrctl stop >> $LOG 2>&1 &
else
echo "Failed to auto-stop Oracle Net Listener using $ORACLE_HOME/bin/tnslsnr"
fi # Determine location of listener.log
mkdir -p -- $ORACLE_BASE_HOME/network/log
LOG=$ORACLE_BASE_HOME/network/log/listener.log
# Stop Oracle Net Listener
if [ -x $ORACLE_HOME/bin/tnslsnr ] ; then
echo "$0: Stopping Oracle Net Listener" >> $LOG 2>&1
$ORACLE_HOME/bin/lsnrctl stop gsp >> $LOG 2>&1 &
else
echo "Failed to auto-stop Oracle Net Listener using $ORACLE_HOME/bin/tnslsnr"
fi4. 配置systemd服务
# more oracle.service
[Unit]
Description=Oracle Database Service
After=network.target
[Service]
Type=forking
User=oracle
Group=oinstall
ExecStart=/opt/oracle19c/product/19.3.0/db_1/bin/dbstart /opt/oracle19c/product/19.3.0/db_1
ExecStop=/opt/oracle19c/product/19.3.0/db_1/bin/dbshut /opt/oracle19c/product/19.3.0/db_1
TimeoutStopSec=5min
Restart=on-failure
[Install]
WantedBy=multi-user.target# systemctl daemon-reload
# systemctl enable oracle.service# systemctl start oracle.service
# systemctl status oracle.service
# systemctl stop oracle.service
方案2
# more oracle.service
[Unit]
Description=Oracle Database Service
After=network.target
[Service]
Type=forking
User=oracle
Group=oinstall
Environment="ORACLE_HOME=/opt/oracle19c/product/19.3.0/db_1"
ExecStart=/opt/oracle19c/product/19.3.0/db_1/bin/dbstart $ORACLE_HOME
ExecStop=/opt/oracle19c/product/19.3.0/db_1/bin/dbshut $ORACLE_HOME
TimeoutStopSec=5min
Restart=no
RemainAfterExit=yes
KillMode=none
[Install]
WantedBy=multi-user.targetORACLE_HOME=/opt/oracle19c/product/19.3.0/db_1
# more oracle.service
[Unit]
Description=Oracle Database Service
After=network.target
[Service]
Type=forking
User=oracle
Group=oinstall
EnvironmentFile=/home/oracle/dba_scripts/oracle.env
ExecStart=/opt/oracle19c/product/19.3.0/db_1/bin/dbstart $ORACLE_HOME
ExecStop=/opt/oracle19c/product/19.3.0/db_1/bin/dbshut $ORACLE_HOME
TimeoutStopSec=5min
Restart=no
RemainAfterExit=yes
KillMode=none
[Install]
WantedBy=multi-user.target# systemctl daemon-reload
方案3
#!/bin/bash
###################################################################################################
# Script used to start or stop oracle instance #
#*************************************************************************************************#
# Version Autor Modified Date Description #
#*************************************************************************************************#
# 1.0 Kerry Kong 2019-09-10 create the shell script. #
###################################################################################################
SUCCESS=0
FAILURE=1
# Check the number of parameter.
if [ $# -lt 2 ]; then
echo "please check the scirpt's parameter"
exit $FAILURE
fi
STATUS=$1
LISTENER_NAME=$2
if [ $STATUS == 'start' ];then
$ORACLE_HOME/bin/lsnrctl start $LISTENER_NAME
$ORACLE_HOME/bin/dbstart $ORACLE_HOME
exit $SUCCESS
elif [ $STATUS == 'stop' ]; then
$ORACLE_HOME/bin/lsnrctl stop $LISTENER_NAME
$ORACLE_HOME/bin/dbshut $ORACLE_HOME
exit $SUCCESS
else
echo "the parameter is not correct"
fi# vi oracle.service
[Unit]
Description=Oracle Database Service
After=network.target
[Service]
Type=forking
User=oracle
Group=oinstall
ExecStart=/home/oracle/dba_scripts/oracle_start_stop.sh start gsp
ExecStop=/home/oracle/dba_scripts/oracle_start_stop.sh stop gsp
TimeoutStopSec=5min
Restart=on-failure
[Install]
WantedBy=multi-user.target# systemctl daemon-reload
# systemctl enable oracle.service问题汇总
问题1: 手工启动oracle实例,使用systemctl stop oracle关闭不了。这是为什么呢?
问题2 在oracle.service中使用变量问题
[Unit]
Description=Oracle Database Service
After=network.target
[Service]
Type=forking
User=oracle
Group=dba
ExecStart=$ORACLE_HOME/bin/dbstart
ExecStop=$ORACLE_HOME/bin/dbshut
Restart=on-failure
[Install]
WantedBy=multi-user.target# systemctl start oracle.service
Failed to start oracle.service: Unit oracle.service has a bad unit file setting.
See system logs and 'systemctl status oracle.service' for details.
# systemctl status oracle.service
● oracle.service - Oracle Database Service
Loaded: bad-setting (Reason: Unit oracle.service has a bad unit file setting.)
Active: inactive (dead)
Oct 21 08:28:30 OraPrefTest systemd[1]: /etc/systemd/system/oracle.service:9: Neither a valid executable name nor an absolute path:$ORACLE_HOME/bin/dbstart
lines 1-5/5 (END)# systemd-analyze verify oracle.service
/etc/systemd/system/./oracle.service:10: Neither a valid executable name nor an absolute path: $ORACLE_HOME/bin/dbstartExecStart=/opt/oracle19c/product/19.3.0/db_1/bin/dbstart $ORACLE_HOME
ExecStop=/opt/oracle19c/product/19.3.0/db_1/bin/dbshut $ORACLE_HOME问题3
[Unit]
Description=Oracle Database Start/Stop Service
After=syslog.target network.target local-fs.target remote-fs.target
[Service]
# systemd, by design does not honor PAM limits
# See: https://bugzilla.redhat.com/show_bug.cgi?id=754285
LimitNOFILE=65536
LimitNPROC=16384
LimitSTACK=32M
LimitMEMLOCK=infinity
LimitCORE=infinity
LimitDATA=infinity
Type=simple
User=oracle
Group=oinstall
Restart=no
ExecStartPre=/bin/rm -rf /u01/app/oracle/product/12.2.0/dbhome_1/listener.log
ExecStartPre=/bin/rm -rf /u01/app/oracle/product/12.2.0/dbhome_1/startup.log
ExecStart=/bin/bash /u01/app/oracle/product/12.2.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.2.0/dbhome_1
RemainAfterExit=yes
ExecStop=/bin/rm -rf /u01/app/oracle/product/12.2.0/dbhome_1/shutdown.log
ExecStop=/bin/bash /u01/app/oracle/product/12.2.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.2.0/dbhome_1
TimeoutStopSec=5min
[Install]
WantedBy=multi-user.target