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

多实例横向扩展Azure AppService的实例间通信方案咨询

多实例Azure AppService缓存同步解决方案

针对你的场景(ASP.NET 4.6 WebApi多实例,静态Azure Tables缓存更新通知),以下几种方案可以实现实例间通信,且符合你"不写入共享存储状态"的要求:

方案一:实例间直接HTTP调用(无需额外服务)

核心思路是让每个实例维护一份当前运行实例的地址列表,当处理POST请求的实例完成数据更新后,遍历列表向所有实例发送缓存更新请求。

实现步骤:

  1. 实例地址注册与维护

    • 在应用启动时,获取当前实例的内部域名(格式为{站点名}.azurewebsites.net),存入全局线程安全集合(如ConcurrentBag<string>)。
    • 添加定时任务(比如用Hangfire或简单的Timer),定期检查实例可用性,移除无法连通的实例地址;同时让每个实例定期向其他实例上报自己的地址,解决扩缩容时新实例无法被旧实例感知的问题。
  2. 触发缓存更新

    • 在处理数据变更的POST接口中,先完成Azure Tables的数据更新,再遍历实例地址列表,向每个实例的缓存更新接口发送HTTP请求。
    • 每个实例提供一个内部接口(如/api/cache/refresh),收到请求后重新加载Azure Tables数据到内存缓存。

代码示例:

// Global.asax 全局实例地址集合
public static ConcurrentBag<string> InstanceAddresses = new ConcurrentBag<string>();

protected void Application_Start()
{
    // 注册当前实例地址
    var siteName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME");
    var instanceUrl = $"https://{siteName}.azurewebsites.net";
    InstanceAddresses.Add(instanceUrl);

    // 启动定时任务,定期同步实例列表(示例用Timer简化)
    var timer = new Timer(UpdateInstanceList, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
}

private void UpdateInstanceList(object state)
{
    // 调用所有已知实例的地址接口,收集最新实例列表
    var newAddresses = new ConcurrentBag<string>();
    foreach (var url in InstanceAddresses)
    {
        try
        {
            using (var client = new HttpClient())
            {
                var response = client.GetAsync($"{url}/api/instances").Result;
                if (response.IsSuccessStatusCode)
                {
                    var addresses = response.Content.ReadAsAsync<List<string>>().Result;
                    foreach (var addr in addresses)
                    {
                        newAddresses.Add(addr);
                    }
                }
            }
        }
        catch
        {
            // 忽略不可用实例
        }
    }
    InstanceAddresses = newAddresses;
}

// 实例地址接口
[HttpGet]
[Route("api/instances")]
public IHttpActionResult GetInstanceAddresses()
{
    var siteName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME");
    var instanceUrl = $"https://{siteName}.azurewebsites.net";
    return Ok(new List<string> { instanceUrl });
}

// 数据变更接口
[HttpPost]
public IHttpActionResult UpdateData(MyDataModel data)
{
    // 1. 更新Azure Tables数据
    UpdateAzureTableData(data);

    // 2. 通知所有实例更新缓存
    foreach (var url in InstanceAddresses)
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.PostAsync($"{url}/api/cache/refresh", null).Wait();
            }
        }
        catch (Exception ex)
        {
            // 记录日志,跳过不可用实例
        }
    }

    return Ok();
}

// 缓存更新接口
[HttpPost]
[Route("api/cache/refresh")]
public IHttpActionResult RefreshCache()
{
    // 重新加载静态表数据到内存
    LoadStaticTablesToCache();
    return Ok();
}

优缺点:

  • ✅ 无需依赖额外Azure服务,成本低
  • ❌ 需要自行维护实例列表,处理扩缩容和实例故障,复杂度略高

方案二:Azure Service Bus主题订阅(可靠、低复杂度)

利用Service Bus的主题-订阅模式,每个实例启动时订阅同一个主题,处理POST请求的实例发送一条缓存更新消息到主题,所有订阅的实例自动收到通知并更新缓存。

实现步骤:

  1. 创建Service Bus主题

    • 在Azure门户创建一个Service Bus命名空间和主题(免费层足够满足每月1-2次的消息量)。
  2. 实例订阅主题

    • 应用启动时,创建一个唯一的订阅(每个实例一个订阅),注册消息处理逻辑:收到消息后刷新缓存。
  3. 发送更新通知

    • 在数据变更的POST接口中,完成Azure Tables更新后,向主题发送一条简单的更新消息。

代码示例:

// Global.asax 订阅Service Bus主题
protected void Application_Start()
{
    var connectionString = "你的Service Bus连接字符串";
    var topicName = "static-cache-update";
    // 每个实例用唯一ID作为订阅名
    var subscriptionName = $"instance-{Guid.NewGuid().ToString("N")}";

    var subscriptionClient = new SubscriptionClient(connectionString, topicName, subscriptionName);
    var handlerOptions = new MessageHandlerOptions(ExceptionHandler)
    {
        MaxConcurrentCalls = 1,
        AutoComplete = true
    };

    // 注册消息处理方法
    subscriptionClient.RegisterMessageHandler(HandleCacheUpdateMessage, handlerOptions);
}

private async Task HandleCacheUpdateMessage(Message message, CancellationToken token)
{
    // 刷新内存缓存
    LoadStaticTablesToCache();
}

private Task ExceptionHandler(ExceptionReceivedEventArgs args)
{
    // 记录异常日志
    return Task.CompletedTask;
}

// 数据变更接口
[HttpPost]
public IHttpActionResult UpdateData(MyDataModel data)
{
    // 1. 更新Azure Tables数据
    UpdateAzureTableData(data);

    // 2. 发送缓存更新消息到Service Bus主题
    var connectionString = "你的Service Bus连接字符串";
    var topicName = "static-cache-update";
    var topicClient = new TopicClient(connectionString, topicName);
    
    var message = new Message(Encoding.UTF8.GetBytes("refresh-cache"));
    topicClient.SendAsync(message).Wait();

    return Ok();
}

优缺点:

  • ✅ 自动处理实例扩缩容,新实例启动后自动订阅即可接收通知
  • ✅ 消息可靠,不会丢失(Service Bus默认持久化)
  • ✅ 每月仅几次消息,成本几乎为0
  • ❌ 需要依赖Azure Service Bus服务(但免费层完全够用)

方案三:Azure SignalR Service(实时性高)

利用Azure SignalR Service实现实例间的实时通信,每个实例作为客户端连接到SignalR服务,处理POST请求的实例向所有客户端发送缓存更新通知。

实现步骤:

  1. 创建Azure SignalR Service

    • 在Azure门户创建SignalR服务,获取连接字符串。
  2. 配置SignalR

    • 在Startup.cs中配置Azure SignalR,创建一个Hub用于发送通知。
  3. 实例连接SignalR

    • 应用启动时,每个实例作为客户端连接到SignalR服务,监听缓存更新事件。
  4. 发送更新通知

    • 在数据变更的POST接口中,通过Hub向所有连接的实例发送更新通知。

代码示例:

// Startup.cs 配置Azure SignalR
public void Configuration(IAppBuilder app)
{
    var signalRConnectionString = "你的SignalR服务连接字符串";
    app.MapAzureSignalR(signalRConnectionString, typeof(CacheHub).FullName);
}

// CacheHub.cs
public class CacheHub : Hub
{
    public async Task SendRefreshNotification()
    {
        await Clients.All.RefreshCache();
    }
}

// Global.asax 连接SignalR并监听事件
protected void Application_Start()
{
    var signalRUrl = "你的SignalR服务端点";
    var connection = new HubConnection(signalRUrl);
    var hubProxy = connection.CreateHubProxy("CacheHub");

    // 监听缓存更新事件
    hubProxy.On("RefreshCache", () => LoadStaticTablesToCache());

    // 启动连接
    connection.Start().Wait();
}

// 数据变更接口
[HttpPost]
public IHttpActionResult UpdateData(MyDataModel data)
{
    // 1. 更新Azure Tables数据
    UpdateAzureTableData(data);

    // 2. 发送更新通知
    var hubContext = GlobalHost.ConnectionManager.GetHubContext<CacheHub>();
    hubContext.Clients.All.RefreshCache();

    return Ok();
}

优缺点:

  • ✅ 实时性高,通知几乎无延迟
  • ✅ 自动处理实例扩缩容
  • ❌ 需要依赖Azure SignalR服务(免费层可满足需求)

方案推荐

如果希望最小化复杂度和维护成本,**方案二(Azure Service Bus主题订阅)**是最优选择:它无需自行维护实例列表,可靠性高,且因消息量极少,几乎没有额外成本。如果完全不想依赖任何额外服务,再考虑方案一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:00:30