这里 “Oracle网络”,并不是指TCP/IP这种网络知识,而是指Oracle自己定义的一套逻辑和概念,它们控制着客户端与数据库的连接。
1、Oracle 网络中的概念
listener:
listener是独立于实例的Oracle服务器端进程,专门用于接受客户端连接。
每个客户端,在服务器端对应一个“服务进程”,客户端首次连接时,不是直接连接“服务进程”,而是先连接listener,listener再为其分配或创建一个“服务进程”,然后客户端再直接和服务进程通讯(客户端连上“服务进程”后,关闭listener,客户端仍能正常查询)。
实例启动不会自动启动listener,listener也可以在实例关闭时启动,互相独立。
如果只启动了实例,没有启动listener,只能本地访问数据库(sqlplus / as sysdba )。
listener还是一个防火墙,通过配置文件listener.ora,设置监听端口和允许接入的客户端IP。
客户端连接使用TCP协议,如果没有listener.ora配置文件,仍可以启动默认listener,默认配置是:监听端口1521,只允许本机连入。
启动/停止监听器:lsnrctl start/stop
查看状态:lsnrctl status
注意,listener.ora是服务器端listener的配置文件,默认位置$ORACLE_HOME/network/admin/listener.ora,内容是忽略大小写的。
listener.ora 中配置 listener的例子:
listener配置的三大要素:网络协议,允许的主机IP,监听端口号
PAASLSR =
(DESCRIPTION_LIST =
(DESCRIPTION =
# (HOST=0.0.0.0)(PORT=1521) 表示监听所有IP的客户端,监听端口是1521
(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))
(ADDRESS=(PROTOCOL=ipc)(KEY=PNPKEY))
)
)
service的概念:
对于非CDB,一个数据库实例就是一个service。对于CDB,根容器和每个PDB都对应一个service。注意,一个service并不是指服务端的一个“服务进程”,而是指一个实例(可能包括许多进程)。客户端连接listener时,要指定IP、PORT和service的名字,listener将请求分发给service代表的实例,然后实例分配一个“服务进程”给客户端,service的名字是dbca建库时设置的Global Database Name。
service需要告诉listener自己的存在,这个过程叫做注册。
动态注册和静态注册:
动态注册:
listener启动后,运行的实例每隔一段时间会告诉listener自己的存在,不需要任何配置,这个称为动态注册。
也可以 alter system register; 手动触发注册。
可以通过 lsnrctl status 查看已经注册的服务,客户端连接时指定这个服务名即可。
静态注册:
还可以将service信息写到listener.ora中,这样listener启动时,从配置文件获知service的信息,这叫做静态注册。
这两种注册方式的唯一区别是:对于静态注册,即使实例没有启动,客户端也可以连入,然后启动实例。
静态注册的例子:
PAASLSR =
(DESCRIPTION_LIST =
(DESCRIPTION =
# (HOST=0.0.0.0)(PORT=1521) 表示监听所有IP的客户端,监听端口是1521
(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))
(ADDRESS=(PROTOCOL=ipc)(KEY=PNPKEY))
)
)
# PAASLSR对应上面的监听器配置名
SID_LIST_PAASLSR=
(SID_LIST=
# 每个SID_DESC定义一个服务
(SID_DESC=
# GLOBAL_DBNAME就是服务名
(GLOBAL_DBNAME=CDB.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
(SID_DESC=
(GLOBAL_DBNAME=pdb1.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
)
GLOBAL_DBNAME就是客户端连接用的service名称,由创建数据库时的名称和pfile里的db_domain组成,也就是dbca建库时填写的Global Database Name。
多个listener:
还可以在 listener.ora 中定义其它 listener,例如,定义监听端口为1522的listener,名称为LSNR1:
LSNR1 =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1522))
)
)
启动和停止时用命令:
lsnrctl start lsnr1
lsnrctl stop lsnr1
lsnrctl status lsnr1
如果想动态注册到lsnr1,则需要设置参数local_listener,静态注册则不需要,例如:
alter system set local_listener='(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1522))';
静态注册到listener lsnr1:
SID_LIST_LSNR1=
(SID_LIST=
(SID_DESC=
(GLOBAL_DBNAME=CDB.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
(SID_DESC=
(GLOBAL_DBNAME=pdb1.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
)
服务端也可以同时开启多个listener,监听多个端口,这些listener可以路由到一个或多个实例,例如,下面配置了两个listener,分别监听1521和1522端口,并且(静态)注册了同样的服务:
PAASLSR =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521))
(ADDRESS=(PROTOCOL=ipc)(KEY=PNPKEY))
)
)
LSNR1 =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1522))
)
)
SID_LIST_PAASLSR=
(SID_LIST=
(SID_DESC=
(GLOBAL_DBNAME=CDB.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
(SID_DESC=
(GLOBAL_DBNAME=pdb1.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
)
# SID_LIST_LSNR1对应上面LSNR1
# 表示这个注册到名称为LSNR1的listener
SID_LIST_LSNR1=
(SID_LIST=
(SID_DESC=
(GLOBAL_DBNAME=CDB.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
(SID_DESC=
(GLOBAL_DBNAME=pdb1.io)
(SID_NAME=CDB)
(ORACLE_HOME=/u01/app/oracle/product/19.3.0/dbhome_1)
)
)
可以执行下面命令同时启动它们:
lsnrctl start
lsnrctl start lsnr1
2、客户端连接
客户端(sqlplus)连接服务器时,有两种方式:
Easy Connect :
这种方式客户端不需要tnsnames.ora配置文件,所有连接信息,都在连接字符串里,例如:
# 注意以sysdba权限远程登录,需要服务端有(创建)密码文件,见体系结构部分
sqlplus sys/123456@192.168.139.141:1521/CDB.io as sysdba
sqlplus pdb1admin/123456@192.168.139.141:1521/pdb1.io
注意这里CDB.io或pdb1.io是Global Database Name而不是SID,这个在创建数据库时有设置。
Local Naming:
这种方式,客户端需要配置tnsnames.ora文件,文件内容由一个个连接配置组成,每个连接配置有一个配置名,配置指定listener所在服务的IP、端口、服务名,sqlplus连接时,指定用户名、密码和配置名,例如:
sqlplus schema1/123456@pdb1
其中pdb1就是tnsnames.ora文件里的配置名(忽略大小写),例如:
cdb =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.32.148.156)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = CDB.io)
)
)
pdb1 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 172.32.148.156)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = pdb1.io)
)
)
其中(SERVICE_NAME = pdb1.io) 的pdb1.io,对应服务端 listener.ora里的 (GLOBAL_DBNAME= pdb1.io) ,tnsnames.ora需要注意四大要素:网络协议、IP、端口、服务名。