• 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
  • 相关阅读:
    实用硬件篇(一)
    iOS通讯录(纯纯的干货)
    iOS社会化分享(干货)
    静态库的打包及使用(干货)
    iOS地图集成示例:百度地图POI检索
    iOS开发之KVC全解
    网络干货
    输入一个字符串,按字典序打印出该字符串中字符的所有排列(剑指offer)
    序列化二叉树
    二叉树中和为某一值的路径
  • 原文地址:https://www.cnblogs.com/fengkun125/p/14780964.html
Copyright © 2020-2023  润新知