# 055. 基于 nginx + lua + java 完成多级缓存架构的核心业务逻辑(二)

# 缓存服务实现

cn.mrcode.cachepdp.eshop.cache.controller.CacheController

/**
  * 这里的代码别看着奇怪,简单回顾下之前的流程: 1. nginx 获取 redis 缓存 2. 获取不到再获取服务的堆缓存(也就是这里的 ecache) 3.
  * 还获取不到就需要去数据库获取并重建缓存
  */
 @RequestMapping("/getProductInfo")
 @ResponseBody
 public ProductInfo getProductInfo(Long productId) {
     ProductInfo productInfo = cacheService.getProductInfoOfReidsCache(productId);
     log.info("从 redis 中获取商品信息");
     if (productInfo == null) {
         productInfo = cacheService.getProductInfoFromLocalCache(productId);
         log.info("从 ehcache 中获取商品信息");
     }
     if (productInfo == null) {
         // 两级缓存中都获取不到数据,那么就需要从数据源重新拉取数据,重建缓存
         // 但是这里暂时不讲
         log.info("缓存重建 商品信息");
     }
     return productInfo;
 }

 @RequestMapping("/getShopInfo")
 @ResponseBody
 public ShopInfo getShopInfo(Long shopId) {
     ShopInfo shopInfo = cacheService.getShopInfoOfReidsCache(shopId);
     log.info("从 redis 中获取店铺信息");
     if (shopInfo == null) {
         shopInfo = cacheService.getShopInfoFromLocalCache(shopId);
         log.info("从 ehcache 中获取店铺信息");
     }
     if (shopInfo == null) {
         // 两级缓存中都获取不到数据,那么就需要从数据源重新拉取数据,重建缓存
         // 但是这里暂时不讲
         log.info("缓存重建 店铺信息");
     }
     return shopInfo;
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

cn.mrcode.cachepdp.eshop.cache.service.CacheService

/**
 * 从 redis 中获取商品
 */
ProductInfo getProductInfoOfReidsCache(Long productId);

/**
 * 从 redis 中获取店铺信息
 */
ShopInfo getShopInfoOfReidsCache(Long shopId);

1
2
3
4
5
6
7
8
9
10

cn.mrcode.cachepdp.eshop.cache.service.impl.CacheServiceImpl

@Override
public ProductInfo getProductInfoOfReidsCache(Long productId) {
    String key = "product_info_" + productId;
    String json = jedisCluster.get(key);
    return JSON.parseObject(json, ProductInfo.class);
}

@Override
public ShopInfo getShopInfoOfReidsCache(Long shopId) {
    String key = "shop_info_" + shopId;
    String json = jedisCluster.get(key);
    return JSON.parseObject(json, ShopInfo.class);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 测试应用层

访问地址:http://eshop-cache02/product?productId=1&shopId=1

tail -f /usr/servers/nginx/logs/error.log
可以看到如下的错误:

2019/05/06 22:46:59 [error] 8834#0: *46 lua entry thread aborted: runtime error: /usr/hello/lualib/resty/http.lua:929: bad argument #2 to 'set_keepalive' (number expected, got nil)
stack traceback:
coroutine 0:
	[C]: in function 'set_keepalive'
	/usr/hello/lualib/resty/http.lua:929: in function 'request_uri'
	/usr/hello/lua/product.lua:24: in function </usr/hello/lua/product.lua:1>, client: 192.168.99.1, server: _, request: "GET /product?productId=1&shopId=1 HTTP/1.1", host: "eshop-cache02"
1
2
3
4
5
6
7
8
9

这次通过 debug 后端服务,服务中能请求到了,响应之后报错 bad argument #2 to 'set_keepalive'

这个问题在前面记忆中已经解决过了,设置下 keepalive=false 即可

local resp, err = httpc:request_uri("http://192.168.99.111:6002",{
    method = "GET",
    path = "/getShopInfo?shopId="..shopId,
    keepalive=false
})
1
2
3
4
5

再次访问:http://eshop-cache02/product?productId=1&shopId=1

product id: 1
product name: iphone7手机
product picture list: a.jpg,b.jpg
product specification: iphone7的规格
product service: iphone7的售后服务
product color: 红色,白色,黑色
product size: 5.5
shop id: 1
shop name: 小王的手机店
shop level: 5
shop good cooment rate: 0.99
1
2
3
4
5
6
7
8
9
10
11

如果响应的中文乱码,需要在拦截的地方添加编码

location /product {
  default_type 'text/html';
  charset utf-8;
  content_by_lua_file /usr/hello/lua/product.lua;
}
1
2
3
4
5

# 优化模板文件

vi /usr/hello/templates/product.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

记得重启 /usr/servers/nginx/sbin/nginx -s reload

再次访问:http://eshop-cache02/product?productId=1&shopId=1

商品 ID: 1
商品名称: iphone7手机
商品图片列表: a.jpg,b.jpg
商品规格: iphone7的规格
商品售后服务: iphone7的售后服务
商品颜色: 红色,白色,黑色
商品尺寸: 5.5
店铺 ID: 1
店铺名称: 小王的手机店
店铺级别: 5
店铺评分: 0.99
1
2
3
4
5
6
7
8
9
10
11

# 测试分发层

刚刚应用层已经测试通过,现在来从分发层测试

访问:http://eshop-cache03/product?method=product&productId=1&shopId=1

TIP

注意,由于使用的是 hash 分发,可以在 eshop-cache01 和 eshop-cache02 上显示访问日志

tail -f /usr/servers/nginx/logs/access.log

这样就能看到被分发到哪台机器上去了。

成功响应 html 信息

商品 ID: 1
商品名称: iphone7手机
商品图片列表: a.jpg,b.jpg
商品规格: iphone7的规格
商品售后服务: iphone7的售后服务
商品颜色: 红色,白色,黑色
商品尺寸: 5.5
店铺 ID: 1
店铺名称: 小王的手机店
店铺级别: 5
店铺评分: 0.99
1
2
3
4
5
6
7
8
9
10
11