Warning
이 설명서는 최신 버전의 SignalR용이 아닙니다. ASP.NET Core SignalR을 살펴보세요.
SignalR 성능 카운터는 Azure 웹 역할에서 앱의 성능을 모니터링하는 데 사용됩니다. 카운터는 Microsoft Azure Diagnostics에 의해 캡처됩니다. 독립 실행형 또는 온-프레미스 앱에 사용되는 것과 동일한 도구인 signalr.exe 사용하여 Azure에 SignalR 성능 카운터를 설치합니다. Azure 역할은 일시적이므로 시작 시 SignalR 성능 카운터를 설치하고 등록하도록 앱을 구성합니다.
필수 조건
- Visual Studio 2015 또는 2017
- Visual Studio용 Microsoft Azure SDK 참고 사항: SDK를 설치한 후 컴퓨터를 다시 시작합니다.
- Microsoft Azure 구독: Azure 평가판 계정에 등록하려면 Azure 평가판을 참조 하세요.
SignalR 성능 카운터를 노출하는 Azure Web Role 애플리케이션 만들기
Visual Studio를 엽니다.
Visual Studio에서 파일>새로 만들기>프로젝트를 선택합니다.
새 프로젝트 대화 상자의 왼쪽에서 Visual C#>Cloud 범주를 선택한 다음, Azure Cloud Service 템플릿을 선택합니다. 앱의 이름을 SignalRPerfCounters로 지정하고 확인을 선택합니다.
참고 항목
클라우드 템플릿 범주 또는 Azure Cloud Service 템플릿이 표시되지 않는 경우 Visual Studio 2017용 Azure 개발 워크로드를 설치해야 합니다. 새 프로젝트 대화 상자의 왼쪽 아래에서 Visual Studio 설치 관리자 열기 링크를 선택하여 Visual Studio 설치 관리자 엽니다. Azure 개발 워크로드를 선택한 다음 수정을 선택하여 워크로드 설치를 시작합니다.
새 Microsoft Azure Cloud Service 대화 상자에서 ASP.NET 웹 역할을 선택하고 단추를 선택하여 > 프로젝트에 역할을 추가합니다. 확인을 선택합니다.
새 ASP.NET 웹 애플리케이션 - WebRole1 대화 상자에서 MVC 템플릿을 선택한 다음 확인을 선택합니다.
솔루션 탐색기 WebRole1에서 diagnostics.wadcfgx 파일을 엽니다.
파일의 내용을 다음 구성으로 바꾸고 파일을 저장합니다.
<?xml version="1.0" encoding="utf-8"?> <DiagnosticsConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration"> <PublicConfig> <WadCfg> <DiagnosticMonitorConfiguration overallQuotaInMB="4096"> <DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Error" /> <Logs scheduledTransferPeriod="PT1M" scheduledTransferLogLevelFilter="Error" /> <Directories scheduledTransferPeriod="PT1M"> <IISLogs containerName ="wad-iis-logfiles" /> <FailedRequestLogs containerName ="wad-failedrequestlogs" /> </Directories> <WindowsEventLog scheduledTransferPeriod="PT1M"> <DataSource name="Application!*[System[(Level=1 or Level=2 or Level=3)]]" /> <DataSource name="Windows Azure!*[System[(Level=1 or Level=2 or Level=3 or Level=4)]]" /> </WindowsEventLog> <CrashDumps containerName="wad-crashdumps" dumpType="Mini"> <CrashDumpConfiguration processName="WaIISHost.exe" /> <CrashDumpConfiguration processName="WaWorkerHost.exe" /> <CrashDumpConfiguration processName="w3wp.exe" /> </CrashDumps> <PerformanceCounters scheduledTransferPeriod="PT1M"> <PerformanceCounterConfiguration counterSpecifier="\Memory\Available MBytes" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\ISAPI Extension Requests/sec" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\Web Service(_Total)\Bytes Total/Sec" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Requests/Sec" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\ASP.NET Applications(__Total__)\Errors Total/Sec" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Queued" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\ASP.NET\Requests Rejected" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\Processor(_Total)\% Processor Time" sampleRate="PT3M" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\% Time in GC" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Exceptions(w3wp)\# of Exceps Thrown / sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current logical Threads" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\# of current physical Threads" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Current Queue Length" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR LocksAndThreads(w3wp)\Contention Rate / sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# Bytes in all Heaps" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# GC Handles" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Memory(w3wp)\# of Pinned Objects" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Connected" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Reconnected" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Disconnected" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connections Current" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Received/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Connection Messages Sent/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Received/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Message Bus Messages Received/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Messages Published/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Current" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Subscribers/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Allocated Workers" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Busy Workers" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Message Bus Topics Current" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: All/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Resolution/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Hub Invocation/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Tranport Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Errors: Transport/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Open" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Streams Buffering" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors Total" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Errors/Sec" sampleRate="PT10S" /> <PerformanceCounterConfiguration counterSpecifier="\SignalR(*)\Scaleout Send Queue Length" sampleRate="PT10S" /> </PerformanceCounters> </DiagnosticMonitorConfiguration> </WadCfg> <StorageAccount></StorageAccount> </PublicConfig> <PrivateConfig> <StorageAccount name="" key="" endpoint="" /> </PrivateConfig> <IsEnabled>true</IsEnabled> </DiagnosticsConfiguration>
도구>NuGet 패키지 관리자 패키지 관리자 콘솔을 엽니다. 다음 명령을 입력하여 최신 버전의 SignalR 및 SignalR 유틸리티 패키지를 설치합니다.
install-package microsoft.aspnet.signalr install-package microsoft.aspnet.signalr.utils
시작하거나 재활용할 때 SignalR 성능 카운터를 역할 인스턴스에 설치하도록 앱을 구성합니다. 솔루션 탐색기 WebRole1 프로젝트를 마우스 오른쪽 단추로 클릭하고 새 폴더 추가>를 선택합니다. 새 폴더 시작 이름을 지정합니다.
프로젝트 폴더>/SignalRPerfCounters/packages/Microsoft.AspNet.SignalR.Utils에서 <signalr.exe 파일(Microsoft.AspNet.SignalR.Utils 패키지와 함께 추가됨)을 복사합니다.<이전 단계에서 만든 시작 폴더에 대한 버전>/도구입니다.
솔루션 탐색기 시작 폴더를 마우스 오른쪽 단추로 클릭하고 기존 항목 추가>를 선택합니다. 표시되는 대화 상자에서 signalr.exe 선택하고 추가를 선택합니다.
만든 시작 폴더를 마우스 오른쪽 단추로 클릭합니다. 추가>새 항목을 선택합니다. 일반 노드를 선택하고 텍스트 파일을 선택한 다음 SignalRPerfCounterInstall.cmd 새 항목의 이름을 지정합니다. 이 명령 파일은 SignalR 성능 카운터를 웹 역할에 설치합니다.
Visual Studio에서 SignalRPerfCounterInstall.cmd 파일을 만들면 주 창에서 자동으로 열립니다. 파일의 내용을 다음 스크립트로 바꾼 다음 파일을 저장하고 닫습니다. 이 스크립트는 signalr.exe 실행하여 SignalR 성능 카운터를 역할 인스턴스에 추가합니다.
SET SignalR_LogDir=%~dp0Log\ MKDIR "%SignalR_LogDir%" cd %~dp0 signalr.exe ipc >> "%SignalR_LogDir%SignalR_Log.txt" 2>&1 net localgroup "Performance Monitor Users" "Network Service" /ADD >> "%SignalR_LogDir%NetworkAdd.txt" 2>&1
솔루션 탐색기 signalr.exe 파일을 선택합니다. 파일의 속성에서 복사를 출력 디렉터리로 설정하여 항상 복사합니다.
SignalRPerfCounterInstall.cmd 파일에 대해 이전 단계를 반복합니다.
SignalRPerfCounterInstall.cmd 파일을 마우스 오른쪽 단추로 클릭하고 [시작]을 선택합니다. 표시되는 대화 상자에서 이진 편집기를 선택하고 확인을 선택합니다.
이진 편집기에서 파일에서 선행 바이트를 선택하고 삭제합니다. 파일을 저장 후 닫습니다.
ServiceDefinition.csdef를 열고 서비스가 시작될 때 SignalrPerfCounterInstall.cmd 파일을 실행하는 시작 작업을 추가합니다.
<?xml version="1.0" encoding="utf-8"?> <ServiceDefinition name="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6"> <WebRole name="WebRole1" vmsize="Small"> <Startup> <Task commandLine="Startup\SignalRPerfCounterInstall.cmd" executionContext="elevated" taskType="background" /> </Startup> <Sites> <Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> </WebRole> </ServiceDefinition>
파일 끝에서 jQuery 번들 스크립트를 열고
Views/Shared/_Layout.cshtml
제거합니다.<div class="container body-content"> @RenderBody() <hr /> <footer> <p>© @DateTime.Now.Year - My ASP.NET Application</p> </footer> </div> @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) </body> </html>
서버에서 메서드를 지속적으로 호출
increment
하는 JavaScript 클라이언트를 추가합니다. 콘텐츠를 열고Views/Home/Index.cshtml
다음 코드로 바꿉니다.@{ ViewBag.Title = "Home Page"; } <script src="~/Scripts/jquery-1.10.2.min.js"></script> <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <script src="~/signalr/hubs" type="text/javascript"></script> <div id="body"> <section class="featured"> <div class="content-wrapper"> <p> Hello World! </p> <div style="font-size:large;"> My Counter: <span id="counter"></span> </div> </div> </section> <section class="content-wrapper main-content clear-fix"></section> </div> <script type="text/javascript"> $(document).ready(function () { var hub = $.connection.myHub; hub.client.sendResult = function (x) { console.log('sendResult(' + x + ')'); $("#counter").text(x); window.setTimeout(function () { hub.server.increment(x); }, 1000); }; $.connection.hub.connected = function () {}; $.connection.hub.disconnected = function () {}; $.connection.hub.stateChanged(function (change) { console.log('new State' + change.newState); if (change.newState === $.signalR.connectionState.disconnected) { $.connection.hub.start(); } if (change.newState === $.signalR.connectionState.reconnecting) { console.log('Re-connecting'); } else if (change.newState === $.signalR.connectionState.connected) { console.log('The server is online'); } }); $.connection.hub.error(function (error) { console.log('error ' + error); }); $.connection.hub.logging = true; $.connection.hub.reconnected(function () { console.log('Reconnected'); hub.server.increment(0); }); $.connection.hub.start().done(function () { console.log('hub started'); hub.server.increment(0); }); }); </script>
Hubs라는 WebRole1 프로젝트에 새 폴더를 만듭니다. 솔루션 탐색기 Hubs 폴더를 마우스 오른쪽 단추로 클릭하고 새 항목 추가>를 선택합니다. 새 항목 추가 대화 상자에서 Web>SignalR 범주를 선택한 다음 SignalR Hub 클래스(v2) 항목 템플릿을 선택합니다. 새 허브 MyHub.cs 이름을 지정하고 추가를 선택합니다.
MyHub.cs 주 창에서 자동으로 열립니다. 내용을 다음 코드로 바꾼 다음 파일을 저장하고 닫습니다.
using System.Threading.Tasks; using Microsoft.AspNet.SignalR; namespace WebRole1.Hubs { public class MyHub : Hub { public async Task Increment(int x) { await this.Clients.Caller.sendResult(x + 1); } } }
Crank.exe SignalR 코드베이스와 함께 제공되는 연결 밀도 테스트 도구입니다. Crank에는 영구 연결이 필요하므로 테스트할 때 사용하기 위해 사이트에 하나를 추가합니다. PersistentConnections라는 WebRole1 프로젝트에 새 폴더를 추가합니다. 이 폴더를 마우스 오른쪽 단추로 클릭하고 클래스 추가>를 선택합니다. 새 클래스 파일의 이름을 MyPersistentConnections.cs 추가를 선택합니다.
Visual Studio는 주 창에서 MyPersistentConnections.cs 파일을 엽니다. 내용을 다음 코드로 바꾼 다음 파일을 저장하고 닫습니다.
using System.Threading.Tasks; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Infrastructure; namespace WebRole1.PersistentConnections { public class MyPersistentConnection : PersistentConnection { protected override Task OnReceived(IRequest request, string connectionId, string data) { //Return data to calling user return Connection.Send(connectionId, data); } } }
클래스를
Startup
사용하여 SignalR 개체는 OWIN이 시작될 때 시작됩니다. Startup.cs 열거나 만들고 내용을 다음 코드로 바꿉니다.using Microsoft.Owin; using Owin; using WebRole1.PersistentConnections; // Marks this class for automatic OWIN startup [assembly: OwinStartup(typeof(WebRole1.Startup))] namespace WebRole1 { public partial class Startup { public void Configuration(IAppBuilder app) { ConfigureAuth(app); // Only needed if "No Authentication" was not selected for the project app.MapSignalR(); app.MapSignalR<MyPersistentConnection>("/echo"); } } }
위의 코드에서 특성은 OWIN을
OwinStartup
시작하도록 이 클래스를 표시합니다. 이 메서드는Configuration
SignalR을 시작합니다.F5 키를 눌러 Microsoft Azure 에뮬레이터 애플리케이션을 테스트합니다.
참고 항목
MapSignalR에서 FileLoadException이 발생하는 경우 web.config의 바인딩 리디렉션을 다음으로 변경합니다.
<dependentAssembly> <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-2.0.2.0" newVersion="2.0.0.0" /> </dependentAssembly>
1분 정도 기다립니다. Visual Studio에서 클라우드 탐색기 도구 창을 열고(클라우드 탐색기 보기>) 경로를
(Local)/Storage Accounts/(Development)/Tables
확장합니다. WADPerformanceCountersTable을 두 번 클릭합니다. 테이블 데이터에 SignalR 카운터가 표시됩니다. 테이블이 표시되지 않으면 Azure Storage 자격 증명을 다시 입력해야 할 수 있습니다. 새로 고침 단추를 선택하여 클라우드 탐색기에서 테이블을 보거나 테이블 열기 창에서 새로 고침 단추를 선택하여 테이블의 데이터를 확인해야 할 수 있습니다.클라우드에서 애플리케이션을 테스트하려면 ServiceConfiguration.Cloud.cscfg 파일을 업데이트하고 유효한 Azure Storage 계정 연결 문자열 설정합니다
Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString
.<?xml version="1.0" encoding="utf-8"?> <ServiceConfiguration serviceName="SignalRPerfCounters" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2015-04.2.6"> <Role name="WebRole1"> <Instances count="1" /> <ConfigurationSettings> <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=<account-name>;AccountKey=<account-key>" /> </ConfigurationSettings> </Role> </ServiceConfiguration>
Azure 구독에 애플리케이션을 배포합니다. Azure에 애플리케이션을 배포하는 방법에 대한 자세한 내용은 클라우드 서비스를 만들고 배포하는 방법을 참조하세요.
잠시 기다립니다. 클라우드 탐색기에서 위에서 구성한 스토리지 계정을 찾아 테이블을 찾
WADPerformanceCountersTable
습니다. 테이블 데이터에 SignalR 카운터가 표시됩니다. 테이블이 표시되지 않으면 Azure Storage 자격 증명을 다시 입력해야 할 수 있습니다. 새로 고침 단추를 선택하여 클라우드 탐색기에서 테이블을 보거나 테이블 열기 창에서 새로 고침 단추를 선택하여 테이블의 데이터를 확인해야 할 수 있습니다.
이 자습서에 사용된 원래 콘텐츠에 대한 마틴 리처드 에게 특별한 감사드립니다.