Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: support for proxy caching plugin based on disk. #1153

Merged
merged 22 commits into from
Mar 15, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions bin/apisix
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,19 @@ http {
{% if proxy_cache then %}
# for proxy cache
{% for _, cache in ipairs(proxy_cache.zones) do %}
proxy_cache_path {* cache.disk_path *} levels=1:2 keys_zone={* cache.name *}:{* cache.memory_size *} inactive=1d max_size={* cache.disk_size *};
proxy_cache_path {* cache.disk_path *} levels={* cache.cache_levels *} keys_zone={* cache.name *}:{* cache.memory_size *} inactive=1d max_size={* cache.disk_size *};
{% end %}
{% end %}

{% if proxy_cache then %}
# for proxy cache
map $upstream_cache_zone $upstream_cache_zone_info {
{% for _, cache in ipairs(proxy_cache.zones) do %}
{* cache.name *} {* cache.disk_path *},{* cache.cache_levels *};
{% end %}
}
{% end %}

lua_ssl_verify_depth 5;
ssl_session_timeout 86400;

Expand Down Expand Up @@ -404,7 +413,7 @@ http {

set $upstream_cache_zone off;
set $upstream_cache_key '';
set $upstream_cache_bypass 'bypass';
set $upstream_cache_bypass '';
set $upstream_no_cache '';
set $upstream_hdr_expires '';
set $upstream_hdr_cache_control '';
Expand Down
2 changes: 2 additions & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ apisix:
memory_size: 50m # The size of shared memory, it's used to store the cache index
disk_size: 1G # The size of disk, it's used to store the cache data
disk_path: "/tmp/disk_cache_one" # The path to store the cache data
cache_levels: "1:2" # The hierarchy levels of a cache
# - name: disk_cache_two
# memory_size: 50m
# disk_size: 1G
# disk_path: "/tmp/disk_cache_two"
# cache_levels: "1:2"

# allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
# - 127.0.0.0/24 # If we don't set any IP list, then any IP access is allowed by default.
Expand Down
1 change: 1 addition & 0 deletions lua/apisix/core/ctx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ do
upstream_uri = true,

upstream_cache_zone = true,
upstream_cache_zone_info = true,
upstream_no_cache = true,
upstream_cache_key = true,
upstream_cache_bypass = true,
Expand Down
138 changes: 100 additions & 38 deletions lua/apisix/plugins/proxy-cache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@
--

local core = require("apisix.core")
local ngx_re = require("ngx.re")
local tab_insert = table.insert
local tab_concat = table.concat
local sub_str = string.sub
local string = string
local io_open = io.open
local io_close = io.close
local ngx = ngx
local os = os
local ipairs = ipairs
local pairs = pairs
local tonumber = tonumber

local plugin_name = "proxy-cache"

Expand Down Expand Up @@ -114,8 +120,8 @@ local function generate_complex_value(data, ctx)
for i, value in ipairs(data) do
core.log.info("proxy-cache complex value index-", i, ": ", value)

if sub_str(value, 1, 1) == "$" then
tab_insert(tmp, ctx.var[sub_str(value, 2)])
if string.sub(value, 1, 1) == "$" then
tab_insert(tmp, ctx.var[string.sub(value, 2)])
else
tab_insert(tmp, value)
end
Expand All @@ -125,32 +131,6 @@ local function generate_complex_value(data, ctx)
end


function _M.rewrite(conf, ctx)
core.log.info("proxy-cache plugin rewrite phase, conf: ", core.json.delay_encode(conf))

ctx.var.upstream_cache_zone = conf.cache_zone

local value, err = generate_complex_value(conf.cache_key, ctx)
if not value then
core.log.error("failed to generate the complex value by: ", conf.cache_key, " error: ", err)
core.response.exit(500)
end

ctx.var.upstream_cache_key = value
core.log.info("proxy-cache cache key value:", value)

local value, err = generate_complex_value(conf.cache_bypass, ctx)
if not value then
core.log.error("failed to generate the complex value by: ",
conf.cache_bypass, " error: ", err)
core.response.exit(500)
end

ctx.var.upstream_cache_bypass = value
core.log.info("proxy-cache cache bypass value:", value)
end


-- check whether the request method and response status
-- match the user defined.
local function match_method_and_status(conf, ctx)
Expand Down Expand Up @@ -178,6 +158,91 @@ local function match_method_and_status(conf, ctx)
return false
end

-- refer to https://gist.github.com/titpetric/ed6ec548af160e82c650cf39074878fb
agile6v marked this conversation as resolved.
Show resolved Hide resolved
local function file_exists(name)
local f = io_open(name, "r")
if f~=nil then io_close(f) return true else return false end
end


local function explode(d, p)
local t, ll
t={}
ll=0
if(#p == 1) then return {p} end
while true do
local l=string.find(p, d, ll, true) -- find the next d in the string
if l~=nil then -- if "not not" found then..
tab_insert(t, string.sub(p, ll, l-1)) -- Save it in our array.
ll=l+1 -- save just after where we found it for searching next time.
else
tab_insert(t, string.sub(p, ll)) -- Save what's left in our array.
break -- Break at end, as it should be, according to the lua manual.
end
end
return t
end


local function generate_cache_filename(cache_path, cache_levels, cache_key)
local md5sum = ngx.md5(cache_key)
local levels = explode(":", cache_levels)
local filename = ""

local index = string.len(md5sum)
for k, v in pairs(levels) do
local length = tonumber(v)
-- add trailing [length] chars to index
index = index - length;
agile6v marked this conversation as resolved.
Show resolved Hide resolved
filename = filename .. md5sum:sub(index+1, index+length) .. "/";
end
if cache_path:sub(-1) ~= "/" then
cache_path = cache_path .. "/";
end
filename = cache_path .. filename .. md5sum
return filename
end


local function cache_purge(conf, ctx)
local cache_zone_info = ngx_re.split(ctx.var.upstream_cache_zone_info, ",")

local filename = generate_cache_filename(cache_zone_info[1], cache_zone_info[2],
ctx.var.upstream_cache_key)
if file_exists(filename) then
os.remove(filename)
agile6v marked this conversation as resolved.
Show resolved Hide resolved
return nil
end

return "Not found"
end


function _M.rewrite(conf, ctx)
core.log.info("proxy-cache plugin rewrite phase, conf: ", core.json.delay_encode(conf))

ctx.var.upstream_cache_zone = conf.cache_zone

local value = generate_complex_value(conf.cache_key, ctx)
ctx.var.upstream_cache_key = value
core.log.info("proxy-cache cache key value:", value)

if ctx.var.request_method == "PURGE" then
local err = cache_purge(conf, ctx)
if err ~= nil then
return 404
end

return 200
end

if conf.cache_bypass ~= nil then
local value = generate_complex_value(conf.cache_bypass, ctx)
ctx.var.upstream_cache_bypass = value
core.log.info("proxy-cache cache bypass value:", value)
end
end


function _M.header_filter(conf, ctx)
core.log.info("proxy-cache plugin header filter phase, conf: ", core.json.delay_encode(conf))
Expand All @@ -188,16 +253,13 @@ function _M.header_filter(conf, ctx)
no_cache = "0"
end

local value, err = generate_complex_value(conf.no_cache, ctx)
if not value then
core.log.error("failed to generate the complex value by: ", conf.no_cache, " error: ", err)
core.response.exit(500)
end

core.log.info("proxy-cache no-cache value:", value)
if conf.no_cache ~= nil then
local value = generate_complex_value(conf.no_cache, ctx)
core.log.info("proxy-cache no-cache value:", value)

if value ~= nil and value ~= "" and value ~= "0" then
no_cache = "1"
if value ~= nil and value ~= "" and value ~= "0" then
no_cache = "1"
end
end

if conf.hide_cache_headers == true then
Expand Down