悟空的路由实现

lua-nginx指令的执行

 order ofdirectives

"
  • init_by_lua
    Runs the Lua code specified by the argument lua-script-str on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file.
    Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems’ copy-on-write (COW) optimization.
    You can also initialize the lua_shared_dict shm storage at this phase.
  • init_worker_by_lua
    Runs the specified Lua code upon every Nginx worker process’s startup when the master process is enabled.
    This hook is often used to create per-worker reoccurring timers (via the ngx.timer.at Lua API), either for backend health-check or other timed routine work.
  • access_by_lua
    Acts as an access phase handler and executes Lua code string specified in lua-script-str for every request. The Lua code may make API calls and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox)
  • balancer_by_lua_block
    This directive runs Lua code as an upstream balancer for any upstream entities defined by the upstream {} configuration block.
  • header_filter_by_lua
    Uses Lua code specified in lua-script-str to define an output header filter.
  • body_filter_by_lua
    Uses Lua code specified in lua-script-str to define an output body filter.

初始化

初始化全局环境变量(init_by_lua*)

1
2
3
4
5
6
7
8
9
10
11
12
13
init_by_lua_block {
local app = require("core.main")
local global_config_path = "D:/workspace/wukong/conf/wukong.json"
local config, store,cache_client = app.init(global_config_path)

--application context
context = {
app = app, #module main
store = store, #mysql
cache_client = cache_client, #redis client
config = config #wukong.json 配置文件
}
}
1
2
3
4
Wukong.init(global_conf_path)
-->加载所有全局配置
-->singletons.loaded_plugins = load_conf_plugin_handlers(app_context)
-->plugin_handler(app_context)//执行每个插件的new方法

初始化任务(init_worker_by_lua*)

1
2
3
4
init_worker_by_lua_block {
local app = context.app
app.initWorker()
}
1
2
3
4
5
6
7
8
9
10
11
12
Wukong.initWorker //初始化事件注册中心,定时器加载配置信息和插件的
-->singletons.worker_events = worker_events
-->timer_at(0, init_worker_timer,...)// [ ngx.timer.every](https://github.com/openresty/lua-nginx-module#ngxtimerevery)
-->load_base_config_data_timer(premature,store, config)//把数据库里面的数据定时加载到share dict中
-->if worker_id == 0 then timer_at(30, load_base_config_data_timer, ...) end;//每30s
-->load_ext_config_data_timer(premature,store,config,cache)
-->if worker_count == 1 then//把数据定时加载到redis中
-->plugin.handler:init_worker_ext_timer()//每5s把每个插件的回调方法执行一次
-->timer_at(5, load_ext_config_data_timer, store,config,cache);
-->end
-->execute_plugin_init_worker()
-->plugin.handler:init_worker() //执行每个插件的init_worker方法(只执行一次)

Timer.at的回调方法可能由于代码错误在系统中累积,耗尽系统资源
(原版解释:Because timer callbacks run in the background and their running time will not add to any client request’s response time, they can easily accumulate in the server and exhaust system resources due to either Lua programming mistakes or just too much client traffic)
Timer.every 版本要求:v0.10.9;openresty-1.11.2.5.tar.gz 及以上版本支持nginx.every

请求处理

access(access_by_lua*)

1
2
3
4
access_by_lua_block {
local app = context.app
app.access()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Wukong.access()
-->plugin.handler:access()//执行每个插件的回调方法access
-->api_route_handler:access()
-->set_proxy_pass_info(api_group_info,req_info)
-->if enable_balancing == 1 then//负载均衡开启
-->upstream_url = concat_upstream_uri(upstream_host,req_info.path,req_info.query_string)//拼url:http://default_upstream/+path+query_string
-->balancer_helper.execute(balancer_address)//按照配置的负载均衡算法求出ip
-->ngx.ctx.balancer_address = balancer_address
-->else
-->upstream_url = concat_upstream_uri(upstream_url, req_info.path,req_info.query_string)
-->ngx.var.upstream_url = upstream_url
-->ngx.var.upstream_scheme = upstream_domain_info.scheme
-->ngx.var.upstream_host = upstream_domain_info.host
-->end

balance(balance_by_lua*)

1
2
3
4
5
6
7
8
upstream default_upstream {
server 0.0.0.1;
balancer_by_lua_block {
local app = context.app
app.balancer()
}
keepalive 60;
}
1
2
3
4
5
6
Wukong.balancer()
-->plugin.handler:balancer()
-->api_route_handler : balancer()
-->健康检查
-->set_current_peer(ip, port)//[ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md)
-->set_timeouts(addr.connection_timeout / 1000, addr.send_timeout / 1000, addr.read_timeout /1000)
  • balancer方法执行的次数
    balancer的执行在不超过阀值时,直至成功为止