項目背景:html
當生產產生異常流量而又沒法快速定位流量來源,爲減小數據庫負載,經過全局緩存預熱,以及快速切緩存開關,來控制全站流量導入緩存,減小異常狀況下對數據庫的壓力。java
整體實現爲nginx+memcache+Luanginx
1 首先查看一下nginx版本:git
[root@squid1 sbin]# /usr/local/nginx/sbin/nginx -vgithub
Tengine version: Tengine/2.1.2 (nginx/1.6.2)redis
此處nginx使用的是tengine版,nginx版本必須1.6.0以上。不是則到 http://tengine.taobao.org 下載tengine最新版本。算法
2 安裝Lua環境數據庫
到官網http://luajit.org/download.html 下載安裝包到本地並解壓緩存
tar –zxvf /usr/local/src/LuaJIT-2.0.4.tar.gz服務器
cd LuaJIT-2.0.4
make&&make install
查看是否成功:
[root@puppetmaster LuaJIT-2.0.4]# ls /usr/local/lib
libluajit-5.1.a libluajit-5.1.so libluajit-5.1.so.2 libluajit-5.1.so.2.0.4 lua pkgconfig
[root@puppetmaster LuaJIT-2.0.4]# ls /usr/local/include/luajit-2.0
lauxlib.h luaconf.h lua.h lua.hpp luajit.h lualib.h
編輯/etc/profile文件添加環境變量:
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.0
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
3 下載nginx所需模塊源碼包到/usr/local/src下,並解壓
https://github.com/simpl/ngx_devel_kit (nginx開發環境模塊)
https://github.com/openresty/set-misc-nginx-module (nginx變量函數,算法模塊)
https://github.com/openresty/srcache-nginx-module (緩存http請求,響應定製模塊)
https://github.com/openresty/memc-nginx-module (memcached緩存模塊)
https://github.com/openresty/lua-nginx-module (lua腳本開發框架模塊)
4 tengine再編譯
Tengine的dso_tool是動態加載的工具,用法爲:
/usr/local/nginx/sbin/dso_tool --add-module=/usr/local/src/memc-nginx-module-master
可是並非全部模塊均可以動態加載,因此這裏用再編譯靜態加載。
編譯前查看一下如今程序的編譯參數:
[root@puppetmaster sbin]# /usr/local/nginx/sbin/nginx –V
tar -zxvf /usr/local/src/tengine-2.1.2.tar.gz
cd /usr/local/src/tengine-2.1.2
在以前編譯參數上再將下載的nginx模塊參數添加上編譯:
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx
--with-http_concat_module
--with-http_addition_module
--with-http_dav_module
--with-http_gzip_static_module
--with-http_image_filter_module
--with-http_realip_module
--with-http_stub_status_module
--with-http_ssl_module
--with-http_sub_module
--with-ipv6
--with-file-aio
--with-sha1=/usr/include/openssl
--with-md5=/usr/include/openssl
--with-mail
--with-mail_ssl_module
--with-http_xslt_module
--with-http_geoip_module
--with-http_flv_module
--with-http_mp4_module
--with-http_gzip_static_module
--with-http_random_index_module
--with-http_secure_link_module
--with-http_degradation_module
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic'
--with-ld-opt=-Wl,-E
--add-module=/usr/local/src/ngx_devel_kit-master --add-module=/usr/local/src/set-misc-nginx-module-master --add-module=/usr/local/src/srcache-nginx-module-master --add-module=/usr/local/src/memc-nginx-module-master --add-module=/usr/local/src/lua-nginx-module-master
make
make install
tengine的再編譯並不會將原來自建的配置文件如nginx.conf刪除。
能夠查看一下是否已將模塊編譯進去
[root@puppetmaster sbin]# /usr/local/nginx/sbin/nginx –V
5 將lua源碼並上傳到nginx服務器
/data/nfsroot/client/ngx_lua/
6 新建nginx的配置文件cache.conf用於nginx調用各個模塊
Vim /usr/local/nginx/conf/cache.conf
set $cache_fetch_skip 1;
set $cache_store_skip 1;
set $cmd_key $host$request_uri;
srcache_response_cache_control off;
rewrite_by_lua_file /data/nfsroot/client/ngx_lua/cache_config.lua;
srcache_methods GET; #GET POST
srcache_fetch_skip $cache_fetch_skip;
srcache_store_skip $cache_store_skip;
srcache_store_statuses 200 201 301 302; #200 201 301 302 500
srcache_fetch GET /memc $cmd_key;
srcache_store PUT /memc $cmd_key;
add_header X-Cached-From $srcache_fetch_status;
7 修改配置文件nginx.cof
添加upstream,主機爲memcache服務器
upstream memc_server1 {
server 192.168.0.1:12000;
keepalive 512;
}
upstream memc_server2 {
server 192.168.0.2:12000;
keepalive 512;
}
upstream_list memc_servers memc_server1 memc_server2;
在所須要的虛擬主機下添加:如www.hello.com
location /memc {
#容許內網訪問
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $memc_key $host$request_uri;
#一致性hash算法和java客戶端相似
set_hashed_upstream $memc_backends memc_servers $memc_key;
#設置緩存時間 10分鐘
set $memc_exptime 600;
memc_pass $memc_backends;
}
在所須要緩存的應用下添加配置文件路徑,如:
location /local/{
include /usr/local/nginx/conf/cache.conf;
proxy_pass http://hello_servers/hello/route/;
}
8 pkill nginx
/usr/local/nginx/sbin/nginx -c /etc/nginx/conf/nginx.conf
主要原理:
經過lua 腳本控制緩存的存開關和取開關
/data/nfsroot/client/ngx_lua/cache_config.lua;
ngx.var.cache_fetch_skip=0 標示抓取緩存
ngx.var.cache_store_skip=0 標示緩存被代理的緩存
ngx.var.cache_fetch_skip=1 跳過GET緩存
ngx.var.cache_store_skip=1 跳過PUT緩存
通常咱們只須要設置成這樣既可
ngx.var.cache_fetch_skip=1 標示抓取緩存 須要的時候 修改成0 reload nginx 全站緩存開啓,抵禦流量
ngx.var.cache_store_skip=0 預熱到緩存
附lua源碼
[root@squid1 client]# tree ngx_lua
ngx_lua
├── cache_config.lua
├── module
│ ├── limit_share.lua
│ ├── mySqlClient.lua
│ ├── redisClient.lua
│ └── share.lua
├── README.md
└── test.lua
cache_config.lua
1 ngx.var.cache_fetch_skip=1 2 ngx.var.cache_store_skip=0
limit_share.lua
1 local _M = {} 2 local lrucache = require "lrucache" 3 local c = lrucache.new(600) -- allow up to 200 items in the cache 4 if not c then 5 return error("failed to create the cache: " .. (err or "unknown")) 6 end 7 --開啓全站緩存 8 c:set("full_cache",0) 9 c:set("CACHE_POST",0) 10 function _M.go() 11 c:set("dog", 32) 12 c:set("cat", 56) 13 -- ngx.say("dog: ", c:get("dog")) 14 -- ngx.say("cat: ", c:get("cat")) 15 16 -- c:set("dog", { age = 10 }, 0.1) -- expire in 0.1 sec 17 -- c:delete("dog") 18 end 19 20 function _M.getC() 21 return c 22 end 23 24 return _M
mySqlClient.lua
redisClient.lua
1 local redis = require("redis") 2 local _Redis ={} 3 function _Redis:client() 4 5 local red = redis:new() 6 7 red:set_timeout(1000) -- 1 sec 8 9 10 local ok, err = red:connect("192.168.59.103", 6379) 11 if not ok then 12 ngx.say("failed to connect to redis: ", err) 13 else 14 ngx.ctx.redis=red 15 end 16 17 return ngx.ctx.redis 18 end 19 20 --- 關閉鏈接 21 function _Redis:close() 22 if ngx.ctx.redis then 23 ngx.ctx.redis:set_keepalive(10000, 100) 24 ngx.ctx.redis = nil 25 end 26 end 27 28 return _Redis
share.lua
1 local _M = {} 2 local lrucache = require "lrucache" 3 local c = lrucache.new(200) -- allow up to 200 items in the cache 4 if not c then 5 return error("failed to create the cache: " .. (err or "unknown")) 6 end 7 8 function _M.go() 9 10 -- ngx.say("dog: ", c:get("dog")) 11 -- ngx.say("cat: ", c:get("cat")) 12 13 -- c:set("dog", { age = 10 }, 0.1) -- expire in 0.1 sec 14 -- c:delete("dog") 15 end 16 17 function _M.check(args) 18 ngx.say(args) 19 return c:get(args) 20 end 21 22 function _M.getC() 23 if ngx.ctx.c then 24 return ngx.ctx.c 25 end 26 27 ngx.ctx.c=c 28 return ngx.ctx.c 29 end 30 31 return _M