本文讲述 OpenResty api网关设计,主要涉及api网关介绍、openresty api网关 请求路由(路由判断、路由重写、服务判断、限流)、授权验证(统一认证)、动态Upstream 以及这三部分理论简单实现的Api网关和Api网关admin。

1、什么是api网关

在这个微服务这么火的时代,随之api网关常常被提到。我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务并提供 Rest Api 风格的接口来被 H5, Android, IOS 应用调用,由api网统一关管理这些接口的方方面面,那么什么才是api网关?

百度上针对于 API 网关有如下介绍: 

API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。 API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

2、OpenResty api网关

OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

开发api网关使用到的 OpenResty 一个重要知识:OpenResty 对于一个请求的处理流程。Nginx 把一个请求分为不同的阶段,从而让第三方模块通过挂载行为在不同的阶段来定制自己的行为;OpenResty 拥有同样的特性,不过在不同阶段挂载的是 Lua 脚本。

openresty 应用代理网关 配置 demo openresty api网关_Web

在不同的阶段直接完成大部分典型处理了。

set_by_lua: 流程分之处理判断变量初始化 

rewrite_by_lua: 转发、重定向、缓存等功能(例如特定请求代理到外网) 

access_by_lua: IP准入、接口权限等情况集中处理(例如配合iptable完成简单防火墙) 

content_by_lua: 内容生成 

header_filter_by_lua: 应答HTTP过滤处理(例如添加头部信息) 

body_filter_by_lua: 应答BODY过滤处理(例如完成应答内容统一成大写) 

log_by_lua: 回话完成后本地异步完成日志记录(日志可以记录在本地,还可以同步到其他机器)


那么我们可以开始的api网关设计了:

init_by_lua_block 加载路由信息、服务信息到lua_shared_dict。

init_worker_by_lua_block 持久化通过apiadmin新增或者修改的路由、服务信息到磁盘、服务健康检查。

rewrite_by_lua_block 根据url规则匹配路由信息和服务信息并赋值到ngx上下文

access_by_lua_block 进行统一授权

opengate_upstream 通过ngx上下文的url服务信息通过ngx_balancer.set_current_peer对服务进行转发。

adminapi 提供路由、服务信息管理restful接口

示例代码如下:

lua_shared_dict url_dict      5m;
    lua_shared_dict balancer_dict 5m;

    init_by_lua_block {
        opengate = require 'opengate.openpoint'
        opengate.init()
    }
    
    init_worker_by_lua_block{
        opengate.cofigsync()
        opengate.heathcheck()
    }

    upstream opengate_upstream {
      server 0.0.0.1;
      balancer_by_lua_block {
          opengate.balancer()
      }
      keepalive 60;
    }

    server {

        listen 443 http2 ssl default_server; 
        server_name _; 
        
        ssl on;
        ssl_certificate server.crt; 
        ssl_certificate_key server.key; 
        location / {
           default_type application/json;
           rewrite_by_lua_block {
                opengate.rewrite()
            }

            access_by_lua_block {
                opengate.access()
            }
            
            proxy_pass  http://opengate_upstream;
            proxy_intercept_errors on;
        }
      
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

	      error_page  404   /404.html;
        location = /404.html {
		          root   html;
        }
    }

    server {
        listen  8800;
        server_name _;

        location / {
          default_type application/json;
          content_by_lua_block {
              opengate.adminapi()
          }
        }
        
        location /robots.txt {
              return 200 'User-agent: *\nDisallow: /';
        }
    }


通过如上我们就实现一个简单的api网关。