Штекер вызывает утечку памяти - PullRequest
0 голосов
/ 13 марта 2019

У нас есть веб-приложение elixir (версия 1.8.1), работающее внутри контейнеров Docker (версия сервера 1.12.6, версия клиента 18.09.2) внутри кластера ранчеров (работает в EC2 с использованием AMI Rancheros 1.4.0). Мы используем феникс-фреймворк (версия 1.3).

Я реализовал простой HTML-кеш, используя файловую систему. Это небольшой плагин, который проверяет, существует ли html-файл для запрошенного URL-адреса, и возвращает его, если это так. Если нет, он регистрирует функцию, выполняемую перед отправкой ответа, для сохранения ответа html в кэш.

Очень хорошо работает с временем отклика 4 мс и ниже в случае попадания в кеш. НО, похоже, штекер привел к утечке памяти. Объем памяти, используемой контейнером Docker, со временем увеличивается, в зависимости от объема трафика, который получает веб-приложение. Если у меня есть простой сканер, идущий по сторонам, память увеличивается примерно на 1 МБ / мин.

Интересно, что это происходит не локально на моей машине разработчика, а в нашей рабочей среде и на производстве.

Вот полный штекер:

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
...