openresty 结合 lua 实现动态CDN

项目目的

项目目的, 鉴别是国内还是国外用户,走不同的CDN

file

ps

  • openresty只支持luajit 而且对lua的支持版本也只是在5.1

方案一

用go给lua写扩展..

代码实现

  • 用golang写出业务逻辑
  • 编译.so静态文件
  • 在openrestry中luajit调用静态文件,并判断是否是国内用户,同时修改headers中 cdn_domain 值

用golang写出业务逻辑

package main

import (
    "C"
    "github.com/lionsoul2014/ip2region/binding/golang/ip2region"
)

//export IpSearch
func IpSearch(ip string) (ok int) {
    var (
        err    error
        region *ip2region.Ip2Region
        info   ip2region.IpInfo
    )
    region, err = ip2region.New("/home/ailuoy/goproject/src/ext-ipsearch/ip2region.db")
    defer region.Close()
    if err != nil {
        return
    }
    info, err = region.BtreeSearch(ip)
    if info.CityId == 215 {
        ok = 1
    }
    return
}

func main() {}

编译.so静态文件

go build -buildmode=c-shared -o lequ_ipsearch.so main.go

openrestry调用

location /go-ipsearch2 {
        content_by_lua_block {
                local ffi = require('ffi')
                local client = ffi.load("/home/ailuoy/goproject/src/ext-ipsearch/lequ_ipsearch.so")

                ffi.cdef [[
                        typedef long long GoInt64;
                        typedef GoInt64 GoInt;
                        typedef struct { const char *p; GoInt n; } GoString;
                        extern GoInt IpSearch(GoString ip);
                ]]

                local ip = ffi.new("GoString")
                local s = "114.243.220.159"
                ip.p = s
                ip.n = #s
                local result = client.IpSearch(ip)
                ......
       }
    }

遇到的问题

ab压测过大导致table overflow,或者是处理了一定数量的请求之后

查阅资料说是ffi.cdef频繁调用,建议做成lua模块,只调用一次

    [C]: in function 'cdef'
    content_by_lua(lua-test.conf:45):10: in function <content_by_lua(lua-test.conf:45):1>, client: 127.0.0.1, server: , request: "GET /go-ipsearch2 HTTP/1.0", host: "127.0.0.1:9091"
2019/01/18 02:04:10 [error] 11095#11095: *2281332 lua entry thread aborted: runtime error: table overflow
stack traceback:
coroutine 0:
sudo apt-get install luajit
sudo apt-get install lua5.3

方案二

直接使用开源项目的lua_c, 用方案一会出现问题,所以现在用方案二

安装lua环境

sudo yum install lua-devel gcc

克隆 ip2region

  • ip2region.db ip池数据库文件
  • /usr/local/share/lua/5.1/Ip2region.so 编译的 c so文件
cd /tmp

# 克隆git项目
git clone https://github.com/lionsoul2014/ip2region.git
cd ip2region/binding/lua_c
# 修改lua版本
vim Makefile
VER = 5.1
# 编译 & 安装
make
sudo make install
# 复制ip数据库文件
mv /tmp/ip2region/data/ip2region.db /home/server/

openrestry设置

  • /usr/local/ip2region/data/ip2region.db 是克隆ip2region项目的db文件
lua_package_cpath "/usr/local/share/lua/5.1/?.so;;";

init_by_lua_block {
    local Ip2region = require "Ip2region";
    ip2region = Ip2region.new("/usr/local/ip2region/data/ip2region.db");
}

server {
        listen  8080;

        error_log /var/log/nginx/ipsearch/error.log notice;
        error_log /var/log/nginx/ipsearch/error.log info;
        access_log  /var/log/nginx/ipsearch/access.log  main;

        location / {
            access_by_lua_block {
                local ip = ngx.var.remote_addr
                data = ip2region:memorySearch(ip);
                ngx.req.set_header('region',data.region)
            }
            proxy_pass  http://127.0.0.1:80;
        }
}

产考文章