ITPub博客

首页 > 数据库 > 数据库开发技术 > Sybase ASE案例-使用DB Tunnel无法正常连接Cloud中的ASE目标数据库

Sybase ASE案例-使用DB Tunnel无法正常连接Cloud中的ASE目标数据库

原创 数据库开发技术 作者:数据库杂记 时间:2023-06-11 06:20:00 0 删除 编辑


前言

这是一个真实的案例。发生在ASE SP1603 PL12及以后的版本。而所有的老版本1603 PL11以及以前的版本都不受影响,都能正常连接。

首先介绍一下DB Tunnel,它基本上只用于Cloud环境下对Sybase ASE(以下简称ASE)的连接。主要是因为所有连接都是在于SSL的,而且网络是隔离的。不能直接访问主机。所以,SAP提供了NEO SDK的一套纯Java工具,建立起一个SSL通道,充当DB的SSL proxy的功能。

分析

这个现象确实比较诡异,上边说的无法连接,也不完全准确。从测试人员的测试来看,它是在多次尝试的连接测试中,偶尔有那么一次两次连接可以生效。更准确的描述是:JDBC client connection to ASE DB 1603PL12 or later via NEO SDK tunnel often fails

使用我前边开发的Java命令行工具(ase.isql-1.0.2-16.0.03.12.30318-spring-boot.jar),可以非常简单的模拟出来。在建立db tunnel以后,

neo.bat open-db-tunnel -h <cloudhost> -a <account> -u <user> -i <dbinstance>

连接测试连接的测试脚本bug12.bat,内容如下:

:ASE1603PL12
echo "sleep 2 seconds"
PING -n 2 127.0.0.1>nul

echo SELECT @@version | java  -jar .\target\ase.isql-1.0.2-16.0.03.12.30318-spring-boot.jar -S "jdbc:sybase:Tds:localhost:30015/{DBNAME}?ENABLE_SSL=true&SSL_TRUST_ALL_CERTS=true" -U USER -P password

for /l %%a in (0,0,1) do call :ASE1603PL12 %%a

从中间JDBC的相关log,能得到大量的:

2023-02-10 17:15:22 Connection time : 3633 Error: JZ00M: Login timed out. Check that your database server is running on the host and port number you specified. Also, check the database server for other conditions (such as a full tempdb) that might be causing it to hang.

2023-02-10 17:15:26 Connection time : 3031 Error: JZ00M: Login timed out. Check that your database server is running on the host and port number you specified. Also, check the database server for other conditions (such as a full tempdb) that might be causing it to hang.

2023-02-10 17:15:30 Connection time : 3032 Error: JZ00M: Login timed out. Check that your database server is running on the host and port number you specified. Also, check the database server for other conditions (such as a full tempdb) that might be causing it to hang.

2023-02-10 17:15:34 Connection time : 3030 Error: JZ00M: Login timed out. Check that your database server is running on the host and port number you specified. Also, check the database server for other conditions (such as a full tempdb) that might be causing it to hang.

下边只列出了一部分版本之间的测试结果:

而SDK Tunnel的log在连接失败(HANG)的时候,最后会报下边的错:

2022-10-17 16:08:30,381 ERROR [forwardingproxy-5-3] com.sap.core.connectivity.tunnel.core.handlers.AbstractErrorHandler: Input/output exception in forwarding-proxy; Closing channel: [id: 0xc4abfcd8, L:/10.180.0.88:30015 - R:/10.47.147.239:63378]
java.io.IOException: An existing connection was forcibly closed by the remote host
  at sun.nio.ch.SocketDispatcher.read0(Native Method) ~[?:1.8.0_341]
  at sun.nio.ch.SocketDispatcher.read(Unknown Source) ~[?:1.8.0_341]
  at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source) ~[?:1.8.0_341]
  at sun.nio.ch.IOUtil.read(Unknown Source) ~[?:1.8.0_341]
  at sun.nio.ch.SocketChannelImpl.read(Unknown Source) ~[?:1.8.0_341]
  at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:253) ~[netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132) ~[netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350) ~[netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.68.Final.jar:4.1.68.Final]
  at java.lang.Thread.run(Unknown Source) [?:1.8.0_341]
2022-10-17 16:10:17,511 WARN  [forwardingproxy-5-4] com.sap.core.persistence.commands.tunnel.connection.DbTunnelManager$2: Tunnel reported an internal error, state of tunnel not clear
2022-10-17 16:10:17,526 WARN  [forwardingproxy-5-4] com.sap.core.persistence.commands.tunnel.connection.DbTunnelManager$2: Received unexpected error code 300 (connection closed by backend) from tunnel

经常相当长一段时间的比对分析,发现db-tunnel的行为基本一直没有发生什么变化。 一直是将packet尽量拆分成512。通过分析JDBC的TDS包,发现:一个541字节的packet会拆成两段:(512 + 29)

    0x0160:  0b45 c3d3 ab67 1481 2349 3919 0574 6046  .E...g..#I9..t`F
    0x0170:  eb5b d35e 6dd1 43cd 792f 2ec7 245c be87  .[.^m.C.y/..$\..
    0x0180:  2b2c 71c3 98f8 4cb7 f309 707f e387 f4db  +,q...L...p.....
    0x0190:  9728 a9a6 2364 0f40 974d 6d37 2419 9554  .(..#d.@.Mm7$..T
    0x01a0:  428d 8f05 8b6b 16ca b977 1616 25f4 bc44  B....k...w..%..D
    0x01b0:  27b5 e303 e7ec 705e e0c9 04cf 9a24 367a  '.....p^.....$6z
    0x01c0:  98b5 29bb 2d64 7eb5 2e35 3fde d049 d93e  ..).-d~..5?..I.>
    0x01d0:  7c97 e4f9 ad44 2155 d7b8 6b1e bad4 d9e5  |....D!U..k.....
    0x01e0:  8a70 6884 a068 e5f1 1c62 1f15 941c 0e47  .ph..h...b.....G
    0x01f0:  a3e2 4b46 8f30 d8f3 b538 bf86 86b5 75d6  ..KF.0...8....u.
    0x0200:  9bff a9be c738 5d2c 783f 06b3 1b28 480d  .....8],x?...(H.
    0x0210:  3a31 7489 983d 62ad f443 0cf2 23ff 43fd  :1t..=b..C..#.C.
    0x0220:  b8d9 c24b 0ae1 f4f1 770b 919c 45ba dc3a  ...K....w...E..:
    0x0230:  dc44 c8b6 6db8 77af cf09 be25 9dfd ee9f  .D..m.w....%....          NB: split is here:     ".D.."  <--->. "m.w....%...." 
    0x0240:  db0b 12ed 856c e1f4 e7fc e2ad 509f 6537  .....l......P.e7
    0x0250:  8c                                       .
17:16:12.873751 IP localhost.30015 > localhost.53812: Flags [.], ack 1127, win 6362, options [nop,nop,TS val 1044068216 ecr 3119475487], length 0
    0x0000:  4500 0034 0000 4000 4006 0000 7f00 0001  E..4..@.@.......
    0x0010:  7f00 0001 753f d234 de91 e88a 8ae8 9aa7  ....u?.4........
    0x0020:  8010 18da fe28 0000 0101 080a 3e3b 3778  .....(......>;7x
    0x0030:  b9ef 6b1f                                ..k.

因为整个过程以及相当长一段时间以内db tunnel的处理都没有发生变化。所以,问题应该极大可能出在ASE Server端对接收和处理SSL packet的方式上。

可是,这个问题非常特殊,它只发生在使用dbtunnel 的情况下。如果抛开这一层,ASE和jdbc之间以及isql之间都能良好的工作。于是在哪一个层次去尝试解决问题也成了关键。

这里不给最终的解决方案,一种到目前可行的解决方法是修改NEO SDK中的有关SSL通信处理的部分,让它不对>512的packet进行拆分。在proxy forward的选项里加入:

channel.config().setOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(1024,2048,65536));

也就是说让最小拆分的packet大小为1024.而不是512. 似乎这样修改以后,整个连接处理就变得正常了。

小结:

Cloud环境下如果出了底层的问题,处理起来将比非Cloud环境复杂的多。非Cloud环境,你至少可以手动搭建一个,快速模拟重现,然后层层DEBUG,而Cloud环境如果要完全搭建,从资源上和各个角度来看,有时候很难复现出一模一样的环境。

上边这个案例,就涉及到最终解决问题的方式,因为它本质上不能算是DB Tunnel的问题,它的行为一直没有发生变化。但是ASE自某一个版本以后(PL12及以后),对于SSL包大小的处理方式似乎变了,导致以前的proxy处理方式不可用。但是因为这个修复可能要调整的地方实在太大,代价也会非常大。因此,在哪个地方解决问题就需要协调了。

因为使用dbtunnel主要是DevOps或者部分DBA日常维护需要,因为,临时性的,可以将NEO SDK (dbtunnel),打一个简单的patch,能够用上就好。

其实,从这中间也可以总结出一个教训,无论多复杂的软件,要保证最终的良好质量,就得有足够充分的测试用例。上边这个案例,应该是缺少一个db tunnel不断连接ASE的测试用例。它不是说每次都不能连。有时候也能连上(包大小小于512字节的情况下)。测试用例充分 的话,很容易就能重现出来。问题虽然不严重(毕竟不影响日常业务运行),但是确实值得引起重视。



原文作者:数据库杂记;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-04-22

  • 博文量
    276
  • 访问量
    160360