代码改变世界

Linux平台Oracle开机自启动设置

2024-11-14 10:57  潇湘隐者  阅读(243)  评论(0编辑  收藏  举报

网上和官方文档已经有不少介绍如何设置开机启动Oracle实例的文章(Linux平台),不过以sysvinit和service这种方式居多。最近遇到了UAT环境的服务器打补丁后需要重启服务器的情况, 需要DBA去手工启动Oracle实例的情形,和同事讨论,决定将UAT环境的Oracle实例启停设置成systemd服务,使其开机自启动,避免在服务器打补丁重启的情况下, 需要DBA去手工启动Oracle实例。这样可以大大减少工作量。 下面是设置Linux平台Oracle开机自启动的总结性文档,仅供参考。

实验环境:

操作系统版本: Red Hat Enterprise Linux release 8.10 (Ootpa)

数据库版本 : Oracle 19c

方案1

1. 修改oratab文件

修改/etc/oratab的配置,找到如下这样的配置(不同环境,ORACLE_SID以及Oracle安装路径可能不一致,以实际情况为准)

原始值:

gsp:/opt/oracle19c/product/19.3.0/db_1:N

修改后:

gsp:/opt/oracle19c/product/19.3.0/db_1:Y

在oratab文件中,ORACLE_SID:$ORACLE_HOME:<N|Y>,设置为Y时,表示允许Oracle实例开机自启动,当设置为N时,则不允许开机自启动。 这个文件里的配置仅仅起一个开关的作用, 其实它并不会具体的执行启动和关闭Oracle实例操作. 因为后面的脚本dbstart中会从oratab获取相关值,它类似一个参数配置文件。所以这一步至关重要。

[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:Y

简单方式,可以使用下面命令修改

sed -i 's/:N/:Y/' /etc/oratab

2.修改dbstart

dbstart文件的具体路径为:$ORACLE_HOME/bin/dbstart

上述脚本在启动监听时,只启动了默认监听服务(LISTENER),不会启动命名的监听服务,如果你配置的是命名监听的话, 那么需要修改脚本,如下所示,如果你使用的是默认的监听服务的话,那么直接跳过这一步。

--修改前

  # 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

--修改后

此处监听名为gsp,那么我们调整为"$ORACLE_HOME/bin/lsnrctl start gsp"

  # 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"
  fi

另外,这里不需要修改其它配置,网上有些文章修改"ORACLE_HOME_LISTNER=$1",其实这个看你的方案与思路,至少这里无需修改其它任何代码。 因为调用dbstart脚本的时候,会传入参数。

3.设置dbshut

dbshut文件的具体路径为:$ORACLE_HOME/bin/dbshut

这里跟步骤2一致,如果是默认的监听服务,那么也请跳过这一步。

修改前:

  # 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"
  fi

4. 配置systemd服务

在/etc/systemd/system/下创建一个新的systemd服务文件,命名为oracle.service

方式1:

# 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

注意:/opt/oracle19c/product/19.3.0/db_1为$ORACLE_HOME,根据实际情况进行调整。

配置完成,执行下面命名后,就可以使用systemctl启动或停止Oracle实例了。

# systemctl daemon-reload
# systemctl enable oracle.service

在测试oracle服务的启停前,先确保oracle实例和监听服务已经关闭,如果手工启动的oracle实例,使用下面命令关闭时会异常。详情请见下文"问题1"。

# systemctl start oracle.service
# systemctl status oracle.service
# systemctl stop oracle.service
 

此时,你通过命令"systemctl status oracle.service",可以知道查看oracle实例是否正常,你也可以通过$ORACLE_HOME/rdbms/log/startup.log日志查看 其实这个日志是在dbshut中生成的。当前测试环境为/opt/oracle19c/product/19.3.0/db_1/rdbms/log/startup.log

方案2

如下所示,我们可以在systemd中引入环境变量,如下所示

# 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.target

我们也可以使用EnvironmentFile来指定环境变量,如下所示,创建文件/home/oracle/dba_scripts/oracle.env,在文件中指定环境变量

ORACLE_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

做完上述操作后,执行下面命令重新加载systemd系统和服务管理器配置

# systemctl daemon-reload

方案3

上面的方案有一个问题,就是如果监听服务是命名监听,那么必须修改dbstart或dbshut脚本,如果是一台或两台数据库实例,这样修改倒也没有什么问题。 如果服务器多了的话,那么每一台都要修改,那么我们应该考虑不修改这些脚本,通过另外的形式来事项。这个就是方案3的出现的理由。

我们新建一个脚本oracle_start_stop.sh

#!/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

新建一个oracle.service的systemd服务文件,如下所示,ExecStart和ExecStop中去调用执行oracle_start_stop.sh文件

# 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启动或停止Oracle实例了。

# systemctl daemon-reload
# systemctl enable oracle.service

问题汇总

问题1: 手工启动oracle实例,使用systemctl stop oracle关闭不了。这是为什么呢?

systemctl是systemd系统和服务管理器的命令行工具,主要用于控制systemd管理的服务。对于那些不是通过 systemd 启动的服务或进程, systemctl 默认情况下是无法直接控制的。例如,如果Oracle实例是通过sqlplus手工启动的话,脚本中不做一些特殊控制或修改,默认情况下, systemctl将无法控制它(关闭它)。

问题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

这种情况下,无法获取系统变量$ORACLE_HOME的值。会报如下错误,如下所示:

# 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/dbstart

其实出现这个问题,是因为在systemd中脚本必须使用绝对路径。这个归因于systemd的工作方式和路径解析机制,出于安全(避免路径遍历攻击、防止命令注入等) 等方面的原因。

但是可以在脚本后面使用环境变量,如下所示

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

问题3

关于有些版本的一些bug问题,systemd服务里面可能需要设置一些系统变量,如下所示。具体参考官方文档Automatic Stop of Database (dbshut) not working in OL 7 with systemd (Doc ID 2229679.1)。

[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