跨机房(跨防火墙)数据库访问超时问题分析TNS-12535、TNS-00505
背景说明和问题描述
自从数据库迁移到其它机房后,应用经常反馈有会话超时的问题(而且会出现900多秒才返回超时报错的现象),虽然量很小,但也影响用户感知
而未割接的数据库访问一直无超时现象
两者的区别:异机房访问跨防火墙,同机房访问不涉及防火墙
异常日志
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 2020-02-04T20:43:28.882055+08:00 Fatal NI connect error 12170. VERSION INFORMATION: TNS for Linux: Version 12.2.0.1.0 - Production Oracle Bequeath NT Protocol Adapter for Linux: Version 12.2.0.1.0 - Production TCP/IP NT Protocol Adapter for Linux: Version 12.2.0.1.0 - Production Time : 04-FEB-2020 20:43:28 Tracing not turned on . Tns error struct: ns main err code: 12535 TNS-12535: TNS:operation timed out ns secondary err code: 12560 nt main err code: 505 TNS-00505: Operation timed out nt secondary err code: 110 nt OS err code: 0 Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=*.*.*.*)(PORT=37852)) |
分析过程
先说下思路,涉及数据库出现访问超时,无非考虑的几点
1、网络异常(防火墙层面)
2、数据库负载高,建立会话响应超时(数据库层面)
3、主机会话异常(主机层面)
防火墙层面:
因为是迁移到异机房后出现的超时问题,流量经过防火墙是唯一的变数,所以第一时间想到的是防火墙问题导致
从目前架构看,跨机房后涉及两种型号的防火墙:华为防火墙,华三防火墙
防火墙层对建立的会话有过期策略,华为防火墙默认20分钟,华三防火墙默认1小时
也就是说,如果业务在访问数据库时,如果会话停留超过20分钟无流量交互,防火墙会主动将会话断开
这是防火墙层面的超时机制,通过修改防火墙会话过期策略,可以解决超时问题
此类会话在主机层面是以非正常TCP策略断开,属于异常会话,而主机有针对异常会话的回收机制
主机层面:
主机层面提供针对会话存活的探测机制:tcp_keepalive
1 2 3 4 | [root ~] # sysctl -a | grep keepalive(默认配置) net.ipv4.tcp_keepalive_time = 7200 #代表每隔7200s发起ack探测 net.ipv4.tcp_keepalive_probes = 9 #探测频次,如果超过9次对方无ack响应,第10次发送rst net.ipv4.tcp_keepalive_intvl = 75 #每次相隔75s发送一次ack |
当防火墙将会话过期后,主机在2个小时后会按时发起ack探测包
而在防火墙会话没有过期时,假设net.ipv4.tcp_keepalive_time=960,则主机每16分钟发送一次ack探测包,防火墙会话过期倒计时会重置
针对两种结果的得出的结论:
1)如果net.ipv4.tcp_keepalive_time >= 防火墙会话过期时间,会话会正常被防火墙过期,keepalive探测发现后,会正常中断进程,回收资源
2)如果net.ipv4.tcp_keepalive_time < 防火墙会话过期时间,keepalive机制正常发送ack探测包,防火墙会话过期倒计时会被重置,会话一直处于active状态
数据库层面:
提取问题时间点的awr和主机性能报告分析,并未出现负载高峰
涉及监听链接超时设置虽然默认值,但从应用反馈的情况来看,业务是dblink访问的(长链接),跟此参数影响不大
从上面防火墙和主机分析来看,是由于防火墙会话过期导致,针对这种情况,Oracle数据库也提供了一种会话存活探测机制:DCD(dead connection detection)
具体设置方法:
1 2 | vi $ORACLE_HOME /network/admin/sqlnet .ora SQLNET.EXPIRE_TIME=10 <br> #代表的意思是会话处于inactive 10分钟后,服务端会发送10字节的小包到客户端,进行存活探测,如果无响应,则会话关闭,资源回收 |
需要注意的是:
1)如果SQLNET.EXPIRE_TIME设置时间小于防火墙会话超时限制,防火墙会话会一直保持active状态,不会发生过期
2)如果SQLNET.EXPIRE_TIME设置时间大于防火墙会话超时限制,防火墙会话过期就会正常发生,此时数据库实例会探测到会话异常,并且正常关闭链接,回收资源
针对应用经常出现900多s才返回超时报错日志的问题:
该问题是由系统参数tcp_retries2的设置决定的
该参数表示在丢弃激活(已建立通讯状况)的TCP连接之前﹐需要进行多少次重试。默认值为15
该参数的值是根据RTO值来的,一般响应超时时间为retransmit N次=(N+1)th RTO,默认15次,需要924s
在系统优化时,该参数建议设置为5
总结
为了避免数据库跨防火墙访问出现超时,可以做如下优化:
1、调整防火墙会话过期策略,明确来源IP,目标IP,目标端口,避免范围过大,在线会话过多,影响防火墙性能
2、主机keepalive合理设置,如果防火墙会话过期策略不能调整,建议设置小于防火墙会话超时时间
3、数据库启用DCD策略,设置值小于防火墙会话超时时间
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?