Oracle Listener

时间:2023-03-09 14:23:29
Oracle Listener

一、监听器功能

1)监听客户端请求:监听器作为独立进程运行在数据库服务器上,监听特定网络端口(默认1521)服务请求。

2)为客户端请求分配oracle Server Process:监听器不直接处理客户端发送过来的SQL命令,而是作为代理,将分配一个服务进程与客户端建立通信连接,由server process处理SQL命令并返回结果。

3)注册服务:通过注册过程实现监听器与数据库实例之间了联系,注册的过程就是告知监听器数据库实例名称和服务名,目前Oracle版本中,提供动态注册和静态注册两种方式。

4)故障转移failover: Failover是RAC容错的一个重要方面功能,当数据库实例发生崩溃时,监听器可以自动将请求转移到其它可用实例上。

5)负载均衡衡:在RAC架构中,当一个客户请求到来时,Oracle会根据当前RAC集群环境中所有实例的负载情况,避开负载较高的实例,将请求转移到负载较低的实例进行处理。

二、注册过程

注册的作用就是实现数据库实例名和服务名注册到运行的监听器程序中。

Figure 2-1 Example listener.ora File

LISTENER=
  (DESCRIPTION=
    (ADDRESS_LIST=
      (ADDRESS))
      (ADDRESS=(PROTOCOL=ipc)(KEY=extproc))))

# -- 静态注册部分
SID_LIST_LISTENER=
  (SID_LIST=
    (SID_DESC=
      (GLOBAL_DBNAME=sales.us.acme.com)
      (ORACLE_HOME=/oracle9i)
      (SID_NAME=sales))
    (SID_DESC=
      (SID_NAME=plsextproc)
      (ORACLE_HOME=/oracle9i)
      (PROGRAM=extproc)))

2.1) 默认是动态注册的时候,只有PLSExtProc项目。SID_LIST里用来配置当前监听器静态注册的服务项目,其中,通过一个或多个SID_DESC进行配置。静态配置项目中,通过GLOBAL_NAME配置服务项目,通过SID_NAME指定数据库实例的名称,通过ORACLE_HOME配置Oracle数据库软件安装的基本目录。

2.2)动态注册由PMON后台进程周期(2分钟)发起注册。

-- 手工进行注册
alter system set LOCAL_LISTENER='(ADDRESS = (PROTOCOL = TCP)(HOST = 10.150.10.150)(PORT = 1521))';
alter system register;

三、监听器信息

通过lsnrctl监听器控制程序与监听器进行交互和控制操作获取相对应信息。

Oracle Listener

Oracle Listener

注:

-- 这在10g及以后版本不是必要的安全检查条件,若想要取消此安全设置,可以在listener.ora文件中设置上LOCAL_OS_AUTHENTICATION_[listener name]=OFFset password

  监听器密码设置在ORACLE 9i版本中有效,在10g版本中,即使设置密码后,依然可以不用输入密码停止监听服务,因为In Oracle 10, the TNSListener is secure out of the box and there should not be a need to set a listener password as in older versions of the Oracle listener。
  Oracle10g以后,设置Listener密码已经不是安全检查的必要条件了,因为默认在10g里面除了启动监听的用户之外,其它用户都无法停止Listener(还有另外一些lsnrctl的命令也同样被禁止了,比如trace, reload等),即使Listener没有设置密码。在默认情况下,启动Listener或者使用lsnrctl status命令查看监听状态,可以看到:Security ON: Password OR Local OS Authentication这表明Listener的安全机制使用了Password方式或者Local OS Authentication方式,在这种状态下,即使是设置了监听密码,对于启动监听的user来说,也仍然是不需要任何密码就可以停止监听的。

3.1)set 命令操作配置

参数

描叙

set password

 

set rawmode

设置rawmode

set displaymode

把lsnrctl工具的显示模式设置成RAW、COMPACT、NORMAL或VERBOSE

set trc_file

设置监听跟踪文件的名称

set trc_directory

设置监听器跟踪目录的名称

set trc_level

把跟踪级别设置为OFF、USER、ADMIN、SUPPORT模式

set log_file

显示或设置日志文件

set log_directory

设置日志目录位置

set log_status

设置是否为该监听器打开日志特性

set current_listener

设置当前监听器为指定监听器

set inbound_connect_timeout

设置参数指定的时间,在几秒钟内为客户完成网络连接已经建立后,其连接请求的监听

set startup_waittime

设置监听器等待响应lsnrctl 命令行工具中的一条STATUS命令的时间长度

set save_config_on_stop

在退出lsnrctl工具时保存对listener.ora文件的修改

set dynamic_registration

使用的DYNAMIC_REGISTRATION_listener_name的参数启用或禁用动态注册。当设置为on,听者接受动态登记;设置为关闭时,听者拒绝动态注册。静态注册不受影响

set enable_global_dynamic_endpoint

 

3.2)通过TNS_ADMIN命令指定监听器配置文件路径

expport TNS_ADMIN=$ORACLE_HOME/network/admin

四、监听器日志解析

1)日志格式:TIMESTAMP * CONNECT DATA [* PROTOCOL INFO] * EVENT [* SID] * RETURN CODE, 使用*进行内容分割。

Oracle Listener

2)监听日志截断,防止日志文件过大,一般不能超过2GB,超过会导致LISTENER监听器无法处理新的连接或是给写入、查看带来的一些性能问题。

Step 1:首先停止监听服务进程(tnslsnr)记录日志。

Step 2:将监听日志文件(listener.log)复制一份,以listener.log.yyyymmdd格式命名

Step 3:将监听日志文件(listener.log)清空。(如:mv命令等)

Step 4:开启监听服务进程(tnslsnr)记录日志

 #!/bin/sh
 #  * * * * su - username -c sh clean_lsnrlog.sh

 # reload user profile
 [ -f "${HOME}/.bash_profile" ] && . ${HOME}/.bash_profile
 [ -f "${HOME}/.profile" ] && . ${HOME}/.profile

 # HP-UX操作系统使用ksh环境执行脚本,AIX使用ksh93环境执行,其他环境使用sh
 # AIX则ECHO=echo(AIX系统没有-e的参数,默认会进行转义)
 export OSTYPE=$(uname -s)
 case ${OSTYPE} in
     "HP-UX")
       export LANG=en_US
       EXEC_SHELL="ksh -x"
       ECHO="echo -e"
     ;;
     "AIX")
       EXEC_SHELL="sh -x"
       [ -f "/usr/bin/ksh93" ] && EXEC_SHELL="/usr/bin/ksh93 -x"
       ECHO="echo"
     ;;
     *)
       EXEC_SHELL="sh -x"
       ECHO="echo -e"
 esac
 export EXEC_SHELL ECHO

 # scripts directory
 WDIR=${HOME}/scripts
 LOGDIR=${WDIR}/log
 [ -d "${HOME}/scripts" ] || mkdir -p ${WDIR}
 [ -d "${WDIR}/log" ] || mkdir -p ${WDIR}/log
 LSNRNAMEFILE=${LOGDIR}/listener_name.txt

 # output listener username
 # USERID=$(ps -ef|grep tnslsnr |grep -v grep | awk  '{print $1}' |sort -u)
 # output listener name to the file
 ps -ef|grep tnslsnr |grep -v grep | awk '{print $(NF-1)}' > ${LSNRNAMEFILE}
 # ps -ef|grep tnslsnr |perl -lane 'print $F[-2] if/bin\/tnslsnr/' |awk '{$0=tolower($0);print $0}'|sort -u

 # Get datetime format is yyyymmddhh24missss()
 dtime=$(
 CLR_TIME=$(
 OPT_TIME=$(date +%Y%m%d%H%M)

 # clean options
 for LSN in $(cat "${LSNRNAMEFILE}" | awk '{ $0=tolower($0);print $0 }'); do
     ${ECHO} "\n  ----------------------------  Begin ---------------------------- \n">> ${OPT_LOGFILE}
     lsnrctl status ${LSN} > ${LOGDIR}/${LSN}.stat
     # 监听配置文件
     LSNRORAFILE=$(grep -i 'Listener Parameter File' ${LOGDIR}/${LSN}.stat |awk ' {print $NF}')
     # output listener log directory
     STR=$(grep -i 'Listener Log File' ${LOGDIR}/${LSN}.stat |awk ' {print $NF}')
     # 监听日志文件[listener_name.log]所在目录
     LSNR_DIR=${STR%'alert'*}trace
     # 监听日志文件[log*.xml]所在目录
     LSNXML_DIR=${STR%/*}
     # 监听日志文件绝对路径
     LSNLOGFILE=${LSNR_DIR}/${LSN}.log
     # 监听日志文件大小
     LSN_LOGFILE_SIZE=$(du -k ${LSNLOGFILE} | awk '{print $1}')

     # clean operations logs
     OPT_LOGFILE=${LOGDIR}/clean_${LSN}_${OPT_TIME}.log

     # if xml directory exits,then delete 30 days agos xml files
     if [ -d "${LSNXML_DIR}" ]; then
         # change into xml directory
         cd ${LSNXML_DIR} || exit 1
         touch -t ${dtime} today
         # recode deleting files
         find ${LSNXML_DIR} -type f ! -newer today |xargs ls -ltr |grep 'xml$' >> ${OPT_LOGFILE}
         # delete xml file actions
         find ${LSNXML_DIR} -type f ! -newer today |grep 'xml$' |xargs -n1000 rm -f
     fi

     # if listener.log file exits,then backup and clear them
     # if [ `du -sk ${LSNR_DIR}/trace` eq 1048576 && -f "${LSNLOGFILE}" ]
     if [[ -f "${LSNLOGFILE}" ]] && [[ "${LSN_LOGFILE_SIZE}" -gt "1048576" ]]; then
         ${ECHO} "\n  -------The size of ${LSNLOGFILE} is: ${LSN_LOGFILE_SIZE}'K' ------- \n">> ${OPT_LOGFILE}
         cd ${LSNR_DIR} || exit 1
         #如果存在监听配置文件,且有设置ADMIN_RESTRICTIONS,则OFF再进行mv的操作
         if [[ -f "${LSNRORAFILE}" ]]; then
             # 回退安全加固参数
             grep -i "ADMIN_RESTRICTIONS_${LSN}" ${LSNRORAFILE}
             ADMINSTAT=$?
             if [[ "${ADMINSTAT}" = "0" ]]; then
                 perl -i.${OPT_TIME}.1 -pe "s/ADMIN_RESTRICTIONS_${LSN}=ON/ADMIN_RESTRICTIONS_${LSN}=OFF/ig" "${LSNRORAFILE}"
                 ${ECHO} '\n  ------- reload begin ------- \n'>> ${OPT_LOGFILE}
                 lsnrctl << EOFRELOAD
 set CURRENT_LISTENER ${LSN}
 reload
 status
 exit
 EOFRELOAD
                 ${ECHO} '\n  ------- reload END ------- \n'>> ${OPT_LOGFILE}
             fi
         fi

         #关闭监听的日志输出
         ${ECHO} '\n  ------- set logfile off -------  \n'>> ${OPT_LOGFILE}
         lsnrctl << EOFOFF >> ${OPT_LOGFILE}
 set CURRENT_LISTENER ${LSN}
 set log_status off
 status
 exit
 EOFOFF
         ${ECHO} '\n  ------- set logfile off END ------- \n'>> ${OPT_LOGFILE}

         #确认监听状态是否log_status已off,off则进行move操作
         lsnrctl status ${LSN}|grep ${LSNLOGFILE}
         if [[ "$?" != "0" ]] ; then
             # 备份并压缩监听日志文件
             [[ -f "${LSNLOGFILE}" ]] && mv ${LSNLOGFILE} ${LSNLOGFILE}.${OPT_TIME} && gzip -f ${LSNLOGFILE}.${OPT_TIME} && ${ECHO} "\n  ------- command: \nmv ${LSNLOGFILE} ${LSNLOGFILE}.${OPT_TIME}\ngzip -f ${LSNLOGFILE}.${OPT_TIME} \n------- \n" >> ${OPT_LOGFILE}
         fi

         #开启监听日志的输出
         ${ECHO} '\n  ------- set logfile on ------- \n'>> ${OPT_LOGFILE}
         lsnrctl << EOFON >> ${OPT_LOGFILE}
 set CURRENT_LISTENER ${LSN}
 set log_status on
 status
 exit
 EOFON
         ${ECHO} '\n  ------- set logfile on END ------- \n'>> ${OPT_LOGFILE}

         # 安全加固参数
         # grep -i "ADMIN_RESTRICTIONS_${LSN}" ${LSNRORAFILE}
         if [[ "${ADMINSTAT}" = "0" ]]; then
             perl -i.${OPT_TIME}.2 -pe "s/ADMIN_RESTRICTIONS_${LSN}=OFF/ADMIN_RESTRICTIONS_${LSN}=ON/ig" "${LSNRORAFILE}"
             ${ECHO} '\n  ------- reload begin ------- \n'>> ${OPT_LOGFILE}
             lsnrctl << EOFRELOAD
 set CURRENT_LISTENER ${LSN}
 reload
 status
 exit
 EOFRELOAD
             ${ECHO} '\n  ------- reload END ------- \n'>> ${OPT_LOGFILE}
         fi

         # 清理历史备份文件
         touch -t ${CLR_TIME} cleansfile
         ${ECHO} '\n  ------- Deleting histoty compress file before 180 days ago. ------- \n'>> ${OPT_LOGFILE}
         find ${LSNR_DIR} -type f ! -newer cleansfile |xargs ls -ltr |grep '.gz$' >> ${OPT_LOGFILE}
         find ${LSNR_DIR} -type f ! -newer cleansfile |grep '.gz$' |xargs -n100 rm -f
     fi
     ${ECHO} "\n  ----------------------------  Finish ---------------------------- \n">> ${OPT_LOGFILE}
 done

4.3 监听文件的各个参数的作用作个描述:

LISTENER

指出一个监听器定义的起始点。它实际上是正被定义的当前监听器的名称。默认的名称是LISTENER

DESCRIPTION

描述每个监听位置

ADDRESS_LIST

含有与监听器正在监听的那些位置有关的地址信息

PROTOCOL

指定用于本监听位置的协议

HOST

保存监听器所驻留在的那台计算机的名称

PORT

含有监听器正在上面监听的地址

SID_LIST_LISTENER

定义配置监听器所针对的ORACLE服务的列表

SID_DESC

描述每个Oracel SID

GLOBAL_DBNAME

标识全局数据库名称。本项应该与当前Oracle服务的init.ora文件中的SERVICE_NAMES项一致

ORACLE_HOME

给出服务器上Oracle可执行程序的位置

SID_NAME

含有用于本Oracle实例的Oracle SID的名称

五、sqlplus连接数据库实例方式,其它类似

5.1) sqlplus / as sysdba
    操作系统认证,不需要数据库服务器启动listener,也不需要数据库服务器处于可用状态。比如我们想要启动数据库就可以用这种方式进入
    sqlplus,然后通过startup命令来启动。
5.2) sqlplus username/password
    连接本机数据库,不需要数据库服务器的listener进程,但是由于需要用户名密码的认证,因此需要数据库服务器处于可用状态才行。
5.3) sqlplus usernaem/password@orcl
    通过网络连接,这是需要数据库服务器的listener处于监听状态。此时建立一个连接的大致步骤如下 
  a. 查询sqlnet.ora,看看名称的解析方式,默认是TNSNAME  
  b. 查询tnsnames.ora文件,从里边找orcl的记录,并且找到数据库服务器的主机名或者IP,端口和service_name  
  c. 如果服务器listener进程没有问题的话,建立与listener进程的连接。  
  d. 根据不同的服务器模式如专用服务器模式或者共享服务器模式,listener采取接下去的动作。默认是专用服务器模式,没有问题的话客户端
            就连接上了数据库的server process。
  e. 这时连接已经建立,可以操作数据库了。
5.4)sqlplus username/password@//host:port/sid
  用sqlplus远程连接oracle命令(例:sqlplus risenet/@//192.168.130.99:1521/risenet)

六、oracle 11G 的监听器默认开启了ADR特性,客户端连接信息记录客户端2种日志格式(xml 和 listener_name.log),占用大量的空间,通常只需一种日志即可满足日常维护需求。下面通过关闭其ADR特性的方式检查空间占用

. 在sqlnet.ora文件中增加
DIAG_ADR_ENABLED=off

. 在监听器文件listener.ora中增加
DIAG_ADR_ENABLED_<Listener_name>=off

For example, if the listener name is 'LISTENER_SCAN1', the parameter should be:
DIAG_ADR_ENABLED_LISTENER_SCAN1=OFF

. reload or start 监听器,使得配置生效

. 日志路径可通过命令获取
lsnrctl status|grep 'Listener Log File'