SCAN是Oracle RAC专用的DNS轮询名称,需客户端11.2+网络栈、正确tnsnames.ora(含LOAD_BALANCE=on)、sqlnet.ora配置NAME.DIRECTORY_PATH=(TNSNAMES,EZCONNECT),且DNS返回A记录而非CNAME。
SCAN 是什么,为什么单实例客户端连不上
scan(single client access name)本质是一个 oracle rac 专用的 dns 轮询名称,背后绑定 3 个 vip(默认),但客户端**不直接解析或连接这些 vip**,而是靠 oracle 客户端的 sqlnet.ora 和 tnsnames.ora 配合服务端 scan listener 协同工作。单实例客户端连不上 scan,90% 是因为没配对两件事:sqlnet.allowed_logon_version_server 兼容性、以及客户端没启用 scan 感知能力。
- Oracle 12c 及以后,默认
SQLNET.ALLOWED_LOGON_VERSION_SERVER=12a,会拒绝 11g 客户端(如 Instant Client 11.2)用 SCAN 连接 —— 错误现象是ORA-12537: TNS:connection closed或静默失败 - 客户端必须使用 Oracle 11.2+ 的网络栈(哪怕只是 Instant Client),老版本(如 10.2)根本不识别 SCAN 名称,会报
ORA-12154: TNS:could not resolve the connect identifier specified - DNS 必须返回至少一个 A 记录(不能只配 CNAME),且不能配置成 round-robin 的负载均衡器(如 F5、Nginx)反代 —— SCAN 要求客户端自己做轮询,中间设备会破坏连接亲和性
tnsnames.ora 里 SCAN 的标准写法
不是随便写个主机名就能走 SCAN;必须用 ADDRESS_LIST + 多个 ADDRESS + LOAD_BALANCE=on,否则 Oracle 客户端不会触发 SCAN 的连接分发逻辑。漏掉 LOAD_BALANCE=on 或写成 LOAD_BALANCE=yes(无效值)都会退化为直连第一个地址。
- 正确写法:
ORCL_SCAN = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = myscan.example.com)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = orcl) ) (LOAD_BALANCE = on) ) -
HOST值必须是 DNS 可解析的 SCAN 名称(如myscan.example.com),不能填 IP;也不能填集群任意节点的 VIP 或公网 IP - 不要加
FAILOVER=on到 SCAN 条目里——SCAN 本身已内置故障转移,额外加反而干扰行为 - 如果数据库启用了 GDS(Global Data Services),
SERVICE_NAME应换成GLOBAL_NAME,否则可能路由到错误副本
客户端 sqlnet.ora 关键配置项
光有 tnsnames.ora 不够,sqlnet.ora 控制底层连接策略。最常被忽略的是 NAME.DIRECTORY_PATH 和 SQLNET.EXPIRE_TIME:前者决定客户端用什么方式解析 SCAN 名,后者影响空闲连接在防火墙/NAT 后的存活表现。
-
NAME.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)是底线;如果删了TNSNAMES,即使 tnsnames.ora 存在,SCAN 条目也不会被加载 - Oracle 12.2+ 客户端默认开启
SQLNET.EXPIRE_TIME=0(禁用死连接检测),但在有状态防火墙环境下,建议显式设为10(单位分钟),避免连接中途断开 - 若客户端跑在容器或云主机上,DNS 缓存可能过长(如 systemd-resolved 默认缓存 30s),导致 SCAN VIP 切换后无法及时感知 —— 可临时加
USE_DEDICATED_SERVER=off强制走共享模式验证是否真连上了 SCAN
验证 SCAN 是否真正生效
别只看 tnsping 通不通,它只测监听器响应,不验证连接是否走 SCAN 分发路径。真实判断要看客户端实际建立的 TCP 连接目标 IP,以及服务端 lsnrctl services 输出中该连接对应的 listener 名。
- Linux/macOS 下抓包:
tcpdump -i any host <scan_ip> and port 1521</scan_ip>,执行一次sqlplus /@ORCL_SCAN,确认连接发起方确实连向某个 SCAN VIP(如192.168.10.101),而非某个节点 VIP - 连上后查视图:
SELECT inst_id, service_name FROM gv$session WHERE sid = (SELECT sid FROM v$mystat WHERE rownum = 1);—— 如果service_name是你定义的 service(如orcl),且inst_id在多个节点间跳变,说明负载均衡起了作用 - RAC 节点上运行:
lsnrctl services LISTENER_SCAN1(注意是 SCAN listener,不是 node listener),查看输出里是否有你的 service 注册进来;没有则检查数据库参数remote_listener是否指向了正确的 SCAN:1521
SCAN 的负载均衡粒度是「新连接」,不是语句或事务;连接建立后就绑定到固定实例,这点和应用层 LB 完全不同。最容易被忽略的是 DNS TTL 设置 —— 若设成 86400(24 小时),节点故障后 SCAN VIP 切换,客户端可能长达一天都连不到新地址。










