38. 【实战】基于nginx+lua+java完成多级缓存架构的核心业务逻辑

分发层nginx,lua应用,会将商品id,商品店铺id,都转发到后端的应用nginx

nginx+lua+java多级缓存流程

修改分发层nginx

  1. 分发层nginxeshop-cache03<192.168.0.108>vi /usr/hello/hello.conf
    在这里插入图片描述
location /product {
        default_type 'text/html';
        # lua_code_cache off;
        content_by_lua_file /usr/hello/lua/distribute.lua;
    }
  1. 修改lua脚本: vi /usr/hello/lua/distribute.lua
local uri_args = ngx.req.get_uri_args()
local productId = uri_args["productId"]
local shopId = uri_args["shopId"]

local host = {"192.168.0.106", "192.168.0.107"}
local hash = ngx.crc32_long(productId)
local index = (hash % 2) + 1
local backend = "http://"..host[index]

local requestPath = uri_args["requestPath"]
requestPath = "/"..requestPath.."?productId="..productId.."&shopId="..shopId

local http = require("resty.http")
local httpc = http.new()

local resp, err = httpc:request_uri(backend, {
    method = "GET",
    path = requestPath,
    keepalive=false
})

if not resp then
    ngx.say("request error :", err)
    return
end
ngx.say(resp.body)
httpc:close()
  1. 重新加载nginx配置:
# 验证配置
/usr/servers/nginx/sbin/nginx -t
# 启动nginx
/usr/servers/nginx/sbin/nginx
# 重载配置
/usr/servers/nginx/sbin/nginx -s reload

配置应用层nginx

  1. 应用层nginx的lua脚本接收到之前分发层nginx分发的请求

  2. 获取请求参数中的商品id:productId,以及商品店铺id:shopId

  3. 根据商品id和商品店铺id,在nginx本地缓存中尝试获取数据

  4. 如果在nginx本地缓存中没有获取到数据,那么就到redis分布式缓存服务中获取数据,获取到了数据后,还要设置到nginx本地缓存中

但是这里有个问题,建议不要用nginx+lua直接去获取redis数据,因为openresty没有太好的redis cluster的支持包,所以建议是发送http请求到缓存数据生产服务,由该服务提供一个http接口

  1. 缓存数据生产服务可以基于redis cluster api从redis中直接获取数据,并返回给nginx

应用层nginx会发送http请求到后端的缓存数据服务,所以eshop-cache01eshop-cache02也要先引入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 
  1. 如果缓存数据生产服务没有在redis分布式缓存中没有获取到数据,那么就在自己本地ehcache中获取数据,返回数据给nginx,也要设置到nginx本地缓存中

  2. 如果ehcache本地缓存都没有数据,那么就需要去原始的服务中拉去数据,该服务会从mysql中查询,拉去到数据之后,返回给nginx,并重新设置到ehcache和redis中

后面会讲分布式缓存重建并发冲突的问题和解决方案

  1. 应用层nginx最终利用获取到的数据,动态渲染网页模板

eshop-cache01eshop-cache02引入lua

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
  1. vi /usr/hello/hello.conf:配置模板位置
    在这里插入图片描述
set $template_location "/templates";  
set $template_root "/usr/hello/templates";
  1. 创建页面模板目录和文件
mkdir /usr/hello/templates
vi product.html
<html>
        <head>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <title>商品详情页</title>
        </head>
<body>
商品id: {* productId *}<br/>
商品名称: {* productName *}<br/>
商品图片列表: {* productPictureList *}<br/>
商品规格: {* productSpecification *}<br/>
商品售后服务: {* productService *}<br/>
商品颜色: {* productColor *}<br/>
商品大小: {* productSize *}<br/>
店铺id: {* shopId *}<br/>
店铺名称: {* shopName *}<br/>
店铺等级: {* shopLevel *}<br/>
店铺好评率: {* shopGoodCommentRate *}<br/>
</body>
</html>
  1. 配置使用nginx的本地缓存
    在这里插入图片描述
vi /usr/servers/nginx/conf/nginx.conf

# nginx配置全局本地缓存名称:my_cache,内存大小:128m
lua_shared_dict my_cache 128m;
  1. 将渲染后的网页模板作为http响应,返回给分发层nginx
    在这里插入图片描述
vi /usr/hello/hello.conf

location /product {
    default_type 'text/html';
    content_by_lua_file /usr/hello/lua/product.lua;
}
  1. vi /usr/hello/lua/product.lua 脚本:
-- 获取请求参数
local uri_args = ngx.req.get_uri_args()
local productId = uri_args["productId"]
local shopId = uri_args["shopId"]
-- 获取nginx缓存
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)
-- 如果nginx本地缓存没有,发送请求到缓存服务
if productCache == "" or productCache == nil then
	local http = require("resty.http")
	local httpc = http.new()
-- 此处ip地址为你java服务部署或测试启动地址
	local resp, err = httpc:request_uri("http://192.168.0.113:8080",{
  		method = "GET",
  		path = "/getProductInfo?productId="..productId,
-- lua lib库bug,必须设置下面参数
  		keepalive=false
	})

	productCache = resp.body
-- 设置到nginx本地缓存中,过期时间10分钟
	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.0.113:8080",{
  		method = "GET",
  		path = "/getShopInfo?shopId="..shopId,
  		keepalive=false
	})

	shopCache = resp.body
	cache_ngx:set(shopCacheKey, shopCache, 10 * 60)
end
-- 商品信息和店铺信息转成json对象
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配置已经结束。

  1. 重新加载nginx配置:

注意以上配置两个应用层nginx都要配置:eshop-cache01eshop-cache02

# 验证配置
/usr/servers/nginx/sbin/nginx -t
# 启动nginx
/usr/servers/nginx/sbin/nginx
# 重载配置
/usr/servers/nginx/sbin/nginx -s reload

缓存服务Java代码

  1. 可以查看34. 【实战】基于kafka+ehcache+redis完成缓存数据生产服务的开发与测试,生成测试redis数据

  2. 项目地址:eshop-study
    切换到相应分支:
    在这里插入图片描述

测试

  1. 分发层nginxeshop-cache03 [192.168.0.108]发出访问获取商品信息和商家信息请求:
  2. 商品请求:http://192.168.0.108/product?requestPath=product&productId=1&shopId=1
  3. 如果报错,可以查看日志
    在这里插入图片描述
cat /usr/servers/nginx/logs/error.log

在这里插入图片描述

我这里是因为redis中没有商家信息缓存,现在也没有做查询数据库操作,lua解码转json对象时报错了。

  1. 成功请求响应:
    在这里插入图片描述
    在这里插入图片描述

  2. 第一次访问的时候,在nginx本地缓存中是取不到的,会发送http请求到后端的缓存服务里去获取,会从redis中获取

  3. 拿到数据以后,会放到nginx本地缓存里面去,过期时间是之前设置的10分钟

  4. 然后将所有数据渲染到模板中,返回模板

  5. 以后再来访问的时候,就会直接从nginx本地缓存区获取数据了

总结

  1. 缓存数据生产 -> 有数据变更 -> 主动更新两级缓存(ehcache+redis)-> 缓存维度化拆分
  2. 分发层nginx + 应用层nginx -> 自定义流量分发策略提高缓存命中率
  3. nginx shared dict缓存 -> 缓存服务 -> redis -> ehcache -> 渲染html模板 -> 返回页面

如果数据在nginx -> redis -> ehcache三级缓存都不在了,可能就是被LRU清理掉了

这个时候缓存服务会重新拉去数据,去更新到ehcache和redis中,由此会引发下一篇中的分布式的缓存重建的并发问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值