SignalR 中的内存使用重新启动 ASP.NET 网络应用程序

Memory usage in SignalR restarts ASP.NET web app

我正在试玩一个用 ASP.NET MVC (C#) 编写的在线游戏,在游戏的 real-time 方面使用 SignalR,并托管为 Azure Web 应用程序。这是一个相当简单的 table-style 游戏,但我 运行 遇到了一个问题,即在高峰负载下(晚上和周末),应用程序使用过多内存,工作进程会自动重新启动。

这是我的 SignalR 连接的粗略代码大纲 class(包括日志记录、空检查等)已删除:

namespace MyApp.Connections
{
    public class GameConnection : PersistentConnection
    {
        protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
        {
            Game game = GameService.GetGameByConnectionId(connectionId);
            List<Task> connectionTasks = new List<Task>();
            Player player = game.GetPlayer(connectionId);

            game.RemovePlayer(player);

            foreach (Player playerToUpdate in game.Players)
            {
                GameActionResponse response = new GameActionResponse(game);
                response.Message = string.Format("Player '{0}' has left the game.", player.Name);
                connectionTasks.Add(Connection.Send(playerToUpdate.ConnectionId, response));
            }          

            return Task.WhenAll(connectionTasks);
        }

        protected override Task OnReceived(IRequest request, string connectionId, string data)
        {
            Game game = GameService.GetGameByConnectionId(connectionId);
            List<Task> connectionTasks = new List<Task>();
            Player actingPlayer = game.GetPlayer(connectionId);

            GameAction action = JsonConvert.DeserializeObject<GameAction>(data);
            GameActionResponse response = new GameActionResponse(game);
            game.ProcessAction(action, actingPlayer, response);

            foreach (Player playerToUpdate in game.Players)
            {
                response.Message = response.Description;
                response.From = actingPlayer.Name;
                connectionTasks.Add(Connection.Send(playerToUpdate.ConnectionId, response));
            }

            return Task.WhenAll(connectionTasks);
        }
    }
}

基本上,我只是回复消息,使用它们来更改游戏状态(关闭连接 ID 以确定正确的玩家),然后回复新的游戏状态(我的 GameActionResponse class) 给玩家。我不使用 Connection.Broadcast 因为我需要为每个玩家定制响应(尽管上面没有显示该代码)。

我让 Azure 在 运行 负载相当大的情况下给我一个 w3wp.exe 的内存转储,运行 通过 Visual Studio 中的探查器 运行,并且这是结果,按包含大小排序:

这表明 SignalR 或(更有可能)我对它的使用存在问题。我的问题是:我在处理 SignalR 连接和消息的方式上是否做错了什么?

会不会是消息的大小和数量?一个典型的客户端 -> 服务器消息小于 1K(仅包含玩家采取的操作),但服务器 -> 客户端响应消息可以在 5-10K 到 30K 之间的任何地方 "full refresh" 消息。

SignalR 有一个环形缓冲区,用于保存每个信号 的消息。默认情况下,缓冲区大小为 1000 条消息,因此如果您有许多连接的客户端,则会存储大量消息。 (此缓冲区的用途之一是能够发送客户端可能因重新连接而错过的消息)您可以尝试通过更改 DefaultMessageBufferSize property. The minimum size of this buffer is 32 and it is enforced by SignalR 来减少缓冲区(即设置值低于 32 将为您提供 32,如下所示0 会给你一个例外)。您需要尝试使用此值 - 如果您有很多消息并且该值太小,您可能会开始丢失消息。