使用lua調用mongoDB 實例

引言
公司需要做一個類似站長統計的項目,給了很多種方案;其中有個方案就是利用ngx_lua(openResty) 調用mongodb 來做日誌的存儲;在項目之前啓動之前,自己研究了這個方案的可行性,編寫寫了一個demo。


1.準備
(1)看過openresty的都應該知道,openresty只提供redis 的module模塊,沒有提供mongoDB的驅動模塊(不懂openresty;可以看下openresty最佳實現);所以我們這邊要先提供一個驅動,去中文論壇找了一番;發現了幾個不錯的結合lua 的mongodb的libarary項目:
在github上有lua-resty-mongol、還有wuxianglong的lua-mongo等項目;綜合考慮了之後,打算用lua-resty-mongol 這個項目;因爲這個項目本身就是爲了兼容openresty設計的。
(2)這個demo本身是基於openresty中編寫的,所以在你的系統上需要安裝openresty,我這裏用的是centos 6.5 的系統,至於具體的下載 安裝,這裏就不詳細介紹了;如果有需要的話可以看看這篇文章http://www.52yunwei.cn/?p=415
(3) 前面說到過 lua-resty-mongol 項目,我們要下載github下的這個項目;下載後編譯,
make install
把解壓的包 解壓到 lualib/resty/中下
如果你的openresty默認安裝的話是在/usr/local/openresty/lialib 下,我這邊的路徑是在 opt/openresty/lualib/resty 下;
(4)就是對應的mongodb 服務,我這裏的mongodb 服務是在自己的虛擬機中,如果沒有的話,先去官網下載一個mongodb,然後啓動
這裏就不詳細介紹了


2.實例
(1).之前lua-resty-mongol 項目還要有一個配置項,就是要在nginx.conf 中配置上 你mongol 的默認初始化路徑

# 之前說過了,你要是是默認的openresty的話  這裏就可以配置是/usr/local/openresty/lialib/?/了#
 lua_package_path        '/opt/opentresty/lualib/?/init.lua;;';

(2). 對於ngx中的整個nginx.conf 配置如下

user  nginx;
worker_processes  4;
pid                             /opt/logs/nginx/nginx.pid;
error_log               /opt/logs/nginx/error.log;

events {
    use epoll;
    worker_connections  10240;
}
http {
        include       mime.types;
        #default_type           'text/html';
        #定義日誌格式
        #default_type           'application/octet-stream';
        #指定lua_mongol 初始化默認路徑
        default_type            'text/plain';
        lua_package_path        '/opt/opentresty/lualib/?/init.lua;;';
        charset                         utf-8;
        error_log               /opt/logs/nginx/error.log;

        access_log              off;
        #log_format  main  '$remote_addr\t$uid_got$uid_set\t$http_host\t$time_iso8601\t$request\t$status\t$body_bytes_sent\t$http_referer\t$request_time\t$http_user_agent';
        #log_format  tick '$msec^A$remote_addr^A$u_domain^A$u_url^A$u_title^A$u_referrer^A$u_sh^A$u_sw^A$u_cd^A$u_lang^A$http_user_agent^A$u_utrace^A$u_account';
        log_format tick '$msec ^A^ $remote_addr ^A^ $u_domain ^A^ $u_url ^A^ $u_title ^A^ $u_referrer ^A^ $u_sh ^A^ $u_sw ^A^ $u_cd ^A^ $u_lang ^A^ $http_user_agent ^A^ $u_utrace ^A^ $u_account';

        client_max_body_size 100m;
        sendfile        on;
        keepalive_timeout  60;
        fastcgi_intercept_errors on;
        proxy_connect_timeout 60;
        proxy_send_timeout 90;
        proxy_read_timeout 1800;
        large_client_header_buffers 4 128k;
        proxy_ignore_client_abort on;


        gzip on;
        gzip_min_length 10k;
        gzip_buffers 4 16k;
        gzip_comp_level 2;
        gzip_types text/plain text/javascript application/javascript application/x-javascript text/css  application/xml application/octet-stream;
        gzip_vary on;
        #userid
        userid                          on;
        userid_name                     UUID;
        userid_path                     /;
        userid_expires                  max;

        include _ext.conf;
        include apps/*.conf;
  }

(3).配置需要的location
從上面是nginx.conf 中可以看出,我這裏的server都是在apps子文件夾創建,我在apps 文件中有個叫
_mongo.conf 的配置文件,裏面配置這lua 調用mongodb 的location

server {
        listen   8081;
        server_name 192.168.1.128;
        #關閉lua_code 緩存
        lua_code_cache off;
        location /lua {
                content_by_lua_file  /opt/openresty/lualib/resty/mongol/test_lua.lua;
        }
        location /lua_mongo {
                content_by_lua_file /opt/openresty/lualib/resty/mongol/test_mongol.lua;
        }
        location /lua_test {
                set $test "hello world";
                #使用acess 階段做准入條件處理
                access_by_lua '
                        if (ngx.var.test =="hello world") then 
                                ngx.say("驗證通過"..ngx.var.test)
                        else 
                                ngx.log(ngx.ERR,"驗證失敗","")
                        end
                ';
                #業務處理
                content_by_lua '
                        ngx.header.content_type ="text/plain";
                        local a, b =1;
                        ngx.say(ngx.var.test..a);
                ';
        }


}

location lua_mongo 中content_by_lua_file 是lua調用了mongodb具體操作
執行在/opt/openresty/lualib/resty/mongol/下的test_mongol.lua 文件,該文件的內容是:

local mongo =require "resty.mongol"
local json = require "cjson"
--獲取連接對象
local conn =mongo:new()
conn:set_timeout(1000)
--獲取連接客戶端
local ok,err =conn:connect("192.168.1.128",27017)

if not ok then 
        ngx.say("connect failed"..err)
end 
--獲取數據庫
local db = conn:new_db_handle("leo")
--用戶授權
local ok ,err = db:auth("zjf","zjf123456")

if ok then 
        ngx.say("user auth success"..ok)
end 
--獲取集合
local coll = db:get_col("leonardo")
--獲取document集合
local cursor = coll:find({})

--json 轉碼
--
function json_decode( str )
        local json_value =nil
        pcall(function (str) json_value = json.decode(str) end, str)
        return json_value 
end

--循環 
for index,item in cursor:pairs() do
        ngx.say('數據: '..index)
        if not item['url'] then 
                ngx.say('數據:'..item["title"])
        else
                ngx.say('數據:'..item["title"]..item['url'])
                ngx.say(json_decode(item['url']))
        end

end
--獲取單個集合
local res =coll:find_one({key = 150})

if res then 

        ngx.say(res['title'])
end

--插入集合
local bson1 ={title ='哈哈',url = 'www.baidu.com',key = 300};
--插入table 表中 
local docs ={bson1};

local rsOk,err =coll:insert(docs,0,0)

if err then 
        ngx.say('error--'..err)
else 
        ngx.say('ok---- '..rsOk)
end

--刪除操作
local deOk,err = coll:delete({title ='你好'},0,0)

if err then 
        ngx.say('delete error--'..err)
else
        ngx.say('delete ok--'..deOk)
end

--關閉連接
if conn then 

        conn:close()
end 

到這裏一個完整的例子就寫好了 。
(4).啓動mongodb 服務,啓動nginx 服務

[root@leoleo apps]# curl 192.168.1.128:8081/lua_mongo
數據: 1
數據:哈哈www.baidu.com
nil
數據: 2
數據:哈哈www.baidu.com
nil
數據: 3
數據:哈哈www.baidu.com
nil
ok---- -1
delete ok---1
[root@leoleo apps]# 

這個demo 就這樣寫好了


3.後話**
使用lua_nginx+mongodb這個方案最後被我們項目組否決了,原因呢?
雖然用lua 可以實現將網頁上收集到用戶操作行爲通過的nginx寫入mongodb中;但是lua 直接操作mongodb 有很多缺陷,比如這裏是當實例,就是每次寫入都要獲取一個連接實例,開啓一個連接;網頁上的行爲收集是一個高併發的,顯然這個demo 這樣的是不滿足的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章