近期剛改版了上月上線的一個産品應用,以應對将來可能的高并發問題。
第一版産品采用的是Jquery,Nginx,PHP(CI架構),Memcache,Mysql這種常用的架構。作為一名PHP工程師對于這種架構已經非常的熟悉了,目前站點并發并不是很高,線上環境使用的是阿裡雲主機,1.5G的記憶體,PHP并發能支援400~500左右。因為使用memcache的原因,如果在并發特别高的情況下,除了帶寬瓶頸以外就可能會是一直引以為傲PHP瓶頸了。增加機器便會增加成本,對于一個剛剛上線運作的項目,要求公司擴大投入是不合理的。
于是在第二次改版的過程中我們嘗試放棄PHP,采用OpenResty中的LuaJit子產品直接讀取redis中的資料以Json的格式傳回給前端頁面展示,使用PHP腳本定時執行向redis裡面更新内容。這樣整合個前端過程就沒啥php與mysql哈事了(除後端定時執行腳本之外)。憑着nginx與redis的高并發,還怕啥呀!。下圖為新的架構主要結構。
Redis是一個高性能的key-value資料庫。redis的出現,很大程度補償了memcache這類key-value存儲的不足,在部分場合可以對關系資料庫起到很好的補充作用。它提供了Python,Ruby,Erlang,PHP用戶端,使用很友善。
性能測試結果:SET操作每秒鐘110000 次,GET操作每秒鐘81000 次
有了Redis作為保障,新架構就可以開搞了,使用到的主要關鍵詞由openResty,LuaJit,Lua,Redis,PHP,PHPRedis,JSon,JQuery等組成。讀者可以搜尋下各名詞了解它們的功能。下面是openResty中的Nginx配置:
nginx.conf
server {
listen 80;
root/home/boolean/Htdocs/lib.bincent.com;
index index.htmlindex.htm;
server_namelib.bincent.cn;
#預設請求Html轉發到apache,這裡你可以根據自己情況配置
location /
{
proxy_redirect off;
proxy_set_header HOST$host;
proxy_set_headerSERVER_ADDR $server_addr;
proxy_set_headerSERVER_PORT $server_port;
proxy_set_headerREMOTE_ADDR $remote_addr;
proxy_set_headerREMOTE_PORT $remote_port;
}
#更新redis
location /set_redis
internal;
set_unescape_uri$key $arg_key;
set_unescape_uri$val $arg_val;
redis2_queryset $key $val;
redis2_pass127.0.0.1:6379;
#讀取redis
location /get_redis
{
internal;
set_unescape_uri$key $arg_key;
redis2_queryget $key;
redis2_pass127.0.0.1:6379;
}
# 模拟的簡單請求
location /json
default_typetext/html;
content_by_lua_file/home/boolean/Htdocs/lib.bincent.com/lua/redis.lua;
}
redis.lua檔案
#通過URL更新redis
functionsetRedis(key, val)
localres = ngx.location.capture('/set_redis', {
args= {
key= key,
val= val
}
})
ifres.status == 200 then
returntrue
else
returnfalse
end
end
#通過URL讀取redis
functiongetRedis(key)
localcapture = ngx.location.capture('/get_redis', {
key= key
localparser = require 'redis.parser' --require redis.parser
localres, err = parser.parse_reply(capture.body)
returnres
#URL參數$_GET['a']
locala = ngx.var.arg_a
if'clean' == a then
--重置redis
ifsetRedis('love_number', 0) then
ngx.say("CleanRedis Is Success!")
ngx.say("CleanRedis Is failted!")
else
--讀取redis
locallove_number = getRedis('love_number') + 1
setRedis('love_number',love_number)
ngx.say("CurrentLove Number Is: ", love_number)
end如何聯系我:【萬裡虎】www.bravetiger.cn
【QQ】3396726884 (咨詢問題100元起,幫助解決問題500元起)
【部落格】http://www.cnblogs.com/kenshinobiy/