Blazor ?????????????????????
Blazor ???????????? web framework ????????? Microsoft ?????????????????? C# ????????? JavaScript ????????????????????????????????? interactive web UI ?????? 2 hosting models ????????????????????? Blazor Server ?????????????????????????????? server ????????? UI updates ???????????? SignalR WebSocket ????????? Blazor WebAssembly (WASM) ?????????????????????????????? browser ?????????????????????????????? WebAssembly runtime
Blazor Server ??????????????? initial load ???????????? app size ???????????? ????????????????????? server resources ?????????????????? ????????????????????? ?????????????????? connection ???????????????????????? latency ????????????????????? network server ????????????????????????????????? connection ????????? client Blazor WASM ??????????????? ????????????????????? client ????????????????????? connection ???????????? offline ????????? ????????????????????? initial load ????????????????????? download .NET runtime ?????? browser
Capacity Planning ?????????????????? Blazor ???????????????????????????????????????????????? Blazor Server ???????????????????????? client ????????? SignalR connection ?????????????????? memory ????????? CPU ?????? server ??????????????????????????????????????? server ??????????????????????????? concurrent users ????????????????????? resources ???????????????????????? scale ?????????????????????
????????????????????????????????????????????? Blazor Project
Setup Blazor project
# === Blazor Project Setup ===
# 1. Install .NET SDK
# Download from https://dotnet.microsoft.com/download
dotnet --version
# 8.0.xxx
# 2. Create Blazor Server App
dotnet new blazor -n MyBlazorApp --interactivity Server
cd MyBlazorApp
# 3. Project Structure
# MyBlazorApp/
# ????????? Components/
# ??? ????????? Layout/
# ??? ??? ????????? MainLayout.razor
# ??? ??? ????????? NavMenu.razor
# ??? ????????? Pages/
# ??? ??? ????????? Home.razor
# ??? ??? ????????? Counter.razor
# ??? ??? ????????? Weather.razor
# ??? ????????? _Imports.razor
# ??? ????????? App.razor
# ????????? wwwroot/
# ????????? Program.cs
# ????????? appsettings.json
# ????????? MyBlazorApp.csproj
# 4. Configure for Production
cat > appsettings.Production.json << 'EOF'
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft.AspNetCore": "Warning"
}
},
"SignalR": {
"MaximumReceiveMessageSize": 32768,
"KeepAliveInterval": "00:00:15",
"HandshakeTimeout": "00:00:15",
"ClientTimeoutInterval": "00:00:30"
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=myapp;Trusted_Connection=true;"
}
}
EOF
# 5. Run in Development
dotnet run --urls "https://localhost:5001"
# 6. Build for Production
dotnet publish -c Release -o ./publish
# Deploy ./publish folder to server
# 7. Docker Support
cat > Dockerfile << 'EOF'
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyBlazorApp.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyBlazorApp.dll"]
EOF
docker build -t myblazorapp .
docker run -d -p 8080:8080 myblazorapp
echo "Blazor project created"
Capacity Planning ?????????????????? Blazor
?????????????????? capacity ?????????????????? Blazor Server
// CapacityPlanner.cs ??? Blazor Server Capacity Planning
using System;
using System.Collections.Generic;
namespace MyBlazorApp.Planning
{
public class CapacityPlanner
{
// Blazor Server Resource Estimates (per circuit/connection)
// Memory: 250KB - 1MB per circuit (depends on component state)
// CPU: minimal when idle, spikes on interactions
// SignalR connection: 1 WebSocket per client
public CapacityEstimate Calculate(int targetConcurrentUsers)
{
double memoryPerCircuitMB = 0.5; // 500KB average
double cpuPerActiveUser = 0.002; // 0.2% CPU per active user
double signalROverheadMB = 50; // Base SignalR overhead
double totalMemoryMB = (targetConcurrentUsers * memoryPerCircuitMB)
+ signalROverheadMB + 512; // 512MB base app
double totalCPUCores = Math.Ceiling(
targetConcurrentUsers * cpuPerActiveUser + 1); // +1 base core
return new CapacityEstimate
{
ConcurrentUsers = targetConcurrentUsers,
RecommendedMemoryGB = Math.Ceiling(totalMemoryMB / 1024 * 10) / 10,
RecommendedCPUCores = (int)totalCPUCores,
EstimatedBandwidthMbps = targetConcurrentUsers * 0.05,
ServerInstances = CalculateInstances(targetConcurrentUsers),
ScalingStrategy = GetScalingStrategy(targetConcurrentUsers),
};
}
private int CalculateInstances(int users)
{
int usersPerInstance = 5000; // Conservative estimate
return Math.Max(2, (int)Math.Ceiling((double)users / usersPerInstance));
}
private string GetScalingStrategy(int users)
{
if (users < 1000) return "Single server with failover";
if (users < 5000) return "2-3 servers with load balancer (sticky sessions)";
if (users < 20000) return "Auto-scaling group with Redis backplane";
return "Kubernetes with HPA and Redis/Azure SignalR Service";
}
}
public class CapacityEstimate
{
public int ConcurrentUsers { get; set; }
public double RecommendedMemoryGB { get; set; }
public int RecommendedCPUCores { get; set; }
public double EstimatedBandwidthMbps { get; set; }
public int ServerInstances { get; set; }
public string ScalingStrategy { get; set; }
}
// Usage:
// var planner = new CapacityPlanner();
// var estimate = planner.Calculate(10000);
// Console.WriteLine($"Memory: {estimate.RecommendedMemoryGB}GB");
// Console.WriteLine($"CPU: {estimate.RecommendedCPUCores} cores");
// Console.WriteLine($"Instances: {estimate.ServerInstances}");
// Console.WriteLine($"Strategy: {estimate.ScalingStrategy}");
//
// Output for 10,000 users:
// Memory: 5.6GB
// CPU: 21 cores
// Instances: 2
// Strategy: Auto-scaling group with Redis backplane
}
Performance Optimization
???????????????????????????????????????????????? Blazor application
// Program.cs ??? Performance Configuration
using Microsoft.AspNetCore.ResponseCompression;
var builder = WebApplication.CreateBuilder(args);
// 1. SignalR Configuration for Scale
builder.Services.AddSignalR(options =>
{
options.MaximumReceiveMessageSize = 32 * 1024; // 32KB
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
options.HandshakeTimeout = TimeSpan.FromSeconds(15);
options.EnableDetailedErrors = false; // Production
options.MaximumParallelInvocationsPerClient = 1;
})
// Redis Backplane for multi-server
.AddStackExchangeRedis(o =>
{
o.Configuration.ChannelPrefix = "BlazorApp";
});
// 2. Response Compression
builder.Services.AddResponseCompression(opts =>
{
opts.EnableForHttps = true;
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
// 3. Output Caching
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromMinutes(5)));
options.AddPolicy("StaticContent", builder =>
builder.Expire(TimeSpan.FromHours(24)));
});
// 4. Connection Limits
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxConcurrentConnections = 10000;
options.Limits.MaxConcurrentUpgradedConnections = 10000;
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
});
// 5. Memory Cache
builder.Services.AddMemoryCache(options =>
{
options.SizeLimit = 1024; // entries
});
// 6. Health Checks
builder.Services.AddHealthChecks()
.AddCheck("self", () => Microsoft.Extensions.Diagnostics.HealthChecks
.HealthCheckResult.Healthy())
.AddRedis("localhost:6379")
.AddSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
var app = builder.Build();
app.UseResponseCompression();
app.UseOutputCache();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append("Cache-Control", "public, max-age=604800");
}
});
app.MapHealthChecks("/health");
app.MapRazorComponents().AddInteractiveServerRenderMode();
app.Run();
Load Testing ????????? Benchmarking
??????????????? load ?????????????????? Blazor Server
#!/usr/bin/env python3
# load_test_blazor.py ??? Load Testing for Blazor Server
import json
import logging
from datetime import datetime
from typing import Dict, List
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("loadtest")
class BlazorLoadTest:
def __init__(self):
self.results = []
def k6_test_script(self):
"""k6 load test script for Blazor Server"""
return """
// k6-blazor-test.js
import http from 'k6/http';
import ws from 'k6/ws';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
const errorRate = new Rate('errors');
const responseTime = new Trend('response_time');
export const options = {
stages: [
{ duration: '2m', target: 100 }, // Ramp up
{ duration: '5m', target: 500 }, // Stay at 500
{ duration: '2m', target: 1000 }, // Peak
{ duration: '5m', target: 1000 }, // Sustain peak
{ duration: '2m', target: 0 }, // Ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'],
errors: ['rate<0.01'],
},
};
export default function () {
// 1. Load initial page
const res = http.get('https://myapp.example.com/');
check(res, { 'status is 200': (r) => r.status === 200 });
responseTime.add(res.timings.duration);
errorRate.add(res.status !== 200);
// 2. Simulate SignalR connection
const wsUrl = 'wss://myapp.example.com/_blazor';
const wsRes = ws.connect(wsUrl, function (socket) {
socket.on('open', () => {
socket.send(JSON.stringify({ protocol: 'json', version: 1 }));
});
socket.on('message', (data) => {
// Handle SignalR messages
});
sleep(10); // Keep connection for 10 seconds
socket.close();
});
sleep(1);
}
"""
def analyze_results(self):
return {
"test_date": datetime.utcnow().isoformat(),
"scenarios": {
"100_users": {
"avg_response_ms": 45,
"p95_response_ms": 120,
"p99_response_ms": 250,
"error_rate_pct": 0,
"memory_usage_mb": 890,
"cpu_usage_pct": 15,
"status": "PASS",
},
"500_users": {
"avg_response_ms": 85,
"p95_response_ms": 280,
"p99_response_ms": 450,
"error_rate_pct": 0.1,
"memory_usage_mb": 1850,
"cpu_usage_pct": 35,
"status": "PASS",
},
"1000_users": {
"avg_response_ms": 180,
"p95_response_ms": 520,
"p99_response_ms": 980,
"error_rate_pct": 0.5,
"memory_usage_mb": 3200,
"cpu_usage_pct": 65,
"status": "WARNING",
},
"2000_users": {
"avg_response_ms": 450,
"p95_response_ms": 1200,
"p99_response_ms": 2500,
"error_rate_pct": 2.5,
"memory_usage_mb": 5800,
"cpu_usage_pct": 90,
"status": "FAIL - need scaling",
},
},
"recommendations": [
"Current single server handles ~1000 concurrent comfortably",
"Add Redis backplane and second server for 2000+ users",
"Consider Azure SignalR Service for 5000+ users",
"Enable response compression to reduce bandwidth 40%",
"Use output caching for static pages",
],
}
test = BlazorLoadTest()
results = test.analyze_results()
for scenario, data in results["scenarios"].items():
print(f"{scenario}: {data['status']} (p95={data['p95_response_ms']}ms, mem={data['memory_usage_mb']}MB)")
print("\nRecommendations:", json.dumps(results["recommendations"], indent=2))
Monitoring ????????? Scaling
Monitor Blazor Server applications
# === Blazor Monitoring & Scaling ===
# 1. Kubernetes Deployment with HPA
cat > k8s/blazor-deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: blazor-app
spec:
replicas: 2
selector:
matchLabels:
app: blazor-app
template:
metadata:
labels:
app: blazor-app
spec:
containers:
- name: blazor
image: registry/blazor-app:v1
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: Production
- name: ConnectionStrings__Redis
value: redis-service:6379
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 2000m
memory: 2Gi
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: blazor-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: blazor-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
---
apiVersion: v1
kind: Service
metadata:
name: blazor-service
spec:
selector:
app: blazor-app
ports:
- port: 80
targetPort: 8080
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600
EOF
# 2. Nginx Ingress with Sticky Sessions
cat > k8s/ingress.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blazor-ingress
annotations:
nginx.ingress.kubernetes.io/affinity: cookie
nginx.ingress.kubernetes.io/session-cookie-name: blazor-affinity
nginx.ingress.kubernetes.io/session-cookie-max-age: "3600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: blazor-service
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blazor-service
port:
number: 80
EOF
echo "Kubernetes deployment configured"
FAQ ??????????????????????????????????????????
Q: Blazor Server ????????? Blazor WASM ??????????????????????????????????
A: ????????????????????????????????????????????????????????? Blazor Server ?????????????????????????????? ????????????????????? initial load ????????????, ???????????? access server resources (database, file system), ?????????????????????????????? offline support, ?????????????????? latency ????????? network roundtrip ???????????????????????? ???????????? maintain connection ????????????, server cost ???????????????????????? users ???????????? Blazor WASM ?????????????????????????????? ????????????????????? offline capability, ??????????????????????????? server load, app ??????????????? intensive ?????? client, ????????????????????? access server resources ???????????? ???????????????????????? initial load ????????? (download .NET runtime 2-5MB), ????????????????????????????????? SEO (????????????????????? prerendering) .NET 8 ?????????????????? Auto mode ???????????????????????????????????? Server ????????????????????????????????????????????? WASM ??????????????? download ???????????????
Q: Blazor Server ??????????????????????????? concurrent users?
A: ????????????????????? hardware ????????? application complexity ???????????????????????? ???????????????????????????????????? server 4 cores 8GB RAM ?????????????????? 3000-5000 concurrent circuits ?????????????????? app ??????????????? ????????? app ????????????????????? (???????????? state ????????????, render ????????????) ?????????????????????????????? 1000-2000 ???????????????????????????????????????????????????????????????????????? Memory per circuit (250KB-1MB), SignalR message processing, Component rendering server-side ?????????????????? scale ???????????? ????????? Azure SignalR Service ?????????????????? 100,000+ connections
Q: Sticky Sessions ????????????????????????????????????????????? Blazor Server?
A: ??????????????????????????? Blazor Server ????????? SignalR WebSocket connection ??????????????????????????? server instance ??????????????? ????????? load balancer ????????? request ??????????????? instance circuit ??????????????? ???????????? sticky sessions ????????? load balancer ???????????? cookie affinity ?????????????????? Kubernetes ???????????? sessionAffinity: ClientIP ????????? Service ???????????? nginx ingress annotation ?????????????????? cookie affinity ?????????????????? Azure SignalR Service ????????????????????? sticky sessions ??????????????? SignalR Service ?????????????????? connection routing ?????????
Q: Redis Backplane ????????????????????????????????????????
A: ??????????????? run Blazor Server ???????????? instances (scale out) ??????????????? instance ?????? SignalR hub ?????????????????? ????????? client A ???????????? instance 1 ????????? message ???????????????????????????????????? client B ?????? instance 2 ?????????????????????????????????????????????????????????????????? hub Redis Backplane ???????????????????????????????????????????????????????????? broadcast messages ???????????? instances ????????? instance subscribe Redis channel ????????????????????? message ???????????? Redis ????????????????????????????????? instance ????????? subscribe ???????????? ????????????????????????????????? run ????????????????????? 1 instance ????????? instance ?????????????????????????????????????????????
