| 併發 | 原始 QPS | 1000 數據 QPS | CPU | 備註 |
|---|---|---|---|---|
| 500 | 250 | 63~70 | 100% | 連接池 15、慢 SQL 拖垮 |
| 1000 | 255 | 57~65 | 100% |
SELECT * FROM infoobject_table
WHERE category = 'advertisement'
AND deleteflag = false
AND id IN (SELECT info_object_fk FROM timespan_table
WHERE vod_id = ? AND deleteflag = false)
ORDER BY RAND() LIMIT 1;
現象: 小表 100ms,1000 視頻數據量下 > 1s。IN + 子查詢 + ORDER BY RAND() 導致全表掃描 + 文件排序。
JOIN:INNER JOIN timespan_table t ON i.id = t.info_object_fkORDER BY RAND() 改應用層隨機:先 SELECT id FROM ... 取 ID 列表,Java 隨機挑一個再查詳情idx_cat_del (category, deleteflag)、idx_vod_del (vod_id, deleteflag)| 併發 | 優化後 QPS | 瓶頸轉移 |
|---|---|---|
| 500 | 150 | CPU 100% → Tomcat 線程阻塞 |
| 1000 | 160 | QPS 卡在 160,CPU 僅 10%,內存 1G/4G |
max_connections = 1000
<Connector port="8080" protocol="HTTP/1.1"
minSpareThreads="25" maxSpareThreads="75"
maxThreads="800" minThreads="600"
acceptCount="200"
connectionTimeout="20000"
redirectPort="8443" />
JAVA_OPTS="-server -Xms4400M -Xmx4400M -Xss512k -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true"
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://192.168.4.112:3306/iod1000?useUnicode=true&characterEncoding=utf-8"/>
<property name="checkoutTimeout" value="60000"/>
<property name="idleConnectionTestPeriod" value="30"/>
<property name="initialPoolSize" value="50"/>
<property name="maxPoolSize" value="800"/>
<property name="minPoolSize" value="50"/>
<property name="maxStatements" value="100"/>
<property name="properties">
<props>
<prop key="preferredTestQuery">SELECT 1</prop>
<prop key="c3p0.maxIdleTime">25000</prop>
<prop key="c3p0.testConnectionOnCheckout">true</prop>
<prop key="user">root</prop>
<prop key="password">iptv4Um8</prop>
</props>
</property>
</bean>
getNumBusyConnections 長期滿載JConsole 線程堆棧:大量線程 BLOCKED on java.util.logging.ConsoleHandler.publish()。
同步控制台日誌輸出成為串行瓶頸,所有工作線程排隊寫日誌。
logger.info() 輸出 SQL 的代碼QPS 突破 250,CPU 穩定 30-40%,線程無阻塞。
| 層級 | 檢查項 | 關鍵指標 |
|---|---|---|
| 資料庫 | 慢 SQL、索引、連接數、緩衝池 | QPS、延遲、Threads_connected |
| 連接池 | min/max/idle/busy、檢查週期、語句緩存 | getNumBusyConnections < maxPoolSize |
| 中間件 | Tomcat 線程池、Accept 队列、JVM GC | CPU、GC 頻率/停頓、線程狀態 |
| 應用代碼 | 同步阻塞點(日誌/鎖/遠程調用)、N+1 查詢 | 線程堆棧分析 |
| 作業系統 | 文件描述符、網路隊列、磁碟 IO | ulimit -n、netstat -s |
「調優不是疊參數,是找到當前瓶頸、解除它、再找下一個。日誌輸出阻塞線程池是典型的『偽 CPU 瓶頸』—— CPU 閒著,線程卻在排隊寫字符串。」