在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
因为用nginx+lua去开发,所以会选择用最流行的开源方案,就是用OpenResty nginx+lua打包在一起,而且提供了包括redis客户端,mysql客户端,http客户端在内的大量的组件 1、部署第一个nginx,作为应用层nginx (1)部署openresty mkdir -p /usr/servers cd /usr/servers/ yum install -y readline-devel pcre-devel openssl-devel gcc wget http://openresty.org/download/ngx_openresty-1.7.7.2.tar.gz tar -xzvf ngx_openresty-1.7.7.2.tar.gz cd /usr/servers/ngx_openresty-1.7.7.2/ cd bundle/LuaJIT-2.1-20150120/ make clean && make && make install ln -sf luajit-2.1.0-alpha /usr/local/bin/luajit cd bundle wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz tar -xvf 2.3.tar.gz cd bundle wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz tar -xvf v0.3.0.tar.gz cd /usr/servers/ngx_openresty-1.7.7.2 ./configure --prefix=/usr/servers --with-http_realip_module --with-pcre --with-luajit --add-module=./bundle/ngx_cache_purge-2.3/ --add-module=./bundle/nginx_upstream_check_module-0.3.0/ -j2 make && make install cd /usr/servers/ ll /usr/servers/luajit /usr/servers/lualib /usr/servers/nginx /usr/servers/nginx/sbin/nginx -V 启动nginx: /usr/servers/nginx/sbin/nginx
(2)nginx+lua开发的hello world
vi /usr/servers/nginx/conf/nginx.conf 在http部分添加: lua_package_path "/usr/servers/lualib/?.lua;;"; lua_package_cpath "/usr/servers/lualib/?.so;;"; /usr/servers/nginx/conf下,创建一个lua.conf server { listen 80; server_name _; } 在nginx.conf的http部分添加: include lua.conf; 验证配置是否正确: /usr/servers/nginx/sbin/nginx -t 在lua.conf的server部分添加: location /lua { default_type 'text/html'; content_by_lua 'ngx.say("hello world")'; } /usr/servers/nginx/sbin/nginx -t 重新nginx加载配置 /usr/servers/nginx/sbin/nginx -s reload 访问http: http://192.168.31.187/lua vi /usr/servers/nginx/conf/lua/test.lua ngx.say("hello world"); 修改lua.conf location /lua { default_type 'text/html'; content_by_lua_file conf/lua/test.lua; }
查看异常日志 tail -f /usr/servers/nginx/logs/error.log (3)工程化的nginx+lua项目结构 项目工程结构 hello hello.conf lua hello.lua lualib *.lua *.so 放在/usr/hello目录下 /usr/servers/nginx/conf/nginx.conf worker_processes 2; error_log logs/error.log; events { worker_connections 1024; } http { include mime.types; default_type text/html; lua_package_path "/usr/hello/lualib/?.lua;;"; lua_package_cpath "/usr/hello/lualib/?.so;;"; include /usr/hello/hello.conf; } /usr/hello/hello.conf server { listen 80; server_name _; location /lua { default_type 'text/html'; lua_code_cache off; content_by_lua_file /usr/example/lua/test.lua; } } 用eshop-cache01和eshop-cache02作为应用层nginx服务器,用eshop-cache03作为分发层nginx 在eshop-cache03,也就是分发层nginx中,编写lua脚本,完成基于商品id的流量分发策略 步骤: 1、获取请求参数,比如productId 作为一个流量分发的nginx,会发送http请求到后端的应用nginx上面去,所以要先引入lua http lib包 cd /usr/hello/lualib/resty/ wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua 代码:
local uri_args = ngx.req.get_uri_args() local productId = uri_args["productId"] local hosts = {"192.168.31.187", "192.168.31.19"} local hash = ngx.crc32_long(productId) local index = (hash % 2) + 1 backend = "http://"..hosts[index] local requestPath = uri_args["requestPath"] requestPath = "/"..requestPath.."?productId="..productId local http = require("resty.http") local httpc = http.new() local resp, err = httpc:request_uri(backend,{ method = "GET", path = requestPath }) if not resp then ngx.say("request error: ", err) return end ngx.say(resp.body) httpc:close()
分发层nginx,lua应用,会将商品id,商品店铺id,都转发到后端的应用nginx
位置:/usr/servers/nginx/sbin/nginx -s reload
1、应用nginx的lua脚本接收到请求
2、获取请求参数中的商品id,以及商品店铺id
3、根据商品id和商品店铺id,在nginx本地缓存中尝试获取数据
4、如果在nginx本地缓存中没有获取到数据,那么就到redis分布式缓存中获取数据,如果获取到了数据,还要设置到nginx本地缓存中
但是这里有个问题,建议不要用nginx+lua直接去获取redis数据
因为openresty没有太好的redis cluster的支持包,所以建议是发送http请求到缓存数据生产服务,由该服务提供一个http接口
缓存数生产服务可以基于redis cluster api从redis中直接获取数据,并返回给nginx
cd /usr/hello/lualib/resty/ wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http_headers.lua wget https://raw.githubusercontent.com/pintsized/lua-resty-http/master/lib/resty/http.lua
5、如果缓存数据生产服务没有在redis分布式缓存中没有获取到数据,那么就在自己本地ehcache中获取数据,返回数据给nginx,也要设置到nginx本地缓存中
6、如果ehcache本地缓存都没有数据,那么就需要去原始的服务中拉去数据,该服务会从mysql中查询,拉去到数据之后,返回给nginx,并重新设置到ehcache和redis中
7、nginx最终利用获取到的数据,动态渲染网页模板
cd /usr/hello/lualib/resty/ wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template.lua mkdir /usr/hello/lualib/resty/html cd /usr/hello/lualib/resty/html wget https://raw.githubusercontent.com/bungle/lua-resty-template/master/lib/resty/template/html.lua 在hello.conf的server中配置模板位置 set $template_location "/templates"; set $template_root "/usr/hello/templates"; mkdir /usr/hello/templates vi product.html product id: {* productId *}<br/> product name: {* productName *}<br/> product picture list: {* productPictureList *}<br/> product specification: {* productSpecification *}<br/> product service: {* productService *}<br/> product color: {* productColor *}<br/> product size: {* productSize *}<br/> shop id: {* shopId *}<br/> shop name: {* shopName *}<br/> shop level: {* shopLevel *}<br/> shop good cooment rate: {* shopGoodCommentRate *}<br/>
8、将渲染后的网页模板作为http响应,返回给分发层nginx
hello.conf中: lua_shared_dict my_cache 128m; lua脚本中: local uri_args = ngx.req.get_uri_args() local productId = uri_args["productId"] local shopId = uri_args["shopId"] local cache_ngx = ngx.shared.my_cache local productCacheKey = "product_info_"..productId local shopCacheKey = "shop_info_"..shopId local productCache = cache_ngx:get(productCacheKey) local shopCache = cache_ngx:get(shopCacheKey) if productCache == "" or productCache == nil then local http = require("resty.http") local httpc = http.new() local resp, err = httpc:request_uri("http://192.168.31.179:8080",{ method = "GET", path = "/getProductInfo?productId="..productId }) productCache = resp.body cache_ngx:set(productCacheKey, productCache, 10 * 60) end if shopCache == "" or shopCache == nil then local http = require("resty.http") local httpc = http.new() local resp, err = httpc:request_uri("http://192.168.31.179:8080",{ method = "GET", path = "/getShopInfo?shopId="..shopId }) shopCache = resp.body cache_ngx:set(shopCacheKey, shopCache, 10 * 60) end local cjson = require("cjson") local productCacheJSON = cjson.decode(productCache) local shopCacheJSON = cjson.decode(shopCache) local context = { productId = productCacheJSON.id, productName = productCacheJSON.name, productPrice = productCacheJSON.price, productPictureList = productCacheJSON.pictureList, productSpecification = productCacheJSON.specification, productService = productCacheJSON.service, productColor = productCacheJSON.color, productSize = productCacheJSON.size, shopId = shopCacheJSON.id, shopName = shopCacheJSON.name, shopLevel = shopCacheJSON.level, shopGoodCommentRate = shopCacheJSON.goodCommentRate } local template = require("resty.template") template.render("product.html", context)
第一次访问的时候,其实在nginx本地缓存中是取不到的,所以会发送http请求到后端的缓存服务里去获取,会从redis中获取 拿到数据以后,会放到nginx本地缓存里面去,过期时间是10分钟 然后将所有数据渲染到模板中,返回模板 以后再来访问的时候,就会直接从nginx本地缓存区获取数据了 缓存数据生产 -> 有数据变更 -> 主动更新两级缓存(ehcache+redis)-> 缓存维度化拆分 分发层nginx + 应用层nginx -> 自定义流量分发策略提高缓存命中率 nginx shared dict缓存 -> 缓存服务 -> redis -> ehcache -> 渲染html模板 -> 返回页面 如果你的数据在nginx -> redis -> ehcache三级缓存都不在了,可能就是被LRU清理掉了 这个时候缓存服务会重新拉去数据,去更新到ehcache和redis中 |
请发表评论