【问题标题】:Which mechanism keeps an Oracle session alive on the server?哪种机制使服务器上的 Oracle 会话保持活动状态?
【发布时间】:2015-04-07 08:31:22
【问题描述】:

我有一个通过 Qt QSqlDatabase 接口连接到 Oracle 数据库的 C++ 应用程序。主应用程序建立并使用与数据库的连接,同时为不相关的其他 porpuses 启动子进程。明确一点:子进程不使用任何与数据库相关的东西。

现在的问题是:如果主进程以不寻常的方式终止(它崩溃或被用户通过任务管理器杀死),我可以看到 Oracle 服务器上的数据库会话保持活动状态并且确实无论如何都不会超时。绝对可重现,但是,在我手动终止子进程后,会话立即被取消。

由于那些悬空的孤立会话会导致一些问题(最简单的蜂鸣器达到服务器上的最大会话数),我真的希望尽快关闭所有会话。

我现在的问题是:仅仅因为不相关的子进程仍然存在而使服务器上的会话保持活跃的机制是什么?我如何控制这种行为,即告诉 oracle 客户端在主应用程序进程死亡时断开任何会话?

提前致谢!

【问题讨论】:

  • 子进程可以继承操作系统句柄。使用 Process Explorer 到inspect the file handles,查看是否有与 Oracle Server 相关的。发布生成子进程的代码,并验证 bInheritHandles 是否为 FALSE。
  • PS:有一种方法可以从 OCI 库中获取文件(套接字)句柄,但它需要大量的黑魔法。
  • @sashoalm:感谢您的提示,但不幸的是,这似乎不是原因。我通过QProcess 启动子进程。我刚刚步入Qt源码,QProcess以bInheritHandles == false ({ sizeof(SECURITY_ATTRIBUTES), 0, false })开始进程
  • 如果杀死子进程释放会话,它仍然必须是关于它的。你检查过孩子的把手吗?有什么可疑之处吗?会话连接的本质是什么 - 它是套接字还是其他东西?
  • 在你 fork 一个新进程之前和之后简单地比较 netstat 在双方(客户端和服务器)的输出。文件句柄要么是从父级继承的,要么与 QSqlDatabase 健康检查(如果有)有关。

标签: c++ oracle qt session


【解决方案1】:

更新 https://bugreports.qt.io/browse/QTBUG-9350https://bugreports.qt.io/browse/QTBUG-4465

在 Windows 上,子进程继承套接字和文件描述符,即使 inheritFileDescriptors 设置为 false

这个bug好像在QT5中修复了


Oracle 线程上关于该问题的讨论:

https://community.oracle.com/thread/1048626

TL;DR; oracle 服务器不“知道”客户端已经消失。

一些解决方案: 1.有终止连接检测功能: http://docs.oracle.com/cd/B19306_01/network.102/b14213/sqlnet.htm#sthref474

2.如果您使用 QOCI 驱动程序,我的建议是尝试实现“连接池”。或者您可以使用支持连接池的 ODBC。

【讨论】:

  • 感谢您的想法。但是,我认为这不是我的问题:服务器 确实 知道客户端消失了 - 如果我通过任务管理器终止子进程,服务器上的数据库会话将立即关闭。因此,我的问题是为什么子进程首先要使会话保持活动状态。
  • 这里可能有 2 件事: 1. 服务器“知道”:如果会话处于活动状态,首先将等待完成,然后将继续回滚未提交的工作,并且状态将在 v$session 中被 KILLED。 2. 服务器不知道:可能是不同类型的杀戮(如在 UNIX 系统上,您有 ABORT、KILL、TERM 等信号),如果这些信号被捕获以及之后如何处理它们,则可能会引发其他复杂情况。
  • 即使是所有只有 SELECT 的查询,终止会话的任务也可能需要很长时间。
  • 但问题似乎又不是会话的清理。可以观察到两个事实:(1)只要子进程存在,服务器上的会话也存在(甚至数天)。 (2) 如果子进程被杀死,服务器的会话也会关闭。
  • 所以我的问题仍然存在:即使子进程没有任何与数据库相关的东西,为什么它还要在数据库服务器上保持会话。子进程从未打开或与数据库连接有任何关系。
【解决方案2】:

看起来主进程没有成功终止,并在关闭数据库连接之前在终结代码的某个位置等待子进程终止。
从另一边,子进程异常终止引发的异常情况成功传播到父进程,父进程启动终结进程并关闭与 Oracle 的连接。

所以第一个建议是检查子进程是否正确响应 kill() 和 terminate() 调用,甚至父进程也会在异常终止的情况下尝试终止子进程。

【讨论】:

  • 不,在这种情况下父进程完全终止(通过 procexp 仔细检查)。子进程在异常崩溃的情况下不能被父进程终止,因为它突然停止执行(没有异常可以处理但立即终止)。
  • 在 Windows 中可以通过 Job Objects 自动终止子进程,就像在 this question 中讨论的那样。如果主进程从任务管理的应用程序选项卡中终止,则可以处理这种情况并按照here 的讨论执行清理。
  • 自动终止子进程会很棒。但是,作业对象似乎没有完成它的工作......我按照您的链接中描述的方式实现了它; SetInformationJobObject 和 AssignProcessToJobObject 返回 true 但如果我终止父进程,子进程将继续运行...
猜你喜欢
  • 2020-03-11
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 2012-04-10
  • 2012-02-06
  • 1970-01-01
  • 2018-11-26
  • 1970-01-01
相关资源
最近更新 更多