您好,欢迎访问一九零五行业门户网

nginx_lua案例分析:动态路由实现

这里的路由指的是在web开发中,访问路径以及具体实现内容的映射。比如,/a映射到某个具体的页面,这个就称之为一个路由。而动态路由,顾名思义就是动态添加这种路由映射关系。
    在nginx中,通过rewrite和proxy_pass来实现路由映射或者说反向代理,但是这种关系按照传统的配置必须写死在配置文件中,然后通过快速无缝重启nginx。虽说是无缝,但是其繁琐的配置和枯燥的重启操作还是无法避免。
    最近,在github上看到个项目ceryx,是nginx结合lua进行动态路由的映射的,也就是上面所说的映射关系,用lua来管理,虽然是比较简单的实现,但是可以分析学习下。该项目通过用redis的结构来保存这种映射关系,这样在nginx中可以快速获得这种关系,以便做出处理,同时,采用http的形式暴露对redis这种路由关系进行管理的接口。
from ceryx.db import redisrouterresource_fields = { 'source': fields.string, 'target': fields.string,}parser = reqparse.requestparser()parser.add_argument( 'source', type=str, required=true, help='source is required')parser.add_argument( 'target', type=str, required=true, help='target is required')router = redisrouter.from_config()def lookup_or_abort(source): returns the target for the given source, or aborts raising a 404 try: return {'source': source, 'target': router.lookup(source)} except redisrouter.lookupnotfound: abort( 404, message='route with source {} doesn\'t exist'.format(source) )class route(resource): resource describing a single route. supports get, delete and put. the format is the following: ``` { source: [source], target: [target] } ``` @marshal_with(resource_fields) def get(self, source): fetches the route with the given source route = lookup_or_abort(source) return route @marshal_with(resource_fields) def delete(self, source): deletes the route with the given source route = lookup_or_abort(source) router.delete(source) return route, 204 @marshal_with(resource_fields) def put(self, source): creates or updates the route with the given source, pointing to the given target args = parser.parse_args() router.insert(args['source'], args['target']) return args, 201
上述的代码,是进行路由管理的http api,当然,这个不是我们分析的重点。先来看一下,在这个项目里面,对nginx的配置是怎样的
upstream fallback { server www.something.com;}server { listen 80; default_type text/html; location / { set $container_url fallback; resolver 8.8.8.8; # lua files access_by_lua_file lualib/router.lua;//切入点 # proxy configuration proxy_set_header host $http_host; proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for; proxy_set_header x-real-ip $remote_addr; proxy_set_header x-forwarded-proto $scheme; proxy_redirect ~^(http://[^:]+):\d+(/.+)$ $2; proxy_redirect / /; # upgrade headers proxy_http_version 1.1; proxy_set_header upgrade $http_upgrade; proxy_set_header connection upgrade; proxy_pass http://$container_url$request_uri; } ...}
可以简单的看到,这个配置相当的常见,跟普通的反向代理并没有什么不同,真正的切入点在于access_by_lua_file里面的router.lua代码。
local container_url = ngx.var.container_url//拿到配置文件中的container_urllocal host = ngx.var.host //拿到请求的时候的host,比如我们请求http://www.xxx.com/a.html 那这里的host就是www.xxx.com-- check if key exists in local cachelocal cache = ngx.shared.ceryxlocal res, flags = cache:get(host) //直接在nginx cache中拿host对应的路由映射,如果存在则直接返回结果if res then ngx.var.container_url = res returnendlocal redis = require resty.redis // redis的连接代码 每次都会连接redis,local red = redis:new() //这个操作比较相对比较耗时 所以接下来的操作才会在本地cache中存对应的关系red:set_timeout(100) -- 100 mslocal redis_host = os.getenv(ceryx_redis_host)if not redis_host then redis_host = 127.0.0.1 endlocal redis_port = os.getenv(ceryx_redis_port)if not redis_port then redis_port = 6379 endlocal res, err = red:connect(redis_host, redis_port)-- return if could not connect to redisif not res then returnend-- construct redis keylocal prefix = os.getenv(ceryx_redis_prefix)if not prefix then prefix = ceryx endlocal key = prefix .. :routes: .. host-- try to get target for hostres, err = red:get(key)if not res or res == ngx.null then -- construct redis key for $wildcard key = prefix .. :routes:$wildcard res, err = red:get(key) if not res or res == ngx.null then return end ngx.var.container_url = res returnend-- save found key to local cache for 5 secondscache:set(host, res, 5) // 在redis取出的映射关系存到redis的cache中避免下次继续连redis操作ngx.var.container_url = res
可以看出,这个项目分享的内容,并不尽人意,只是简单的提供了一种思路,如何去实现动态的proxy_pass,在这个基础上我们可以进行对url rewrite的扩展。另外,这里的host对应的routehost 如果只是ip,那样的话,会造成proxy_pass的时候后端的单点,也就是没有应用到upstream,没办法进行负载均衡。但是如果routehost的值是upstream的话,则,在配置文件中,依然要写死,所以,没有办法做到完全意义上的动态路由。
版权声明:本文为博主原创文章,未经博主允许不得转载。
以上就介绍了nginx_lua案例分析:动态路由实现,包括了方面的内容,希望对php教程有兴趣的朋友有所帮助。
其它类似信息

推荐信息