message push gateway based on nginx+lua+redis

    #nginx #lua #redis

    Abstract

    A gateway is needed for client to push message into redis, the article describe the steps to build the gateway based on nginx+lua+redis.

    Message are dispatched by channel and pushed into different redis lists, and at the mean while, a event message will be pushed into the event list, so that the server know which channel comes new messages.

    1. lua-nginx-module

    ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers.

    1.1 installation

    see detail

    1.1.1 Method1: install modules one by one

    1) install luaJIT

    Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is not supported yet).

    Some distribution package managers also distribute LuaJIT and/or Lua.

     #curl -O http://luajit.org/download/LuaJIT-2.0.4.tar.gz
     curl -O http://luajit.org/download/LuaJIT-2.1.0-beta2.tar.gz
     tar -xzvf LuaJIT-2.1.0-beta2.tar.gz
     cd LuaJIT-2.1.0-beta2
     make
     sudo make install
     
     
     # tell nginx's build system where to find LuaJIT 2.1:
     export LUAJIT_LIB=/usr/local/lib
     export LUAJIT_INC=/usr/local/include/luajit-2.1
    

    2) download ngx_devel_kit

    Download the latest version of the ngx_devel_kit (NDK) module:

    curl -o ngx_devel_kit_v0.3.0.tar.gz https://codeload.github.com/simpl/ngx_devel_kit/tar.gz/v0.3.0
    tar -xzvf ngx_devel_kit_0.3.0.tar.gz
    
    

    3) download lua-nginx-module

    Download the latest version of ngx_lua:

    curl -o lua-nginx-module.v0.10.8.tar.gz https://codeload.github.com/openresty/lua-nginx-module/tar.gz/v0.10.8
    tar -xzvf lua-nginx-module.v0.10.8.tar.gz
    

    4) install pcre:

    nginx rewrite needs pcre:

    curl -O https://ftp.pcre.org/pub/pcre/pcre-8.40.tar.gz
    tar -xzvf pcre-8.40.tar.gz
    ./configure
    make
    sudo make install
    

    5) install nginx

    Download the latest version of Nginx:

     curl -O http://nginx.org/download/nginx-1.11.13.tar.gz
     tar -xzvf nginx-1.11.13.tar.gz
     
     curl -O http://nginx.org/download/nginx-1.11.2.tar.gz
     tar -xzvf nginx-1.11.2.tar.gz
     cd nginx-1.11.2
    
     ./configure --prefix=/opt/nginx \
             --with-ld-opt="-Wl,-rpath,/usr/local/lib" \
             --add-module=/Users/gelnyang/temp/ngx_devel_kit-0.3.0 \
             --add-module=/Users/gelnyang/temp/lua-nginx-module-0.10.8
    
     make -j2
     sudo make install
    
    

    1.1.2 Method2: just install openresty release

    # http://openresty.org/en/installation.html
    
    tar -xvf openresty-VERSION.tar.gz
    cd openresty-VERSION/
    ./configure -j2
    make -j2
    sudo make install
    
    # better also add the following line to your ~/.bashrc or ~/.bash_profile file.
    export PATH=/usr/local/openresty/bin:$PATH
    
    

    2. lua-resty-redis

    Lua redis client driver for the ngx_lua based on the cosocket API

    curl -o lua-resty-redis.zip https://codeload.github.com/openresty/lua-resty-redis/zip/master
    sudo unzip lua-resty-redis.zip -d /opt
    

    3. nginx config

    3.1 message_gateway_push.lua

    put the file message_gateway_push.lua in /opt/nginx/lua:

    local redis = require "resty.redis"
    
    local function error(self, message, err)
        if err then
            ngx.print("F|", message, error)
        else
            ngx.print("F|", message)
        end
    end
    
    local function success(self, timestamp, sid)
        ngx.print("S|", timestamp, "|", sid)
    end
    
    local channel = ngx.var.arg_c
    
    if not channel then
        error(self, "no param c")
        return
    end
    
    ngx.req.read_body()
    local data = ngx.req.get_body_data()
    
    local red = redis:new()
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok then
        error(self, "failed to connect: ", err)
        return
    end
    
    red:set_timeout(1000)
    
    
    ok, err = red:multi()
    if not ok then
        if string.find(err, "AUTH", 1, true) then
            ok, err = red:auth("MYPASSWORD")
            if not ok then
                error(self, "failed to auth: ", err)
                return
            end
            ok, err = red:multi()
            if not ok then
                error(self, "failed to multi: ", err)
                return
            end
        else
            error(self, "failed to multi: ", err)
            return  
        end
    end
    
    local timestamp = (ngx.now() * 1000)
    local sid = ngx.var.request_id
    red:lpush(channel,  timestamp.. "|" .. sid .. "|" .. data)
    red:lpush("message_gateway_event", channel)
    
    ok, err = red:exec()
    if not ok then
        error(self, "failed to exec: ", err)
        return
    end
    
    -- put it into the connection pool of size 500,
    -- with 10 seconds max idle time
    ok, err = red:set_keepalive(10000, 500)
    if not ok then
        red:close()
    end
    
    success(self, timestamp, sid)
    
    

    3.2 nginx.conf

    worker_processes  1;
    
    events {
        worker_connections  1024;
    }
    
    http {
        lua_package_path "/opt/nginx/lua/?.lua;/opt/lua-resty-redis-master/lib/?.lua;;";
    
        server {
            listen 80;
    
        	location /push {
                default_type text/plain;
                content_by_lua_file lua/message_gateway_push.lua;
        	}
        }
    
    }
    

    27 Apr 2017,gelnyang