摘要:初步分析提升可從兩方面入手,一個是增加并發(fā)數(shù),其二是減少平均響應(yīng)時間。大部分的時間花在系統(tǒng)與數(shù)據(jù)庫的交互上,到這,便有了一個優(yōu)化的主題思路最大限度的降低平均響應(yīng)時間。不要輕易否定一項公認(rèn)的技術(shù)真理,要拿數(shù)據(jù)說話。
本文最早發(fā)表于個人博客:Pylixm"Wiki
應(yīng)項目的需求,我們使用tornado開發(fā)了一個api系統(tǒng),系統(tǒng)開發(fā)完后,在8核16G的虛機(jī)上經(jīng)過壓測qps只有200+。與我們當(dāng)初定的QPS 大于2k差了一個數(shù)量級,于是便開始了漫長的優(yōu)化之路。在優(yōu)化過程中,學(xué)了許多東西,有必要整理記錄下備查。
我們的技術(shù)選型:
python2.7
tornado4.4.3
sqlalchemy1.1.5
mysql5.6
rabbitmq
當(dāng)初技術(shù)選型的時候選擇tornado,便是因為其優(yōu)秀的性能,這么低的QPS自然是不甘心。究竟tornado可以達(dá)到多少Q(mào)PS呢?于是編寫了簡單的hello world,在上邊的虛擬機(jī)中起16個進(jìn)程下,使用ab壓測QPS竟然達(dá)到了驚人的6K,平均響應(yīng)時間在毫秒級。這下有信心將api的QPS繼續(xù)優(yōu)化了。
初步分析提升QPS, 可從兩方面入手,一個是增加并發(fā)數(shù),其二是減少平均響應(yīng)時間。從目前情況看,增加進(jìn)程并發(fā)數(shù)是最直接的手段,但當(dāng)達(dá)到機(jī)器資源的瓶頸時,可靠堆疊機(jī)器來解決。那么
相比較下,減小平均響應(yīng)更為重要。初步分析了我們開發(fā)的api,平均響應(yīng)時間在幾百毫秒級別。大部分的時間花在系統(tǒng)與數(shù)據(jù)庫的交互上,到這,便有了一個優(yōu)化的主題思路:最大限度的降低平均響應(yīng)時間。
我們API完成的功能為,接受請求參數(shù)做一些列的認(rèn)證判斷(與數(shù)據(jù)庫交互),將消息以廣播的形式發(fā)送到rabbitmq供消費(fèi)者消費(fèi),最后返回給客戶端發(fā)送結(jié)果。根據(jù)此邏輯,影響響應(yīng)時間的地方,分析如下:
與mysql 數(shù)據(jù)庫的交互
使用rabbitmq廣播消息時的時間耗費(fèi)
耗時的業(yè)務(wù)邏輯代碼片段
優(yōu)化思路根據(jù)上邊的問題,從以下幾個方面入手:
增加tornado的異步特性
分析與數(shù)據(jù)庫的交互,減少與數(shù)據(jù)庫的交互時間
分析rabbitmq的時間耗費(fèi),減少發(fā)送信息時間
優(yōu)化業(yè)務(wù)代碼邏輯
具體實施 tornado 的異步特性開發(fā)api時,因為對tornado 的異步特性不是很熟悉,便沒有使用。后來隨著測試的深入,發(fā)現(xiàn)需要使用后,開始了解。
隨著了解的深入,發(fā)現(xiàn)tornado是并沒有很好的支持?jǐn)?shù)據(jù)庫的異步特性,更多是對網(wǎng)絡(luò)的異步,官網(wǎng)上也是寫的”網(wǎng)絡(luò)非阻塞框架“。
查閱官方文檔,tornado的異步實現(xiàn),見官方文檔
總的來說,使程序異步的方式有3種,參考這里。如下:
第一種,使用tornado 的 gen.coruntine。
使用此種方式,需要異步數(shù)據(jù)庫的驅(qū)動庫,經(jīng)查找現(xiàn)階段并沒有很好的成熟的支持異步查詢mysql的python驅(qū)動,放棄此種方案。
第二種,使用tornado 的線程模塊。
此種方式比較方便,只需要在耗時的函數(shù)上添加裝飾器即可,簡單方便,可以說是一種萬能方案,但此方案耗費(fèi)系統(tǒng)資源。 系統(tǒng)資源并不是我們的瓶頸,我們最后采納了此種方式。
第三種,使用外部隊列,多帶帶其worker 進(jìn)程或線程去處理。例如,celery 等。
此種方式增加了外部的依賴,增加了系統(tǒng)的復(fù)雜性和后期的維護(hù)難度,放棄此種方案。
增加了異步特性外有顯著的提升。
mysql 數(shù)據(jù)庫的優(yōu)化數(shù)據(jù)庫方便,我們適用的是SQLAlchemy。使用ORM時,在減少裸sql帶來的查詢復(fù)雜度的同時,必然會增加查詢數(shù)據(jù)庫的耗時。我們也做過測試,
使用pymsql鏈接mysql,直接使用裸sql查詢與使用sqlalcemy 的對象查詢的耗時差別有7、8個毫秒的時差,與sqlalchemy的裸sql方式執(zhí)行時間幾乎一致。
可見,sqlalchemy的orm方式是有一定時間耗損的。stackoverflow的一個問題,也驗證了我的想法,見Why is loading SQLAlchemy objects via the ORM 5-8x slower than rows via a raw MySQLdb cursor?
針對數(shù)據(jù)庫方面,我們做了如下優(yōu)化:
將SQLAlchemy 查詢改為核心裸sql方式,可參考這里。
優(yōu)化數(shù)據(jù)庫,增加必要的索引。
將邏輯中的過濾條件,盡量的移到sql中,減少sql結(jié)果集的大小,加快查詢速度。
將可以單詞查詢出的數(shù)據(jù)集放到一次查詢中,減少鏈接數(shù)據(jù)庫的次數(shù)。
分析rabbitmq的時間耗費(fèi),減少發(fā)送信息時間rabbitmq 方面,使用的是pika 作為驅(qū)動庫連接的,使用方式是每次發(fā)送數(shù)據(jù)的時候創(chuàng)建鏈接和通道,發(fā)送完畢后立即關(guān)閉鏈接。考慮到是否可以使用長鏈接,創(chuàng)建鏈接后不關(guān)閉,只關(guān)閉channel。修改后發(fā)現(xiàn)報錯,具體代碼如下:
# -*- coding:utf-8 -*- import pika from settings import settings class Client(object): def __init__(self, host, port, username, pwd): self.host = host self.port = port self.username = username self.pwd = pwd self.init_connection() def init_connection(self): user_pwd = pika.PlainCredentials(self.username, self.pwd) self.connection = pika.BlockingConnection(pika.ConnectionParameters( host=self.host, port=self.port, credentials=user_pwd)) # ...
補(bǔ)充錯誤材料分析 - todo
翻閱了pika的文檔,發(fā)現(xiàn)其有異步的使用方式,且有與tornando 框架的結(jié)合的實例,見文檔。
pika的異步方式,使用了和tornado 相同的基于epull的事件循環(huán)模型,如何將其與tornado 的IOloop結(jié)合是個問題,
其有個tornado的鏈接適配器,翻看其代碼還是有些不太明確如何使用,有時間的時候再繼續(xù)研究下。
針對rabbitmq的優(yōu)化我們放棄了,但優(yōu)化過程中有些值得分析的文章,整理如下:
rabbitmq-amqp-channel-best-practices
rabbitmq-best-practices-for-designing-exchanges-queues-and-bindings
tornado與pika結(jié)合實例
優(yōu)化業(yè)務(wù)代碼邏輯代碼邏輯方便的優(yōu)化,如下:
減少循環(huán)
review 邏輯,去除冗余邏輯
提取公共變量,賦值一次,減少查詢數(shù)據(jù)庫。
總結(jié)經(jīng)過以上的優(yōu)化,我們的api 的 QPS 提升到了1200+, 由于時間問題,我們暫停了繼續(xù)的優(yōu)化。通過本次QPS的優(yōu)化過程,有幾點感悟:
使用一項新技術(shù)時,一定要認(rèn)真閱讀官方文檔,了解清楚后,再使用。
不要輕易否定一項公認(rèn)的“技術(shù)真理”,要拿數(shù)據(jù)說話。
個人工作總結(jié),歡迎留言交流!文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40750.html
摘要:這是多處理器系統(tǒng)中,調(diào)度器用來分散任務(wù)到不同的機(jī)制,通常也被稱為處理器間中斷,。文章編寫計劃 待完成: 詳細(xì)介紹用到的各個工具 作者: 萬千鈞(祝星) 適合閱讀人群 文中的調(diào)優(yōu)思路無論是php, java, 還是其他任何語言都是用. 如果你有php使用經(jīng)驗, 那肯定就更好了 業(yè)務(wù)背景 框架及相應(yīng)環(huán)境 laravel5.7, mysql5.7, redis5, nginx1.15 cento...
摘要:這是多處理器系統(tǒng)中,調(diào)度器用來分散任務(wù)到不同的機(jī)制,通常也被稱為處理器間中斷,。文章編寫計劃 待完成: 詳細(xì)介紹用到的各個工具 作者: 萬千鈞(祝星) 適合閱讀人群 文中的調(diào)優(yōu)思路無論是php, java, 還是其他任何語言都是用. 如果你有php使用經(jīng)驗, 那肯定就更好了 業(yè)務(wù)背景 框架及相應(yīng)環(huán)境 laravel5.7, mysql5.7, redis5, nginx1.15 cento...
摘要:展示如下場景再現(xiàn)經(jīng)過分析,最后我們定位到是使用產(chǎn)生的內(nèi)存泄露問題。下面通過一個,來簡單講下具體內(nèi)存泄露的原因。這一次的內(nèi)存泄露問題算是解決了。總結(jié)關(guān)于內(nèi)存泄露問題在第一次排查時,往往是有點不知所措的。 記一次 JAVA 的內(nèi)存泄露分析 摘要:本文屬于原創(chuàng),歡迎轉(zhuǎn)載,轉(zhuǎn)載請保留出處:https://github.com/jasonGeng88/blog 當(dāng)前環(huán)境 jdk == 1.8 ...
摘要:目前來說文章亮點就是解耦做的還行,有一定的可擴(kuò)展性簡單的仿實現(xiàn)路由分發(fā)規(guī)定應(yīng)用程序需要是一個可調(diào)用的對象可調(diào)用對象接收兩個參數(shù)可調(diào)用對象要返回一個值,這個值是可迭代的。 最近web服務(wù)器知識,中間懶癌犯了,斷了一兩天后思路有點接不上來,手頭上也有其他事情要做,先簡單的總結(jié)下學(xué)習(xí)進(jìn)度,很多重要的功能都沒跑通,目前flask只是簡單實現(xiàn)路由分顯示不同的結(jié)果,cgi可以根據(jù)不同的靜態(tài)資源或者...
閱讀 3029·2021-11-18 10:07
閱讀 3778·2021-11-17 17:00
閱讀 2108·2021-11-15 18:01
閱讀 936·2021-10-11 10:58
閱讀 3387·2021-09-10 10:50
閱讀 3453·2021-08-13 15:05
閱讀 1232·2019-08-30 15:53
閱讀 2657·2019-08-29 13:01