Elixir、Phoenix 和 Ecto:当数据库宕机时,提供缓存数据的请求变得非常慢(从 100 毫秒到 3 秒)
Elixir, Phoenix and Ecto : When database is down, requests to serve cached data become really slow (from 100ms to 3 seconds)
我使用 --no-html 和 --database mysql
创建了一个 phoenix 项目
我们在工作中使用的版本是:
Erlang/OTP 21 [erts-10.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]
Elixir 1.8.0 (compiled with Erlang/OTP 20)
我正在做一个项目,作为状态页面工具 (hund.io) 和我们自己的 API 和报告工具之间的代理,所以我需要一个数据库来存储服务名称 + url 请求,并且,因为我需要一点与数据库 Cachex (https://github.com/whitfin/cachex) 分离,以便将我的数据放入缓存
缓存数据时,使用邮递员请求我的包装器 api 需要大约 100 毫秒才能获得响应,而 phoenix 的日志会显示类似 [info] Sent 200 in 1ms
的内容
但是,我曾经关闭过数据库,邮递员最多需要 3 秒才能得到响应,phoenix 日志仍然会说那种事情 [info] Sent 200 in 1ms
我确定包装器在这两种情况下都使用缓存数据:
我的代码:
def show(conn, %{"service_name" => service_name}) do
Logger.debug("Top of show func")
case Cachex.get(:proxies, service_name) do
{:ok, nil} ->
Logger.debug("Service #{service_name} not found in cache")
proxy = Health.get_proxy_by_name!(service_name)
Logger.debug("Service #{service_name} found in db")
Cachex.put(:proxies, service_name, proxy)
proxy_with_health = Checker.call_api(proxy)
render(conn, "show.json", proxy_health: proxy_with_health)
{:ok, proxy} ->
Logger.debug("Found service #{service_name} in cache")
proxy_with_health = Checker.call_api(proxy)
render(conn, "show.json", proxy_health: proxy_with_health)
end
end
日志:
[info] GET /api/proxies_health/docto
[debug] Processing with StatusWeb.ProxyHealthController.show/2
Parameters: %{"service_name" => "docto"}
Pipelines: [:api]
[debug] Top of show func
[debug] Found service docto in cache
路由器部分:
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", StatusWeb do
pipe_through :api
resources "/proxies", ProxyController, except: [:new, :edit]
get "/proxies_health", ProxyHealthController, :index
get "/proxies_health/:service_name", ProxyHealthController, :show
end
我在日志中也有两个错误:
[error] MyXQL.Connection (#PID<0.373.0>) failed to connect: ** (DBConnection.ConnectionError) connection refused
当应用程序想要重新连接到数据库时,这看起来很“正常”
而这个,就在处理请求之前(至少根据日志)
[error] Could not create schema migrations table. This error usually happens due to the following:
* The database does not exist
* The "schema_migrations" table, which Ecto uses for managing
migrations, was defined by another library
* There is a deadlock while migrating (such as using concurrent
indexes with a migration_lock)
To fix the first issue, run "mix ecto.create".
To address the second, you can run "mix ecto.drop" followed by
"mix ecto.create". Alternatively you may configure Ecto to use
another table and/or repository for managing migrations:
config :status, Status.Repo,
migration_source: "some_other_table_for_schema_migrations",
migration_repo: AnotherRepoForSchemaMigrations
The full error report is shown below.
[error] GenServer #PID<0.620.0> terminating
** (DBConnection.ConnectionError) connection refused
(db_connection) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
State: MyXQL.Connection
我试图在查看
时放入我的 Status.Repo 文件 (repo.ex)
backoff_type: :stop
但这对我的问题没有任何改变
作为我的代码,在缓存中找到一个对象的路径中(根本)不涉及数据库,我们最终在不一致的情况下发现问题来自端点中应该存在的插件仅在开发环境中 (MyAppWeb/endpoint.ex)
if code_reloading? do
plug Phoenix.CodeReloader
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :status
end
这是一个插件,可以在每次请求时检查数据库是否启动,迁移是否 运行 等
等待 Ecto 的回答,在 genserver 中超时意识到调用导致经历了延迟!
修复方法是简单地注释行
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :status
我使用 --no-html 和 --database mysql
创建了一个 phoenix 项目我们在工作中使用的版本是:
Erlang/OTP 21 [erts-10.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]
Elixir 1.8.0 (compiled with Erlang/OTP 20)
我正在做一个项目,作为状态页面工具 (hund.io) 和我们自己的 API 和报告工具之间的代理,所以我需要一个数据库来存储服务名称 + url 请求,并且,因为我需要一点与数据库 Cachex (https://github.com/whitfin/cachex) 分离,以便将我的数据放入缓存
缓存数据时,使用邮递员请求我的包装器 api 需要大约 100 毫秒才能获得响应,而 phoenix 的日志会显示类似 [info] Sent 200 in 1ms
的内容
但是,我曾经关闭过数据库,邮递员最多需要 3 秒才能得到响应,phoenix 日志仍然会说那种事情 [info] Sent 200 in 1ms
我确定包装器在这两种情况下都使用缓存数据:
我的代码:
def show(conn, %{"service_name" => service_name}) do
Logger.debug("Top of show func")
case Cachex.get(:proxies, service_name) do
{:ok, nil} ->
Logger.debug("Service #{service_name} not found in cache")
proxy = Health.get_proxy_by_name!(service_name)
Logger.debug("Service #{service_name} found in db")
Cachex.put(:proxies, service_name, proxy)
proxy_with_health = Checker.call_api(proxy)
render(conn, "show.json", proxy_health: proxy_with_health)
{:ok, proxy} ->
Logger.debug("Found service #{service_name} in cache")
proxy_with_health = Checker.call_api(proxy)
render(conn, "show.json", proxy_health: proxy_with_health)
end
end
日志:
[info] GET /api/proxies_health/docto
[debug] Processing with StatusWeb.ProxyHealthController.show/2
Parameters: %{"service_name" => "docto"}
Pipelines: [:api]
[debug] Top of show func
[debug] Found service docto in cache
路由器部分:
pipeline :api do
plug :accepts, ["json"]
end
scope "/api", StatusWeb do
pipe_through :api
resources "/proxies", ProxyController, except: [:new, :edit]
get "/proxies_health", ProxyHealthController, :index
get "/proxies_health/:service_name", ProxyHealthController, :show
end
我在日志中也有两个错误:
[error] MyXQL.Connection (#PID<0.373.0>) failed to connect: ** (DBConnection.ConnectionError) connection refused
当应用程序想要重新连接到数据库时,这看起来很“正常” 而这个,就在处理请求之前(至少根据日志)
[error] Could not create schema migrations table. This error usually happens due to the following:
* The database does not exist
* The "schema_migrations" table, which Ecto uses for managing
migrations, was defined by another library
* There is a deadlock while migrating (such as using concurrent
indexes with a migration_lock)
To fix the first issue, run "mix ecto.create".
To address the second, you can run "mix ecto.drop" followed by
"mix ecto.create". Alternatively you may configure Ecto to use
another table and/or repository for managing migrations:
config :status, Status.Repo,
migration_source: "some_other_table_for_schema_migrations",
migration_repo: AnotherRepoForSchemaMigrations
The full error report is shown below.
[error] GenServer #PID<0.620.0> terminating
** (DBConnection.ConnectionError) connection refused
(db_connection) lib/db_connection/connection.ex:100: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
State: MyXQL.Connection
我试图在查看
backoff_type: :stop
但这对我的问题没有任何改变
作为我的代码,在缓存中找到一个对象的路径中(根本)不涉及数据库,我们最终在不一致的情况下发现问题来自端点中应该存在的插件仅在开发环境中 (MyAppWeb/endpoint.ex)
if code_reloading? do
plug Phoenix.CodeReloader
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :status
end
这是一个插件,可以在每次请求时检查数据库是否启动,迁移是否 运行 等 等待 Ecto 的回答,在 genserver 中超时意识到调用导致经历了延迟!
修复方法是简单地注释行
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :status