在
之前的文章中,已經介紹了ngx_lua的一些基本介紹,這篇文章主要著重討論一下如何通過ngx_lua同後端的memcached、redis進行非阻塞通訊。
1. memcached
在nginx中訪問memcached需要模組的支援,這裡選用httpmemcmodule,這個模組可以與後端的memcached進行非阻塞的通訊。我們知道官方提供了memcached,這個模組只支援get操作,而memc支援大部分memcached的命令。
memc模組採用入口變數作為引數進行傳遞,所有以$memc_為字首的變數都是memc的入口變數。memc_pass指向後端的memcached server。
配置:[plain]view plain
copy
print?
#使用httpmemcmodule
location = /memc
輸出:[plain]view plain
這就實現了memcached的訪問,下面看一下如何在lua中訪問memcached。
配置:[plain]view plain
copy
print?
#在lua中訪問memcached
location = /memc
location = /lua_memc
})
if res.status == 200 then
ngx.say(res.body)
end
';
}
輸出:
通過lua訪問memcached,主要是通過子請求採用一種類似函式呼叫的方式實現。首先,定義了乙個memc location用於通過後端memcached通訊,就相當於memcached storage。由於整個memc模組時非阻塞的,ngx.location.capture也是非阻塞的,所以整個操作非阻塞。
2. redis
訪問redis需要httpredis2module的支援,它也可以同redis進行非阻塞通行。不過,redis2的響應是redis的原生響應,所以在lua中使用時,需要解析這個響應。可以採用luaredismodule,這個模組可以構建redis的原生請求,並解析redis的原生響應。
配置:[plain]view plain
copy
print?
#在lua中訪問redis
location = /redis
location = /lua_redis
})
if res.status == 200 then
reply = parser.parse_reply(res.body)
ngx.say(reply)
end
';
}
輸出:
和訪問memcached類似,需要提供乙個redis storage專門用於查詢redis,然後通過子請求去呼叫redis。
3. redis pipeline 在實際訪問redis時,有可能需要同時查詢多個key的情況。我們可以採用ngx.location.capture_multi通過傳送多個子請求給redis storage,然後在解析響應內容。但是,這會有個限制,nginx核心規定一次可以發起的子請求的個數不能超過50個,所以在key個數多於50時,這種方案不再適用。
幸好redis提供pipeline機制,可以在一次連線中執行多個命令,這樣可以減少多次執行命令的往返時延。客戶端在通過pipeline傳送多個命令後,redis順序接收這些命令並執行,然後按照順序把命令的結果輸出出去。在lua中使用pipeline需要用到redis2模組的redis2_raw_queries進行redis的原生請求查詢。
配置:[plain]view plain
copy
print?
#在lua中訪問redis
location = /redis
location = /pipeline
pipeline.lua
[plain]view plain
copy
print?
-- conf/pipeline.lua file
local parser = require(『redis.parser』)
local reqs = ,
} -- 構造原生的redis查詢,get one\r\nget two\r\n
local raw_reqs = {}
for i, req in ipairs(reqs) do
table.insert(raw_reqs, parser.build_query(req))
end
local res = ngx.location.capture(『/redis?』..#reqs, )
if res.status and res.body then
-- 解析redis的原生響應
local replies = parser.parse_replies(res.body, #reqs)
for i, reply in ipairs(replies) do
ngx.say(reply[1])
end
end
輸出:
前面訪問redis和memcached的例子中,在每次處理乙個請求時,都會和後端的server建立連線,然後在請求處理完之後這個連線就會被釋放。這個過程中,會有3次握手、timewait等一些開銷,這對於高併發的應用是不可容忍的。這裡引入connection pool來消除這個開銷。
連線池需要httpupstreamkeepalivemodule模組的支援。
配置:[plain]view plain
這個模組提供keepalive指令,它的context是upstream。我們知道upstream在使用nginx做反向**時使用,實際upstream是指「上游」,這個「上游」可以是redis、memcached或是mysql等一些server。upstream可以定義乙個虛擬server集群,並且這些後端的server可以享受負載均衡。keepalive 1024就是定義連線池的大小,當連線數超過這個大小後,後續的連線自動退化為短連線。連線池的使用很簡單,直接替換掉原來的ip和埠號即可。
有人曾經測過,在沒有使用連線池的情況下,訪問memcached(使用之前的memc模組),rps為20000。在使用連線池之後,rps一路飆到140000。在實際情況下,這麼大的提公升可能達不到,但是基本上100-200%的提高還是可以的。
5. 小結
這裡對memcached、redis的訪問做個小結。
1. nginx提供了強大的程式設計模型,location相當於函式,子請求相當於函式呼叫,並且location還可以向自己傳送子請求,這樣構成乙個遞迴的模型,所以採用這種模型實現複雜的業務邏輯。
2. nginx的io操作必須是非阻塞的,如果nginx在那阻著,則會大大降低nginx的效能。所以在lua中必須通過ngx.location.capture發出子請求將這些io操作委託給nginx的事件模型。
3. 在需要使用tcp連線時,盡量使用連線池。這樣可以消除大量的建立、釋放連線的開銷。
使用ngx lua構建高併發應用(2)
在之前的文章中,已經介紹了ngx lua的一些基本介紹,這篇文章主要著重討論一下如何通過ngx lua同後端的memcached redis進行非阻塞通訊。1.memcached 在nginx中訪問memcached需要模組的支援,這裡選用httpmemcmodule,這個模組可以與後端的memca...
使用ngx lua構建高併發應用(2)
這篇文章簡單介紹了一下ngx lua的基本用法,後一篇會對ngx lua訪問redis memcached已經連線池進行詳細介紹。在之前的文章 中,已經介紹了ngx lua的一些基本介紹,這篇文章主要著重討論一下如何通過ngx lua同後端的memcached redis進行非阻塞通訊。1.memc...
Ngx lua與go高併發效能對比
language lifeibo 1 comment nginx在處理高併發能力上非常出色,而go作為新時代網際網路語言,在設計之初就為實現高併發。ngx lua由nginx來處理網路事件,並使用協程來實現非阻塞,從而實現高併發。go語言級別提供非阻塞的api,同樣使用協程來提供高併發處理。我們來測...