前提:
1.nginx+lua+openresty环境搭建
https://blog.csdn.net/Mr_xiayijie/article/details/111224818
2.Nginx静态化html本地缓存处理
https://blog.csdn.net/Mr_xiayijie/article/details/111225089
1.思路流程图:
叙述:
1.用户通过前端发送请求Nginx,获取Nginx本地缓存渲染Html模板
2.如果Nginx本地缓存没有找到,就去Redis中获取,并且放入Nginx缓存
3.Redis中没有找到就去Ehcache中获取,并且放入redis和Nginx缓存
4.Ehcache没有找到就去请求Mysql,并且放入Ehcache、redis和Nginx缓存
5.如果数据发生变更就给kafka或者其他MQ发送消息,监听到了将Ehcache、redis和Nginx缓存更新
核心代码如下:
lua脚本:
-- ===========Nginx本地缓存处理=====================
local uri_args = ngx.req.get_uri_args()
local goodsId = uri_args [goodsId]
local cache_ngx = ngx.shared.my_cache
local goodsCacheKey = Goods..goodsId
local goodsCache = cache_ngxget(goodsCacheKey)
-- =======发送http请求===========
if goodsCache == or goodsCache == nil or goodsCache==null then --这里是redis没有数据存如Nginx就去发送http获取数据
ngx.say(开始发送HTTP请求获取数据=========,br)
local http = require(resty.http)
local httpc =http.new()
local resp,err=httpcrequest_uri(http172.16.21.589999,{
method=GET,
path=goodsCachegetgoods..goodsId ,
keepalive=false
})
goodsCache = resp.body --得到请求响应结果
cache_ngxset(goodsCacheKey ,goodsCache,10) --10秒失效
end
-- ================JSON化处理(导入)================
local cjson = require(cjson)
local goodsJson=cjson.decode(goodsCache) -- redis Json化处理
--=====最后Json数据重组=========
local context = {
goodsId=goodsJson.goodsId,
goodsName=goodsJson.goodsName,
price=goodsJson.price,
desc=goodsJson.desc,
}
--==template模板处理=========
local template = require(resty.template)
template.render(goods.html,context)
Controller处理:
package com.zking.controller;
import com.alibaba.fastjson.JSON;
import com.zking.config.GoodsEhcache;
import com.zking.pojo.GoodsInfo;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: codinglife
* @time: 2020/12/14 13:51
*/
@Controller
@RequestMapping("/goodsCache")
public class GoodsCacheController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private KafkaTemplate kafkaTemplate;
/**
* 发送kafka消息模拟修改数据
*
* @param
*/
@GetMapping("/send/message")
public String kafkaTest() {
GoodsInfo goodsInfo = new GoodsInfo();
goodsInfo.setGoodsId("1");
goodsInfo.setGoodsName("kafka改变的华为P");
goodsInfo.setDesc("这是kafka改变的一款华为的产品");
goodsInfo.setPrice(Integer.valueOf(12));
String str = JSON.toJSONString(goodsInfo);
kafkaTemplate.send("goods_topic_N01", str);
return "kafka执行成功";
}
/**
* 模拟后台数据请求操作
* 注:尽量保持ehcache和redis的key一致
*
* @param goodsId
*/
@GetMapping("/get/goods/{goodsId}")
@ResponseBody
public GoodsInfo queryGoodsInfo(@PathVariable String goodsId) {
GoodsInfo goodsInfo = null;
Cache cache = GoodsEhcache.commonEchache("GoodsCache"); //设置了20秒过期
Element element = cache.get("Goods" + goodsId); //从ehcache获取数据
if (element != null && !"".equals(element)) { //ehcache有直接返回
goodsInfo = (GoodsInfo) element.getObjectValue();
logger.info("ehcache有直接返回");
} else { //如果ehcache没有 就去Redis数据库获取数据
ValueOperations ops = redisTemplate.opsForValue();
goodsInfo = (GoodsInfo) ops.get("Goods" + goodsId);
logger.info("Redis数据库获取数据");
if (goodsInfo != null) { //redis中获取到的数据存存入ehcache
Element elementPut = new Element("Goods" + goodsId, goodsInfo);
cache.put(elementPut); //放入ehcache
}
if (goodsInfo == null) { //redis中没有数据请求Mysql数据库获取数据
logger.info("Mysql数据库获取数据");
//模拟数据库回去出来的商品详情数据
goodsInfo = new GoodsInfo();
goodsInfo.setGoodsId(goodsId + "");
goodsInfo.setGoodsName("华为P" + goodsId);
goodsInfo.setDesc("这是一款华为的产品" + goodsId);
goodsInfo.setPrice(Integer.valueOf(goodsId));
Element elementPut = new Element("Goods" + goodsId, goodsInfo);
cache.put(elementPut); //放入ehcache
ops.set("Goods" + goodsId, goodsInfo, 600, TimeUnit.SECONDS); //再存入redis
}
}
return goodsInfo;
}
}
kafka监听处理:
package com.zking.monitor;
import com.alibaba.fastjson.JSONObject;
import com.zking.config.GoodsEhcache;
import com.zking.pojo.GoodsInfo;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* @description:
* @author: codinglife
* @time: 2020/12/10 14:02
*/
@Component
public class GoodsMonitor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RedisTemplate redisTemplate;
@KafkaListener(topics = {"goods_topic_N01"})
public void processMessage(String content){
logger.info("kafka接收消息:{}",content);
GoodsInfo goodsInfo =JSONObject.parseObject(content,GoodsInfo.class);
//kafka接收到消息 将redis中的数据和ehcache中的数据进行替换
ValueOperations ops = redisTemplate.opsForValue();
ops.set("Goods" + goodsInfo.getGoodsId(), goodsInfo, 600, TimeUnit.SECONDS); //再存入redis
Cache cache = GoodsEhcache.commonEchache("GoodsCache");
Element elementPut = new Element("Goods" + goodsInfo.getGoodsId(), goodsInfo);
cache.put(elementPut);
}
}
结果:
资料获取: 这里面包括源码,包和配置信息
链接: https://pan.baidu.com/s/1sJ6VsUgLXT63j9ok6-pmxQ
提取码: tsmu
问题:
1.lua如何整合Redis?
我这里有个整合脚本:
-- ================JSON化处理(导入)================
local cjson = require("cjson")
-- ===========Nginx本地缓存处理=====================
local uri_args = ngx.req.get_uri_args()
local goodsId = uri_args ["goodsId"]
local cache_ngx = ngx.shared.my_cache
local goodsCacheKey = "Goods"..goodsId
local goodsCache = cache_ngx:get(goodsCacheKey)
--======= 连接redis===============================
if goodsCache == "" or goodsCache == nil or goodsCache==null then --判断是否有Nginx缓存开始
ngx.say("Nginx缓存没有开始获取Redis缓存数据========")
local ngx_redis = require("resty.redis")
--创建实例
local redis_instance = ngx_redis :new()
--设置超时(毫秒)
redis_instance:set_timeout(3000)
--建立连接
local host = "127.0.0.1"
local port = 6379
local ok, err = redis_instance:connect(host, port)
if not ok then --连接失败
ngx.say("connect to redis error : ", err)
return close_redis(redis_instance)
end
local resp, err = redis_instance:get(goodsCacheKey)
redis_instance:close()
if resp~=ngx.null then --redis存在就放入nginx本地缓存
-- ===========创建JSON实例============
-- local expireTime=math.random(10,20) --//随机时间
cache_ngx:set(goodsCacheKey ,resp,10) -- //这个过期时间要随机设置 反正并发对机器的负载过大
end
end
-- =======发送http请求===========
goodsCache = cache_ngx:get(goodsCacheKey ) --再次从Nginx缓存中获取
if goodsCache == "" or goodsCache == nil or goodsCache==null then --这里是redis没有数据存如Nginx就去发送http获取数据
ngx.say("Redis缓存没有开始发送HTTP请求获取数据=========")
local http = require("resty.http")
local httpc =http.new()
local resp,err=httpc:request_uri("http://172.16.21.58:9999",{
method="GET",
path="/goodsCache/get/goods/"..goodsId ,
keepalive=false
})
goodsCache = resp.body --//得到请求响应结果
end
local goodsJson=cjson.decode(goodsCache) -- redis Json化处理
--=====最后Json数据重组=========
local context = {
goodsId=goodsJson.goodsId,
goodsName=goodsJson.goodsName,
price=goodsJson.price,
desc=goodsJson.desc,
}
--==template模板处理=========
local template = require("resty.template")
template.render("goods.html",context)
但是lua在cjson.decode(Json数据) 只解析
{"goodsName":"华为P1","goodsId":"1","price":1,"desc":"这是一款华为的产品1"} 这种格式
而我通过java进行redis存储的格式是
["com.zking.pojo.GoodsInfo",{"goodsName":"华为P1","goodsId":"1","price":1,"desc":"这是一款华为的产品1"}]
或者
"{\"desc\":\"这是一款华为的产品2\",\"goodsId\":\"2\",\"goodsName\":\"华为P2\",\"price\":2}"
lua脚本根本无法解析
2.在数据发生改变通过kafka消息队列去更新缓存数据如果更新Nginx缓存?
大家在研究到这里的时候 希望大佬能够指点一下,蟹蟹