我们有一个elixir(1.8.1版)Web应用程序在rancher群集(使用AMI Rancheros 1.4.0在EC2中运行)的docker(服务器版本1.12.6,客户端版本18.09.2)容器中运行。我们正在使用phoenix框架(版本1.3)。
我使用文件系统实现了一个简单的html缓存。这是一个小插件,用于检查所请求url的html文件是否存在,如果存在,则返回该文件。如果没有,它将注册一个函数,以便在发送响应之前将html响应保存到缓存中。
在缓存命中的情况下,它在4ms以下的响应时间下效果很好。但是似乎插头确实引起了内存泄漏。 Docker容器使用的内存随着时间的推移而增长,具体取决于Web应用程序收到的流量。如果我有一个简单的爬虫通过侧面,则内存将以每分钟1MB的速度增长。
有趣的是,这不是在我的开发机器上本地发生的,而是在我们的暂存和生产环境中发生的。
这是完整的插头:
defmodule PagesWeb.Plugs.Cache do
@moduledoc false
import Plug.Conn
def init(default), do: default
def call(
%Plug.Conn{method: "GET", query_string: query_string, request_path: request_path} = conn,
_default
) do
case page_cached?(request_path, query_string) do
true ->
conn
|> put_resp_header("x-phoenix-cache", "true")
|> put_resp_header("content-type", "text/html; charset=utf-8")
|> send_file(200, "priv/static/html#{uri_to_filepath(request_path, query_string)}")
|> halt()
false ->
conn
|> Plug.Conn.register_before_send(&PagesWeb.Plugs.Cache.save_html_to_cache/1)
|> put_resp_header("x-phoenix-cache", "false")
end
end
def call(conn, _default) do
conn
end
def save_html_to_cache(
%Plug.Conn{request_path: request_path, query_string: query_string, resp_body: resp_body} =
conn
) do
case conn.status do
200 ->
html_file = uri_to_filepath(request_path, query_string)
File.mkdir_p(Path.dirname("priv/static/html#{html_file}"))
File.write("priv/static/html#{html_file}", resp_body)
conn
_ ->
conn
end
end
def read_cached_page(url, query_string) do
case File.open("priv/static/html#{uri_to_filepath(url, query_string)}", [:read, :utf8]) do
{:ok, file} ->
content = IO.read(file, :all)
File.close(file)
content
{:error, _} ->
:err
end
end
def page_cached?(url, query_string) do
File.exists?("priv/static/html#{uri_to_filepath(url, query_string)}", [:raw])
end
defp uri_to_filepath(url, query_string) do
query_string =
case query_string do
"" -> ""
qs -> "-#{qs}"
end
case url do
"/" -> "/index.html"
path -> "#{path}#{query_string}.html"
end
end
end