在上一篇文章中,我們了解了 odoo 的多行程設定和效能改善的理論基礎。在這一章中,我將透過實際的實驗,調整 odoo.conf
中的多行程與資料庫連線設定,並觀察對系統效能的影響。
我使用 Siege 進行壓力測試,模擬多個使用者同時訪問 odoo 系統的情況。我不是這方面的專家,所以這只是一個非常粗糙的測試方式。測試指令如下:
siege -c [並發使用者數] -t 1M https://odoo-dev.internal.example.local
-c
:指定並發的使用者數量。-t
:測試持續時間,這裡設為 1 分鐘。我這次的測試統一都讓它跑滿一分鐘,讓資料更好進行比較。有一些測試因為失敗率太高,會被強制中止,可以在 Siege 的設定裡把預設的 1024 次失敗跳出調高,讓測試可以跑完。
cat ~/.siege/siege.conf | grep failure -A 4 -B 4
#
# Failures: This is the number of total connection failures allowed
# before siege aborts. Connection failures (timeouts, socket failures,
# etc.) are combined with 400 and 500 level errors in the final stats,
# but those errors do not count against the abort total. If you set
# this total to 10, then siege will abort after ten socket timeouts,
# but it will NOT abort after ten 404s. This is designed to prevent a
# run-away mess on an unattended siege.
#
# The default value is 1024
#
# ex: failures = 50
#
failures = 1048576
首先,在未修改任何設定的情況下,我以 60 個並發使用者進行測試,結果如下:
{ "transactions": 20033,
"availability": 99.94,
"elapsed_time": 59.25,
"data_transferred": 1219.25,
"response_time": 0.18,
"transaction_rate": 338.11,
"throughput": 20.58,
"concurrency": 59.82,
"successful_transactions": 20045,
"failed_transactions": 12,
"longest_transaction": 0.46,
"shortest_transaction": 0.00
}
另外在測試時,我也進入容器中使用 top
觀察系統資源的利用狀況。
分析:
python3
的行程,並且 CPU 使用率高達 120%,但符合預期。接下來,我將並發使用者數增加到 100 個。
{
"transactions": 17687,
"availability": 91.22,
"elapsed_time": 59.66,
"data_transferred": 1009.77,
"response_time": 0.34,
"transaction_rate": 296.46,
"throughput": 16.93,
"concurrency": 99.49,
"successful_transactions": 19669,
"failed_transactions": 1702,
"longest_transaction": 0.84,
"shortest_transaction": 0.00
}
分析:
psycopg2.pool.PoolError: The Connection Pool Is Full
,這表示 odoo 連線到資料庫的連線池已滿,無法處理更多連線。為了解決連線池已滿的問題,我查看 odoo.conf
的 db_maxconn
設定,發現其預設值為 64,剛好可以容納我們 60 人的測試。於是我嘗試在 odoo.conf
中將 db_maxconn
從預設值增加到 128。
db_maxconn = 128
再次以 100 個並發使用者進行測試。
{
"transactions": 500,
"availability": 8.04,
"elapsed_time": 59.38,
"data_transferred": 1.24,
"response_time": 11.78,
"transaction_rate": 8.42,
"throughput": 0.02,
"concurrency": 99.23,
"successful_transactions": 1026,
"failed_transactions": 5717,
"longest_transaction": 1.02,
"shortest_transaction": 0.00
}
分析:
PostgreSQL
的日誌中,大量出現以下訊息:FATAL: sorry, too many clients already
,也就是說,雖然我在 odoo 中將連線數設定變大了,但是資料庫那邊無法處理這麼多的連線。意識到問題出在資料庫那邊後,我檢查了 PostgreSQL 的設定:
root@0abc279cce9b:/# cat /var/lib/postgresql/data/postgresql.conf | grep max_connections
max_connections = 100
發現資料庫預設的最大連線數為 100,而我在 odoo 中將 db_maxconn
設為 128,導致超過資料庫的負荷,而無法服務的資料庫反而造成 odoo 更多的問題,最終導致效能驟降。
於是我嘗試將 odoo 的 db_maxconn
往回調整成 100 ,配合資料庫的設定。
db_maxconn = 100
再次進行測試。
{
"transactions": 305,
"availability": 5.09,
"elapsed_time": 59.63,
"data_transferred": 1.16,
"response_time": 19.39,
"transaction_rate": 5.11,
"throughput": 0.02,
"concurrency": 99.16,
"successful_transactions": 861,
"failed_transactions": 5687,
"longest_transaction": 2.01,
"shortest_transaction": 0.00
}
分析:
於是我關閉了瀏覽器的分頁後,再次進行測試。
{
"transactions": 19090,
"availability": 99.80,
"elapsed_time": 59.44,
"data_transferred": 1156.29,
"response_time": 0.31,
"transaction_rate": 321.16,
"throughput": 19.45,
"concurrency": 99.53,
"successful_transactions": 19116,
"failed_transactions": 38,
"longest_transaction": 0.85,
"shortest_transaction": 0.00
}
分析:
為了驗證問題是否是因為超過了 100 的上限,我再次進行測試,增加並發使用者數到 105 個。
{
"transactions": 18496,
"availability": 99.69,
"elapsed_time": 59.19,
"data_transferred": 1138.82,
"response_time": 0.33,
"transaction_rate": 312.49,
"throughput": 19.24,
"concurrency": 104.62,
"successful_transactions": 18736,
"failed_transactions": 57,
"longest_transaction": 0.93,
"shortest_transaction": 0.00
}
測試的結果表明超過上限不是問題,於是我又把瀏覽器的分頁打開並進行測試,但還是無法復現之前的問題,這有點奇怪,但我決定先不理會了。
為了進一步提升效能,我決定將 odoo 的運行模式從多執行緒(Multi-Thread)改為 多行程(Multi-Process),調整了一些設定。
odoo.conf
設定workers = 10
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 60
limit_time_real = 120
進行 100 個並發使用者的測試。
{
"transactions": 106175,
"availability": 99.85,
"elapsed_time": 59.48,
"data_transferred": 6530.79,
"response_time": 0.06,
"transaction_rate": 1785.05,
"throughput": 109.80,
"concurrency": 99.58,
"successful_transactions": 106372,
"failed_transactions": 160,
"longest_transaction": 1.26,
"shortest_transaction": 0.00
}
並且同時進入容器中觀察系統資源使用狀況:
分析:
top
顯示我們這次有 14 個 python3
行程,雖然跟設定的好像不太一樣,但仔細觀察看起來 CPU 占用率較高的是 10 個,應該是對應 worker 的數量,剩下的可能就是 cron 之類的連線。資料庫連線設定需在 odoo 端和資料庫端匹配:調整 odoo 的 db_maxconn
時,需考慮資料庫的 max_connections
設定,避免超過資料庫的負荷。
環境因素可能影響測試結果:測試時應確保沒有其他佔用連線的應用程式,例如關閉不必要的瀏覽器分頁,以免影響測試準確性。
多行程模式顯著提升效能:雖然我切換到 Multi-Process 模式並開了 10 個 worker
,效能卻只提升了五倍多,但這可能是因為我 host 系統的資源已經吃滿了,導致效能無法再往上,可以看到下圖我的本機 CPU 使用率全部達到 100%,這在 Multi-Thread 模式下是達不到的,不管怎麼催,都會有 CPU 在發呆。這證明了如果使用 Multi-Process 可以解放更多硬體該有的效能,而不會被軟體設計限制,是生產環境中推薦的設定。
下一篇,我們將來探討如何透過已經設定好的 Multi-Process 模式,結合 Nginx 反向代理設定,讓 odoo 的實時系統正常運作。