Spring Boot 輕量級直播平臺全線實戰:系統設計、限流、監控與安全
作者:編程疏影
通過整合 Spring Boot + SRS + WebSocket + FFmpeg + MinIO 技術棧,我們打造了一套可量產化、可編排、可觀測、可監控、可評價的直播平臺。通過日志、指標、AOP限流和內容安全功能,確保了系統的穩定性和可靠性,適合用于級聯相對較高的直播場景開發。
系統模塊概述
本文實現了一套基于 Spring Boot + WebSocket + Redis + SRS + MinIO 的開源直播系統,支持:
- 直播間創建/觀看/點贊統計
- SRS 接入,實現 RTMP/HLS/FLV 播放流
- WebSocket 實時聊天和評論通信
- FFmpeg 實現播放回放錄制
- MinIO 上傳視頻回放文件
- Prometheus/Grafana 監控指標
- 基于 AOP + Redis 實現限流
- 播放/推流鑒權 + 內容安全過濾
限流設計 (AOP + RedisToken Bucket)
@RateLimit 注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
String key();
int capacity() default 10;
int period() default 60;
}限流切面 RateLimitAspect
@Aspect
@Component
public class RateLimitAspect {
private final RedisRateLimiter rateLimiter;
@Autowired
public RateLimitAspect(RedisRateLimiter rateLimiter) {
this.rateLimiter = rateLimiter;
}
@Around("@annotation(rateLimit)")
public Object rateLimit(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ip = getClientIp(request);
String key = "rate_limit:" + rateLimit.key() + ":" + ip;
boolean allowed = rateLimiter.tryAcquire(key, rateLimit.capacity(), rateLimit.period(), 1);
if (allowed) return joinPoint.proceed();
else throw new TooManyRequestsException("請求過于頻繁");
}
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
// ... 解析各種轉發地址定位
return ip;
}
}操作控制器中使用
@PostMapping("/room")
@RateLimit(key = "create_room", capacity = 5, period = 3600)
public ResponseEntity<LiveRoom> createLiveRoom(...) {...}
@PostMapping("/room/{roomId}/view")
@RateLimit(key = "view_increment", capacity = 1, period = 5)
public ResponseEntity<Void> incrementViewCount(...) {...}監控指標 + Prometheus + Grafana
公共配置
@Configuration
public class MonitoringConfig {
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "live-streaming-service");
}
}自定義指標
@Service
public class LiveStreamMonitoringService {
private final Counter liveStartCounter;
private final Counter liveEndCounter;
private final Gauge activeStreamGauge;
private final Timer streamProcessingTimer;
@Autowired
public LiveStreamMonitoringService(MeterRegistry registry) {
liveStartCounter = Counter.builder("live.stream.start").register(registry);
liveEndCounter = Counter.builder("live.stream.end").register(registry);
activeStreamGauge = Gauge.builder("live.stream.active", this::getActiveStreamCount).register(registry);
streamProcessingTimer = Timer.builder("live.stream.processing").register(registry);
}
private long getActiveStreamCount() {
return redisTemplate.opsForSet().size("live:active_rooms");
}
public void recordLiveStart() { liveStartCounter.increment(); }
public void recordLiveEnd() { liveEndCounter.increment(); }
public <T> T recordProcessingTime(Supplier<T> supplier) {
return streamProcessingTimer.record(supplier);
}
public void recordError(String type) {
meterRegistry.counter("live.stream.errors", "type", type).increment();
}
}安全性設計
推流鑒權
public class StreamSecurityService {
public boolean isIpAllowed(String ip) { return ipWhitelist.contains(ip) || ... }
public String generateSecureStreamUrl(String baseUrl, String streamKey, long expireSeconds) {...}
}播放鑒權
public class PlayAuthService {
public String generateAuthPlayUrl(String baseUrl, String streamKey, Long userId) {...}
public boolean validatePlayUrl(...) {...}
}內容安全
public class ContentSecurityService {
@PostConstruct
public void init() { // 加載敏感詞庫 }
public String filterContent(String content) {...}
public boolean containsSensitiveWords(String content) {...}
}WebSocket 消息處理中應用:
@MessageMapping("/chat/{roomId}")
public void sendMessage(...) {
message.setContent(contentSecurityService.filterContent(message.getContent()));
if (message.getContent().matches("\\*+")) return;
messagingTemplate.convertAndSend("/topic/chat/" + roomId, message);
}實操演示
環境需求
- Java 21+
- Redis
- MySQL
- OBS Studio
- Docker 安裝 SRS
- FFmpeg 與 MinIO
啟動 SRS
docker pull ossrs/srs:4
docker run --name srs -d --restart=always \
-p 1935:1935 -p 1985:1985 -p 8080:8080 \
-v $(pwd)/conf:/usr/local/srs/conf \
ossrs/srs:4 objs/srs -c conf/srs.conf演示流程
創建直播間
curl -X POST http://localhost:8080/api/live/room -H "Content-Type: application/json" -d '{"title":"測試","userId":1}'OBS 推流
服務器: rtmp://localhost:1935/live/streamKey?auth_key=...&expire=...
播放測試
回放錄制
curl -X POST http://localhost:8080/api/live/room/1/record/start
# 稍后
curl -X POST http://localhost:8080/api/live/record/1/stop
curl http://localhost:8080/api/live/room/1/recordings結束直播 OBS 結束推流,或 API 手動更新狀態
總結
通過整合 Spring Boot + SRS + WebSocket + FFmpeg + MinIO 技術棧,我們打造了一套可量產化、可編排、可觀測、可監控、可評價的直播平臺。通過日志、指標、AOP限流和內容安全功能,確保了系統的穩定性和可靠性,適合用于級聯相對較高的直播場景開發。
責任編輯:武曉燕
來源:
路條編程





























