OpenResty 가 흐름 제한 을 실현 하 는 몇 가지 방식

16279 단어 openrestynginx
개발 중  api  게 이 트 웨 이 를 닫 을 때 간단 한 흐름 제한 을 한 적 이 있다. 예 를 들 어 정적 차단 과 동적 차단 등 이다.정적 차단 은 특정한 인터페이스 가 일정 시간 창 에 있 는 요청 수 를 제한 하 는 것 이다.사용 자 는 시스템 에서 그들의 인터페이스 에 초당 최대 호출 량 을 설정 할 수 있 습 니 다. 만약 에 이 제한 을 초과 하면 서비스 이 인 터 페 이 스 를 거부 합 니 다. 동적 차단 도 정적 차단 을 바탕 으로 개선 할 수 있 습 니 다. 우 리 는 현재 시스템 의 응답 시간 에 따라 제한 흐름 의 한도 값 을 동적 으로 조정 할 수 있 습 니 다. 만약 에 응답 이 빠 르 면 한도 값 을 크게 조정 하고 더 많은 요 구 를 할 수 있 습 니 다.반대로 흐름 제한 한도 값 을 자동 으로 낮 추고 소량의 요청 만 통과 시킨다.
사실 이것 은 매우 간단 한 흐름 제한 방식 이다.하지만 이 장면 들 은 우리 가 개발 할 때 자주 만 나 기 때문에 여기 서 사용 합 니 다.  OpenResty  대략 흔히 볼 수 있 는 제한 방식 을 실현 하 다.(이곳 에 서 는 OpenResty1.13.6.1 버 전의 자체 테이프 lua-resty-limit-traffic 모듈 을 사용 하여 실현 하기에 더욱 편리 합 니 다)
인터페이스 총 병발 수 제한
장면:  ip  동시 접속 수 제한
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 ua_shared_dict my_limit_conn_store 100m; ... location /hello {      access_by_lua_block {          local limit_conn = require "resty.limit.conn"          --   ip   1           -- burst   0, , 503,          --  ,  burst  ( )          --  ( ) ,                     local lim, err = limit_conn.new("my_limit_conn_store", 1, 0, 0.5)                        if not lim then              ngx.log(ngx.ERR, "failed to instantiate a resty.limit.conn object: ", err)              return ngx.exit(500)          end            local key = ngx.var.binary_remote_addr          -- commit  true  shared dict key ,          -- false           local delay, err = lim:incoming(key, true)          if not delay then              if err == "rejected" then                  return ngx.exit(503)              end              ngx.log(ngx.ERR, "failed to limit req: ", err)              return ngx.exit(500)          end            --  shared dict , ctx ,          --  ,          if lim:is_committed() then              local ctx = ngx.ctx              ctx.limit_conn = lim              ctx.limit_conn_key = key              ctx.limit_conn_delay = delay          end            local conn = err          --   delay  ,          --  , 100 , 200 , 500 , 200          -- 100 , 200 , 200 ,0-100 0.5 ,          -- 101-200 0.5*2=1 (0.5 )          if delay >= 0.001 then              ngx.sleep(delay)          end      }        log_by_lua_block {          local ctx = ngx.ctx          local lim = ctx.limit_conn          if lim then              local key = ctx.limit_conn_key              --  , shared dict ,              --  , limit_conn.new ,              --               local conn, err = lim:leaving(key, 0.5)              if not conn then                  ngx.log(ngx.ERR,                          "failed to record the connection leaving ",                          "request: ", err)                  return              end          end      }      proxy_pass http://10.100.157.198:6112;      proxy_set_header Host $host;      proxy_redirect off;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout 60;      proxy_read_timeout 600;      proxy_send_timeout 600;
설명: 사실 이곳 은 설정 되 어 있 지 않 습 니 다.  burst  의 값 은 단순 한 제한 최대 병발 수 입 니 다. 설정 하면  burst 의 값 과 지연 처 리 를 했 습 니 다. 사실은 병발 수 에 누 통 알고리즘 을 사 용 했 지만 지연 처 리 를 하지 않 으 면 사용 하 는 토 큰 통 알고리즘 입 니 다. 아래 요청 수 에 누 통 토 큰 통 을 사용 하 는 부분 을 참고 하여 병발 수의 누 통 토 큰 통 은 이와 비슷 합 니 다.
인터페이스 시간 창 요청 수 제한
필드: 제한  ip  분당 120 회 만 호출 가능  /hello  인터페이스 (시간 대 시작 시 120 개의 요청 을 한꺼번에 놓 칠 수 있 음)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 lua_shared_dict my_limit_count_store 100m; ...   init_by_lua_block {      require "resty.core" } ....   location /hello {      access_by_lua_block {          local limit_count = require "resty.limit.count"            -- rate: 10/min           local lim, err = limit_count.new("my_limit_count_store", 120, 60)          if not lim then              ngx.log(ngx.ERR, "failed to instantiate a resty.limit.count object: ", err)              return ngx.exit(500)          end            local key = ngx.var.binary_remote_addr          local delay, err = lim:incoming(key, true)          --  , ( 0, )          if not delay then              if err == "rejected" then                  return ngx.exit(503)              end                ngx.log(ngx.ERR, "failed to limit count: ", err)              return ngx.exit(500)          end      }        proxy_pass http://10.100.157.198:6112;      proxy_set_header Host $host;      proxy_redirect off;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout 60;      proxy_read_timeout 600;      proxy_send_timeout 600; }
부 드 러 운 제한 인터페이스 요청 수
필드: 제한  ip  분당 120 회 만 호출 가능  /hello  인터페이스 (매 끄 러 운 처리 요청, 즉 1 초 에 2 개의 요청 을 놓 치 는 것)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 lua_shared_dict my_limit_req_store 100m; ....   location /hello {      access_by_lua_block {          local limit_req = require "resty.limit.req"          --  rate=2/s, 0,( )           --  resty.limit.req ,          local lim, err = limit_req.new("my_limit_req_store", 2, 0)          if not lim then              ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)              return ngx.exit(500)          end            local key = ngx.var.binary_remote_addr          local delay, err = lim:incoming(key, true)          if not delay then              if err == "rejected" then                  return ngx.exit(503)              end              ngx.log(ngx.ERR, "failed to limit req: ", err)              return ngx.exit(500)          end      }        proxy_pass http://10.100.157.198:6112;      proxy_set_header Host $host;      proxy_redirect off;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout 60;      proxy_read_timeout 600;      proxy_send_timeout 600; }
누 출 통 알고리즘 제한 흐름
필드: 제한  ip  분당 120 회 만 호출 가능  /hello  인터페이스 (부 드 러 운 처리 요청, 즉 1 초 에 2 개의 요청 을 놓 치 는 것), 부분 을 초과 하여 통 에 들 어가 기다 리 고 (통 용량 은 60), 통 이 가득 차 면 흐름 제한 을 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 lua_shared_dict my_limit_req_store 100m; ....   location /hello {      access_by_lua_block {          local limit_req = require "resty.limit.req"          --  rate=2/s, 0,( )           --  resty.limit.req ,          local lim, err = limit_req.new("my_limit_req_store", 2, 60)          if not lim then              ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)              return ngx.exit(500)          end            local key = ngx.var.binary_remote_addr          local delay, err = lim:incoming(key, true)          if not delay then              if err == "rejected" then                  return ngx.exit(503)              end              ngx.log(ngx.ERR, "failed to limit req: ", err)              return ngx.exit(500)          end                     --  , delay ,          --  , ,          --           if delay >= 0.001 then              ngx.sleep(delay)          end      }        proxy_pass http://10.100.157.198:6112;      proxy_set_header Host $host;      proxy_redirect off;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout 60;      proxy_read_timeout 600;      proxy_send_timeout 600; }
토 큰 통 알고리즘 흐름 제한
토 큰 통 은 사실 누 출 통 의 역 조작 을 볼 수 있 습 니 다. 우리 가 요청 속 도 를 초과 하여 통 에 들 어 가 는 요 구 를 어떻게 처리 하 는 지 볼 수 있 습 니 다. 만약 에 우리 가 이 부분 을 대기 행렬 에 넣 었 다 면 사실은 누 출 통 알고리즘 을 사 용 했 습 니 다. 그러나 우리 가 이 부분의 돌발 요 구 를 직접 처리 할 수 있다 면 사실은 토 큰 통 알고리즘 을 사용 한 것 입 니 다.
필드: 제한  ip  분당 120 회 만 호출 가능  /hello  인터페이스 (부 드 러 운 처리 요청, 즉 1 초 에 2 개의 요청 을 놓 치지 만 일정한 돌발 유량 (돌발 유량, 즉 통 의 용량 (통 의 용량 은 60) 을 허용 하고 통 의 용량 을 초과 하면 직접 거절 합 니 다.
여 기 는 통 에서 요청 한 지연 처리 코드 를 백 엔 드 서비스 로 바로 보 내 면 됩 니 다. 이렇게 하면 토 큰 통 을 사용 합 니 다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 lua_shared_dict my_limit_req_store 100m; ....   location /hello {      access_by_lua_block {          local limit_req = require "resty.limit.req"            local lim, err = limit_req.new("my_limit_req_store", 2, 0)          if not lim then              ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)              return ngx.exit(500)          end            local key = ngx.var.binary_remote_addr          local delay, err = lim:incoming(key, true)          if not delay then              if err == "rejected" then                  return ngx.exit(503)              end              ngx.log(ngx.ERR, "failed to limit req: ", err)              return ngx.exit(500)          end                     --  , delay ,          --  , ,          --             if delay >= 0.001 then          --    ngx.sleep(delay)          end      }        proxy_pass http://10.100.157.198:6112;      proxy_set_header Host $host;      proxy_redirect off;      proxy_set_header X-Real-IP $remote_addr;      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;      proxy_connect_timeout 60;      proxy_read_timeout 600;      proxy_send_timeout 600; }
설명: 사실 nginxngx_http_limit_req_module 이 모듈 의 delaynodelay 는 여기 서 통 에 지연 처 리 를 요청 하 는 것 과 유사 한 두 가지 방안 이다. 즉, 각각 대응 하 는 누 출 통 과 토 큰 통 두 가지 알고리즘 이다.

좋은 웹페이지 즐겨찾기