Skip to content

Commit

Permalink
Merge pull request #21 from horan-geeker/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
horan-geeker authored Mar 29, 2020
2 parents 59014dd + 43d8baa commit 48e363e
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 150 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ env.lua
.vscode
storage/*
.env
.DS_Store
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,22 @@ curl https://api.lua-china.com/index?id=1&foo=bar

## 压力测试

### 阿里云单核4G内存
### 单 worker 绑定一个 CPU:

```shell
ab -c 100 -n 10000 api.lua-china.com/index
wrk -t10 -c 100 -d10s http://localhost:60000/

---
Requests per second: 4621.10 [#/sec] (mean)
Time per request: 21.640 [ms] (mean)
---
Running 10s test @ http://localhost:60000/
10 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.87ms 4.42ms 170.11ms 97.75%
Req/Sec 2.84k 308.14 5.77k 85.09%
282184 requests in 10.04s, 63.50MB read
Requests/sec: 28105.03
Transfer/sec: 6.32MB
```

> 内存基本没有变化,单核 CPU 打满
> 内存基本没有变化, CPU 打满
## 安装

Expand All @@ -119,6 +123,8 @@ Time per request: 21.640 [ms] (mean)
route:post('/login', 'auth_controller', 'login')
```

> 框架内核使用 `trie` 字典树实现路由结构,算法复杂度 O(1),可以高效的匹配定义路由
#### 支持 http 请求类型

* GET
Expand Down Expand Up @@ -154,11 +160,11 @@ end

#### 路由群组

路由群组目前主要的作用是使用中间件来解决一些问题,比如下边需要在 `注销``重置密码` 的时候验证用户需要处于登录态,利用路由中间件只需要在路由群组的地方集中配置中间件就会对群组下的所有路由起作用,这样在调用 `controller` 之前先调用 `middleware > authenticate.lua``handle()` 方法来对用户进行鉴权:
路由群组主要用来定义一群 uri 的公共属性,目前支持群组中间件,比如下边需要在 `注销``重置密码` 的时候验证用户需要处于登录态,利用路由中间件只需要在中间件进行鉴权,这里会在调用 `controller` 之前先调用 `middleware > authenticate.lua``handle()` 方法来对用户进行鉴权,这样就不用在每个 `controller` 的方法里都进行鉴权操作了

```lua
route:group({
'authenticate',
middleware = {'authenticate'},
}, function()
route:post('/logout', 'auth_controller', 'logout') -- route:http_method(uri, controller, action)
route:post('/reset-password', 'user_controller', 'resetPassword')
Expand All @@ -167,16 +173,14 @@ route:group({

### 中间件

> 中间件都需要写在 `middleware` 文件夹下,并且需要写上命名为 `handle()` 的方法
`中间件` 的设计模式解决了代码的复用,我们可以在中间件中自定义自己的东西,如`middleware > authenticate.lua`
> 中间件都需要写在 `middleware` 文件夹下,并且需要写上命名为 `handle()` 的方法 `中间件` 的设计模式解决了代码的复用,我们可以在中间件中自定义自己的逻辑,如`middleware > authenticate.lua`
```lua
function _M:handle()
if not auth_service:check() then
return false, response:json(4,'no authorized in authenticate')
end
end

```

当返回 false 的时候会直接返回第二个 `response` 参数,从而不再执行 `controller` 的内容,当返回 true 的时候继续执行,你可以把你自定义的中间件写到 `middleware` 的文件夹下, 该文件夹下已有了一个示例中间件 `example_middleware.lua`
Expand Down Expand Up @@ -259,8 +263,8 @@ local ok,msg = validator:check(args, {
`lib/helpers.lua` 中包含了 `cookie` 的辅助方法

```lua
set_cookie(key, value, expire) -- expire 是可选参数,单位是时间戳,精确到秒
get_cookie(key)
helpers.set_cookie(key, value, expire) -- expire 是可选参数,单位是时间戳,精确到秒
helpers.get_cookie(key)
```

### 数据库操作 ORM
Expand Down
20 changes: 12 additions & 8 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,19 @@ curl https://api.lua-china.com/index?id=1&foo=bar

## Benchmark

### ab test
### wrk test one worker in nginx

```shell
ab -c 100 -n 10000 api.lua-china.com/index

---
Requests per second: 4621.10 [#/sec] (mean)
Time per request: 21.640 [ms] (mean)
---
wrk -t10 -c 100 -d10s http://localhost:60000/

Running 10s test @ http://localhost:60000/
10 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.87ms 4.42ms 170.11ms 97.75%
Req/Sec 2.84k 308.14 5.77k 85.09%
282184 requests in 10.04s, 63.50MB read
Requests/sec: 28105.03
Transfer/sec: 6.32MB
```

## Install
Expand Down Expand Up @@ -151,7 +155,7 @@ Route groups allow you to share route attributes, such as middleware, across a l

```lua
route:group({
'authenticate',
middleware = 'authenticate',
}, function()
route:post('/logout', 'auth_controller', 'logout') -- http_method/uri/controller/action
route:post('/reset-password', 'user_controller', 'resetPassword')
Expand Down
5 changes: 2 additions & 3 deletions config/app.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
local helpers = require("lib.helpers")
local env = helpers.env
local env = require('env')

return {
env = env('APP_ENV', 'production'),
env = env.APP_ENV,

locale = 'en',
fallback_locale = 'zh',
Expand Down
26 changes: 15 additions & 11 deletions config/database.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
local helpers = require("lib.helpers")
local env = helpers.env
local env = require('env')

return {
redis_prefix = 'NANA:',
mysql = {
db_name = env("mysql.db_name", "nana"),
db_name = env.MYSQL.DB_NAME,
write = { -- mysql write database
host=env("mysql.write.host", "127.0.0.1"),
port=env("mysql.write.port", 3306),
user=env("mysql.write.user", "root"),
password=env("mysql.write.password", "root"),
host = env.MYSQL.WRITE.HOST,
port = env.MYSQL.WRITE.PORT,
user = env.MYSQL.WRITE.USER,
password = env.MYSQL.WRITE.PASSWORD,
},
read = { -- mysql read database
host=env("mysql.read.host", "127.0.0.1"),
port=env("mysql.read.port", 3307),
user=env("mysql.read.user", "root"),
password=env("mysql.read.password", "root"),
host = env.MYSQL.READ.HOST,
port = env.MYSQL.READ.PORT,
user = env.MYSQL.READ.USER,
password = env.MYSQL.READ.PASSWORD,
},
charset = 'utf8',
pool_timeout = 1000, -- mysql pool timeout
pool_size = 10000, -- mysql pool size
timeout = 1000, -- mysql timeout
},
redis = {
host = env.REDIS.HOST,
port = env.REDIS.PORT,
password = env.REDIS.PASSWORD
},
}
2 changes: 1 addition & 1 deletion controllers/index_controller.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local _M = {}
-- todo controller extends

function _M:index(request)
return response:json(0, 'request args', request.params)
return response:json(0, 'index args', request.params)
end

return _M
25 changes: 18 additions & 7 deletions env.example.lua
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
return {
APP_ENV = "dev", -- dev/prod

mysql = {
db_name = "nana",
write = {host="127.0.0.1", port=3306, user="root", password="root"},
read = {host="127.0.0.1", port=3306, user="root", password="root"},
MYSQL = { -- mysql read/write config
DB_NAME = "",
WRITE = { -- mysql write config
HOST = "127.0.0.1",
PORT = 3306,
USER = "",
PASSWORD = ""
},
READ = { -- mysql read config(if only one host the same as write)
HOST = "127.0.0.1",
PORT = 3306,
USER = "",
PASSWORD = ""
},
},

redis = {
host = "127.0.0.1", -- redis host
port = 6379, -- redis port
REDIS = {
HOST = "127.0.0.1", -- redis host
PORT = 6379, -- redis port
PASSWORD = nil -- redis password
}
}
30 changes: 21 additions & 9 deletions lib/application.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
local request = require('lib.request')
local http_request = require('lib.request')
local http_response = require('lib.response')
local router = require('routes')
local database = require('lib.database')
local ngx = ngx

local _M = {}


-- process middlewares in order
local function run_middlewares(middlewares)
if type(middlewares) ~= 'table' then
return false, http_response:error(500, {}, 'system error: middleware is not a table, please read readme about middleware usage')
end
for _, middleware in ipairs(middlewares) do
local result, err_response = middleware:handle()
if result == false then
Expand All @@ -27,17 +29,24 @@ local function handle(request, context, route_param)
-- run controller action
local controller = context.required_controller
local action = context.action
local response
if #route_param ~= 0 then
return controller[action](nil, table.unpack(route_param), request)
table.insert(route_param, request)
response = controller[action](nil, table.unpack(route_param))
else
response = controller[action](nil, request)
end
if type(response) ~= 'table' then
return http_response:error(500, {}, 'system error: controller return response is not a table, please read readme about controller usage')
end
return controller[action](nil, request)
return response
end


-- run application kernel
function _M:run()
local function run()
-- get http request infomation
local request_capture = request:capture()
local request_capture = http_request:capture()
-- match route, get target controller and action
local context, route_param, err_response = router:match(request_capture.uri, request_capture.method)
if err_response ~= nil then
Expand All @@ -48,10 +57,13 @@ function _M:run()
end


function _M:terminate()
local function terminate()
database:close()
ngx.exit(ngx.OK)
end


return _M
return {
run = run,
terminate = terminate,
}
6 changes: 0 additions & 6 deletions lib/database.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ local mt = { __index = _M }
--]]
function _M:get_connection()
if ngx.ctx[self.db_type] then
-- ngx.log(ngx.WARN, self.db_type, ' mysql reconnect')
-- if write before read, make sure write read connection the same
if ngx.ctx[WRITE] then
return ngx.ctx[WRITE], nil
end
return ngx.ctx[self.db_type], nil
end
-- ngx.log(ngx.WARN, 'new mysql connection!')
local db, err = mysql_c:new()
if not db then
ngx.log(ngx.ERR, "failed to instantiate mysql: ", err)
Expand All @@ -43,7 +41,6 @@ function _M:get_connection()
ngx.log(ngx.ERR, "failed to connect: ", err, ": ", errcode, " ", sqlstate)
return nil, err
end
-- ngx.log(ngx.WARN, self.db_type, ' mysql connect')
ngx.ctx[self.db_type] = db
return db, nil
end
Expand All @@ -58,12 +55,10 @@ function _M.close(self)
if ngx.ctx[READ] then
ngx.ctx[READ]:set_keepalive(self.db_pool_timeout,self.db_pool_size)
ngx.ctx[READ] = nil
-- ngx.log(ngx.WARN,'read mysql close')
end
if ngx.ctx[WRITE] then
ngx.ctx[WRITE]:set_keepalive(self.db_pool_timeout,self.db_pool_size)
ngx.ctx[WRITE] = nil
-- ngx.log(ngx.WARN,'write mysql close')
end
end

Expand All @@ -74,7 +69,6 @@ end
@return bool, data, err
--]]
function _M.mysql_query(self, sql)
-- ngx.log(ngx.WARN, self.db_type, sql)
local db, err = self:get_connection()
if err ~= nil then
return nil, err
Expand Down
34 changes: 5 additions & 29 deletions lib/helpers.lua
Original file line number Diff line number Diff line change
@@ -1,30 +1,8 @@
local ngx = ngx
local ngx_re = require('ngx.re')
local cjson = require("cjson.safe")
local _M = {}

-- splite str to arr by symbol
local function explode(str, symbol)
local rt= {}
string.gsub(str, '[^'..symbol..']+', function(w) table.insert(rt, w) end )
return rt
end


-- get env config
local function env(key, default)
local env_config = require("env")
local arr = explode(key, '.')
local tmp_config = env_config
for _, v in pairs(arr) do
if not tmp_config[v] then
return default
end
if type(tmp_config[v]) == 'table' then
tmp_config = tmp_config[v]
else
return tmp_config[v]
end
end
end


-- here you need use . not :
local function table_reverse(tbl)
Expand Down Expand Up @@ -164,25 +142,23 @@ end

-- data not in order
local function log(...)
local args = {}
local args
if #{...}>1 then
args = {...}
else
args = ...
end
ngx.log(ngx.WARN, require("cjson.safe").encode(args))
ngx.log(ngx.WARN, cjson.encode(args))
end

_M.log = log
_M.env = env
_M.trim = trim
_M.get_cookie = get_cookie
_M.set_cookie = set_cookie
_M.get_local_time = get_local_time
_M.sort_by_key = sort_by_key
_M.implode = implode
_M.unique = unique
_M.explode = explode
_M.table_reverse = table_reverse
_M.table_remove = table_remove

Expand Down
Loading

0 comments on commit 48e363e

Please sign in to comment.