: This article mainly introduces the nginx_lua case study: dynamic routing implementation. if you are interested in the PHP Tutorial, refer to it. The routing here refers to the ing of access paths and specific implementation content in web development. For example, if/a maps to a specific page, it is called a route. Dynamic routing, as its name implies, dynamically adds this route ing relationship.
In nginx, you can use rewrite and proxy_pass to implement route ing or reverse proxy. However, this relationship must be written to the configuration file according to the traditional configuration, and then restart nginx through quick "seamless" restart. Although it is seamless, its tedious configuration and boring restart operations cannot be avoided.
Recently, I saw a project ceryx on github, which is a ing of dynamic routing by nginx and lua, that is, the ing relationship mentioned above, which is managed by lua, although it is relatively simple to implement, it can be analyzed and learned. This project uses Structure to save this ing relationship, so that you can quickly obtain this relationship in nginx for processing. at the same time, the interface for managing the redis routing relationship is exposed in the form of HTTP.
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
The above code is an http api for route management. of course, this is not the focus of our analysis. Let's take a look at the configuration of nginx in this project.
Upstream fallback {server listener;} 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; // entry point # Proxy configuration proxy_set_header Host $ http_host; proxy_set_header X-Forwarded-For $ response; 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 ;}...}
As you can see, this configuration is quite common and is no different from the normal reverse proxy. the actual starting point is the router. lua code in access_by_lua_file.
Local container_url = ngx. var. container_url // Obtain the container_urllocal host = ngx. var. host in the configuration file // Obtain the host in the request. for example, we request http://www.xxx.com/a.html The host here is www.xxx.com -- Check if key exists in local cachelocal cache = ngx. shared. ceryxlocal res, flags = cache: get (host) // directly obtain the route ING of the host in the nginx cache. if yes, the result if res then ngx is directly returned. var. container_url = res returnendlocal redis = require "resty. redis "// redis connection code will connect to redis every time, local red = redis: new () // This operation is relatively time-consuming, so the next operation will save the corresponding relationship in the local 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 cocould 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) // The ing relationships retrieved from redis are stored in the redis cache to prevent the next connection to redis for ngx operations. var. container_url = res
It can be seen that the content shared by this project is not satisfactory, but it provides a simple idea to implement dynamic proxy_pass, on this basis, we can extend the url rewrite. In addition, if the routeHost corresponding to the host is only an IP address, it will cause a single point of failure at the backend during proxy_pass, that is, it is not applied to upstream and there is no way to perform load balancing. However, if the routeHost value is upstream, it will still be written to the configuration file. Therefore, there is no way to achieve dynamic routing in a full sense.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.
The above introduces the nginx_lua case analysis: dynamic routing implementation, including content, hope to be helpful to friends who are interested in PHP tutorials.