什么是网关
从一个房间到另一个房间,必须必须要经过一扇门,同样,从一个网络向另一个网络发送信息,必须经过一道“关口”,这道关口就是网关。顾名思义,网关(Gateway)就是一个网络连接到另一个网络的“关口”。
那什么是 api 网关呢?
在微服务流行起来之前,api 网关就一直存在,最主要的应用场景就是开放平台,也就是 open api; 这种场景大家接触的一定比较多,比如阿里的开放平台。微服务流行起来后,api网关就成了上层应用集成的标配组件。

为什么需要网关?

1、把 API 网关放到微服务的最前端,让 API 网关变成所有应用请求的入口。这样就可以简化客户端实现和微服务应用程序之间的沟通方式。
网关功能示意图:
在这里插入图片描述
2、当服务越来越多以后,我们需要考虑一个问题,就是对某些服务进行安全校验以及用户身份校验。甚至包括对流量进行控制。 开始我们会再需要做流控、需要做身份认证的服务内单独提供认证功能,但是服务越来越多以后,会发现很多组件的校验是重复的。这些东西很明显不是每个微服务组件需要去关心的事情。微服务组件只需要负责接收请求以及返回响应即可。可以把身份认证、流控都放在 API 网关层进行控制。

OpenResty 为什么能做网关?
前面我们了解到了网关的作用,通过网关,可以对 api 访问的前置操作进行统一的管理,比如鉴权、限流、负载均衡、日志收集、请求分片等。所以 API 网关的核心是所有客户端对接后端服务之前,都需要统一接入网关,通过网关层将所有非业务功能进行处理。
OpenResty 为什么能实现网关呢? 有一个非常重要的因素是,对于每一个请求,Openresty 会把请求分为不同阶段,从而可以让第三方模块通过挂载行为来实现不同阶段的自定义行为。这种机制可以非常方便的设计api网关
在这里插入图片描述

Nginx 本身在处理一个用户请求时,会按照不同的阶段进行处理,总共会分为 11个阶段。而 openresty 的执行指令,就是在这 11 个步骤中挂载 lua 执行脚本实现扩展,我们分别看看每个指令的作用。
initbylua : 当 Nginx master 进程加载 nginx 配置文件时会运行这段 lua 脚本,一般用来注册全局变量或者预加载 lua 模块
initwokerby_lua: 每个 Nginx worker 进程启动时会执行的 lua 脚本,可以用来做健康检查
setbylua:设置一个变量
rewritebylua:在 rewrite 阶段执行,为每个请求执行指定的 lua 脚本
accessbylua:为每个请求在访问阶段调用 lua 脚本
contentbylua:前面演示过,通过 lua 脚本生成 content 输出给 http 响应
balancerbylua:实现动态负载均衡,如果不是走 contentbylua,则走 proxy_pass,再通过 upstream 进行转发
headerfilterby_lua: 通过 lua 来设置 headers 或者 cookie
bodyfilterby_lua:对响应数据进行过滤
logbylua : 在 log 阶段执行的脚本,一般用来做数据统计,将请求数据传输到后端进行分析

实现网关的灰度发布功能
灰度发布就是新版本刚上线时,可以只对某一部分用户开放,比如90%的客户还是只能访问到旧版本,另外10%的用户被添加到灰度名单中可以访问最新版本。
openresty 根目录下创建 gray目录 gray目录下创建 conf logs lua 三个目录 如下:

[root@zk03 openresty]# mkdir gray
[root@zk03 openresty]# cd gray
[root@zk03 gray]# mkdir conf logs lua
[root@zk03 gray]# ll
总用量 0
drwxr-xr-x. 2 root root 6 1月  30 05:05 conf
drwxr-xr-x. 2 root root 6 1月  30 05:05 logs
drwxr-xr-x. 2 root root 6 1月  30 05:05 lua

在gray/conf 下新增nginx.conf 文件如下:

[root@zk03 gray]# vi conf/nginx.conf 
worker_processes 1;
error_log logs/error.log;
events{
  worker_connections 1024;
}
http{
  lua_package_path "$prefix/lualib/?.lua;;";
  lua_package_cpath "$prefix/lualib/?.so;;";
  upstream prod {
    server zk03:8080;
  }
  upstream pre {
    server zk03:8081;
  }
  server {
    listen 80;
    server_name localhost;
    location /api {
      content_by_lua_file lua/gray.lua;
    }
    location @prod {
      proxy_pass http://prod;
    }
    location @pre {
      proxy_pass http://pre;
    }
  }
  server {
    listen 8080;
    location / {
      content_by_lua_block {
        ngx.say("I'm prod env");
      }
    }
  }

  server {
    listen 8081;
    location / {
      content_by_lua_block {
        ngx.say("I'm pre env");
      }
    }
  }
}

在gray/lua 目录下新增 gray.lua文件如下 实现逻辑:在名单中的ip 访问 pre环境 否则访问prod环境:

[root@zk03 gray]# vi lua/gray.lua 
local redis=require "resty.redis";
local red=redis:new();
red:set_timeout("1000");
local ok,err=red:connect("127.0.0.1",6379);
if not ok then
  ngx.say("failed to connect redis",err);
  return;
end
local ip=ngx.var.remote_addr;
local ip_lists=red:get("gray");
if string.find(ip_lists,ip) == nil then      
  ngx.exec("@prod");
else
  ngx.exec("@pre");
end
local ok,err=red:close();

启动openresty

[root@zk03 gray]# ../nginx/sbin/nginx -s reload  -p /usr/local/openresty/gray

连接redis 将 gray 设置为 192.168.68.2 即将该ip加入到名单中 如下:

[root@zk03 src]# ./redis-cli
127.0.0.1:6379> set gray 192.168.68.2
OK

浏览器访问 zk03/api 返回 pre 环境
在这里插入图片描述
修改 redis 中的 gray 为 192.168.68.1 如下:

127.0.0.1:6379> set gray 192.168.68.1
OK

浏览器访问 zk03/api 返回 prod 环境 如下:
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐