面試官:如何設計一個高并發系統?你會怎么回答呢?
一、高并發系統面臨的挑戰
在互聯網業務場景中,當系統需要處理每秒數萬甚至數十萬的并發請求時,傳統的單體架構將面臨嚴峻考驗。典型的高并發瓶頸主要存在于以下四個層面:
1. 硬件資源瓶頸:單機CPU處理能力、內存容量、磁盤I/O吞吐量、網絡帶寬等物理限制
2. 數據庫瓶頸:傳統關系型數據庫的ACID特性導致寫入性能低下,單表存儲能力受限
3. 網絡瓶頸:TCP連接數限制、HTTP協議頭冗余、頻繁的三次握手消耗
4. 同步阻塞瓶頸:線程上下文切換開銷、鎖競爭導致的資源等待
二、核心架構設計原則
2.1 水平擴展架構
負載均衡策略
? LVS四層負載均衡:基于IP+端口進行流量分發,支持DR/NAT/TUN模式
? Nginx七層負載均衡:支持HTTP/HTTPS協議,提供加權輪詢、IP哈希、最小連接數等算法
? 動態權重調整:基于節點負載情況(CPU、內存、連接數)實時調整權重
? 一致性哈希算法:通過虛擬節點實現平滑擴容縮容,減少數據遷移量
upstream backend {
hash $request_uri consistent;
server 10.0.0.1:8080 weight=5;
server 10.0.0.2:8080 weight=3;
server 10.0.0.3:8080 backup;
}無狀態服務設計
? Session狀態存儲:采用Redis Cluster存儲會話數據,通過JWT Token傳遞會話信息
? 請求上下文傳遞:使用TraceID實現全鏈路追蹤,結合OpenTracing協議
? 配置中心化:通過Apollo或Nacos實現配置動態下發,避免服務重啟
2.2 多級緩存體系
緩存架構層次
1. 客戶端緩存:HTTP Cache-Control、ETag、LocalStorage
2. CDN緩存:邊緣節點緩存靜態資源,通過Purge API主動刷新
3. 反向代理緩存:Nginx Proxy Cache基于LRU算法緩存動態內容
4. 進程內緩存:Caffeine實現本地熱點緩存,設置軟引用避免OOM
5. 分布式緩存:Redis Cluster集群模式,采用CRC16分片算法
緩存更新策略
? Cache-Aside Pattern:先讀緩存,未命中時查詢數據庫并回填
? Write-Through:同步更新緩存和數據庫,保證強一致性
? Write-Behind:異步批量更新,提升寫入吞吐量
? 過期策略:TTL隨機化(基礎時間±隨機值)避免緩存雪崩
public Object getData(String key) {
Object value = redis.get(key);
if (value == null) {
if (redis.setnx(key + ":mutex", 1, 60)) {
value = db.query(key);
redis.setex(key, 300, value);
redis.del(key + ":mutex");
} else {
Thread.sleep(50);
return getData(key);
}
}
return value;
}2.3 數據庫優化方案
分庫分表策略
? 垂直分庫:按業務模塊拆分(用戶庫、訂單庫、商品庫)
? 水平分表:采用ShardingKey(用戶ID哈希)分片,使用基因法避免跨片查詢
? 全局索引表:建立ID映射關系表,解決分片鍵與查詢條件不匹配問題
? 雙寫機制:新老分片方案并行期間,通過canal同步數據
讀寫分離架構
? 主從復制:基于GTID的半同步復制,設置從庫read_only=ON
? 讀寫分離中間件:MyCat實現SQL路由,自動識別SELECT語句
? 數據延遲處理:通過影子庫壓測確定延遲閾值,重要業務強制讀主
2.4 異步處理機制
消息隊列設計
? Kafka分區設計:根據業務Key(如訂單ID)分區,保證順序性
? 消費冪等性:通過Redis原子操作實現去重
? 批量壓縮:配置linger.ms=20和batch.size=16384提升吞吐量
? 死信隊列:處理失敗消息,設置重試次數閾值
@KafkaListener(topics = "order_topic")
public void process(OrderMessage message) {
String idempotentKey = "msg:" + message.getMsgId();
if (redis.set(idempotentKey, "1", "NX", "EX", 3600)) {
orderService.createOrder(message);
}
}異步化改造
? Servlet3.0異步請求:通過AsyncContext釋放容器線程
? CompletableFuture鏈式調用:整合多個微服務調用
? 響應式編程:基于Project Reactor實現背壓控制
2.5 限流降級策略
限流算法實現
? 滑動窗口算法:基于Redis的zset實現時間窗計數
? 令牌桶算法:Guava RateLimiter的SmoothBursty實現
? 動態限流:Sentinel根據QPS/線程數/系統負載動態調整閾值
public voidconfigureRules() {
List<FlowRule> rules = newArrayList<>();
FlowRulerule=newFlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(1000);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
rule.setWarmUpPeriodSec(10);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}熔斷降級機制
? 熔斷狀態機:Closed->Open->Half-Open狀態轉換
? 異常比例統計:Hystrix滑動窗口統計最近10秒失敗率
? 服務降級方案:返回兜底數據(緩存值/默認值)、排隊頁面、服務托底
三、進階優化手段
3.1 連接池優化
? Redis連接池:Lettuce配置共享連接,設置maxActive=1000
? 數據庫連接池:Druid開啟異步銷毀,配置minIdle=50,maxActive=500
? HTTP連接池:OkHttp設置連接保活5分鐘,最大空閑連接數200
3.2 協議優化
? 序列化協議:Protobuf相比JSON減少50%數據體積
? 長連接復用:HTTP/2多路復用替代短連接
? 二進制傳輸:WebSocket替代輪詢方案
3.3 流量調度策略
? DNS智能解析:根據用戶地理位置返回最優IP
? 全站加速:QUIC協議解決TCP隊頭阻塞問題
? 邊緣計算:在CDN節點運行WebAssembly處理簡單邏輯
四、全鏈路壓測方案
1. 影子庫壓測:復制生產環境數據庫結構,隔離測試數據
2. 流量錄制回放:通過tcpdump抓取真實流量,調整時間倍率
3. 服務全鏈路監控:Pinpoint追蹤每個Span的耗時和狀態
4. 彈性擴縮容:根據CPU利用率動態調整K8s副本數
五、容災設計要點
1. 多活架構:單元化部署,每個單元包含完整業務閉環
2. 數據同步:使用GoldenGate實現跨機房雙向同步
3. 故障演練:ChaosBlade模擬網絡分區、節點宕機等場景
4. 灰度發布:基于Header的流量染色,逐步切量驗證
六、總結
高并發系統設計需要從架構設計、中間件選型、代碼優化等多個維度進行系統性優化。在實際實施過程中,需要建立完善的監控體系,持續跟蹤系統瓶頸。建議采用漸進式優化策略,通過全鏈路壓測驗證優化效果,同時建立容災預案,保證業務連續性。隨著云原生技術的發展,Service Mesh、Serverless等新范式正在改變高并發系統的實現方式,架構師需要持續關注技術演進趨勢。
本文轉載自微信公眾號「程序員秋天」,可以通過以下二維碼關注。轉載本文請聯系公眾號。

































