天天看點

第4章 lua、Canal實作廣告緩存

1.Lua

1.1 在linux安裝lua

1.1.1 先安裝lua相關依賴庫的支援

yum install libtermcap-devel ncurses-devel libevent-devel readline-devel

1.1.2 再安裝

curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
tar zxf lua-5.3.5.tar.gz
cd lua-5.3.5
make linux test
           

1.2 文法

1.2.1 互動式程式設計 Lua 互動式程式設計模式可以通過指令 lua -i 或 lua 來啟用,然後輸入指令直接輸出結果 print(“hello”);

1.2.2 腳本式程式設計

編輯檔案hello.lua vi hello.lua

在檔案中輸入 print(“hello”); 儲存并退出

執行指令 lua hello.lua 輸出:hello

1.3 變量

– 全局變量指派

a=1

– 局部變量指派

local b=2

1.4子產品

建立一個檔案叫module.lua

-- 檔案名為 module.lua
-- 定義一個名為 module 的子產品
module = {}
 
-- 定義一個常量
module.constant = "這是一個常量"
 
-- 定義一個函數
function module.func1()
    print("這是一個公有函數")
end
 
local function func2()
    print("這是一個私有函數!")
end
 
function module.func3()
    func2()
end
 
return module
           

1.3.1:

require 函數

require 用于 引入其他的子產品,類似于java中的類要引用别的類的效果

1.3.2 引用

建立一個test_module.lua檔案

-- test_module.lua 檔案
-- module 子產品為上文提到到 module.lua
require("module")

print(module.constant)

module.func3()
           

輸出 lua test_module.lua

2.OpenResty介紹

2.1 安裝

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.2 安裝nginx

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

cd /usr/local/openresty/nginx/conf

vi nginx.conf

第4章 lua、Canal實作廣告緩存

查詢資料放入redis中

a.連接配接mysql ,按照廣告分類ID讀取廣告清單,轉換為json字元串。

b.連接配接redis,将廣告清單json字元串存入redis 。

步驟

1.

移到 /root/lua目錄,在該目錄下建立update_content.lua: 目的就是連接配接mysql 查詢資料 并存儲到redis中。

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

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

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

第4章 lua、Canal實作廣告緩存
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
           

測試位址:

http://192.168.211.132/update_content?id=1

此時會将分類ID=1的所有廣告查詢出來,并存入到Redis緩存。

第4章 lua、Canal實作廣告緩存

測試位址:

http://192.168.211.132/read_content?id=1

此時會擷取分類ID=1的所有廣告資訊。

第4章 lua、Canal實作廣告緩存

nginx的限流

nginx提供兩種限流的方式:

  • 一是控制速率
  • 二是控制并發連接配接數

1 控制速率

控制速率的方式之一就是采用漏桶算法。

(1)漏桶算法實作控制速率限流

漏桶(Leaky Bucket)算法思路很簡單,水(請求)先進入到漏桶裡,漏桶以一定的速度出水(接口有響應速率),當水流入速度過大會直接溢出(通路頻率超過接口響應速率),然後就拒絕請求,可以看出漏桶算法能強行限制資料的傳輸速率.示意圖如下:

第4章 lua、Canal實作廣告緩存

(2)nginx的配置

修改/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 友善測試。

測試:

重新加載配置檔案

cd /usr/local/openresty/nginx/sbin

./nginx -s reload

(3)處理突發流量

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

burst 往往結合 nodelay 一起使用

完整代碼如下

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個請求,突發不超過4個請求,并且處理突發4個請求的時候,沒有延遲,等到完成之後,按照正常的速率處理。

控制并發量(連接配接數)

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次。

canal同步

canal可以用來監控資料庫資料的變化,進而獲得新增資料,或者修改的資料

Canal工作原理

第4章 lua、Canal實作廣告緩存

原理相對比較簡單:

  1. canal模拟mysql slave的互動協定,僞裝自己為mysql slave,向mysql master發送dump協定
  2. mysql master收到dump請求,開始推送binary log給slave(也就是canal)
  3. canal解析binary log對象(原始為byte流)

繼續閱讀