Springboot3 如何打造一個能承載百萬用戶同時在線的超強直播評論系統?
隨著直播行業的迅猛發展,越來越多的平臺開始承載著數百萬甚至上千萬用戶的同時在線互動。尤其在直播評論系統中,如何保持高并發、大規模的用戶參與,成為了一個不可回避的技術挑戰。類似于抖音、B站的實時彈幕系統,它們能夠處理每秒成千上萬的評論請求,同時又要確保低延遲、穩定性以及系統的高可用性。
在本篇文章中,我們將通過系統設計的思路,逐步解析如何用 Spring Boot 3 打造一個支持百萬用戶同時在線的超強直播評論系統。我們將通過面試官與候選人的對話模式,結合實際應用場景,一步步搭建起這個系統架構。希望通過這篇文章,能幫助你在技術面試中應對類似的系統設計問題時,展示出更加清晰和理性的思維。
需求梳理與邊界界定
面試官: “如果要你設計一個類似 B站 的直播評論系統,你會怎么著手?”
候選人: “首先,我們需要明確直播評論系統的核心功能和非功能需求。”
功能需求
- 核心需求:
a.發布評論:用戶能夠在觀看直播時發布實時評論。
b.實時查看評論:所有觀眾能夠實時看到新發布的評論。
c.歷史評論展示:新加入的觀眾能夠看到他們加入直播前已發布的評論。
- 非核心需求:
a.評論回復功能:允許評論之間進行嵌套回復。
b.評論點贊與表情回應:增加互動性。
非功能需求
明確了核心功能需求后,我們需要確認系統在百萬級并發情況下的非功能性要求:
- 高擴展性:支持水平擴展,處理數百萬觀眾的并發評論。
- 高可用性:即使在分布式環境下也能保證系統高可用,最終一致性可接受。
- 低延遲:評論廣播的端到端延遲應控制在200毫秒以內。
底層設計
面試官: “需求很清晰。接下來你打算如何進行底層設計?”
候選人: “我傾向于從宏觀到微觀,先定義系統的核心實體和接口,這樣能夠幫助我們理清系統的基本構成。”
核心實體定義
我們需要關注三個核心實體:
- 用戶(User):發布評論的用戶,可以是觀眾或主播。
- 直播視頻(LiveVideo):評論依附的直播視頻。
- 評論(Comment):用戶發布的評論。
系統接口設計
我們可以為每個功能設計接口,確保清晰的功能實現。
- 發布評論接口:
@PostMapping("/comments/{liveVideoId}")
public ResponseEntity<Void> createComment(@PathVariable String liveVideoId,
@RequestBody CommentRequest commentRequest,
@RequestHeader("Authorization") String token) {
commentService.createComment(liveVideoId, commentRequest, token);
return ResponseEntity.ok().build();
}- 獲取歷史評論接口:
@GetMapping("/comments/{liveVideoId}")
public ResponseEntity<List<CommentResponse>> getComments(@PathVariable String liveVideoId,
@RequestParam Long cursor,
@RequestParam int pageSize) {
List<CommentResponse> comments = commentService.getComments(liveVideoId, cursor, pageSize);
return ResponseEntity.ok(comments);
}高層架構設計
面試官: “從架構層面看,如何實現高并發評論發布?”
候選人: “我們可以采用三層架構:客戶端、服務端、數據庫。”
- 客戶端:負責向后端發送評論請求并進行用戶認證。
- 服務端:處理評論的接收、校驗及持久化操作。
- 數據庫:使用如 AWS DynamoDB 或阿里云 Table Store 這樣的 NoSQL 數據庫來存儲評論數據。
實現評論發布
在客戶端提交評論后,通過 RESTful 接口 POST /comments/{liveVideoId} 將評論發送到服務端,服務端校驗并將評論存儲到數據庫中。
@Service
public class CommentService {
@Autowired
private CommentRepository commentRepository;
@Autowired
private RedisService redisService;
public void createComment(String liveVideoId, CommentRequest commentRequest, String token) {
User user = userService.getUserFromToken(token);
Comment comment = new Comment(liveVideoId, user.getId(), commentRequest.getMessage(), new Date());
commentRepository.save(comment);
// 使用Redis進行實時評論推送
redisService.pushToChannel(liveVideoId, comment);
}
}高性能設計
面試官: “如何解決實時評論的廣播問題?”
候選人: “要解決實時廣播的問題,我們可以采用 WebSocket 或服務器發送事件(SSE)。考慮到直播場景下讀寫不平衡,SSE 更為合適。”
實時廣播評論
- WebSocket:適用于雙向通信,確保客戶端實時接收到新評論,但對于高并發場景,維護大量的 WebSocket 連接開銷較大。
- SSE(推薦方案):通過建立持久化的 HTTP 連接,服務端可以主動推送數據,適合大規模閱讀場景。
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new CommentWebSocketHandler(), "/comments/{liveVideoId}")
.setAllowedOrigins("*");
}
}如何水平擴展 SSE 服務?
要支持百萬級并發,SSE 服務必須能夠水平擴展,處理大量的并發連接。單臺服務器無法承載百萬個長連接,必須采用分布式架構和負載均衡方案。
負載均衡與分布式 SSE
為確保高并發時服務端可以支撐數百萬觀眾,我們需要引入 負載均衡 和 分布式 SSE 服務。具體步驟如下:
- 負載均衡:通過負載均衡器(如 Nginx 或 HAProxy)將客戶端的 SSE 請求分配到不同的后端服務器。
- 發布/訂閱機制(Pub/Sub):使用 Redis 或 Kafka 等消息隊列系統進行實時的評論推送,確保所有的服務器都能夠獲取到新的評論并推送到觀眾客戶端。
分布式 SSE 服務實現
我們可以通過 Redis 來實現分布式 SSE 服務。在 Redis 中設置一個頻道,當有新的評論時,服務器將其發布到該頻道,所有訂閱了該頻道的 SSE 服務實例會收到新評論并推送給客戶端。
- Redis Pub/Sub 實現:
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void pushToChannel(String liveVideoId, Comment comment) {
redisTemplate.convertAndSend("live:" + liveVideoId, comment);
}
}- SSE 服務端推送實現:
@Service
public class SSEService {
private final Map<String, List<SseEmitter>> emittersMap = new ConcurrentHashMap<>();
public SseEmitter connect(String liveVideoId) {
SseEmitter sseEmitter = new SseEmitter();
emittersMap.computeIfAbsent(liveVideoId, k -> new ArrayList<>()).add(sseEmitter);
sseEmitter.onTimeout(() -> emittersMap.get(liveVideoId).remove(sseEmitter));
sseEmitter.onCompletion(() -> emittersMap.get(liveVideoId).remove(sseEmitter));
return sseEmitter;
}
public void pushComment(String liveVideoId, Comment comment) throws IOException {
List<SseEmitter> emitters = emittersMap.get(liveVideoId);
if (emitters != null) {
for (SseEmitter emitter : emitters) {
emitter.send(comment);
}
}
}
}- SSE Controller 實現:
@RestController
public class CommentController {
@Autowired
private SSEService sseService;
@GetMapping("/sse/comments/{liveVideoId}")
public SseEmitter getComments(@PathVariable String liveVideoId) {
return sseService.connect(liveVideoId);
}
@PostMapping("/comments/{liveVideoId}")
public ResponseEntity<Void> createComment(@PathVariable String liveVideoId,
@RequestBody CommentRequest commentRequest,
@RequestHeader("Authorization") String token) throws IOException {
commentService.createComment(liveVideoId, commentRequest, token);
sseService.pushComment(liveVideoId, new Comment(liveVideoId, commentRequest.getMessage()));
return ResponseEntity.ok().build();
}
}系統擴展與優化
面試官: “如何進一步優化系統性能并保證高可用性?”
候選人: “我們可以采用分區發布/訂閱機制(Partitioned Pub/Sub)和 L7 負載均衡器(如 NGINX 或 Envoy)來實現。”
- 分區發布/訂閱:將評論流分為多個頻道,減少單個服務器的負載。
- L7 負載均衡:智能地將同一視頻的觀眾路由到同一服務器,避免資源浪費。
小結
至此,我們完成了一個高并發、低延遲的直播評論系統的設計。回顧我們的設計過程:
- 需求驅動:明確系統的核心功能需求。
- 迭代演進:從簡單的 MVP 開始,逐步優化系統架構。
- 技術權衡:在每個關鍵點上做出合理的技術選型。
本篇文章不僅展示了如何設計一個百萬級并發的直播評論系統,還強調了在系統設計過程中結構化思考的重要性。通過不斷迭代、權衡不同方案,最終實現了高效且穩定的架構設計。





























