用openresty做后台服务器,openresty后台


与OpenResty及其原作者邂逅

      OpenResty是一个优秀的开源项目,作者是章亦春。官网是http://openresty.org/en/。这已经是我第二次在公司项目中使用它展开业务了。分享使用经历的时候,顺便帮春哥推广一下:

       其实,我想说的是春哥真的像知乎上传的一样,热情,专业。同时也希望大家都到邮件列表里问问题,像我一样莽莽撞撞直接私发邮件,确实显得不大矜持,汗!

我们后台选用的第三方库和文件

       我们后台采用: openresty框架+lua脚本+c函数+mongoDB数据库.这其中的技术细节我们都论证过,现把他们都链接粘出来。

架构思想和坑

       想成为高手,得首先学会跟高手一样思考问题,我觉得这也是每一个有志向的程序员练级所必须经历的。下面是我跟架构师的工作交流时,从正面和侧面所总结的,即为什么要采用:openresty框架+lua脚本+c函数+mongoDB数据库作为后台的原因。

  • 对于openresty,我的理解是openresty = web服务器nginx + lua虚拟机。它的好处官网都有,如”能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关
  • 。对于我们的项目,架构师看中的似乎是openresty对nginx的lua扩展,因为接下来我们会调用第三方提供的dll文件,即lua调C。在操作数据库方面,openresty提供的很多精良的数据库驱动,如memcached、mysql、redis。虽然官方没有提供mongodb,但bigplum大神已经做到了,见上方链接。经过测试,bigplum大神提供的测试文件可用,对文档的数据库、集合和文档的增删改查均可用,点个赞。
  • openresty官方已经实现了redis的驱动,我们为什么选用mongodb而不是redis?架构师是这么回答我的,1、redis太重了,mongodb稍微轻一点点,而且我们的项目是在win上部署的对内存有一些要求,架构师希望它在普通的pc上也能运行;2、项目要求数据库同步,也就是a/b/c/d/四台机器数据保持数据的一致性。在这一点上,我们采取的是mongodb的副本集。

讨论太廉价了,直接上代码吧


nginx.conf文件

worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    lua_package_path '/c/Users/wuxian/Desktop/BlackHole/openresty-1.9.15.1-win32/lualib/resty/mongol/init.lua;;';


    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            #解决跨域问题
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Headers' 'Content-Type';
                return 204;
            }   
            if ($request_method = 'POST') {
                add_header 'Access-Control-Allow-Origin' '*';
            }   

            #处理业务的文件
            default_type text/html;
            content_by_lua_file './lua_script/app.lua'; 
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

app.lua文件
local mongo = require "resty.mongol"
local cjson = require "cjson.safe"

-----------------------------------------------------------------------------
--lua call c module
square = package.loadlib("./ADD.dll", "isquare")
alert  = package.loadlib("./ADD.dll", "alert")
add    = package.loadlib("./ADD.dll", "l_add")
sub    = package.loadlib("./ADD.dll", "l_sub")

-----------------------------------------------------------------------------
--Connect mongodb database
conn = mongo:new()

ok, err = conn:set_timeout(5000) 
ok, err = conn:connect("127.0.0.1", 27017)
if not ok then
    ngx.say("connect failed: "..err)
end

local db = conn:new_db_handle("tamigroup")
if not db then
    ngx.say(db)
end

local col = db:get_col("number")

-----------------------------------------------------------------------------
-- Process request data
local function post_request(data)
    local result = {}
    local request = cjson.decode(data)
    if not request or not request["cmd"] then
        result["result"] = "failed"
        result["reason"] = "no 'cmd' field or not a json struct"
        return result
    end

    local sql_str = ""

    --测试
    if request["cmd"] == "demo" then
        local result = {}
        result["result"] = "ok"
        result["reason"] = "This is a test cmd"
        return result
    end

    --插入人员
    if request["cmd"] == "add" then
        local result = {}

        local t = {}
        table.insert(t, {name=request["name"], id=request["id"]})
        r, err = col:insert(t, nil, true)
        if not r then 
            result["result"] = "insert failed: "..err
        else
            result["result"] = "ok"
        end
        return result
    end

    --删除人员
    if request["cmd"] == "delete" then
        local result = {}

        r, err = col:delete({name=request["name"]}, nil, true)
        if not r then 
            request["result"] = "delete failed: "..err
        else
            result["request"] = "ok" 
        end
        return result
    end

    --修改人员
    if request["cmd"] == "update" then
        local result = {}

        r,err = col:update({name=request["old"]},{name=request["new"]}, nil, nil, true)
        if not r then 
            request[result] = "update failed: "..err
        else
            request[result] = "ok"
        end
        return result
    end

    --查询人员
    if request["cmd"] == "find" then
        local result = {}

        r = col:find({name=result["name"]})
        r:limit(1)
        for i , v in r:pairs() do
            result["data"] = v["name"];
        end

        if not result["data"] then
            result["result"] = "He or she don't exist"
        else
            result["result"] = "ok"
        end
        return result
    end

    --调用c模块
    if request["cmd"] == "lua_call_c" then
        local result = {}
        result["data"] = square(12)
        result["add"] = add(100, 50)
        result["result"] = "ok"
        return result
    end

end

-----------------------------------------------------------------------------
-- Parse request body
ngx.req.read_body()
local method = ngx.var.request_method
if method ~= "POST" then
    local result = {}
    result["result"] = "failed"
    result["reason"] = "use POST method"
    ngx.say(cjson.encode(result))
else
    local data = ngx.req.get_body_data()
    ngx.say(cjson.encode(post_request(data)))
end

后记

      整个项目的大致思路就是这酱紫的。在这里面,我们曾调研lua在win下怎样调用c;openresty怎样驱动mongodb;mongodb搭建集群数据怎么保持一致…….也傻乎乎的给春哥和云风写过邮件等等。最终前期调研终于顺利完成,累。

相关内容

    暂无相关文章