成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

由一條OpenResty Error log談?wù)刵gx.exit與ngx.eof的區(qū)別

wslongchen / 3076人閱讀

摘要:一看果然是在響應(yīng)發(fā)出后報(bào)的錯(cuò),但日志沒(méi)有反應(yīng)出報(bào)錯(cuò)的具體位置。而我期望的當(dāng)前請(qǐng)求直接終止,不應(yīng)該使用而是。自起,執(zhí)行成功返回,失敗則返回和錯(cuò)誤描述信息。

事由

我們基于Vanilla開(kāi)發(fā)了一個(gè)類似于一個(gè)網(wǎng)關(guān)的流量分發(fā)服務(wù),在原來(lái)的業(yè)務(wù)線上對(duì)不同的業(yè)務(wù)使用不同的后端(PHP、Python、Lua...)進(jìn)行處理,最近在緊鑼密鼓的測(cè)試(當(dāng)然這里咱們主要看問(wèn)題),在掃蕩日志的過(guò)程中發(fā)現(xiàn)有這樣的一條 [error] (日志已打碼)

2016/03/01 16:35:36 [error] 32462#0: *1 attempt to set ngx.status after sending out response headers while sending to client, client: xx.xx.xx.xx, server: x.sina.cn, request: "GET /xxx HTTP/1.1", host: "xx.sina.cn:9110"

沒(méi)錯(cuò),就是條: attempt to set ngx.status after sending out response headers while sending to client,大致意思是我在響應(yīng)頭已經(jīng)發(fā)出后又嘗試對(duì) ngx.status 進(jìn)行了修改,可是我肯定不會(huì)想那么干的,而且頁(yè)面請(qǐng)求看著明明是正常的。

本著認(rèn)真負(fù)責(zé)的態(tài)度,我又對(duì)代碼邏輯和寫法前前后后梳理數(shù)次,然事實(shí)上并沒(méi)有發(fā)現(xiàn)我試圖那么干,至少本意是確定的。面對(duì)這個(gè)幽靈般的錯(cuò)誤,一個(gè)程序員的直覺(jué)告訴我,肯定是我寫了一個(gè)bug?或者我的某些邏輯觸發(fā)了Vanilla的bug?或者觸發(fā)了OpenResty的bug?越想越激動(dòng),我必須把它找出來(lái)。

為了避免大家混淆各種Vanilla,這里先附上Vanilla項(xiàng)目地址:

Github:https://github.com/idevz/vanilla

GitOSC:http://git.oschina.net/idevz/vanilla

Debug

邏輯上肉眼沒(méi)看出什么問(wèn)題,只能通過(guò)debug來(lái)解決。到底哪行報(bào)出來(lái)的錯(cuò)誤呢?在公司開(kāi)發(fā)機(jī)上添加 --with-debug 參數(shù)重新編譯了OpenResty,打開(kāi)debug日志。

2016/03/01 16:35:36 [debug] 32462#0: *1 posix_memalign: 0000000000E8DA10:4096 @16
2016/03/01 16:35:36 [debug] 32462#0: *1 HTTP/1.1 200 OK
Server: openresty/1.9.3.1
Date: Tue, 01 Mar 2016 08:35:36 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Power-By: Vanilla-0.1.0-rc4
Set-Cookie: xx=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.sina.cn
Set-Cookie: xx=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=.sina.cn
cache-status: MISS
X-Powered-By: PHP/7.0.0

2016/03/01 16:35:36 [debug] 32462#0: *1 write new buf t:1 f:0 0000000000E8DA80, pos 0000000000E8DA80, size: 460 file: 0, size: 0
2016/03/01 16:35:36 [debug] 32462#0: *1 http write filter: l:0 f:0 s:460
2016/03/01 16:35:36 [debug] 32462#0: *1 lua sending last buf of the response body
2016/03/01 16:35:36 [debug] 32462#0: *1 http output filter "/xxx"
2016/03/01 16:35:36 [debug] 32462#0: *1 http copy filter: "/xxx"
2016/03/01 16:35:36 [debug] 32462#0: *1 lua capture body filter, uri "/xxx"
2016/03/01 16:35:36 [debug] 32462#0: *1 http postpone filter "/xxx" 00007FFFE0ECB970
2016/03/01 16:35:36 [debug] 32462#0: *1 http chunk: 0
2016/03/01 16:35:36 [debug] 32462#0: *1 write old buf t:1 f:0 0000000000E8DA80, pos 0000000000E8DA80, size: 460 file: 0, size: 0
2016/03/01 16:35:36 [debug] 32462#0: *1 write new buf t:0 f:0 0000000000000000, pos 00000000004F811A, size: 5 file: 0, size: 0
2016/03/01 16:35:36 [debug] 32462#0: *1 http write filter: l:1 f:0 s:465
2016/03/01 16:35:36 [debug] 32462#0: *1 http write filter limit 0
2016/03/01 16:35:36 [debug] 32462#0: *1 writev: 465 of 465
2016/03/01 16:35:36 [debug] 32462#0: *1 http write filter 0000000000000000
2016/03/01 16:35:36 [debug] 32462#0: *1 http copy filter: 0 "/xxx"
2016/03/01 16:35:36 [error] 32462#0: *1 attempt to set ngx.status after sending out response headers while sending to client, client: xx.xx.xx.xx, server: x.sina.cn, request: "GET /xxx HTTP/1.1", host: "xx.sina.cn:9110"

一看果然是在響應(yīng)發(fā)出后報(bào)的錯(cuò),但日志沒(méi)有反應(yīng)出報(bào)錯(cuò)的具體位置。沒(méi)辦法,我只能通過(guò)“二分步進(jìn)法”,打一堆日志來(lái)跟進(jìn),人肉找出來(lái)到底什么地方報(bào)的錯(cuò)。

ngx_log(ngx.ERR, "-------------=====1=======--------------------->")
ngx.exit(ngx.ERROR)

最后跟到這樣一處邏輯:

if response:response() then ngx.eof() end

請(qǐng)求正常完成后,response:response() 執(zhí)行結(jié)果確定是true,問(wèn)題一定出在 ngx.eof(),
我的本意在于如果在routerShutdown階段(Vanilla請(qǐng)求處理的第二個(gè)階段)請(qǐng)求完成響應(yīng),則后面的幾個(gè)階段就不再執(zhí)行,直接結(jié)束當(dāng)前請(qǐng)求。查閱文檔發(fā)現(xiàn) ngx.eof() 只是顯式指定了響應(yīng)流輸出結(jié)束,后面的代碼邏輯會(huì)在服務(wù)端繼續(xù)執(zhí)行。而我期望的當(dāng)前請(qǐng)求直接終止,不應(yīng)該使用 ngx.eof() 而是 ngx.exit()。下面我們細(xì)節(jié)來(lái)認(rèn)識(shí)下這兩個(gè)API。

ngx.eof() 與 ngx.exit()

雖然在OpenResty ngx-lua 模塊文檔中這兩個(gè)API文檔位置緊鄰,但用法和功能方面卻截然不同。

ngx.exit

用法: ngx.exit(status)
執(zhí)行上下文: rewrite_by_lua, access_by_lua, content_by_lua, header_filter_by_lua, ngx.timer., balancer_by_lua, ssl_certificate_by_lua*
ngx.exit()的使用相對(duì)簡(jiǎn)單些:

當(dāng)傳入的status >= 200(200即為ngx.HTTP_OK),ngx.exit() 會(huì)中斷當(dāng)前請(qǐng)求,并將傳入的狀態(tài)碼(status)返回給nginx。

當(dāng)傳入的status == 0(0即為ngx.OK)則 ngx.exit() 會(huì)中斷當(dāng)前執(zhí)行的phrase(ngx-lua模塊處理請(qǐng)求的階段,如content_by_lua*),進(jìn)而繼續(xù)執(zhí)行下面的phrase。

對(duì)于 ngx.exit() 需要進(jìn)一步注意的是參數(shù)status的使用,status可以傳入ngx-lua所定義的所有的HTTP狀態(tài)碼常量(如:ngx.HTTP_OK、ngx.HTTP_GONE、ngx.HTTP_INTERNAL_SERVER_ERROR等)和兩個(gè)ngx-lua模塊內(nèi)核常量(只支持NGX_OK和NGX_ERROR這兩個(gè),如果傳入其他的如ngx.AGAIN等則進(jìn)程hang住)。

文檔中推薦的 ngx.exit() 最佳實(shí)踐是同 return 語(yǔ)句組合使用,目的在于增強(qiáng)請(qǐng)求被終止的語(yǔ)義(return ngx.exit(...))。

ngx.eof

用法: ok, err = ngx.eof()
執(zhí)行上下文: rewrite_by_lua, access_by_lua, content_by_lua*
ngx.eof 除了前面所說(shuō)的顯式指定了響應(yīng)流輸出的結(jié)束,后面的邏輯繼續(xù)在服務(wù)端執(zhí)行外,還需要注意以下幾點(diǎn):

當(dāng)你禁用了HTTP1.1的keep-alive特性后可以通過(guò)調(diào)用 ngx.eof() 來(lái)使客戶端主動(dòng)斷開(kāi)連接,這個(gè)技巧可以用來(lái)做一些back-ground jobs 而不需要HTTP客戶端等待連接(不過(guò)文檔推薦的back-ground jobs的處理方式是 ngx.timer.at API,詳情請(qǐng)看文檔說(shuō)明)。

當(dāng)你創(chuàng)建子請(qǐng)求來(lái)請(qǐng)求在其他 location 配置的上游模塊時(shí),你應(yīng)該配置這些上游模塊來(lái)忽略客戶端連接的中斷,如果默認(rèn)不是忽略的話。例如默認(rèn)的標(biāo)準(zhǔn) ngx_http_proxy_module 模塊會(huì)在客戶端斷開(kāi)連接后立即同時(shí)終止子請(qǐng)求和主請(qǐng)求,所以在模塊 ngx_http_proxy_moduleproxy_ignore_client_abort 設(shè)置為開(kāi)啟(proxy_ignore_client_abort on;)就十分重要。

v0.8.3 起, ngx.eof() 執(zhí)行成功返回1,失敗則返回 nil 和錯(cuò)誤描述信息。

實(shí)踐發(fā)現(xiàn) ngx.exit()ngx.eof() 本質(zhì)區(qū)別在于ngx.exit()作用在于中斷當(dāng)前操作,不管是ngx-lua模塊請(qǐng)求處理的當(dāng)前階段還是整個(gè)請(qǐng)求,而 ngx.eof() 只是結(jié)束響應(yīng)流的輸出,中斷HTTP連接,后面的代碼邏輯還會(huì)繼續(xù)在服務(wù)端執(zhí)行,而且 ngx.eof()支持運(yùn)行的上下文比 ngx.exit()少太多, ngx.eof() 有返回值, ngx.exit()則沒(méi)有,因?yàn)檎?qǐng)求已經(jīng)結(jié)束。

在bug和debug中成長(zhǎng)

其實(shí)這是一個(gè)不大不小的bug,說(shuō)它小,因?yàn)楹髞?lái)我在文檔中對(duì)ngx.status的描述中發(fā)現(xiàn)這么一句 Setting ngx.status after the response header is sent out has no effect but leaving an error message in your nginx"s error log file 說(shuō)明,也就是試圖在響應(yīng)頭發(fā)出后更改ngx.status會(huì)在錯(cuò)誤日志中記錄一條 [error] 但是這個(gè)錯(cuò)誤對(duì)本次請(qǐng)求的響應(yīng)沒(méi)有影響;說(shuō)它大,如果沒(méi)有仔細(xì)查出來(lái)這個(gè)沒(méi)有影響,那一切都是未知,很可能給系統(tǒng)埋下一個(gè)未知的坑,不知道哪天就會(huì)爆出來(lái)坑你一下,關(guān)鍵的一點(diǎn)還是對(duì)API的理解。OpenResty的文檔是我見(jiàn)過(guò)開(kāi)源項(xiàng)目中寫的比較好的,雖然是英文。還是值得仔細(xì)研習(xí)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/39244.html

相關(guān)文章

  • nginx lua api解讀

    摘要:對(duì)于需要進(jìn)一步注意的是參數(shù)的使用,可以傳入所定義的所有的狀態(tài)碼常量如等和兩個(gè)模塊內(nèi)核常量只支持和這兩個(gè),如果傳入其他的如等則進(jìn)程住。 序 本文主要解讀下nginx lua module的主要方法和api。 ngx_lua運(yùn)行階段 showImg(https://segmentfault.com/img/bVHFqI?w=1005&h=910); initialization phase...

    shery 評(píng)論0 收藏0
  • Nginx+Lua+Redis訪問(wèn)頻率控制

    摘要:來(lái)處理訪問(wèn)控制的方法有多種,實(shí)現(xiàn)的效果也有多種,訪問(wèn)段,訪問(wèn)內(nèi)容限制,訪問(wèn)頻率限制等。用來(lái)做訪問(wèn)限制主要是考慮到高并發(fā)環(huán)境下快速訪問(wèn)控制的需求。處理請(qǐng)求的過(guò)程一共劃分為個(gè)階段,分別是在中,可以找到,,,等方法。那么訪問(wèn)控制應(yīng)該是,階段。 showImg(http://77l5jp.com1.z0.glb.clouddn.com/blog/logo-nginx-lua.png); ...

    沈儉 評(píng)論0 收藏0
  • OpenResty debugger: lua-resty-repl

    摘要:根據(jù)作者介紹這是一個(gè)簡(jiǎn)單和容易調(diào)試運(yùn)行在的。簡(jiǎn)單介紹一下這次大會(huì),這次大會(huì)的主題是開(kāi)發(fā),涉及到在前端系統(tǒng)框架集群服務(wù)語(yǔ)音云服務(wù)智能硬件等方面的實(shí)踐,以及軟件基金會(huì)背后的故事。 在2016年第二屆 OpenResty 的全球開(kāi)發(fā)者大會(huì)上看到了一個(gè)比較有意思的項(xiàng)目 lua-resty-repl,后來(lái)聽(tīng)聞一些開(kāi)發(fā)者看了項(xiàng)目的介紹后還是覺(jué)得一頭霧水,不知道怎么使用。這篇文章主要是介紹一下這個(gè)項(xiàng)...

    zhonghanwen 評(píng)論0 收藏0
  • OpenrestyOpenresty增加waf配置

    摘要:說(shuō)明防止注入,本地包含,部分溢出,測(cè)試,等攻擊防止備份之類文件泄漏防止之類壓力測(cè)試工具的攻擊屏蔽常見(jiàn)的掃描黑客工具,掃描器屏蔽異常的網(wǎng)絡(luò)請(qǐng)求屏蔽圖片附件類目錄執(zhí)行權(quán)限防止上傳下載使用使用安裝下載解壓后,將整放到目錄中,并命名為配置安裝路徑假 1. Ngx lua waf 說(shuō)明 防止sql注入,本地包含,部分溢出,fuzzing測(cè)試,xss,SSRF等web攻擊防止svn/備份之類文件泄...

    iliyaku 評(píng)論0 收藏0
  • openresty 日志輸出處理

    摘要:我處理的方式是使用每一個(gè)請(qǐng)求,都會(huì)有自己獨(dú)立的這個(gè)會(huì)貫穿整個(gè)請(qǐng)求的始終,簡(jiǎn)單的函數(shù)如下到了階段要把追蹤日志寫入到硬盤里,處理代碼如下小于秒的請(qǐng)求不記錄可以用在模塊,也可以用在模塊,也能直接精確到模塊,即只到某個(gè)請(qǐng)求。 最近出了個(gè)故障,有個(gè)接口的請(qǐng)求居然出現(xiàn)了長(zhǎng)達(dá)幾十秒的處理時(shí)間,由于日志缺乏,網(wǎng)絡(luò)故障也解除了,就沒(méi)法再重現(xiàn)這個(gè)故障了。為了可以在下次出現(xiàn)問(wèn)題的時(shí)候能追查到問(wèn)題,所以需要添...

    BingqiChen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<