针对性的了解apisix插件化api网关,期望能给项目提供一些参考和优化(•̀⌄•́)
—— By Jihan
官方Git
管理端页面
router-radixtree
结构设计
安装参考
APISIX高性能实践
APISIX高性能实践续
APISIX上手
官方参考dashboard
目前只在Coentos 7上安装测试,Centos 6上需要升级gcc,要支持GLIBC_2.14
简介和安装
apisix安装
直接看这个就可以了官方中文
可能遇到问题:
- openresty libssl.so.1.1 not found
升级openssl - 需要注意的是,etcd的协议版本问题,需要支持2版本?
export ETCDCTL_API=2
APISIX Dashboard安装
-
安装前置环境:mysql,golang,nodejs(version >=10.xx)
-
安装启用apisix
-
配置mysql
1
2
3输入你的密码和用户名
mysql –uroot –p123456
source ./api/script/db/schema.sql -
编译运行后端程序
1
2cd api && go build -o ../manager-api . && cd ..
sh ./api/run/run.sh & -
编译前端
1
2
3npm insert -g yarn
yarn install
yarn build -
联合apisix使用
-
将刚刚前端编译得到的
/dist
的内容,放到apisix下的dashboard文件夹 -
修改apisix脚本,添加如下服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24vi ./bin/apisix
server {
listen 10080;
# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
root /usr/share/nginx/html;
include /usr/local/openresty/nginx/conf/mime.types;
location / {
alias dashboard/;
try_files $uri $uri/index.html /index.html =404;
}
location /apisix/admin {
proxy_pass http://127.0.0.1:8080/apisix/admin;
}
} -
重启apisix
./bin/apisix restart
-
-
访问
http://192.168.81.128:10080/
ip根据自己而定。默认登录名admin
密码admin
,可以在dashboard的conf.json
中自己修改。
APISIX的route匹配
项目需要,了解下apisix的route匹配方式。
首先apisix的架构参考结构设计
apisix扩展匹配介绍router-radixtree
匹配原理和机制
其核心的实现机制是使用了resty.radixtree
这个lua库,详情。包括路由匹配,域名匹配,方法匹配等。说白,都是字符匹配。
route
匹配源码如下:
1 | local require = require |
而在访问过程中对这个调用方式如下:
1 | --调用上述的match函数 |
resty.radixtree匹配原理
主要分为两个部分,初始化注册router
和运行时匹配过滤:
初始化:
- 数据存储和查找的主key都是uri,全量匹配使用hash,通用匹配使用的都是radixtree。数据结构都可以参考图中的表。
- 同一个uri有多个route的情况,会以数组的方式扩展,并且使用sort排序,排序顺序依据route中
priority
参数,越大优先级越高,越优先匹配。
运行时Match:
-
调用
router:match(api_ctx.var.uri, match_opts, ...)
时,先使用hash
来寻找相应的注册routes(routes在注册的时候,也是根据uri来进行hash表插入,如果hash表设置不能用,才使用radix_tree)。如果hash找不到,就使用radix_tree
查找匹配(这部分是c代码,还没看) -
如果都匹配成功,
dispatch
会调用route
里加入的handler
。而match
函数会返回metadata
-
自定义函数方面,在定义route的时候,自定义
filter_fun
函数,进行匹配过滤的时候,就会调用filter_fun
调用。类似示例如下: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=== TEST 1: sanity
--- config
location /t {
content_by_lua_block {
local radix = require("resty.radixtree")
local rx = radix.new({
{
paths = "/aa",
metadata = "metadata /aa",
filter_fun = function(vars)
ngx.log(ngx.WARN, "start to filter")
return vars['arg_k'] == 'v'
end
}
})
ngx.say(rx:match("/aa", {vars = ngx.var}))
ngx.say(rx:match("/aa", {}))
}
}
--- request
GET /t?k=v
--- no_error_log
[error]
--- error_log
start to filter
--- response_body
metadata /aa
metadata /aa -
对于自定义变量的读取,比如有header,args和cookie里分别有个stub;nginx.var可以分别通过’http_','arg_'和’cookie_'直接读取相应的变量:
nginx配置:1
2
3
4
5
6
7
8
9
10
11
12
13access_by_lua_block {
ngx.say("nnnnnnnnngxxxxxxx say:")
ngx.say(ngx.var['http_stub'])
ngx.say(ngx.var['arg_stub'])
ngx.say(ngx.var['cookie_stub'])
apisix.http_access_phase()
}
curl -H 'stub:cloudxx' --cookie "stub=cccccookie" http://192.168.81.128:9080/args/?stub=arrrrg
nnnnnnnnngxxxxxxx say:
cloudxx
arrrrg
cccccookie
{"error_msg":"failed to match any routes"}
route匹配成功后server或upstream流程
首先,在route的配置中,plugins
、script
、upstream/upstream_id
、service_id
至少选择一个
当route匹配成功后会相应执行plugins
…(目前猜测是根据优先级)
server最后关联的也是upstream,那么主要的还是介绍upstream的外发:
在route匹配成功后,会进行server_id和upstream_id的检查,如果有,就将相应的upstream结构赋值到api_ctx.upstream_conf
,如果只有一个node,那么可以直接赋值相应的upstream_host
,进行负载平衡,负载平衡特点:
- 动态支持有权重的 round-robin 负载平衡
- 动态支持一致性 hash 的负载均衡。
- 启用上游节点的健康检查,将在负载均衡期间自动过滤不健康的节点,以确保系统稳定性。
- 可以在 balancer 阶段使用自定义负载均衡算法。
性能
route匹配性能
lua-resty-radixtree
We wrote some simple benchmark scripts. Machine environment: MacBook Pro (16-inch, 2019), CPU 2.3 GHz Intel Core i9.
1 | $ make |