如何在客户端仍处于连接状态时更新 DataSnap 服务器?
我们使用有状态的 DataSnap 服务器来执行某些业务逻辑任务,并提供客户端数据集数据。
如果我们必须更新服务器来修改业务规则,我们将新版本复制到新的空文件夹中并注册它(取决于 Delphi 版本,只需启动或运行 TRegSvr 实用程序)。
即使旧服务器实例正在运行,我们也可以执行此操作。 但是,注册新版本后,所有新的客户端连接仍将使用当前运行的(旧)服务器实例。 所有客户端必须首先断开连接,然后新服务器将用于下一个客户端。
有没有办法在注册后立即将所有新客户端连接定向到新服务器?
(我知道新的或更改的方法签名也需要更改并重新启动客户端,但这个问题是关于不影响接口的内部修改)
我们正在使用套接字连接,并且所有客户端共享相同的服务器应用程序(只有一个)申请窗口已打开)。 早期,我们使用了远程数据模块的不同配置,这导致每个客户端有一个应用程序窗口。 也许这可以是一个解决方案? (因为每个新客户端都会启动当前注册的可执行文件)
更新:Delphi XE 是否为(更新服务器的)“热部署”提供一些支持? 我们目前使用 Delphi 2009,但如果 XE 能够更轻松地实现“热部署”,我们将升级到 XE。
We use stateful DataSnap servers for some business logic tasks and also to provide clientdataset data.
If we have to update the server to modify a business rule, we copy the new version into a new empty folder and register it (depending on the Delphi version, just by launching or by running the TRegSvr utility).
We can do this even while the old server instance is running. However, after registering the new version, all new client connections will still use the currently running (old) server instance. All clients have to disconnect first, then the new server will be used for the next clients.
Is there a way to direct all new client connections to the new server, immediately after registering?
(I know that new or changed method signatures will also require a change and restart of the clients but this question is about internal modifications which do not affect the interface)
We are using Socket connections, and all clients share the same server application (only one application window is open). In the early days we have used a different configuration of the remote datamodule which resulted in one app window per client. Maybe this could be a solution? (because every new client will launch the currently registered executable)
Update: does Delphi XE offer some support for 'hot deployment' (of updated servers)? We use Delphi 2009 at the moment but would upgrade to XE if it offers easier implementation of 'hot deployment'.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以将您的应用程序服务器分成两个新服务器,一个是一个简单的代理对象,将所有方法(并且可选地包含状态信息,如果有)重定向到实际实现您的业务逻辑的第二个服务器。 您还需要在代理服务器中实现“静默重新连接”功能,以便在您决定随时更换业务应用程序服务器时不打扰连接的客户端。 我自己以前从未做过这样的设计,但希望这个想法很清楚
you could separate your appserver into 2 new servers, one being a simple proxy object redirecting all methods (and optionally containing state info if any) to the second one actually implementing your business logic. you also need to implement "silent reconnect" feature within your proxy server in order not to disturb connected clients if you decide to replace business appserver any time you want. never did such design myself before but hope the idea is clear
您是否尝试过重命名当前服务器并将新服务器以正确的名称放置在同一位置(而不是更改注册表位置)。 我之前已经成功地为 COM 库完成了此操作。 我不确定它是否适用于远程启动规则,因为它可能会寻找要附加的现有实例而不是全新的服务器。
这可能有点黑客,但您可以让客户端调用服务器上的方法来指示有更新的版本可用。 这将允许它执行任何必要的清理,因此它最终不会同时与现有服务器实例和新服务器实例通信。
Have you tried renaming the current server and placing the new in the same location with the correct name (versus changing the registry location). I have done this for COM libraries before with success. I am not sure if it would apply to remote launch rules through as it may look for an existing instance to attach to instead of a completely fresh server.
It may be a bit hackish but you would have the client call a method on the server indicating that a newer version is available. This would allow it to perform any necessary cleanup so it doesn't end up talking to both the existing server instance and new server instance at the same time.
这个问题可能没有一个简单的答案,我怀疑您将不得不修改客户端。 我能想到的最简单的解决方案是在服务器上有一个标志(某个常用方法上的属性或输出参数),客户端定期检查该标志,告诉客户端断开连接并重新连接(称为 ImBeingRetired 之类的东西)。
在某些情况下也可以为 datasnap 编写回调(尽管我从未这样做过)。 这将允许服务器通知客户端它应该重新启动或重新连接。
我能想到的最后一个选项(尚未提及)是使客户端/服务器无状态,以便每次客户端需要它连接的东西时,得到它想要的东西然后断开连接。
不幸的是,这些选项都不是您想要的问题答案,但可能会给您一些想法。
There is probably not a simple answer to this question, and I suspect that you will have to modify the client. The simplest solution I can think of is to have a flag (a property or an out parameter on some commonly called method) on the server that the client checks periodically that tells the client to disconnect and reconnect (called something like ImBeingRetired).
It's also possible to write callbacks under certain circumstances for datasnap (although I've never done this). This would allow the server to inform the client that it should restart or reconnect.
The last option I can think of (that hasn't already been mentioned) would be to make the client/server stateless, so that every time the client wants something it connects, gets what it wants then disconnects.
Unfortunately none of these options are the answer you want to your question, but might give you some ideas.
使用 DNS 可能是最简单的,但映射传播到客户端需要时间(如果客户端位于 LAN 之外),而且两个客户端可能会看到不同的结果。 有些防火墙具有IP地址映射功能,可以映射公共IP地址和内部IP地址。 理想的方法是使用负载均衡器并将其配置为 50:50,当您要升级时将其更改为 100:0,但这需要花钱。 一个更便宜的替代方案是在 BSD 虚拟机上运行软件负载平衡器,但它可能需要一些工作。
编辑:我的意思是说会话变量,而不是会话。 你说服务器是有状态的。 如果它包含一些使用会话变量的业务逻辑,则需要将其存储在外部,以便在切换期间重新连接时保留。 实际的 DataSnap 会话将会丢失,因此当您在升级过程中关闭 Web Box 1 时,客户端将收到 Web Box 1 的“Session {some-uuid} is not found”错误,并且它将重新连接到 Web Box 2。
您还可以使用 3 个 IP 地址(1 个公共 IP 地址和 2 个私有 IP 地址),以便客户端始终看到 1 个地址,这是更好的方法。
Using DNS is probably easiest, but it takes time for the mapping to propagate to the client (if the client is outside your LAN) and also two clients may see different results. Some firewalls have IP address mapping feature that you can map public IP address and internal IP address. The ideal way is to use load balancer and configure it to 50:50 and change it to 100:0 when you want to do upgrade, but it costs money. A cheaper alternative is to run software load balancer on BSD vm, but it probably requires some work.
Edit: What I meant to say is session variables, not session. You said the server is stateful. If it contains some business logic that uses session variable, it needs to get stored externally to be preserved across reconnection during switch over. Actual DataSnap session will be lost, so when you shutdown web box 1 during upgrade, the client will get "Session {some-uuid} is not found" error by web box 1, and it will reconnect to web box 2.
Also you could use 3 IP addresses (1 public and 2 private) so the client always sees 1 address , which is better method.
我通过使用一个保存我的“数据版本”的特定表来完成类似的操作。 每次我更新服务器或更改系统范围的全局设置时,我都会增加此字段。 当客户端启动时,它总是检查该值,并在任何事务/查询之前再次检查。 如果该值与我第一次开始时不同,那么我需要执行重新初始化逻辑,其中可以轻松地包括重新登录到更新的服务器。
我使用 IIS 发布我的应用程序服务器,因此将更改的数据将是应用程序服务器的路径。 我保留了旧的可用,以响应任何正在进行的现有交易。 最终,一旦我知道不再有客户端连接到该版本,这些就会被删除。
如果您也记录客户端最后连接的服务器(因此会知道),您可以轻松地知道要保留哪些版本。
I have done something similar by having a specific table which held my "data version". Each time I would update the server or change a system wide global setting, I would increment this field. When a client starts it always checks this value, and will check again before any transactions/queries. If the value was ever different from when I first started, then I needed to go through my re-initialization logic, which could easily include a re-login to an updated server.
I was using IIS to publish my app servers, so the data that would change would be the path to the app server. I kept the old ones available, to respond to any existing transactions that were in play. Eventually these would be removed once I knew there were no more client connections to that version.
You could easily handle knowing what versions to keep around if you log what server the client last connected too (and therefore would know about).
有一个有趣的解决方案
: Andreano Lanusse 在 DataSnap 2010 中实现故障转移和负载平衡
如何将 DataSnap 客户端连接定向到各种 DS 服务器?
For newer versions (Delphi 2010 and up), there is an interesting solution
Implementing Failover and Load Balancing in DataSnap 2010 by Andreano Lanusse
How to direct DataSnap client connections to various DS Servers?