# 053. 部署分发层 nginx 以及基于 lua 完成基于商品 id 的定向流量分发策略

eshop-03 上也需要搭建一个 应用层 nginx,参考上一章节

nginx 三台的作用:

  • eshop-01:应用层
  • eshop-02:应用层
  • eshop-03:分发层

在 eshop-cache03 中编写 lua 脚本,完成基于商品 id 的流量分发策略

这里简化业务逻辑,实际上在你的公司中,你可以随意根据自己的业务逻辑和场景,去制定自己的流量分发策略

步骤如下:

  1. 获取请求参数,比如 productId
  2. 对 productId 进行 hash
  3. hash 值对应用服务器数量取模,获取到一个应用服务器
  4. 利用 http 发送请求到应用层 nginx
  5. 获取响应后返回

为了能分发看出来效果,我们把之前 hello 输出信息修改为自己的主机名,如 hello world,eshop-cache03

使用 lua 转发需要用到 lua 的 http 包,这里导入下

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
2
3

脚本编写

/usr/hello/lua/hello.lua

-- 拿一个地址来说明:http://eshop-cache03/lua?method=hello&productId=1
-- 获取问号后面的参数列表
local uri_args = ngx.req.get_uri_args()
-- 获取参数
local productId = uri_args["productId"]

-- 定义后端应用 ip
local host = {"192.168.99.170", "192.168.99.171"}
-- 对商品 id 取模并计算 hash 值
local hash = ngx.crc32_long(productId)
hash = (hash % 2) + 1  
-- 拼接 http 前缀
backend = "http://"..host[hash]

-- 获取到参数中的路径,比如你要访问 /hello,这个例子中是需要传递访问路径的
local method = uri_args["method"]
-- 拼接具体的访问地址不带 host,如:/hello?productId=1
local requestBody = "/"..method.."?productId="..productId

-- 获取 http 包
local http = require("resty.http")  
local httpc = http.new()  

-- 访问,这里有疑问:万一有 cooke 这些脚本支持吗?会很麻烦吗?
local resp, err = httpc:request_uri(backend, {  
    method = "GET",  
    path = requestBody,
    keepalive=false
})

-- 如果没有响应则输出一个 err 信息
if not resp then  
    ngx.say("request error :", err)  
    return  
end

-- 有响应测输出响应信息
ngx.say(resp.body)  

-- 关闭 http 客户端实例
httpc:close()
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
38
39
40
41

刷新配置:/usr/servers/nginx/sbin/nginx -s reload

访问

这里的意思是,访问 03 这台分发 nginx,但是需要告诉它我访问后端哪个服务路径
由于后端两个 nginx 都只有 /lua 这个请求路径,所以就访问了它
http://eshop-cache03/lua?method=lua&productId=1
页面输出:hello world,eshop-cache02

http://eshop-cache03/lua?method=lua&productId=4
页面输出:hello world,eshop-cache01
1
2
3
4
5
6
7

基于商品 id 的定向流量分发策略的 lua 脚本就开发完了,而且也测试过了

我们就可以看到,如果你请求的是固定的某一个商品,那么就一定会将流量打到固定的一个应用 nginx 上面去

TIP

如果访问报错,可以查看 nginx 的错误日志:cat /usr/servers/nginx/logs/error.log

一开始访问报错,看错误日志看到的,百度了下解决了在请求的时候增加了 keepalive=false 参数

2019/04/02 02:00:33 [error] 8451#0: *16 lua entry thread aborted: runtime error: /usr/hello/lualib/resty/http.lua:926: 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:926: in function 'request_uri'
	/usr/hello/lua/hello.lua:25: in function </usr/hello/lua/hello.lua:1>, client: 192.168.99.111, server: _, request: "GET /lua?method=lua&productId=1 HTTP/1.1", host: "eshop-cache03"

1
2
3
4
5
6
7