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

資訊專(zhuān)欄INFORMATION COLUMN

對(duì) ngx.ctx 的一次 hack

qc1iu / 2917人閱讀

摘要:于是才有了對(duì),或者說(shuō)的一次過(guò)程。另外,這類(lèi)基礎(chǔ)的操作,不適合存放在業(yè)務(wù)態(tài),由調(diào)用者自己控制,因?yàn)檫@兩個(gè)函數(shù)必須成對(duì)調(diào)用,否則就會(huì)造成內(nèi)存泄漏。使用之后,強(qiáng)烈建議進(jìn)行壓測(cè),確認(rèn)沒(méi)有內(nèi)存泄漏的隱患。

緣起

ngx.ctxlua-nginx-module 提供的一個(gè)充滿(mǎn)魔力的 Lua table,它可以存放任何我們想要存放的內(nèi)容,生命周期貫穿整個(gè) location,也正因?yàn)樯芷诰窒拊趩蝹€(gè) location 里,所以當(dāng)發(fā)生內(nèi)部跳轉(zhuǎn)(例如通過(guò) ngx.exec)之后,之前的 ngx.ctx
將被銷(xiāo)毀。所以很多時(shí)候,我們不得不轉(zhuǎn)而使用 ngx.var.VARIABLE 來(lái)替代 ngx.ctx,例如我們需要在 log 階段的時(shí)候收集之前準(zhǔn)備好的字段,然后發(fā)送到日志服務(wù)器或者 nsq 等組件。

然而,事物總是具有兩面性,`ngx.var.VARIABLE` 生命周期雖然貫穿于一個(gè)請(qǐng)求,但是其代價(jià)卻更加昂貴,它具有計(jì)算 `hash` 值,查找 `hash` 表,分配內(nèi)存等等操作,這相比于 `ngx.ctx` 實(shí)在是繁重得多了。通過(guò)觀察火焰圖,大量的使用 `ngx.var.VARIABLE` 已經(jīng)成為了一個(gè)瓶頸。于是才有了對(duì) `ngx.ctx`,或者說(shuō) `ngx.exec` 的一次 hack 過(guò)程。

ngx.ctx

既然要對(duì) ngx.ctx 進(jìn)行 hack,首先需要了解 ngx.ctx 的機(jī)制,事實(shí)上,ngx.ctx 就是一個(gè)普通的 Lua table,lua-nginx-module 創(chuàng)建一個(gè) table 之后,將其存放在 Lua 的注冊(cè)表里,利用 luaL_ref 來(lái)索引每個(gè) ngx.ctx,利用 luaL_unref 來(lái)解除索引。這個(gè)索引,是被存放在 lua-nginx-module 的模塊上下文里的,也就是 ngx_http_lua_ctx_s::ctx_ref 這個(gè)成員變量。

為什么經(jīng)過(guò)內(nèi)部跳轉(zhuǎn),ngx.ctx 會(huì)被銷(xiāo)毀

Nginx 核心在進(jìn)行內(nèi)部跳轉(zhuǎn)的時(shí)候,會(huì)把對(duì)應(yīng)請(qǐng)求所有的模塊上下文全部清除,可以參考函數(shù) ngx_http_internal_redirect,所以 lua-nginx-modulectx_ref 也會(huì)被銷(xiāo)毀。在 lua-nginx-module 關(guān)于 ngx.exec 的源碼里也可以看到對(duì) ngx.ctx 的解索引過(guò)程。

Hack it

了解了它的機(jī)制之后,我們可以試著來(lái)繞過(guò)這種限制,既然 lua-nginx-module 利用一個(gè)數(shù)字來(lái)索引 ngx.ctx,我們也可以主動(dòng)創(chuàng)建一個(gè)索引,將它存在一個(gè)介質(zhì)里,只要這個(gè)介質(zhì)不隨著內(nèi)部跳轉(zhuǎn)而消失即可(例如 Nginx 變量就是一個(gè)非常好的選擇),等到內(nèi)部跳轉(zhuǎn)完成之后,第一時(shí)間將 ngx.ctx 恢復(fù)出來(lái)即可,下面來(lái)介紹下這個(gè)過(guò)程。

首先我們需要一個(gè)變量

set ctx_ref "";

設(shè)計(jì)一個(gè)函數(shù),創(chuàng)建一個(gè)新的索引

function _M.stash_ngx_ctx()
    local ctxs = registry.ngx_lua_ctx_tables
     local ctx_ref = base.ref_in_table(ctxs, ngx.ctx)
    ngx.var.ctx_ref = tostring(ctx_ref)
end

registry 就是 Lua 的注冊(cè)表,通過(guò)下面的方法獲得。

local debug = require "debug"
local registry = debug.getregistry()

所有請(qǐng)求的 ngx.ctx 放置在一張表里,這張表存放在注冊(cè)表里,key 就是 "ngx_http_lua_ctx_tables",所以上述代碼里的 ctxs 就是存放所有請(qǐng)求的 ngx.ctx 的那張表了。

local ctx_ref = base.ref_in_table(ctxs, ngx.ctx)

這行代碼給 ngx.ctx 創(chuàng)建了一個(gè)新的索引,關(guān)于具體的細(xì)節(jié),大家有興趣可以查看 lua-resty-corebase.ref_in_table,這個(gè)函數(shù)的原理和 luaL_ref 一致。

拿到索引之后,將它存放到我們的變量即可。至此,當(dāng)前請(qǐng)求的 ngx.ctx 就存在 2 個(gè)索引了(一個(gè)索引由 lua-nginx-module 管理,另外一個(gè)則由我們自己管理)。

執(zhí)行完內(nèi)部跳轉(zhuǎn)后,恢復(fù)跳轉(zhuǎn)前的 ngx.ctx

function _M.apply_ngx_ctx()
    local ctx_ref = tonumber(ngx.var.ctx_ref)
     if not ctx_ref then
        return
    end
 
     local ctxs = registry.ngx_lua_ctx_tables
     local origin_ngx_ctx = ctxs[ctx_ref]
     ngx.ctx = origin_ngx_ctx

     local FREE_LIST_REF = 0
     ctxs[ctx_ref] = ctxs[FREE_LIST_REF]
     ctxs[FREE_LIST_REF] = ctx_ref
     ngx.var.ctx_ref = ""
 end

我們通過(guò)存放在變量的 ctx_ref 來(lái)得到執(zhí)行內(nèi)部跳轉(zhuǎn)前的 ngx.ctx 表,接著需要把我們自己管理的這個(gè)索引解除,否則會(huì)造成嚴(yán)重的內(nèi)存泄漏!

    local FREE_LIST_REF = 0
     ctxs[ctx_ref] = ctxs[FREE_LIST_REF]
     ctxs[FREE_LIST_REF] = ctx_ref

這三行代碼即完成了解索引(和 LuaL_unref 一直),這里簡(jiǎn)單解釋下, LuaL_unref 管理索引的時(shí)候,用 0 這個(gè) index 記錄上一次解索引的 index(為 nil 則表示目前還沒(méi)有過(guò)解索引的操作),所以上述兩行代碼,實(shí)際上就是在當(dāng)前需要解索引的 index 處記錄了上一次解索引的 index,然后在 0 下標(biāo)處記錄當(dāng)前最新的 index,有點(diǎn)像鏈表。這樣操作有什么好處呢?當(dāng)下次需要產(chǎn)生索引的時(shí)候,可以首先檢查 0 下標(biāo),看看是否有解過(guò)索引的位置,如果有,復(fù)用即可,否則需要返回 #table + 1,所以利用這個(gè) “鏈表”,可以避免很多 Lua table 擴(kuò)大,導(dǎo)致內(nèi)存拷貝,影響到性能。

后續(xù)

這兩個(gè)函數(shù)的代碼已經(jīng)經(jīng)過(guò)充分測(cè)試,目前已經(jīng)運(yùn)行在我們的一個(gè)項(xiàng)目當(dāng)中。

另外,這類(lèi)基礎(chǔ)的 Hack 操作,不適合存放在業(yè)務(wù)態(tài),由調(diào)用者自己控制,因?yàn)檫@兩個(gè)函數(shù)必須成對(duì)調(diào)用,否則就會(huì)造成內(nèi)存泄漏。

使用之后,強(qiáng)烈建議進(jìn)行壓測(cè),確認(rèn)沒(méi)有內(nèi)存泄漏的隱患。

如果你有更多的 idea,可以給我發(fā)送郵件([email protected])。

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

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

相關(guān)文章

  • 【Nginx源碼研究】Master進(jìn)程淺析

    摘要:內(nèi)核代表進(jìn)程來(lái)執(zhí)行信號(hào)處理器函數(shù),當(dāng)處理器返回時(shí),主程序會(huì)在處理器被中斷的位置恢復(fù)執(zhí)行。進(jìn)程信號(hào)掩碼內(nèi)核會(huì)為每個(gè)進(jìn)程維護(hù)一個(gè)信號(hào)掩碼。這個(gè)競(jìng)態(tài)條件發(fā)生在主程序和信號(hào)處理器對(duì)同一個(gè)被解除信號(hào)的競(jìng)爭(zhēng)關(guān)系。 運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 季偉濱 一、前言 眾所周如,Nginx是多進(jìn)程架構(gòu)。有1個(gè)master進(jìn)程和N個(gè)worker進(jìn)程,一般N等于cpu的核數(shù)。另外, 和文件緩存相關(guān),還有cache mana...

    wupengyu 評(píng)論0 收藏0
  • Nginx 源碼分析:從模塊到配置(上)

    摘要:結(jié)構(gòu)體數(shù)組,用來(lái)表示該模塊可以在配置文件中配置的項(xiàng)目,及其操作指令。 源文件路徑 srccore gx_conf_file.h srccore gx_conf_file.c 主要內(nèi)容 本篇的主要目的在于分析Nginx的配置功能。由于Nginx的配置基本就是對(duì)模塊的配置,因此,在討論配置功能之前,需要先分析Nginx的模塊功能。 對(duì)于模塊功能,這里的重點(diǎn)不在于某個(gè)模塊的細(xì)節(jié),而...

    gotham 評(píng)論0 收藏0
  • 【Nginx源碼研究】nginx限流模塊詳解

    摘要:限流算法最簡(jiǎn)單粗暴的限流算法就是計(jì)數(shù)器法了,而比較常用的有漏桶算法和令牌桶算法計(jì)數(shù)器計(jì)數(shù)器法是限流算法里最簡(jiǎn)單也是最容易實(shí)現(xiàn)的一種算法。 運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 李樂(lè) 高并發(fā)系統(tǒng)有三把利器:緩存、降級(jí)和限流; 限流的目的是通過(guò)對(duì)并發(fā)訪(fǎng)問(wèn)/請(qǐng)求進(jìn)行限速來(lái)保護(hù)系統(tǒng),一旦達(dá)到限制速率則可以拒絕服務(wù)(定向到錯(cuò)誤頁(yè))、排隊(duì)等待(秒殺)、降級(jí)(返回兜底數(shù)據(jù)或默認(rèn)數(shù)據(jù)); 高并發(fā)系統(tǒng)常見(jiàn)的限流有:限制總并發(fā)...

    voyagelab 評(píng)論0 收藏0
  • ngx_http_limit_req_module 源碼分析

    摘要:如果當(dāng)前需要延遲處理,又會(huì)把請(qǐng)求放到定時(shí)器中,等到定時(shí)器過(guò)期以后,執(zhí)行寫(xiě)事件回調(diào),這個(gè)函數(shù)里會(huì)執(zhí)行,重新進(jìn)行的個(gè)階段。 ngx_http_limit_req_module 是 Nginx 官方提供的一個(gè) http 模塊,它工作在 NGX_HTTP_PREACCESS_PHASE 階段,通過(guò)在 nginx.conf 中進(jìn)行簡(jiǎn)單地配置,我們可以輕易地對(duì)請(qǐng)求速率進(jìn)行限制。 配置指令 官方文檔...

    lentrue 評(píng)論0 收藏0
  • 不再依靠巧合編寫(xiě) Nginx 配置

    摘要:找到這個(gè)模塊的指令后,則會(huì)調(diào)用這個(gè)指令的解析回調(diào)函數(shù)即結(jié)構(gòu)體的第三個(gè)參數(shù)來(lái)進(jìn)行處理。調(diào)用他們上面提到的中的回調(diào)函數(shù)來(lái)申請(qǐng)和初始化對(duì)應(yīng)模塊的配置結(jié)構(gòu)體。需要注意的是,即時(shí)當(dāng)前是直接在塊級(jí)別,這三個(gè)回調(diào)函數(shù)都會(huì)被調(diào)用。拒絕暴力枚舉式編寫(xiě)配置文件 原博:https://blog.coordinate35.cn/... 熱身 首先來(lái)看下這幾個(gè)小例子: 第一個(gè)例子: server { l...

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

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

0條評(píng)論

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