nginx+memcache增加全站缓存系统

项目背景:

    当生产产生异常流量而又无法快速定位流量来源,为减少数据库负载,通过全局缓存预热,以及快速切缓存开关,来控制全站流量导入缓存,减少异常情况下对数据库的压力。

 

总体实现为nginx+memcache+Lua

 

1 首先查看一下nginx版本:

 

  [root@squid1 sbin]# /usr/local/nginx/sbin/nginx -v

Tengine version: Tengine/2.1.2 (nginx/1.6.2)

 

此处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

 

posted @ 2016-03-01 16:07  我是小蚂蚁  阅读(1104)  评论(0编辑  收藏  举报