앤드류 스탠튼 간호사, 브래디 가스터, 톰 다이크스트라
이 문서에서는 ASP.NET Core SignalR를 사용하는 트래픽이 많은 앱에 대한 호스팅 및 크기 조정 고려 사항을 설명합니다.
스티키 세션
SignalR 에서는 특정 연결에 대한 모든 HTTP 요청을 동일한 서버 프로세스에서 처리해야 합니다. 서버 팜(여러 서버)에서 실행되는 경우 SignalR "고정 세션"을 사용해야 합니다. "고정 세션"을 세션 선호도라고도 합니다. Azure App Service는 ARR(애플리케이션 요청 라우팅)을 사용하여 요청을 라우팅합니다. Azure App Service에서 "세션 선호도"(ARR 선호도) 설정을 사용하도록 설정하면 "고정 세션"이 활성화됩니다. 앱에 고정 세션이 필요하지 않은 유일한 상황은 다음과 같습니다.
- 단일 프로세스에서 단일 서버에서 호스팅하는 경우
- Azure SignalR 서비스를 사용하는 경우(고정 세션은 앱이 아닌 서비스에 대해 사용하도록 설정됨)
- 모든 클라이언트가 WebSocket만 사용하도록 구성되고 설정이 클라이언트 구성에서 활성화된 경우
Redis 백플레인을 사용하는 경우를 포함하여 다른 모든 상황에서는 고정 세션에 대해 서버 환경을 구성해야 합니다.
Azure App Service를 구성하는 방법에 대한 SignalR지침은 Azure App Service에 ASP.NET Core SignalR 앱 게시를 참조하세요. Blazor 사용하는 앱에 대한 고정 세션을 구성하는 방법에 대한 SignalR 지침은 Blazor.
TCP 연결 리소스
웹 서버에서 지원할 수 있는 동시 TCP 연결 수는 제한됩니다. 표준 HTTP 클라이언트는 임시 연결을 사용합니다. 클라이언트가 유휴 상태가 되면 이러한 연결을 닫고 나중에 다시 열 수 있습니다. 반면에 연결은 SignalR영구적입니다. SignalR 클라이언트가 유휴 상태로 전환되더라도 연결은 계속 열려 있습니다. 많은 클라이언트에 서비스를 제공하는 트래픽이 많은 앱에서 이러한 영구 연결로 인해 서버가 최대 연결 수에 도달할 수 있습니다.
또한 영구 연결은 각 연결을 추적하기 위해 일부 추가 메모리를 사용합니다.
연결 관련 리소스를 SignalR 많이 사용하면 동일한 서버에서 호스트되는 다른 웹앱에 영향을 줄 수 있습니다. 마지막으로 사용할 수 있는 TCP 연결을 열고 보유하는 경우 SignalR 동일한 서버의 다른 웹앱에도 더 이상 사용할 수 있는 연결이 없습니다.
서버에 연결이 없으면 임의의 소켓 오류 및 연결 재설정 오류가 표시됩니다. 다음은 그 예입니다.
An attempt was made to access a socket in a way forbidden by its access permissions...
리소스 사용량이 다른 웹앱에서 오류를 발생시키는 것을 방지 SignalR 하려면 다른 웹앱과 다른 서버에서 실행 SignalR 합니다.
SignalR 앱에서 리소스 사용량이 오류를 일으키지 않도록 하려면 서버가 처리해야 하는 연결 수를 제한하도록 스케일링합니다.
규모 확장
사용하는 SignalR 앱은 모든 연결을 추적해야 하므로 서버 팜에 문제가 발생합니다. 서버를 추가하고 다른 서버가 모르는 새 연결을 가져옵니다. 예를 들어 SignalR 다음 다이어그램의 각 서버에서 다른 서버의 연결을 인식하지 못합니다. 서버 중 하나에서 모든 클라이언트에 메시지를 보내려는 경우 SignalR 메시지는 해당 서버에 연결된 클라이언트로만 이동합니다.
이 문제를 해결하기 위한 옵션은 Azure SignalR 서비스 및 Redis 백플레인입니다.
Azure SignalR 서비스
Azure SignalR 서비스는 실시간 트래픽에 대한 프록시로 작동하며 앱이 여러 서버에서 확장될 때 백플레인으로 두 배가 됩니다. 클라이언트가 서버에 대한 연결을 시작할 때마다 클라이언트는 서비스에 연결하도록 리디렉션됩니다. 이 프로세스는 다음 다이어그램에서 설명합니다.
그 결과 서비스는 모든 클라이언트 연결을 관리하지만 각 서버에는 다음 다이어그램과 같이 서비스에 대한 적은 수의 연결만 필요합니다.
스케일 아웃에 대한 이 방법은 Redis 백플레인 대안에 비해 다음과 같은 몇 가지 이점이 있습니다.
- 클라이언트 선호도라고도 하는 고정 세션은 클라이언트가 연결할 때 즉시 Azure SignalR 서비스로 리디렉션되기 때문에 필요하지 않습니다.
- 앱은 SignalR 전송된 메시지 수에 따라 스케일 아웃할 수 있으며, Azure SignalR 서비스는 모든 수의 연결을 처리하도록 확장됩니다. 예를 들어 수천 개의 클라이언트가 있을 수 있지만 초당 몇 개의 메시지만 전송 SignalR 되는 경우 앱은 연결 자체를 처리하기 위해 여러 서버로 확장할 필요가 없습니다.
- 앱은 SignalR 웹앱이 없는 SignalR경우보다 훨씬 더 많은 연결 리소스를 사용하지 않습니다.
이러한 이유로 App Service, VM 및 컨테이너를 포함하여 Azure SignalR 에서 호스트되는 모든 ASP.NET Core SignalR 앱에 Azure 서비스를 사용하는 것이 좋습니다.
자세한 내용은 Azure SignalR 서비스 설명서를 참조하세요.
Redis 백플레인
Redis 는 게시/구독 모델을 사용하여 메시징 시스템을 지원하는 메모리 내 키-값 저장소입니다. Redis 백플레인은 SignalR pub/sub 기능을 사용하여 메시지를 다른 서버로 전달합니다. 클라이언트가 연결하면 연결 정보가 백플레인에 전달됩니다. 서버가 모든 클라이언트에 메시지를 보내려는 경우 백플레인으로 보냅니다. 백플레인은 연결된 모든 클라이언트와 연결된 서버를 알고 있습니다. 해당 서버를 통해 모든 클라이언트에 메시지를 보냅니다. 이 프로세스는 다음 다이어그램에 설명되어 있습니다.
Redis 백플레인은 자체 인프라에서 호스트되는 앱에 권장되는 스케일 아웃 접근 방식입니다. 데이터 센터와 Azure 데이터 센터 간에 상당한 연결 대기 시간이 있는 경우 Azure SignalR 서비스는 대기 시간이 낮거나 처리량 요구 사항이 높은 온-프레미스 앱에 대한 실용적인 옵션이 아닐 수 있습니다.
앞에서 설명한 Azure SignalR 서비스 이점은 Redis 백플레인의 단점입니다.
-
클라이언트 선호도라고도 하는 고정 세션은 다음 둘 다 참인 경우를 제외하고 필요합니다.
- 모든 클라이언트는 WebSocket 만 사용하도록 구성됩니다.
- SkipNegotiation 설정은 클라이언트 구성에서 사용하도록 설정됩니다. 서버에서 연결이 시작되면 해당 서버에 연결이 유지되어야 합니다.
- SignalR 전송되는 메시지가 거의 없더라도 클라이언트 수에 따라 앱을 확장해야 합니다.
- SignalR 앱은 SignalR가 없는 웹앱보다 훨씬 더 많은 연결 리소스를 사용합니다.
Windows 클라이언트 OS의 IIS 제한 사항
Windows 10 및 Windows 8.x는 클라이언트 운영 체제입니다. 클라이언트 운영 체제의 IIS는 10개의 동시 연결로 제한됩니다. SignalR'의 연결은 다음과 같습니다.
- 일시적이고 자주 다시 설정됩니다.
- 더 이상 사용되지 않을 때 즉시 삭제되지 않습니다.
이전 조건을 사용하면 클라이언트 OS에서 10 연결 제한에 도달할 가능성이 높습니다. 클라이언트 OS를 개발에 사용하는 경우 다음을 권장합니다.
- IIS를 사용하지 않습니다.
- Kestrel 또는 IIS Express를 배포 대상으로 사용하십시오.
Nginx를 사용하는 Linux
다음은 WebSocket, ServerSentEvents 및 LongPolling SignalR을 사용하도록 설정하는 데 필요한 최소 설정을 포함합니다.
http {
map $http_connection $connection_upgrade {
"~*Upgrade" $http_connection;
default keep-alive;
}
server {
listen 80;
server_name example.com *.example.com;
# Configure the SignalR Endpoint
___location /hubroute {
# App server url
proxy_pass http://localhost:5000;
# Configuration for WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache off;
# WebSockets were implemented after http/1.0
proxy_http_version 1.1;
# Configuration for ServerSentEvents
proxy_buffering off;
# Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
proxy_read_timeout 100s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
여러 백 엔드 서버를 사용하는 경우 연결할 때 연결이 서버를 전환하지 못하도록 SignalR 고착 세션을 추가해야 합니다. Nginx에서 고정 세션을 추가하는 방법에는 여러 가지가 있습니다. 사용 가능한 항목에 따라 두 가지 방법이 아래에 나와 있습니다.
이전 구성 외에도 다음이 추가됩니다. 다음 예제 backend
에서는 서버 그룹의 이름입니다.
Nginx 오픈 소스에서 클라이언트의 IP 주소를 기반으로 서버에 연결을 라우팅하는 데 사용합니다ip_hash
.
http {
upstream backend {
# App server 1
server localhost:5000;
# App server 2
server localhost:5002;
ip_hash;
}
}
Nginx Plus를 사용하여 sticky
를 추가하고 cookie 사용자의 요청을 서버에 고정합니다.
http {
upstream backend {
# App server 1
server localhost:5000;
# App server 2
server localhost:5002;
sticky cookie srv_id expires=max ___domain=.example.com path=/ httponly;
}
}
마지막으로 proxy_pass http://localhost:5000
섹션의 server
을 proxy_pass http://backend
로 변경하십시오.
Nginx를 통해 WebSockets에 대한 자세한 내용은 NGINX를 WebSocket 프록시로 참조하세요.
부하 분산 및 고정 세션에 대한 자세한 내용은 NGINX 부하 분산을 참조하세요.
Nginx의 ASP.NET Core에 대한 자세한 내용은 다음 문서를 참조하세요.
타사 SignalR 백플레인 공급자
다음 단계
자세한 내용은 다음 리소스를 참조하세요.
ASP.NET Core