天天看點

openresty實作網關功能

什麼是網關

從一個房間到另一個房間,必須必須要經過一扇門,同樣,從一個網絡向另一個網絡發送資訊,必須經過一道“關口”,這道關口就是網關。顧名思義,網關(Gateway)就是一個網絡連接配接到另一個網絡的“關口”。

那什麼是 api 網關呢?

在微服務流行起來之前,api 網關就一直存在,最主要的應用場景就是開放平台,也就是 open api; 這種場景大家接觸的一定比較多,比如阿裡的開放平台。微服務流行起來後,api網關就成了上層應用內建的标配元件。

為什麼需要網關?

1、把 API 網關放到微服務的最前端,讓 API 網關變成所有應用請求的入口。這樣就可以簡化用戶端實作和微服務應用程式之間的溝通方式。

網關功能示意圖:

openresty實作網關功能

2、當服務越來越多以後,我們需要考慮一個問題,就是對某些服務進行安全校驗以及使用者身份校驗。甚至包括對流量進行控制。 開始我們會再需要做流控、需要做身份認證的服務内單獨提供認證功能,但是服務越來越多以後,會發現很多元件的校驗是重複的。這些東西很明顯不是每個微服務元件需要去關心的事情。微服務元件隻需要負責接收請求以及傳回響應即可。可以把身份認證、流控都放在 API 網關層進行控制。

OpenResty 為什麼能做網關?

前面我們了解到了網關的作用,通過網關,可以對 api 通路的前置操作進行統一的管理,比如鑒權、限流、負載均衡、日志收集、請求分片等。是以 API 網關的核心是所有用戶端對接後端服務之前,都需要統一接入網關,通過網關層将所有非業務功能進行處理。

OpenResty 為什麼能實作網關呢? 有一個非常重要的因素是,對于每一個請求,Openresty 會把請求分為不同階段,進而可以讓第三方子產品通過挂載行為來實作不同階段的自定義行為。這種機制可以非常友善的設計api網關

openresty實作網關功能

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 三個目錄 如下:

[[email protected] openresty]# mkdir gray
[[email protected] openresty]# cd gray
[[email protected] gray]# mkdir conf logs lua
[[email protected] 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 檔案如下:

[[email protected] 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環境:

[[email protected] 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

[[email protected] gray]# ../nginx/sbin/nginx -s reload  -p /usr/local/openresty/gray
           

連接配接redis 将 gray 設定為 192.168.68.2 即将該ip加入到名單中 如下:

[[email protected] src]# ./redis-cli
127.0.0.1:6379> set gray 192.168.68.2
OK
           

浏覽器通路 zk03/api 傳回 pre 環境

openresty實作網關功能

修改 redis 中的 gray 為 192.168.68.1 如下:

127.0.0.1:6379> set gray 192.168.68.1
OK
           

浏覽器通路 zk03/api 傳回 prod 環境 如下:

openresty實作網關功能