一、监听器功能
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=(PROTOCOL=tcp)(HOST=sale-server)(PORT=1521)) (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监听器控制程序与监听器进行交互和控制操作获取相对应信息。
注:
-- 这在10g及以后版本不是必要的安全检查条件,若想要取消此安全设置,可以在listener.ora文件中设置上LOCAL_OS_AUTHENTICATION_[listener name]=OFF
set 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, 使用*进行内容分割。
2)监听日志截断,防止日志文件过大,一般不能超过2GB,超过会导致LISTENER监听器无法处理新的连接或是给写入、查看带来的一些性能问题。
Step 1:首先停止监听服务进程(tnslsnr)记录日志。
Step 2:将监听日志文件(listener.log)复制一份,以listener.log.yyyymmdd格式命名
Step 3:将监听日志文件(listener.log)清空。(如:mv命令等)
Step 4:开启监听服务进程(tnslsnr)记录日志
1 #!/bin/sh 2 # 00 * * * * su - username -c sh clean_lsnrlog.sh 3 4 # reload user profile 5 [ -f "${HOME}/.bash_profile" ] && . ${HOME}/.bash_profile 6 [ -f "${HOME}/.profile" ] && . ${HOME}/.profile 7 8 # HP-UX操作系统使用ksh环境执行脚本,AIX使用ksh93环境执行,其他环境使用sh 9 # AIX则ECHO=echo(AIX系统没有-e的参数,默认会进行转义) 10 export OSTYPE=$(uname -s) 11 case ${OSTYPE} in 12 "HP-UX") 13 export LANG=en_US 14 EXEC_SHELL="ksh -x" 15 ECHO="echo -e" 16 ;; 17 "AIX") 18 EXEC_SHELL="sh -x" 19 [ -f "/usr/bin/ksh93" ] && EXEC_SHELL="/usr/bin/ksh93 -x" 20 ECHO="echo" 21 ;; 22 *) 23 EXEC_SHELL="sh -x" 24 ECHO="echo -e" 25 esac 26 export EXEC_SHELL ECHO 27 28 # scripts directory 29 WDIR=${HOME}/scripts 30 LOGDIR=${WDIR}/log 31 [ -d "${HOME}/scripts" ] || mkdir -p ${WDIR} 32 [ -d "${WDIR}/log" ] || mkdir -p ${WDIR}/log 33 LSNRNAMEFILE=${LOGDIR}/listener_name.txt 34 35 # output listener username 36 # USERID=$(ps -ef|grep tnslsnr |grep -v grep | awk '{print $1}' |sort -u) 37 # output listener name to the file 38 ps -ef|grep tnslsnr |grep -v grep | awk '{print $(NF-1)}' > ${LSNRNAMEFILE} 39 # ps -ef|grep tnslsnr |perl -lane 'print $F[-2] if/bin/tnslsnr/' |awk '{$0=tolower($0);print $0}'|sort -u 40 41 # Get datetime format is yyyymmddhh24missss(201606150000) 42 dtime=$(perl -e "use POSIX qw(strftime); print strftime '%Y%m%d' , localtime( time()-3600*24*30) ")0000 43 CLR_TIME=$(perl -e "use POSIX qw(strftime); print strftime '%Y%m%d' , localtime( time()-3600*24*180) ")0000 44 OPT_TIME=$(date +%Y%m%d%H%M) 45 46 # clean options 47 for LSN in $(cat "${LSNRNAMEFILE}" | awk '{ $0=tolower($0);print $0 }'); do 48 ${ECHO} " ---------------------------- Begin ---------------------------- ">> ${OPT_LOGFILE} 49 lsnrctl status ${LSN} > ${LOGDIR}/${LSN}.stat 50 # 监听配置文件 51 LSNRORAFILE=$(grep -i 'Listener Parameter File' ${LOGDIR}/${LSN}.stat |awk ' {print $NF}') 52 # output listener log directory 53 STR=$(grep -i 'Listener Log File' ${LOGDIR}/${LSN}.stat |awk ' {print $NF}') 54 # 监听日志文件[listener_name.log]所在目录 55 LSNR_DIR=${STR%'alert'*}trace 56 # 监听日志文件[log*.xml]所在目录 57 LSNXML_DIR=${STR%/*} 58 # 监听日志文件绝对路径 59 LSNLOGFILE=${LSNR_DIR}/${LSN}.log 60 # 监听日志文件大小 61 LSN_LOGFILE_SIZE=$(du -k ${LSNLOGFILE} | awk '{print $1}') 62 63 # clean operations logs 64 OPT_LOGFILE=${LOGDIR}/clean_${LSN}_${OPT_TIME}.log 65 66 # if xml directory exits,then delete 30 days agos xml files 67 if [ -d "${LSNXML_DIR}" ]; then 68 # change into xml directory 69 cd ${LSNXML_DIR} || exit 1 70 touch -t ${dtime} today 71 # recode deleting files 72 find ${LSNXML_DIR} -type f ! -newer today |xargs ls -ltr |grep 'xml$' >> ${OPT_LOGFILE} 73 # delete xml file actions 74 find ${LSNXML_DIR} -type f ! -newer today |grep 'xml$' |xargs -n1000 rm -f 75 fi 76 77 # if listener.log file exits,then backup and clear them 78 # if [ `du -sk ${LSNR_DIR}/trace` eq 1048576 && -f "${LSNLOGFILE}" ] 79 if [[ -f "${LSNLOGFILE}" ]] && [[ "${LSN_LOGFILE_SIZE}" -gt "1048576" ]]; then 80 ${ECHO} " -------The size of ${LSNLOGFILE} is: ${LSN_LOGFILE_SIZE}'K' ------- ">> ${OPT_LOGFILE} 81 cd ${LSNR_DIR} || exit 1 82 #如果存在监听配置文件,且有设置ADMIN_RESTRICTIONS,则OFF再进行mv的操作 83 if [[ -f "${LSNRORAFILE}" ]]; then 84 # 回退安全加固参数 85 grep -i "ADMIN_RESTRICTIONS_${LSN}" ${LSNRORAFILE} 86 ADMINSTAT=$? 87 if [[ "${ADMINSTAT}" = "0" ]]; then 88 perl -i.${OPT_TIME}.1 -pe "s/ADMIN_RESTRICTIONS_${LSN}=ON/ADMIN_RESTRICTIONS_${LSN}=OFF/ig" "${LSNRORAFILE}" 89 ${ECHO} ' ------- reload begin ------- '>> ${OPT_LOGFILE} 90 lsnrctl << EOFRELOAD 91 set CURRENT_LISTENER ${LSN} 92 reload 93 status 94 exit 95 EOFRELOAD 96 ${ECHO} ' ------- reload END ------- '>> ${OPT_LOGFILE} 97 fi 98 fi 99 100 #关闭监听的日志输出 101 ${ECHO} ' ------- set logfile off ------- '>> ${OPT_LOGFILE} 102 lsnrctl << EOFOFF >> ${OPT_LOGFILE} 103 set CURRENT_LISTENER ${LSN} 104 set log_status off 105 status 106 exit 107 EOFOFF 108 ${ECHO} ' ------- set logfile off END ------- '>> ${OPT_LOGFILE} 109 110 #确认监听状态是否log_status已off,off则进行move操作 111 lsnrctl status ${LSN}|grep ${LSNLOGFILE} 112 if [[ "$?" != "0" ]] ; then 113 # 备份并压缩监听日志文件 114 [[ -f "${LSNLOGFILE}" ]] && mv ${LSNLOGFILE} ${LSNLOGFILE}.${OPT_TIME} && gzip -f ${LSNLOGFILE}.${OPT_TIME} && ${ECHO} " ------- command: mv ${LSNLOGFILE} ${LSNLOGFILE}.${OPT_TIME} gzip -f ${LSNLOGFILE}.${OPT_TIME} ------- " >> ${OPT_LOGFILE} 115 fi 116 117 #开启监听日志的输出 118 ${ECHO} ' ------- set logfile on ------- '>> ${OPT_LOGFILE} 119 lsnrctl << EOFON >> ${OPT_LOGFILE} 120 set CURRENT_LISTENER ${LSN} 121 set log_status on 122 status 123 exit 124 EOFON 125 ${ECHO} ' ------- set logfile on END ------- '>> ${OPT_LOGFILE} 126 127 # 安全加固参数 128 # grep -i "ADMIN_RESTRICTIONS_${LSN}" ${LSNRORAFILE} 129 if [[ "${ADMINSTAT}" = "0" ]]; then 130 perl -i.${OPT_TIME}.2 -pe "s/ADMIN_RESTRICTIONS_${LSN}=OFF/ADMIN_RESTRICTIONS_${LSN}=ON/ig" "${LSNRORAFILE}" 131 ${ECHO} ' ------- reload begin ------- '>> ${OPT_LOGFILE} 132 lsnrctl << EOFRELOAD 133 set CURRENT_LISTENER ${LSN} 134 reload 135 status 136 exit 137 EOFRELOAD 138 ${ECHO} ' ------- reload END ------- '>> ${OPT_LOGFILE} 139 fi 140 141 # 清理历史备份文件 142 touch -t ${CLR_TIME} cleansfile 143 ${ECHO} ' ------- Deleting histoty compress file before 180 days ago. ------- '>> ${OPT_LOGFILE} 144 find ${LSNR_DIR} -type f ! -newer cleansfile |xargs ls -ltr |grep '.gz$' >> ${OPT_LOGFILE} 145 find ${LSNR_DIR} -type f ! -newer cleansfile |grep '.gz$' |xargs -n100 rm -f 146 fi 147 ${ECHO} " ---------------------------- Finish ---------------------------- ">> ${OPT_LOGFILE} 148 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/1@//192.168.130.99:1521/risenet)
六、oracle 11G 的监听器默认开启了ADR特性,客户端连接信息记录客户端2种日志格式(xml 和 listener_name.log),占用大量的空间,通常只需一种日志即可满足日常维护需求。下面通过关闭其ADR特性的方式检查空间占用
1. 在sqlnet.ora文件中增加 DIAG_ADR_ENABLED=off 2. 在监听器文件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 3. reload or start 监听器,使得配置生效 4. 日志路径可通过命令获取 lsnrctl status|grep 'Listener Log File'