openresty 中文文檔_OpenResty 入門指南


 

OpenResty學習筆記

Nginx作為基礎網關服務在現在主流服務端開發中占據重要作用,要在網關層支持更多的特性,這時候就需要OpenResty了,本文記錄一下OpenResty 做api gateway的一些知識

概述

OpenResty: 是基於Nginx與Lua的高性能Web平台,帶有很多優秀的Lua庫,可以做動態服務網關。

OpenResty:設計哲學:對於不同的階段,進行相應的不同的處理

  • Nginx非阻塞I/O模型
  • Lua:是一種擴展式的動態類型語言,沒有main函數概念,只能嵌入宿主功能,高性能。關於Lua的語言介紹可參考Lua中文手冊

架構

Nginx的請求處理階段有11,其中最重要的也是最常見的3個階段依次為rewriteaccess,content.

下圖為Lua Nginx Module指令的執行順序圖,可以根據具體的業務場景設置不同的lua腳本。幾個重要的部分:

  • init_by_lua init_by_lua_block: 運行在Nginx loading-config 階段,注冊Nginx Lua全局變量,和一些預加載模塊。是Nginx master進程在加載Nginx配置時執行。
  • init_worker_by_lua: 在Nginx starting-worker階段,即每個nginx worker啟動時會調用,通常用來hook worker進程,並創建worker進行的計時器,用來健康檢查,或者設置熔斷記時窗口等等。
  • access_by_lua: 在access tail階段,用來對每次請求做訪問控制,權限校驗等等,能拿到很多相關變量。例如:請求體中的值,header中的值,可以將值添加到ngx.ctx, 在其他模塊進行相應的控制
  • balancer_by_lua: 通過Lua設置不同的負載均衡策略, 具體可以參考lua-resty-balancer
  • content_by_lua: 在content階段,即content handler的角色,即對於每個api請求進行處理,注意不能與proxy_pass放在同一個location下
  • proxy_pass: 真正發送請求的一部分, 通常介於access_by_lualog_by_lua之間
  • header_filter_by_lua:在output-header-filter階段,通常用來重新響應頭部,設置cookie等,也可以用來作熔斷觸發標記
  • body_filter_by_lua:對於響應體的content進行過濾處理
  • log_by_lua:記錄日志即,記錄一下整個請求的耗時,狀態碼等

 

a9cb17197e5c64164c18c5af93b7a854.png

常用命令

  • ngx.var.<arg>, lua使用nginx內置的綁定變量. ngx.var.remote_addr為獲取遠程的地址,ngx.var.http_cookie獲取cookie信息
  • ngx.ctx: 每次請求的上下文,可以在ctx里記錄,每次請求上下文的一些信息,例如:request_idaccess_key等等
  • upstream 塊里的的balancer_by_lua_file, 使用ngx.balancer模塊,可以實現不同的負載均衡策略,並調用set_current_peer函數設置當前query調用的backend
  • 對Openresty寫的網關,測試也至關重要,測試是基於perl的單元測試,包含了Nginx C model和OpenResty文檔地址 OpenResty Test guide
  • ngx.shared.DICT dict = ngx.shared[name_var] : 獲取共享內存的lua dict. 且shared.DICT在當前nginx server實例中被所有nginx worker進程共享。
  • ngx.shared.DICT當到達定義的大小限制時,再次調用set操作,會使用LRU淘汰一些key。set操作會返回三個值(success, err, forcible).
  • ngx.shared.DICT支持過期操作,expire等等
  • 對於ngx.shared.DICT的並發安全,使用resty.lock庫進行加速控制
  • cosocket 可以理解為coroutine + socket: 協程特性支撐 + nginx事件循環回調機制
  • ngx.timer.at(delay, callback, user_arg1)cosocket API,定時任務, 定時執行某些異步任務,即異步執行某些操作,不必等待結果返回時調用。例如:統計一段窗口期的請求耗時,發送通知管理員郵件的等等。 ngx.timer.at通過遞歸的方式,來實現每隔多長時間,執行某些操作。

配置

  • lua_package_path: lua擴展的庫的地址, ;;為設置默認的路徑
  • lua_package_cpath: Lua 擴展c 的so庫地址, ;;為設置默認的路徑
  1.  
    # set search paths for pure Lua external libraries (';;' is the default path):
  2.  
    lua_package_path '/foo/bar/?.lua;/blah/?.lua;;';
  3.  
     
  4.  
    # set search paths for Lua external libraries written in C (can also use ';;'):
  5.  
    lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;';
  6.  
     
  7.  
    server {
  8.  
    location /lua_content {
  9.  
    # MIME type determined by default_type:
  10.  
    default_type 'text/plain';
  11.  
     
  12.  
    content_by_lua_block {
  13.  
    ngx.say('Hello,world!')
  14.  
    }
  15.  
    }
  16.  
     
  17.  
    location /nginx_var {
  18.  
    # MIME type determined by default_type:
  19.  
    default_type 'text/plain';
  20.  
     
  21.  
    # try access /nginx_var?a=hello,world
  22.  
    content_by_lua_block {
  23.  
    ngx.say(ngx.var.arg_a)
  24.  
    }
  25.  
    }
  26.  
     
  27.  
    location = /request_body {
  28.  
    client_max_body_size 50k;
  29.  
    client_body_buffer_size 50k;
  30.  
     
  31.  
    content_by_lua_block {
  32.  
    ngx.req.read_body() -- explicitly read the req body
  33.  
    local data = ngx.req.get_body_data()
  34.  
    if data then
  35.  
    ngx.say("body data:")
  36.  
    ngx.print(data)
  37.  
    return
  38.  
    end
  39.  
     
  40.  
    -- body may get buffered in a temp file:
  41.  
    local file = ngx.req.get_body_file()
  42.  
    if file then
  43.  
    ngx.say("body is in file ", file)
  44.  
    else
  45.  
    ngx.say("no body found")
  46.  
    end
  47.  
    }
  48.  
    }
  49.  
     
  50.  
    # transparent non-blocking I/O in Lua via subrequests
  51.  
    # (well, a better way is to use cosockets)
  52.  
    location = /lua {
  53.  
    # MIME type determined by default_type:
  54.  
    default_type 'text/plain';
  55.  
     
  56.  
    content_by_lua_block {
  57.  
    local res = ngx.location.capture("/some_other_location")
  58.  
    if res then
  59.  
    ngx.say("status: ", res.status)
  60.  
    ngx.say("body:")
  61.  
    ngx.print(res.body)
  62.  
    end
  63.  
    }
  64.  
    }
  65.  
     
  66.  
    location = /foo {
  67.  
    rewrite_by_lua_block {
  68.  
    res = ngx.location.capture("/memc",
  69.  
    { args = { cmd = "incr", key = ngx.var.uri } }
  70.  
    )
  71.  
    }
  72.  
     
  73.  
    proxy_pass http://blah.blah.com;
  74.  
    }
  75.  
     
  76.  
    location = /mixed {
  77.  
    rewrite_by_lua_file /path/to/rewrite.lua;
  78.  
    access_by_lua_file /path/to/access.lua;
  79.  
    content_by_lua_file /path/to/content.lua;
  80.  
    }
  81.  
     
  82.  
    # use nginx var in code path
  83.  
    # CAUTION: contents in nginx var must be carefully filtered,
  84.  
    # otherwise there'll be great security risk!
  85.  
    location ~ ^/app/([-_a-zA-Z0-9/]+) {
  86.  
    set $path $1;
  87.  
    content_by_lua_file /path/to/lua/app/root/$path.lua;
  88.  
    }
  89.  
     
  90.  
    location / {
  91.  
    client_max_body_size 100k;
  92.  
    client_body_buffer_size 100k;
  93.  
     
  94.  
    access_by_lua_block {
  95.  
    -- check the client IP address is in our black list
  96.  
    if ngx.var.remote_addr == "132.5.72.3" then
  97.  
    ngx.exit(ngx.HTTP_FORBIDDEN)
  98.  
    end
  99.  
     
  100.  
    -- check if the URI contains bad words
  101.  
    if ngx.var.uri and
  102.  
    string.match(ngx.var.request_body, "evil")
  103.  
    then
  104.  
    return ngx.redirect("/terms_of_use.html")
  105.  
    end
  106.  
     
  107.  
    -- tests passed
  108.  
    }
  109.  
     
  110.  
    # proxy_pass/fastcgi_pass/etc settings
  111.  
    }
  112.  
    }

Reference

  • Lua中文手冊
  • lua-nginx-module
  • OpenResty最佳實踐
  • OpenResty API server


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM