Nginx(四)-- Nginx的擴展-OpenRestry

1. OpenResty 安裝及使用

  OpenResty 是一個經過 Lua 擴展 Nginx 實現的可伸縮的 Web 平臺,內部集成了大量精良的 Lua 庫、第三方模塊以及大多數的依賴項。用於方便地搭建可以處理超高併發、擴展性極高的動態 Web 應用、Web 服務和動態網關。html

安裝:前端

1. 下載安裝包  https://openresty.org/cn/download.htmljava

2. 安裝軟件包  tar -zxvf openresty-1.13.6.2.tar.gz。cd openrestry-1.13.6.2。./configure [默認會安裝在/usr/local/openresty 目錄] --prefix= 指定路徑。make && make installmysql

3. 可能存在的錯誤,第三方依賴庫沒有安裝的狀況下會報錯 yum install readline-devel / pcre-devel /openssl-develnginx

  安裝過程和 Nginx 是同樣的,由於他是基於 Nginx 作的擴展。開始第一個程序,HelloWorld  cd /usr/local/openresty/nginx/conf 編輯 nginx 配置文件 nginx.conf redis

location / {
 default_type text/html;
 content_by_lua_block {
   ngx.say("helloworld");
 }
}

  在 sbin 目錄下執行.nginx 命令就能夠運行,訪問能夠看到 helloworld。算法

創建工做空間:sql

  爲了避免影響默認的安裝目錄,咱們能夠建立一個獨立的空間來練習,先到在安裝目錄下建立 demo 目錄,安裝目錄爲/usr/local/openresty  .mkdir demo。而後在 demo 目錄下建立三個子目錄,一個是 logs 、一個是 conf,一個是 lua。數據庫

  進接下去演示一個實現 API網關功能的簡單demo,而後提供一個算法去計算傳入參數a,b的和。入conf 建立配置文件  vim nginx.conf :vim

worker_processes 1;
error_log logs/error.log;
events {
   worker_connections 1024;
}
http {
   lua_package_path '$prefix/lua/?.lua'; //這裏的¥prefix在啓動的時候指定
   lua_code_cache off; // lua腳本不須要從新加載
   server {
     listen 80;
     // 正則匹配訪問路徑
     location ~ ^/api/([-_a-zA-Z0-9]+) {
        // 請求過濾一下
        access_by_lua_file lua/check.lua;
        content_by_lua_file lua/$1.lua;
     }
   }
}

 

  當來到的請求符合   ^/api/([-_a-zA-Z0-9/]  時 會在NGX_HTTP_CONTENT_PHASE HTTP請求內容階段 交給 lua/$1.lua來處理。好比:

/api/addition                    交給 lua/addition.lua 處理。

/api/lua/substraction       交給 lua/substraction .lua 處理。

  接下去建立 三個 lua 腳本:params.lua:

local _M ={} // 定義一個模塊
//定義一個方法
//該方法用於判斷參數是否爲數字
function _M.is_number(...)
   local args={...}
   local num;
   for i,v in ipairs(arg) do
     num=tonumber(v);
     if nil ==num then
         return false;
     end
   end
   return true;
end
//將該模塊返回出去
return _M;

 

  寫一個用於起到網關過濾的檢查腳本check.lua:

//導入模塊<br>local param=require("params");<br>//獲取uri的參數
local args=ngx.req.get_uri_args();<br>//判斷a,b是否爲空且是否爲數字
if not args.a or not args.b or not param.is_number(args.a,args.b) then
        ngx.exit(ngx.HTTP_BAD_REQUEST);
        return;
end

 

  算法腳本  add.lua:

local args =ngx.req.get_uri_args();
ngx.say(args.a+args.b);

 

  進入nginx的sbin目錄執行:./nginx -p /usr/local/openresty/demo 【-p 主要是指明 nginx 啓動時的配置目錄】,此時會提示一個警告信息,無需理會,有強迫症把對應配置關了就還了:nginx: [alert] lua_code_cache is off; this will hurt performance in /usr/local/openresty/demo/conf/nginx.conf:12。經過訪問http://192.168.254.137/api/add?a=1&b=3 能顯示最後的值:

  庫文件使用:經過上面的案例,咱們基本上對 openresty 有了一個更深的認識,其中咱們用到了自定義的 lua 模塊。實際上 openresty 提供了很豐富的模塊。讓咱們在實現某些場景的時候更加方便。能夠在 /openresty/lualib 目錄下看到;好比在 resty 目錄下能夠看到 redis.lua、mysql.lua 這樣的操做 redis 和操做數據庫的模塊。更多的庫能夠去百度,或者查找相關書籍。

4.什麼是API網關

  從一個房間到另外一個房間,必須必需要通過一扇門,一樣,從一個網絡向另外一個網絡發送信息,必須通過一道「關口」,這道關口就是網關。顧名思義,網關(Gateway)就是一個網絡鏈接到另外一個網絡的「關口」。那什麼是 api 網關呢?

  在微服務流行起來以前,api 網關就一直存在,最主要的應用場景就是開放平臺,也就是 open api; 這種場景你們接觸的必定比較多,好比阿里的開放平臺;當微服務流行起來之後,api 網關就成了上層應用集成的標配組件.

  爲何須要網關?

  對微服務組件地址進行統一抽象,API 網關意味着你要把 API 網關放到你的微服務的最前端,而且要讓 API 網關變成由應用所發起的每一個請求的入口。這樣就能夠簡化客戶端實現和微服務應用程序之間的溝通方式.

  當服務愈來愈多之後,咱們須要考慮一個問題,就是對某些服務進行安全校驗以及用戶身份校驗。甚至包括對流量進行控制。 咱們會對須要作流控、須要作身份認證的服務單獨提供認證功能,可是服務愈來愈多之後,會發現不少組件的校驗是重複的。這些東西很明顯不是每一個微服務組件須要去關心的事情。微服務組件只須要負責接收請求以及返回響應便可。能夠把身份認證、流控都放在 API 網關層進行控制。

5. OpenResty 實現灰度發佈功能

  在單一架構中,隨着代碼量和業務量不斷擴大,版本迭代會逐步變成一個很困難的事情,哪怕是一點小的修改,都必需要對整個應用從新部署。 可是在微服務中,各個模塊是是一個獨立運行的組件,版本迭代會很方便,影響面很小。同時,爲服務化的組件節點,對於咱們去實現灰度發佈(金絲雀發佈:將一部分流量引導到新的版本)來講,也會變的很簡單;因此經過 API 網關,能夠對指定調用的微服務版本,經過版原本隔離。以下圖所示

  OpenResty 實現 API 網關限流及登陸受權

  OpenResty 爲何能作網關?

  前面咱們瞭解到了網關的做用,經過網關,能夠對 api 訪問的前置操做進行統一的管理,好比鑑權、限流、負載均衡、日誌收集、請求分片等。因此 API 網關的核心是全部客戶端對接後端服務以前,都須要統一接入網關,經過網關層將全部非業務功能進行處理。OpenResty 爲何能實現網關呢? OpenResty 有一個很是重要的因素是,對於每個請求,Openresty 會把請求分爲不一樣階段,從而可讓第三方模塊經過掛載行爲來實現不一樣階段的自定義行爲。而這樣的機制可以讓咱們很是方便的設計 api 網關。

Nginx 自己在處理一個用戶請求時,會按照不一樣的階段進行處理,總共會分爲 11個階段。而 openresty 的執行指令,就是在這 11 個步驟中掛載 lua 執行腳本實現擴展,咱們分別看看每一個指令的做用

  init_by_lua : 當 Nginx master 進程加載 nginx 配置文件時會運行這段 lua 腳本,通常用來註冊全局變量或者預加載 lua 模塊。

  init_woker_by_lua: 每一個 Nginx worker 進程啓動時會執行的 lua 腳本,能夠用來作健康檢查。

  set_by_lua:設置一個變量。

  rewrite_by_lua:在 rewrite 階段執行,爲每一個請求執行指定的 lua 腳本。

  access_by_lua:爲每一個請求在訪問階段調用 lua 腳本。

  content_by_lua:前面演示過,經過 lua 腳本生成 content 輸出給 http 響應。

  balancer_by_lua:實現動態負載均衡,若是不是走 contentbylua,則走 proxy_pass,再經過 upstream 進行轉發。

  header_filter_by_lua: 經過 lua 來設置 headers 或者 cookie。

  body_filter_by_lua:對響應數據進行過濾。

  log_by_lua : 在 log 階段執行的腳本,通常用來作數據統計,將請求數據傳輸到後端進行分析。

灰度發佈的實現:

1.跟前面同樣建立一個新的工做空間 mkdir gray。而後在 demo 目錄下建立三個子目錄,一個是 logs 、一個是 conf,一個是 lua。

2.編寫 Nginx 的配置文件 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 {//tomcat地址
  server 192.168.254.137:8080;
 }
 // 預生產環境
 upstream pre {//tomcat地址
  server 192.168.254.139:8080;
 }
 
 server {
  listen 80;
  server_name localhost;
  //當訪問該路徑就會進入lua腳本
  location / {
   content_by_lua_file lua/gray.lua;
  }
  // 定義變量在lua中會使用
  location @prod {
   proxy_pass http://prod;
  }
 
  location @pre {
   proxy_pass http://pre;
  }
 }
}

 

3.編寫 gray.lua 文件

local redis=require "resty.redis";
local red=redis:new();
red:set_timeout(1000);
local ok,err=red:connect("192.168.254.138",6379);
if not ok then
 ngx.say("failed to connect redis",err);
 return;
end
ok, err = red:auth("wuzhenzhao");
local_ip=ngx.var.remote_addr;
local ip_lists=red:get("gray");
if string.find(ip_lists,local_ip) == nil then
 ngx.exec("@prod");
else
 ngx.exec("@pre");
end
local ok,err=red:close();

 

4.

  1.進入sbin目錄 執行命令啓動 nginx: ./nginx -p /usr/local/openresty/gray

  2. 啓動 redis,並設置 set gray 192.168.254.1,因爲我這邊是訪問虛擬機,因此我本地ip去訪問就是這個。

  3. 經過瀏覽器運行: http://192.168.254.137/查看運行結果

  修改 redis gray 的值, 到 redis 中 set gray 192.168.254.2. 再次運行結果,便可看到訪問結果已經發生了變化.

相關文章
相關標籤/搜索