天天看點

使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量

使用OpenResty進行限流的基本配置

  • 1.安裝OpenResty
        • 1. 添加倉庫執行指令
        • 2. 執行安裝
        • 3. 安裝成功後 會在預設的目錄如下:
  • 2.安裝nginx
  • 3.測試通路
  • 4.廣告的載入和讀取
        • 1.聲明nginx緩存
        • 2.在/root/lua目錄下建立read_content.lua:
        • 3.在nginx.conf中進行調用
  • 5. 控制并發量
        • 1. nginx的限流
          • (1) 控制速率
            • 處理突發流量
          • (2) 控制并發量

以商城輪播廣告為例

采用多級緩存的方式來減少下遊系統的服務壓力。

先查詢openresty本地緩存 ,如果沒有,再查詢redis中的資料,如果沒有,再查詢mysql中的資料,但凡有資料 則傳回即可。

記錄使用OpenResty(Nginx+lua)進行限流最基礎的配置。

1.安裝OpenResty

1. 添加倉庫執行指令

yum install yum-utils
 yum-config-manager --add-repo  	 https://openresty.org/package/centos/openresty.repo
           

2. 執行安裝

yum install openresty
           

3. 安裝成功後 會在預設的目錄如下:

/usr/local/openresty
           

2.安裝nginx

預設已經安裝好了nginx,在目錄:/usr/local/openresty/nginx 下。

修改/usr/local/openresty/nginx/conf/nginx.conf,将配置檔案使用的根設定為root,目的就是将來要使用lua腳本的時候 ,直接可以加載在root下的lua腳本。

cd /usr/local/openresty/nginx/conf
vi nginx.conf
           

修改代碼如下:

使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量

3.測試通路

重新開機下centos虛拟機,然後通路測試Nginx

通路位址:http://192.168.211.132/

使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量

4.廣告的載入和讀取

實作思路:

先查詢openresty本地緩存 如果 沒有

再查詢redis中的資料,如果沒有

再查詢mysql中的資料,但凡有資料 則傳回即可。

1.聲明nginx緩存

lua_shared_dict dis_cache 128m;
           

2.在/root/lua目錄下建立read_content.lua:

ngx.header.content_type="application/json;charset=utf8"
local uri_args = ngx.req.get_uri_args();
local id = uri_args["id"];
--擷取本地緩存
local cache_ngx = ngx.shared.dis_cache;
--根據ID 擷取本地緩存資料
local contentCache = cache_ngx:get('content_cache_'..id);

if contentCache == "" or contentCache == nil then
    local redis = require("resty.redis");
    local red = redis:new()
    red:set_timeout(2000)
    red:connect("192.168.211.132", 6379)
    local rescontent=red:get("content_"..id);

    if ngx.null == rescontent then
        local cjson = require("cjson");
        local mysql = require("resty.mysql");
        local db = mysql:new();
        db:set_timeout(2000)
        local props = {
            host = "192.168.211.132",
            port = 3306,
            database = "changgou_content",
            user = "root",
            password = "123456"
        }
        local res = db:connect(props);
        local select_sql = "select url,pic from tb_content where status ='1' and category_id="..id.." order by sort_order";
        res = db:query(select_sql);
        local responsejson = cjson.encode(res);
        red:set("content_"..id,responsejson);
        ngx.say(responsejson);
        db:close()
    else
        cache_ngx:set('content_cache_'..id, rescontent, 10*60);
        ngx.say(rescontent)
    end
    red:close()
else
    ngx.say(contentCache)
end
           

3.在nginx.conf中進行調用

在/usr/local/openresty/nginx/conf/nginx.conf中配置如下:

location /read_content {
     content_by_lua_file /root/lua/read_content.lua;
}
           

5. 控制并發量

1. nginx的限流

nginx提供兩種限流的方式:

  • 一是控制速率
  • 二是控制并發連接配接數
(1) 控制速率
  1. nginx的配置示意圖如下
    使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量
    修改/usr/local/openresty/nginx/conf/nginx.conf:
user  root root;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #cache
    lua_shared_dict dis_cache 128m;

    #限流設定
    limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
        }

        location /read_content {
            #使用限流配置
            limit_req zone=contentRateLimit;
            content_by_lua_file /root/lua/read_content.lua;
        }
    }
}
           

配置說明:

binary_remote_addr 是一種key,表示基于 remote_addr(用戶端IP) 來做限流,binary_ 的目的是壓縮記憶體占用量。
zone:定義共享記憶體區來存儲通路資訊, contentRateLimit:10m 表示一個大小為10M,名字為contentRateLimit的記憶體區域。1M能存儲16000 IP位址的通路資訊,10M可以存儲16W IP位址通路資訊。
rate 用于設定最大通路速率,rate=10r/s 表示每秒最多處理10個請求。Nginx 實際上以毫秒為粒度來跟蹤請求資訊,是以 10r/s 實際上是限制:每100毫秒處理一個請求。這意味着,自上一個請求處理完後,若後續100毫秒内又有請求到達,将拒絕處理該請求.我們這裡設定成2 友善測試。
           

處理突發流量

上面例子限制 2r/s,如果有時正常流量突然增大,超出的請求将被拒絕,無法處理突發流量,可以結合 burst 參數使用來解決該問題。

例如,如下配置表示:

使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量

上圖代碼如下:

server {
    listen       80;
    server_name  localhost;
    location /update_content {
        content_by_lua_file /root/lua/update_content.lua;
    }
    location /read_content {
        limit_req zone=contentRateLimit burst=4;
        content_by_lua_file /root/lua/read_content.lua;
    }
}
           

burst 譯為突發、爆發,表示在超過設定的處理速率後能額外處理的請求數,當 rate=10r/s 時,将1s拆成10份,即每100ms可處理1個請求。

此處,burst=4 ,若同時有4個請求到達,Nginx 會處理第一個請求,剩餘3個請求将放入隊列,然後每隔500ms從隊列中擷取一個請求進行處理。若請求數大于4,将拒絕處理多餘的請求,直接傳回503.

不過,單獨使用 burst 參數并不實用。假設 burst=50 ,rate依然為10r/s,排隊中的50個請求雖然每100ms會處理一個,但第50個請求卻需要等待 50 * 100ms即 5s,這麼長的處理時間自然難以接受。

是以,burst 往往結合 nodelay 一起使用。

例如:如下配置:

server {
    listen       80;
    server_name  localhost;
    location /update_content {
        content_by_lua_file /root/lua/update_content.lua;
    }
    location /read_content {
        limit_req zone=contentRateLimit burst=4 nodelay;
        content_by_lua_file /root/lua/read_content.lua;
    }
}
           

如上表示:

平均每秒允許不超過2個請求,突發不超過4個請求,并且處理突發4個請求的時候,沒有延遲,等到完成之後,按照正常的速率處理。

如上兩種配置結合就達到了速率穩定,但突然流量也能正常處理的效果。完整配置代碼如下:

user  root root;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #cache
    lua_shared_dict dis_cache 128m;

    #限流設定
    limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
        }

        location /read_content {
            limit_req zone=contentRateLimit burst=4 nodelay;
            content_by_lua_file /root/lua/read_content.lua;
        }
    }
}
           
(2) 控制并發量

ngx_http_limit_conn_module 提供了限制連接配接數的能力。主要是利用limit_conn_zone和limit_conn兩個指令。

利用連接配接數限制 某一個使用者的ip連接配接的數量來控制流量。

注意:并非所有連接配接都被計算在内 隻有當伺服器正在處理請求并且已經讀取了整個請求頭時,才會計算有效連接配接。此處忽略測試。

配置文法:

Syntax:	limit_conn zone number;
Default: —;
Context: http, server, location;
           

(1)配置限制固定連接配接數

如下,配置如下:

使用OpenResty進行限流的基本配置1.安裝OpenResty2.安裝nginx3.測試通路4.廣告的載入和讀取5. 控制并發量

上圖配置如下:

http {
    include       mime.types;
    default_type  application/octet-stream;

    #cache
    lua_shared_dict dis_cache 128m;

    #限流設定
    limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;

    #根據IP位址來限制,存儲記憶體大小10M
    limit_conn_zone $binary_remote_addr zone=addr:1m;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;
        #所有以brand開始的請求,通路本地changgou-service-goods微服務
        location /brand {
            limit_conn addr 2;
            proxy_pass http://192.168.211.1:18081;
        }

        location /update_content {
            content_by_lua_file /root/lua/update_content.lua;
        }

        location /read_content {
            limit_req zone=contentRateLimit burst=4 nodelay;
            content_by_lua_file /root/lua/read_content.lua;
        }
    }
}
           

表示:

limit_conn_zone $binary_remote_addr zone=addr:10m;  表示限制根據使用者的IP位址來顯示,設定存儲位址為的記憶體大小10M

limit_conn addr 2;   表示 同一個位址隻允許連接配接2次。
           

限制每個用戶端IP與伺服器的連接配接數,同時限制與虛拟伺服器的連接配接總數。

如下配置:

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m; 
server {  
    listen       80;
    server_name  localhost;
    charset utf-8;
    location / {
        limit_conn perip 10;#單個用戶端ip與伺服器的連接配接數.
        limit_conn perserver 100; #限制與伺服器的總連接配接數
        root   html;
        index  index.html index.htm;
    }
}