Py学习  »  NGINX

Kong[nginx]-16 玩转ngx.location.capture_multi

国服最坑开发 • 4 年前 • 659 次点击  

KONG专题目录


0x00 本文目的: 网关层合并并发请求

有这样一种场景:
当用户打开点餐类的网页, 需要展示如下信息:

  • 商家信息
  • 菜品列表
  • 好评列表

一般的做法, 就是分开三个接口, 让客户端发请三次api请求即可完成.

那么请问如何优化这种场景呢?

今天就提供一个解决思路:

  • 合并请求
    减少请求次数,肯定可以提高客户端的响应速度
    但是, 这里说的合并请求, 不是指在一个接口处理内,读取数据库三次哦
  • 网关层并行请求
    假设后端服务有三个微服务分别提供上述三种信息.那么我们在网关层同时请求三个后端服务, 然后在网关层完成信息整合, 最后返回给客户端结果.

如此一来, 相当于我们同时做了两件优化项了.

0x01 后端接口准备

我们先准备一个后端接口:
功能很"复杂": 完成输入参数的平方计算, 并返回结果.
然后, 分别部署到 90009001 的端口服务中:

    @RequestMapping("/square")
    public int sum(@RequestParam("value") int value) {
        return value * value;
    }

部署后, 请在服务器上执行并验证接口可用性:


接口准备

0x02 添加Service, Router

我们添加一个请求Router, 访问地址为aaa.com/cal

/cal

0x03 编写插件

编写这个插件前, 会用到上一篇里提到的 /internal_api 这里不太赘述.
结合ngx.location.capture_multi API, 我们可以写出如下的代码:

  • handler.lua
-- handler.lua
local BasePlugin   = require "kong.plugins.base_plugin"
local GGHandler    = BasePlugin:extend()

GGHandler.VERSION  = "1.0.0"
GGHandler.PRIORITY = 10

function GGHandler:access(config)

    local a = kong.request.get_query_arg('a') or 0
    local b = kong.request.get_query_arg('b') or 0
    kong.log('a = ' .. a .. ' ,b = ' .. b)

    -- nginx内部接着执行子请求
    local rst1, rst2 = ngx.location.capture_multi {
        { "/internal_api",
          {
              args   = { url = "http://127.0.0.1:9000/square?value=" .. a },
              method = ngx.HTTP_GET,
          }
        },
        { "/internal_api",
          {
              args   = { url = "http://127.0.0.1:9001/square?value=" .. b },
              method = ngx.HTTP_GET,
          }
        },

    }
    -- 两个子请求执行完了 才会执行到这里
    kong.log('rst1  = ' .. rst1.body)
    kong.log('rst2  = ' .. rst2.body)

    local sum = 0

    if rst1.status == ngx.HTTP_OK then
        sum = sum + tonumber(rst1.body)
    end

    if rst2.status == ngx.HTTP_OK then
        sum = sum + tonumber(rst2.body)
    end

    kong.log('rst = ' .. sum)
    return kong.response.exit(200, tostring(sum), {
        ["Content-Type"] = "text/plain"
    })
end

return GGHandler
  • schema.lua
local typedefs     = require "kong.db.schema.typedefs"

return {
  name   = "multi_req",
  fields = {
    { protocols = typedefs.protocols_http },
    { config = {
      type   = "record",
      fields = { },
    },
    },
  },
}

0x04 启用插件

这个技能我们已经使用过很次, 不知道的同学请查看前面的系列.
发布插件三步走即可完成:

  • 插件代码复制到指定目录
  • 修改 /etc/kong/kong.conf
  • kong restart

添加插件
添加完成

0x05 验证效果

我们在浏览器发启请求: http://aaa.com/cal?a=3&b=4
就可以看到插件日志 和 最后的返回结果.

插件日志

执行结果

0x06 后记

本文提供了一个新的脑洞:
一次网关输入请求, 可以向多个后端(接口)发起请求.

但是, 也有其不足的地方:
已知问题: 这些子请求一定要都有返回结果后, 才会向客户端返回结果 .
也就是说, 可能会由于其中一个接口超时或者故障,可能导致整个请求失败!!!


2019.8.16翌日, 新しい時代が始まった


KONG专题目录


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/37831
 
659 次点击