You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在集群环境中使用.NET实现服务的离线/在线切换

集群环境下服务离线/在线切换的.NET/C#实现方案

在集群环境中直接停止服务会触发故障转移,因此需要通过集群资源管理API主动操作服务的在线状态,而非直接终止进程。以下是针对Windows Server Failover Cluster(WSFC)场景的具体实现方案:

核心思路

  1. 利用集群管理API将服务对应的集群资源设置为离线(Offline),集群会将此判定为主动操作而非故障,不会触发故障转移。
  2. 资源离线时,集群会正常停止服务进程,此时在服务内部的停止逻辑中添加衍生进程树的终止代码,确保所有子进程被清理。
  3. 需要重新上线时,通过集群API将资源设置为在线(Online),集群会重新启动服务。

一、集群资源离线/在线操作代码

通过WMI调用WSFC的管理接口,实现资源状态的切换:

1. 将集群资源离线

using System;
using System.Management;
using System.Threading;

public static void TakeClusterResourceOffline(string clusterName, string resourceName, int timeoutMilliseconds)
{
    var managementScope = new ManagementScope($@"\\{clusterName}\root\mscluster");
    var resourceQuery = new ObjectQuery($"SELECT * FROM MSCluster_Resource WHERE Name = '{resourceName}'");

    using (var searcher = new ManagementObjectSearcher(managementScope, resourceQuery))
    {
        foreach (ManagementObject resource in searcher.Get())
        {
            int currentState = (int)resource["State"];
            // 仅当资源处于在线状态(State=2)时执行离线操作
            if (currentState == 2)
            {
                resource.InvokeMethod("Offline", null);

                // 等待资源切换为离线状态(State=3)
                DateTime timeout = DateTime.Now.AddMilliseconds(timeoutMilliseconds);
                while (DateTime.Now < timeout)
                {
                    resource.Get(); // 刷新资源状态
                    currentState = (int)resource["State"];
                    if (currentState == 3)
                        break;
                    Thread.Sleep(100);
                }

                if (currentState != 3)
                {
                    throw new TimeoutException($"资源 {resourceName} 未能在超时时间内完成离线操作");
                }
            }
        }
    }
}

2. 将集群资源在线

public static void BringClusterResourceOnline(string clusterName, string resourceName, int timeoutMilliseconds)
{
    var managementScope = new ManagementScope($@"\\{clusterName}\root\mscluster");
    var resourceQuery = new ObjectQuery($"SELECT * FROM MSCluster_Resource WHERE Name = '{resourceName}'");

    using (var searcher = new ManagementObjectSearcher(managementScope, resourceQuery))
    {
        foreach (ManagementObject resource in searcher.Get())
        {
            int currentState = (int)resource["State"];
            // 仅当资源处于离线状态(State=3)时执行在线操作
            if (currentState == 3)
            {
                resource.InvokeMethod("Online", null);

                // 等待资源切换为在线状态(State=2)
                DateTime timeout = DateTime.Now.AddMilliseconds(timeoutMilliseconds);
                while (DateTime.Now < timeout)
                {
                    resource.Get(); // 刷新资源状态
                    currentState = (int)resource["State"];
                    if (currentState == 2)
                        break;
                    Thread.Sleep(100);
                }

                if (currentState != 2)
                {
                    throw new TimeoutException($"资源 {resourceName} 未能在超时时间内完成上线操作");
                }
            }
        }
    }
}

二、衍生服务进程终止逻辑

在Windows服务的OnStop方法中添加递归终止进程树的逻辑,确保服务停止时清理所有衍生进程:

using System.Diagnostics;
using System.Management;

protected override void OnStop()
{
    // 终止当前服务的所有衍生进程
    KillProcessTree(Process.GetCurrentProcess().Id);
    base.OnStop();
}

private void KillProcessTree(int parentProcessId)
{
    // 查询所有子进程
    using (var searcher = new ManagementObjectSearcher(
        $"SELECT * FROM Win32_Process WHERE ParentProcessId = {parentProcessId}"))
    {
        foreach (ManagementObject processObj in searcher.Get())
        {
            int childProcessId = (int)(uint)processObj["ProcessId"];
            // 递归终止子进程的子进程
            KillProcessTree(childProcessId);
            try
            {
                Process.GetProcessById(childProcessId).Kill();
            }
            catch (System.Exception)
            {
                // 忽略进程已终止的异常
            }
        }
    }
}

关键注意事项

  • 权限要求:执行代码的账户需要具备WSFC集群管理员权限,才能调用集群管理API。
  • 资源名称匹配:代码中的resourceName是集群中注册的服务资源名称,而非Windows服务的名称,需确认两者对应关系。
  • 状态枚举说明:MSCluster_Resource的State字段枚举值:2=在线,3=离线,1=在线中,4=离线中,可根据实际场景调整等待逻辑。
  • 其他集群场景:若使用Kubernetes等容器集群,需改用Kubernetes Client库操作Deployment/StatefulSet的副本状态或节点调度标记,核心逻辑仍是通过集群API主动控制服务状态,避免触发故障转移。

内容的提问来源于stack exchange,提问作者NoBullMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 11:57:48