日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

流量低峰也烦人-lighttpd耗时长问题追查

發布時間:2025/6/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 流量低峰也烦人-lighttpd耗时长问题追查 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

結論

如果你用lighttpd1.5(以下lighttpd均指1.5)做靜態文件服務器,或者你雖然用lighttpd處理php請求,但是用到$PHYSICAL作為mod_proxy_core的條件, 且某個時候你的單機流量很低(幾個/s), 或許你也有類似的問題,但是影響程度或許不會引起你的注意!
1.Lighttpd的mod_proxy_core不建議用$PHYSICAL作為條件;
2.Lighttpd的stat cache機制沒有節省任何開銷;
3.Lighttpd子線程和主線程通過管道+epoll的通信機制,存在event丟失問題;

?

現象

用戶反饋凌晨的時候訪問百度某頁面,某些模塊的數據出不來;

其它依賴于我們的前端接口的產品線反饋訪問時間有時候超過1s;

我們自己的QA環境偶爾也會出現請求超過1s的問題;

因此我們打開lighttpd的日志的%D配置,打印ms級別的處理時間,發現晚上1點到凌晨8點有很多處理時間超過1s的請求,500ms以上的也有很多,并且流量越低, 比例越大;

1點-8點是流量低峰時期,流量越低,性能越差

這個現象每到高峰時期就正常了,因為是流量低峰才會出現這樣的慢請求,占總比例非常之少,對整體的性能和穩定性影響極小,所以性能和穩定性監控報表中沒有發現這個問題。

追查過程

由于這個頁面對性能要求相對比較嚴格,雖然性能和穩定性衡量數據已經非常好, 但是這個問題一直是一個陰影,不解決終歸不爽,所以開始了下面的追查過程:

由于處理路徑是lighttpd->php-cgi->框架+邏輯, 首先的懷疑是框架+邏輯問題,但是通過查看php的處理時間,流量低峰高峰都非常正常,極少超過100ms,所以排除是框架+邏輯問題;那究竟是php-cgi的問題還是lighttpd本身的問題呢?為了排除php-cgi的問題,我們嘗試了從線下復現這個問題,看訪問靜態文件是否也有類似的問題。但是悲劇的是線下就是復現不了這個問題。那再對比和線上環境的不同,會不會是先要經過一段時間的大流量,然后再小流量才會出現這個問題呢?于是用ab 30qps壓了2個小時后停止,然后再手動訪問試了一下,果然如此!通過訪問靜態文件,發現靜態文件也是如此,處理時間超過1s, 因此基本排除php-cgi本身的原因,問題應該是出在lighttpd本身

通過這個線下實驗,我們還發現了如下規律:

1.前期用ab壓的時間不定,有時候壓2個小時后然后低流量訪問還不會出現這個問題,有一定的隨機性;

2.手動低流量訪問的時候,并不是每次都慢,對同一個url, 緊接著的兩次訪問(訪問第一次后馬上訪問第二次),第一次會慢,但第二次會很快,然后再過個1-2s鐘再訪問第三次,又會很慢;

3.手動請求的時候,如果慢,總是慢1s, 但是線上有慢1s的,也有不是慢1s的,最多1s;

4.重啟lighttpd后,所有請求會恢復正常,需要重新壓;

于是產生兩個最大的疑問, lighttpd在公司使用這么廣,處理靜態資源和php請求的都有用到, 別的產品線為什么不報? 為什么是1s? 對于第一個疑問,覺得可能是因為這種情況影響的平均性能非常少,可能其他產品線不會這么敏感,或者是流量低峰的單機請求量也很高,沒有頻繁的觸發這個問題,這個時候還對比了其它產品線的lighttpd.conf, 這個時候是沒有發現有什么問題的。于是就從第二個問題開始著手追查:為什么是1s?

帶著問題,開始讀lighttpd的源代碼了。。。

該頁面lighttpd event-handler用的是linux-sysepoll;

首先發現lighttpd代碼中有各個地方和1s有關的代碼:

源文件server.c

第一個1000ms是lighttpd的epoll的超時時間,也就是如果沒有任何句柄有事件發生,epoll最多等待1000ms后即會返回,如果有事件發生,epoll會馬上返回有事件發生的所有句柄,然后lighttpd會處理joblist中已經準備好的connection,重新進入狀態機;第二個1s是lighttpd有個一個trigger機制,每隔1s會觸發一次SIGALRM, 然后lighttpd處理超時的請求,清理stat_cache等;因此,通過修改這兩個1s, 發現當改成fdevent_poll(srv->ev, 500);? 后,慢請求都變成500了, 所以慢請求是因為的那個connection已經放在joblist, 但是沒有成功觸發epoll返回, epoll只有等待超時后返回,該connection才會被處理,這也就解釋了為什么流量高峰的時候沒有這個問題,因為高峰的時候epoll返回得相當頻繁,也可以解釋為什么線上的慢請求慢100,200ms的都有,但是最多不超過1s了,線下手工訪問的時候總是慢1s, 這也是因為每秒的請求量的原因, 這其實也是類似epoll這種異步事件處理模型所帶來的通病,用延遲換吞吐量;

問題進一步,那為什么重啟lighttpd后,就算流量低也沒問題呢,所以進一步看代碼,通過把lighttpd所有debug日志打開,發現這個問題和lighttpd-的stat cache機制有關, 為了避免反復的調用stat來獲取文件信息,lighttpd用了一個全局的hash表保存了每個物理路徑的所對應文件的stat結果,這個機制和server. stat-cache-engine這個配置有關,我們用的默認配置“simple”, cache結果會緩存1s, 如果沒有命中或者失效,lighttpd會把這個stat任務放在一個隊列里面, 然后告訴狀態機HANDLER_WAIT_FOR_EVENT, 暫時退出狀態機,由另外幾個線程來異步處理這個stat任務,處理完這個任務后,會重新把這個任務關聯的connection加到joblist_queue中,然后通過管道通知主線程,讓epoll返回, 相關代碼如下:

源文件joblist.c

上面的代碼可以看出, lighttpd是通過判斷一個全局的變量srv->did_wakeup,如果是0,就把它改成1,然后往這個管道發生一個空格字符串,觸發主線程的epoll返回,如果這個變量不是0,就不會通知主進程。

下面的代碼是主線程epoll返回后,和這個管道句柄對于的處理函數,可以看出主線程又把srv->did_wakeup初始化成0了, 這樣下次還會wakeup主線程;

源文件server.c

這就引發一個思考,如果因為某種原因srv->did_wakeup被修改成1了,但是主線程由于某種原因沒有收到這個write事件,導致srv->did_wakeup沒有被改成0,那不是后面都不會通過管道通知主線程了,為了證明這個假設,我加了下trace代碼,發現確實是這樣的,設置srv->did_wakeup =1 做了2456次,但是設置srv->did_wakeup = 0只做了2455次,只差一次,并且后續都沒有做這個操作了,另外還發現子線程每次write管道都是成功的,但是最后一次主線程沒有收到這個事件,至于為什么沒有收到,就沒有繼續查了。

但是,還是有個疑問,我訪問的php請求,lighttpd應該把請求路徑發給php-fpm,自己應該不關心物理路徑的啊,就不用搞什么stat cache吧,這個時候想起了當時為了解決某擴展能夠正確獲取到PATH_INFO的問題,把mod_proxy_core的條件配置從$HTTP["url"] =~ “\.php$”改成了$PHYSICAL["existing-path"] =~ “\.php$”。馬上修改配置,再測試,問題果然沒有了, 通過查看lighttpd代碼,發現如果配置成$PHYSICAL這種形式,會導致lighttpd去stat這個物理文件,這個操作在mod_proxy_core之前執行,如果用$HTTP[“url”]就不會引發這個問題,到此,一切都清楚了,我看到的其它老的產品線都是配的$HTTP[“url”], 只有少數的幾個產品線不是用的$HTTP[“url”],也只是單機流量非常低的情況才會出現這個問題,很難會讓人覺察到!

另外,在追查問題的過程中還發現lighttpd stat_cache機制的兩個問題,第一個問題就是處理stat任務的子線程,在stat之后,并沒有更新這個stat cache的狀態為FINISHED, 下次來查的時候還是沒有命中cache, 等于是白干了。如下代碼所示:

源文件stat_cache.c

第二個問題是就是命中了stat cache, 其實還是需要調用stat判斷改cache有沒有過期, 所以覺得stat cache本身這個機制也是白搞了,比較沒有節省stat的開銷,還多搞了,如下代碼所示:

源文件stat_cache.c

遺留問題

子線程和主線程通過管道+epoll的機制來通信,為什么會有一定的概率失敗呢?write管道其實是成功的,由于精力有限,這個問題沒有繼續追查;

管道其實是成功的,由于精力有限,這個問題沒有繼續追查;

對lighttpd配置的建議

如果利用mod_proxy_core做php處理,還是用$HTTP[“url”]做條件吧,例如:

$HTTP["url"] =~ “\.php” {

proxy-core.balancer = “static”

proxy-core.protocol = “fastcgi”

proxy-core.allow-x-sendfile = “enable”

proxy-core.backends = ( “unix:/home/super/php/var/php-cgi.sock” )

proxy-core.rewrite-request = (

“_pathinfo” => ( “(/[^\?]*)/index\.php(/[^\?]*)” => “$2″ ),

“_scriptname” => ( “(.*\.php)” => “$1″ )

)

注意,為了讓php-cgi取到正確的PATH_IFNO, 請注意添加“_pathinfo” rewrite規則!

對lighttpd代碼優化的建議

1.在每隔1s的trigger操作中,新增一個操作:將srv->did_wakeup重置為0,防止這個變量變成1以后永遠便不會0的情況發生;
2.stat_cache_thread處理完stat_job之后,要更新源stat_cache_entry的狀態為FINISHED, 否則就白搞了;
3.命中stat cache后,不用再通過stat判斷該cache是不是最新的,因為最多緩存1s鐘;

?

?

【本文首發于:搜索研發部官方博客】http://stblog.baidu-tech.com/?p=1444 【關注百度技術沙龍

?


本文轉自百度技術51CTO博客,原文鏈接:http://blog.51cto.com/baidutech/779536,如需轉載請自行聯系原作者

總結

以上是生活随笔為你收集整理的流量低峰也烦人-lighttpd耗时长问题追查的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。