【问题标题】:How can I update a DataSnap server while clients are still connected?如何在客户端仍然连接时更新 DataSnap 服务器?
【发布时间】:2009-06-03 13:09:12
【问题描述】:

我们将有状态的 DataSnap 服务器用于一些业务逻辑任务,并提供客户端数据集数据。

如果我们必须更新服务器来修改业务规则,我们将新版本复制到一个新的空文件夹并注册(取决于 Delphi 版本,只需启动或运行 TRegSvr 实用程序即可)。

即使旧服务器实例正在运行,我们也可以这样做。但是,注册新版本后,所有新的客户端连接仍将使用当前正在运行的(旧)服务器实例。所有客户端都必须先断开连接,然后新服务器将用于下一个客户端。

有没有办法在注册后立即将所有新客户端连接定向到新服务器

(我知道新的或更改的方法签名也需要更改并重新启动客户端,但这个问题是关于不影响接口的内部修改)

我们使用的是 Socket 连接,所有客户端共享同一个服务器应用程序(只打开一个应用程序窗口)。在早期,我们使用了远程数据模块的不同配置,这导致每个客户端有一个应用程序窗口。也许这可能是一个解决方案? (因为每个新客户端都会启动当前注册的可执行文件)

更新:Delphi XE 是否为“热部署”(更新的服务器)提供一些支持?我们目前使用 Delphi 2009,但如果它提供更轻松的“热部署”实施,我们将升级到 XE。

【问题讨论】:

  • 有趣的问题。答案取决于您的服务器实例是如何创建和管理的,以及它们是有状态的。您使用哪种交通工具?
  • 您使用的是哪个 Delphi/DataSnap 版本? datasnap/D2009 有很多内部变化。解决您的问题需要对 2009 年之前/之后的服务器/客户端有不同的看法......总之,这需要您让事情发生,因为两者都没有为这种情况提供开箱即用的解决方案。
  • 想知道您是否仍然对此感兴趣...因为您没有回答我之前的问题。 :)
  • 抱歉,我忘记添加评论以通知您我上次的编辑:我们目前使用 Delphi 2009,但如果它提供更轻松的“热部署”实施,将升级到 XE。

标签: delphi delphi-2009 delphi-2010 datasnap delphi-xe


【解决方案1】:

您可以将您的应用服务器分成 2 个新服务器,一个是一个简单的代理对象,将所有方法(如果有的话还可以包含状态信息)重定向到第二个实际实现您的业务逻辑的服务器。如果您决定随时更换业务应用服务器,您还需要在代理服务器中实现“静默重新连接”功能,以免打扰连接的客户端。我自己以前从未做过这样的设计,但希望这个想法很清楚

【讨论】:

  • +1 表示该方法。我过去曾为 ISAPI 库这样做过。
  • 但是它会引入另一层重复工作,方法签名的每次更改都需要在三个地方完成。程序员的时间很贵;)
  • 好吧,如果您的 tlb 有许多方法经常更改签名,那么是的,这将需要额外的繁琐工作。我的应用服务器通常只有两个额外的方法(连接和断开连接)除了标准的 IAppServer 接口,所以这里没有大问题:)
  • 另外,您可以通过将业务逻辑放置在由 AppServer 对象加载的包 (bpl) 中来避免引入使用代理服务器实现的另一层间接。只需设置一些标志(例如创建一些外部文件或以您希望的任何其他方式发出信号)以指示应用服务器必须卸载当前加载的包并重新加载新的包,然后就可以了
  • 也许改变方法签名应该是昂贵的。 ;-) 接口的最初想法是它们应该是不可变的合约。这意味着一旦发布接口,您通常无法更改方法签名。但是你可以继承一个新接口并在那里声明你的新方法,保持旧接口兼容。
【解决方案2】:

您是否尝试过重命名当前服务器并将新服务器以正确的名称放在相同的位置(而不是更改注册表位置)。我之前成功地为 COM 库做过这个。我不确定它是否适用于远程启动规则,因为它可能会寻找现有实例来附加到而不是全新的服务器。

这可能有点骇人听闻,但您可以让客户端调用服务器上的一个方法,指示有更新的版本可用。这将允许它执行任何必要的清理,因此它最终不会同时与现有服务器实例和新服务器实例通信。

【讨论】:

  • 重命名在所有客户端断开之前不会生效,它需要一个维护窗口首先踢出所有用户,以便旧服务器终止。即使这可以自动化,用户仍然不得不中断他们的工作(也许他们正处于午休时间并且没有看到“请关闭应用程序”消息)。我们也不能强制退出客户,因为他们知道我们的地址:)
【解决方案3】:

这个问题可能没有一个简单的答案,我怀疑您将不得不修改客户端。我能想到的最简单的解决方案是在客户端定期检查的服务器上有一个标志(一个属性或一些通常称为方法的输出参数),告诉客户端断开连接并重新连接(称为 ImBeingRetired 之类的东西)。

在某些情况下也可以为 datasnap 编写回调(尽管我从未这样做过)。这将允许服务器通知客户端它应该重新启动或重新连接。

我能想到的最后一个选项(还没有提到)是让客户端/服务器无状态,这样每次客户端想要连接的东西时,得到它想要的东西然后断开连接。

很遗憾,这些选项都不是您想要的问题的答案,但可能会给您一些想法。

【讨论】:

  • 回调是一个很好的建议,只要我们使用有状态的连接。我同意无状态方法会更容易处理。
【解决方案4】:
  1. (可选)设置 vmware vSphere、ESX,或查找已有的托管服务。
  2. 将会话变量存储在 db 中。
  3. 准备 2 个具有 2 个不同 IP 地址的网络盒并部署您的东西。
  4. 设置 DNS、防火墙、负载平衡器或 BSD 虚拟机,以便名称“example.com”解析为网络框 1。
  5. 将新版本部署到 web box 2。
  6. 使用您选择的任何路由方法切换到 web box 2。
  7. 如果一切正常,请将新版本部署到 web box 1。

使用 DNS 可能是最简单的,但映射传播到客户端需要时间(如果客户端在您的 LAN 之外),而且两个客户端可能会看到不同的结果。一些防火墙具有 IP 地址映射功能,您可以映射公共 IP 地址和内部 IP 地址。理想的方法是使用负载均衡器并将其配置为 50:50,并在您想要升级时将其更改为 100:0,但它需要花钱。一种更便宜的替代方法是在 BSD vm 上运行软件负载平衡器,但它可能需要一些工作。

编辑:我的意思是会话变量,而不是会话。你说服务器是有状态的。如果它包含一些使用会话变量的业务逻辑,则需要将其存储在外部,以便在切换期间在重新连接时保留。实际的 DataSnap 会话将丢失,因此当您在升级过程中关闭 web box 1 时,客户端将收到 web box 1 的“Session {some-uuid} is not found”错误,它将重新连接到 web box 2。 您也可以使用 3 个 IP 地址(1 个公共和 2 个私有),这样客户端总是看到 1 个地址,这是更好的方法。

【讨论】:

  • 会话是否必须存储在数据库中?一旦与 DataSnap 服务器的 TCP/IP 连接启动并运行,即使服务器 DNS 条目发生更改,客户端也会继续使用它。
【解决方案5】:

我通过一个包含我的“数据版本”的特定表做了类似的事情。每次我更新服务器或更改系统范围的全局设置时,我都会增加这个字段。当客户端启动时,它总是检查这个值,并在任何事务/查询之前再次检查。如果该值与我刚开始时的值不同,那么我需要通过我的重新初始化逻辑,这可以很容易地包括重新登录到更新的服务器。

我使用 IIS 发布我的应用服务器,因此会更改的数据将是应用服务器的路径。我保留了旧的可用,以响应任何正在进行的现有交易。最终,一旦我知道该版本不再有客户端连接,这些将被删除。

如果您也记录客户端上次连接的服务器(因此会知道),您可以轻松地知道要保留哪些版本。

【讨论】:

  • 服务器应用程序本身在客户端仍然连接时无法替换 - 所以我猜客户端将首先断开连接然后进入“暂停”模式足够长的时间以同时替换服务器应用程序?如果客户端在数据版本表更改后立即连接,它不会看到版本更改。也许“直到 hh.nn 的维护模式”从服务器返回信息是一个选项 - 但是这个方法需要经常调用,或者它必须作为回调/服务器推送方法来实现。
【解决方案6】:

对于较新的版本(Delphi 2010 及更高版本),有一个有趣的解决方案

  • 对于使用 HTTP 传输的系统:

Implementing Failover and Load Balancing in DataSnap 2010 by Andreano Lanusse

  • 以及有关 TCP/IP 传输的相关问题:

How to direct DataSnap client connections to various DS Servers?

【讨论】:

    猜你喜欢
    • 2019-04-24
    • 2013-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 1970-01-01
    • 2016-07-06
    相关资源
    最近更新 更多