本文讲述 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 脚本。
在不同的阶段直接完成大部分典型处理了。
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网关。