什么是监听

Oracle监听器(Listener)是一个监听客户端请求的网络服务,它在数据库实例与客户端之间架起了一座桥梁。监听器的主要功能如下:

  • 接收客户端发送的连接请求。

  • 将连接请求转发给相应的数据库实例。

  • 监控连接状态,确保连接的稳定性和可靠性。

监听器通过监听指定的端口号,等待客户端的连接请求。当请求到来时,监听器会根据配置信息,将请求转发给对应的数据库实例。

什么要设计监听

为什么要设计这种实例与监听分开的架构呢?这涉及到一种核心的架构哲学“解耦”。这种分离带来了许多关键优势,我们来举个实际案例,如果此时你发现数据库有可能被人黑了,那你首先要做什么呢?向 mysql 和 postgresql 你是不是要先关掉实例,那 Oracle 就不一样了,你只需要关掉监听就行了,然后清除历史会话就行了,不必关实例。

像现在很多的微服务架构设计也是如此,所有的请求都会先经过 gateway 网关,再由 gateway 网关去请求对应的服务,这样的好处是什么呢?我们只需要对外开放 gateway 网关的端口即可,不必把所有的服务的端口都开放。

监听的三个配置文件

oracle的监听服务主要涉及三个文件:服务端文件listener.ora、客户端文件tnsname.ora、sqlnet.ora。三者的默认位置都在:$ORACLE_HOME/network/admin/下。

tnsname.ora服务的简单名称(连接标识符),解析为连接描述符以标识网络位置和服务标识。

sqlnet.ora配置文件是可选的,可能存在于服务端或客户端,它设置的各种默认值会影响所有客户机和服务器。

listener.ora驻留在服务器上的进程,其职责是侦听传入的客户端连接请求并管理和分配到相应的数据库实例服务上。

我们来分析这一段tnsnames.ora配置的相关信息

ORCL =  #网络服务名,可随便命名
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.25)(PORT = 1521)) #远程服务器的IP和地址
    (CONNECT_DATA =
      (SERVER = DEDICATED)  #连接模式
      (SERVICE_NAME = orcl) #远程数据库的SID
    )
  )

我们在使用 PLSQL 连接数据库的时候,就可以不用输入一连串的 IP 和 SID,可以直接下拉选择我们要连接的数据库实例。

PL/SQL 的 tnsnames.ora 的位置可通过工具栏找到 帮助->支持信息来进行查看。

打开后会看到PL/SQL的版本信息及其它的配置信息,往下拉会有一项“TNS File”,这就是你安装的PL/SQL的tnsnames.ora文件路径,修改完成后需要重启PL/SQL。

专用模式(DEDICATED) 和 共享模式(SHARE)

专用服务器(DEDICATED):

一个客户端连接对应一个服务器进程,这个服务器进程会在会话生存期中专门连接服务,对于每个会话,都会出现一个新的专用服务器,会话与专用服务器之间存在一对一的映射,服务器进程没被任何另外的客户共享。 专用服务器体系结构不支持HTTP和IIOP客户,仅支持TTC客户。

一般我们以oracle默认的专用服务器方式就行了,没必要使用共享服务器模式。

共享服务器(SHARE):

1)、也叫做多线程服务器模式

多个用户进程使用同一个服务器进程。

多个客户端连接对应一个服务器进程,服务器端用一个进程调度器来管理。

1、它必须使用net services.

2、必须配置tnsnames.ora。

 2)、适合场景

它适合用于高并发,事务量小的情况,如果这个时候采用了共享模式,可以大大减少由于高度并发对于ORACLE服务器的资源消耗。

共享服务器体系:客户进程最终与一个调度程序连接,PMON进程注册了调度程序的位置和负荷,

使监听器能够提交到负荷最小的调度程序。一个调度程序能并发地支持多重的客户连接。

共享服务器具有以下一些缺点:

1)共享服务器的代码路径比专用服务器长,所以它天生就比专用服务器慢。

2)存在人为死锁的可能,因为它是串行的,只要一个连接阻塞,则该服务器进程上的所有用户都被阻塞,并且极可能死锁。

3)存在独占事务的可能,因为如果一个会话的事务运行时间过长,它独占共享资源,其它用户只能等待,而专用服务器,每个客户端是一个会话。

4)共享服务器模式限制了某些数据库特性,例如:不能单独启动和关闭实例,不能进行介质恢复,不能使用Log Miner,并且SQL_TRACE没有意义(因为是共享而不是当前会话的)。

MTS减少的内存实际上是专用服务器模式下每个用户连接到操作系统进程所需的内存,但它却使用SGA的Large_Pool来分配UGA,拆东墙补西墙,所减少的内存是很少的。

如果用户会话的连接和断开很频繁,数据库进程的创建和删除的开销会非常大,这种情况最好采用共享服务器模式(否则,应该使用连接池技术)。如果客户端一次连接终身使用(会话生命周期内),使用共享服务器模式的意义不大。因为大部分时间,一个会话就连接到一个服务器进程,无法共享服务器进程。

如何配置和关闭共享模式

共享模式相关参数说明

shared_servers :指定了当instance 启动的时候 shared server process 启动的数量,不要将这个参数设置得太大,否则启动数据库instance 的时候 就会花更多时间,Oracle启动过后会根据负载来动态调整shared_servers。如果为0,表示数据库没有启动共享服务模式。 这个参数是配置shared server 必须的,而且只有这个参数是必须的。

max_shared_servers:ORACLE在同一个时刻最大能够使用的 shared server process.不要将这个参数设置小于 shared_servers,如果动态修改shared_servers大于max_shared_servers,ORACLE会覆盖max_shared_servers的值,此时你需要修改max_shared_servers.同时也不能大于processes。这个参数是为了给占用很大资源操作而设的(批处理),为了预留一些process 给DBA任务(rman备份),

shared_server_sesions: 指定了总共允许的的shared server session 的数量。如果设置了这个参数,那么就不要将这个值超过sessions,如果没有设置这个值,那么只要还有空闲的session,就可以被使用。设置这个值是为专有连接预留 user sessions.

dispatchers:配置 dispatcher process .如果不设置这个参数,只要设置了shared_servers ,oracle 也会自动设置一个基于tcp协议的dispatcher。还需要查看操作系统支持一个dispatcher能处理多少个connections

-- 1. 连接数据库
sqlplus / as sysdba

-- 2. 动态设置参数
ALTER SYSTEM SET dispatchers='(PROTOCOL=TCP)(DISPATCHERS=2)' SCOPE=BOTH;
ALTER SYSTEM SET shared_servers=5 SCOPE=BOTH;
ALTER SYSTEM SET max_shared_servers=20 SCOPE=BOTH;

-- 3. 验证调度器
SQL> SELECT name, status FROM v$dispatcher;

NAME      STATUS
-------- ---------
D000      WAIT
D001      WAIT

-- 4. 验证共享服务器进程
SQL> SELECT name, status, requests FROM v$shared_server;

NAME      STATUS   REQUESTS
-------- --------- --------
S000      WAIT(COMMON)      0
S001      WAIT(COMMON)      0
S002      WAIT(COMMON)      0
S003      WAIT(COMMON)      0
S004      WAIT(COMMON)      0

此时再登录就用了共享模式。要注意tnsname.ora 里的配置,如果有配置了专用模式,优先还是用专用模式。

如何切换专用模式

-- 将共享服务器数量设置为0即可
ALTER SYSTEM SET shared_servers=0 SCOPE=BOTH;

-- 同时也可以减少或禁用调度器
ALTER SYSTEM SET dispatchers='' SCOPE=BOTH;

关闭之后,如果tnsname.ora 里的配置参数还是 shared,则登录就会报错 ORA-12520:TNS:listener could not find available handlerfor requested type of server

如何判断oracle是共享模式还是专用模式

#查看哪些进程在服务
select * from v$shared_server_monitor;
#查看会话
SELECT username,status FROM v$session where server='SHARED';
#查看队列
select * from v$queue;
select * from v$circuit;
#查看配置参数
SQL> show parameter shared_server
SQL> show parameter dispatchers

静态监听 VS 动态监听

静态监听

静态注册指实例启动时读取listener.ora配置文件,将实例和服务注册到监听程序。无论何时启动一个数据库,默认都有两条信息注册到监听器中:实例和服务。

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.31.25)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

动态监听

动态注册不需要显示的配置listener.ora文件,实例启动的时候,PMON进程根据instance_name,service_name参数将实例和服务动态注册到listerer中。如果没有设定instance_name,将使用db_name初始化参数值。如果没有设定service_names,将拼接db_name和db_domain参数值来注册监听。

两者监听的区别

静态监听和动态监听的区别主要在于数据库实例服务信息被注册到监听器的方式。

静态监听是通过配置文件,也就是说,不管实例有没有启动成功,都会注册到监听里面。

动态监听则是据库实例启动时,其进程监控进程(PMON) 会主动向监听器“报到”。

这样看的话,貌似动态比静态要好,但我们要考虑某个场景。如果此时数据库实例处于 nomount 或者 mount 状态,此时你想远程连接到实例,如果没有配置静态监听,是不是就没办法连接上了。

监听日志

监听日志没啥好说的,之所以挑出来说说,是因为笔者之前遇到过一个事故跟监听日志有关系。

$ lsnrctl status
Listener Log File         /u01/app/oracle/diag/tnslsnr/oracle19c/listener/alert/log.xml

当时 Oracle 是部署在一台 window server2008 上,早上有客户反馈业务异常,看应用报错是连接不上数据库,当时检查了数据库实例和监听状态都是正常,重启也不管用,telnet 是通的,但是连不上就很奇怪了。

当时经过一个高人指点,让我去检查监听日志的大小有没有超过 4G,看了下,果然超过了,清除了下就正常了。这个 bug 好像就只会出现在 window,linux 好像就不会,不过我们也尽量把监听日志大小保留到 1~2G,不宜过大。

遇到这种情况,我们要怎么处理呢?

lsnrctl set log_status off
注意:此操作仅停止日志文件的写入,不影响数据库的运行!

cat /dev/null > 监听文件

直接删除或者重命名

lsnrctl set log_status on 
启动后如果没有该文件,Oracle会重新创建

ORACLE黑名单

SQLNET.ORA文件中添加下面的语句,即可实现黑名单效果

TCP.VALIDNODE_CHECKING = YES
TCP.EXCLUDED_NODES= (IP1,IP2)

监听重载lsnrctl reload ,让黑名单生效

Lsnctl reload 不影响当前正在连接的会话 只影响reload发生以后产生的新的连接

参考链接https://www.cnblogs.com/aozhejin/p/15991719.html