一、問題背景
? 事情起因是項目上springboot項目提供的tps達不到客戶要求,除了增加服務器提高tps之外,作為團隊的技術總監,架構師,技術扛把子,本著我不入地獄誰入地獄的原則,決心從代碼上優化,讓客戶享受到飛一般的感覺。雖然大多數編程工作在寫下第一行代碼時已經完成,但本著謙虛使人進步,驕傲使人落后的原則還是一步一個腳印的把問題慢慢展開,慢慢分析。以下內容是抽絲剝繭的心路歷程,請君欣賞。
二、TPS與 QPS
? 說到性能優化就要說到高并發,說到高并發就要說到Tps和Qps。或許是小白第一次見到這個概念,但高手都是從低手走過來的,所以請高手以及高高手們,允許小人啰嗦的敘說吧!
以下是TPS(Transactions Per Second)與QPS(Queries Per Second)的核心區別及關聯解析:
2.1. 定義與組成差異
-
TPS(每秒事務數)
? 定義:單位時間內系統完成的完整事務數量,一個事務包含從客戶端請求到服務端處理并返回的全流程(例如:訂單支付包含下單、扣款、生成憑證等多個操作)。
? 組成:通常包括三個階段:
? 客戶端發起請求
? 服務端處理(含業務邏輯、數據庫操作等)
? 服務端返回響應結果。 -
QPS(每秒查詢數)
? 定義:單位時間內服務端響應的獨立查詢請求數量,通常指單個接口或操作的調用次數(例如:一次商品詳情頁查詢)。
? 組成:僅針對單一請求的響應,不涉及多步驟業務邏輯。
2. 應用場景與關系
指標 | 適用場景 | 與事務的關聯性 | 典型示例 |
---|---|---|---|
TPS | 完整業務流程(如電商下單) | 一個事務可能包含多個QPS(如支付流程涉及庫存查詢、支付接口調用) | 支付系統需關注TPS以評估整體業務處理能力 |
QPS | 單一接口或查詢(如API調用) | 單個查詢可能屬于某個事務的組成部分 | 商品搜索接口需關注QPS以優化響應速度 |
關系公式:
? 當單事務僅包含一次查詢時,TPS = QPS
? 當單事務包含多次查詢時,QPS = TPS × 單事務內查詢次數
? 系統整體吞吐量受限于性能最差的環節(如數據庫瓶頸可能導致高QPS但低TPS)
3. 性能測試中的差異
-
測試目標
? TPS反映系統處理復雜業務鏈路的綜合能力(如銀行轉賬事務)
? QPS更關注接口層或服務的單點性能(如高并發下的緩存查詢) -
瓶頸分析
? TPS低可能由事務中某個子環節(如第三方支付接口延遲)導致,需定位具體步驟
? QPS低通常與服務器資源(CPU、內存)或代碼效率直接相關 -
優化策略
? 提升TPS:優化事務內耗時最長的環節(如數據庫批量操作、異步處理)
? 提升QPS:減少單次查詢的響應時間(如索引優化、緩存命中率)
4. 總結
? 核心區別:TPS衡量完整業務流程的吞吐量,QPS衡量單一操作的頻率。
? 選擇依據:需根據業務場景決定主優化方向:
? 電商大促需優先保障TPS(確保訂單流程不積壓)
? 搜索引擎需優先優化QPS(提升單次查詢效率)
? 關聯性:兩者共同構成系統吞吐量的評估體系,實際應用中常需結合分析。
? 通過以上專業的介紹,想必各位已經知道了什么是Tps還是Qps了,如果各位還是不明白,那不能怪你們,要怪就怪小人說的太專業了。
? 知道了客戶想要的是什么,那么接下來就好辦了,結合本身提供的api服務所使用的技術架構就很容易想到NIO和BIO,因為springboot項目打成jar包后是用的內嵌的tomcat,而tomcat7之前是BIO模式,sprinboot2.x內嵌的tomcat已經是8以上了,在spirngboot自動配置中,創建tomcat實例,默認啟用NIO連接器。這一不小心又說的專業了,那BIO與NIO又是什么呢?對于小白來說,滿臉的黑人問號,而高手只是輕輕一笑,這小伙子又在搞什么名堂,且待我慢慢看來。
三、BIO與NIO
? 從TPS和QPS,再到BIO與NIO,各位看官辛苦了。雖然說是“書山有路勤為徑,學海無涯苦作舟”,但是方法不對,努力全費,知道了需求,怎么去解決,那么了解BIO和NIO就是正確的解決之道了。
BIO(Blocking I/O)和NIO(New I/O 或 Non-blocking I/O)是兩種常見的I/O模型,它們在處理網絡請求和數據傳輸時有顯著的區別,適用于不同的應用場景。
1. BIO(Blocking I/O)
- 定義:BIO是同步阻塞I/O模型。線程在執行I/O操作時會被阻塞,直到數據準備完成。
- 工作原理:每個連接都需要一個獨立的線程來處理,線程在等待數據時無法執行其他任務。
- 優點:實現簡單,代碼直觀。
- 缺點:線程資源消耗高,不適合高并發場景。
- 適用場景:連接數較少且穩定的場景。
2. NIO(New I/O 或 Non-blocking I/O)
- 定義:NIO是同步非阻塞I/O模型。線程在發起I/O請求后不會被阻塞,而是可以繼續執行其他任務。
- 工作原理:通過
Selector
(選擇器)和Channel
(通道)來管理多個連接。單個線程可以監聽多個通道的I/O事件(如讀、寫、連接),從而實現高并發。 - 優點:支持高并發,資源利用率高。
- 缺點:編程復雜度較高,需要手動管理事件循環。
- 適用場景:連接數多且連接較短(輕操作)的場景,如聊天服務器。
3. BIO與NIO的對比
特性 | BIO | NIO |
---|---|---|
阻塞模式 | 阻塞 | 非阻塞 |
數據處理方式 | 流(Stream) | 塊(Buffer) |
核心組件 | Socket/ServerSocket | Channel/Buffer/Selector |
并發能力 | 低(一線程一連接) | 高(單線程多連接) |
編程復雜度 | 簡單 | 復雜 |
4. 應用領域
- BIO:適用于低并發、簡單應用場景,如內部工具或原型驗證。
- NIO:適用于高并發、實時通信場景,如API網關、聊天服務。
總結來說嘛,BIO和NIO各有優缺點,選擇合適的I/O模型需要根據實際的業務需求和并發場景來決定。
? 知道了目前已經是NIO模式了,那么怎么增加性能呢,換個語言不就得了,換個c吧,c是世界上最好的語言,嗯,是個不錯的選擇,換go吧,go是世界上最好的語言,嗯,這個也不錯。想的都對,但還是用Java,Java是世界上最好的語言。
于是在一番思索后,依舊使用Java,因為 gRPC 實現依賴了netty,所以netty應該能滿足客戶的需求,那接下來就是見證奇跡的時刻, “實踐是檢驗真理的唯一標準” ,是騾子是馬是時候該拉出來溜溜了。
四、Netty方案
在薅掉十幾根頭發后,終于寫出了這個替代方案,代碼如下:
package com.example.demo;import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import