Elixir/Erlang file_server 消息积压和不可靠的吞吐量导致性能问题
Elixir/Erlang file_server message backlog and unreliable throughput causing performance issues
我正在 运行 开发一个生产应用程序,它可以完成很多 I/O。每当系统被新请求淹没时( 我做了大量的 IO)我看到 Erlang file_server 备份消息。 backup/slowdown 可以持续几个小时,具体取决于我们的音量。
据我了解,很多 File
调用实际上是通过 Erlang file_server 进行的。这似乎具有有限的吞吐量。此外,当消息队列得到备份时,整个应用程序基本上被冻结(锁定)并且它根本无法处理新的 IO 请求。
所有 IO 调用都使用 File
模块。我已经在所有允许的地方指定了 [:raw]
选项。据我了解,传入 :raw
将绕过 file_server.
这对我们来说是一个非常大的问题,我想其他人 运行 在某些时候也会遇到这个问题。我尝试重写 Ruby 中的 IO 逻辑,导致吞吐量大幅增加(我没有确切的数字,但这是一个明显的差异)。
有人知道我还能做些什么来增加 performance/throughput 吗?
示例代码:
defmodule MyModule.Ingestion.Insertion.Folder do
use MyModule.Poller
alias MyModule.Helpers
def perform() do
Logger.info("#{__MODULE__} starting check")
for path <- paths() do
files = Helpers.Path.list_files(path, ".json")
Task.async_stream(
files,
fn file ->
result =
file
|> File.read!()
|> Jason.decode()
case result do
{:ok, data} ->
file_created_at = Helpers.File.created_time(file)
data = Map.put(data, :file_created_at, file_created_at)
filename = Path.basename(file, ".json")
:ok = MyModule.InsertWorker.enqueue(%{data: data, filename: filename})
destination =
Application.fetch_env!(:my_application, :backups) <> filename <> ".json"
File.copy!(file, destination)
File.rm!(file)
_err ->
nil
end
end,
timeout: 60_000,
max_concurrency: 10
)
|> Stream.run()
end
Logger.info("#{__MODULE__} check finished")
end
def paths() do
path = Application.fetch_env!(:my_application, :lob_path)
[
path <> "postcards/",
path <> "letters/"
]
end
end
考虑使用 async_threads
调整虚拟机
对于将来发现此问题的任何人。问题的根源来自于对路径名使用 File.copy!
。当您这样做时,副本将通过 Erlang file_server 是造成极其难以诊断的巨大瓶颈的原因。不要将 File.copy/1
与路径名一起使用,而是使用打开的文件作为输入。像这样
source = "path/to/some/file"
destination = "path/to/destination/"
with {:ok, source} <- File.open(source, [:raw, :read]),
{:ok, destination} <- File.open(destination, [:raw, :write]),
{:ok, bytes} <- File.copy(source, destination),
:ok <- File.close(source),
:ok <- File.close(destination) do
{:ok, bytes}
end
我正在 运行 开发一个生产应用程序,它可以完成很多 I/O。每当系统被新请求淹没时( 我做了大量的 IO)我看到 Erlang file_server 备份消息。 backup/slowdown 可以持续几个小时,具体取决于我们的音量。
据我了解,很多 File
调用实际上是通过 Erlang file_server 进行的。这似乎具有有限的吞吐量。此外,当消息队列得到备份时,整个应用程序基本上被冻结(锁定)并且它根本无法处理新的 IO 请求。
所有 IO 调用都使用 File
模块。我已经在所有允许的地方指定了 [:raw]
选项。据我了解,传入 :raw
将绕过 file_server.
这对我们来说是一个非常大的问题,我想其他人 运行 在某些时候也会遇到这个问题。我尝试重写 Ruby 中的 IO 逻辑,导致吞吐量大幅增加(我没有确切的数字,但这是一个明显的差异)。
有人知道我还能做些什么来增加 performance/throughput 吗?
示例代码:
defmodule MyModule.Ingestion.Insertion.Folder do
use MyModule.Poller
alias MyModule.Helpers
def perform() do
Logger.info("#{__MODULE__} starting check")
for path <- paths() do
files = Helpers.Path.list_files(path, ".json")
Task.async_stream(
files,
fn file ->
result =
file
|> File.read!()
|> Jason.decode()
case result do
{:ok, data} ->
file_created_at = Helpers.File.created_time(file)
data = Map.put(data, :file_created_at, file_created_at)
filename = Path.basename(file, ".json")
:ok = MyModule.InsertWorker.enqueue(%{data: data, filename: filename})
destination =
Application.fetch_env!(:my_application, :backups) <> filename <> ".json"
File.copy!(file, destination)
File.rm!(file)
_err ->
nil
end
end,
timeout: 60_000,
max_concurrency: 10
)
|> Stream.run()
end
Logger.info("#{__MODULE__} check finished")
end
def paths() do
path = Application.fetch_env!(:my_application, :lob_path)
[
path <> "postcards/",
path <> "letters/"
]
end
end
考虑使用 async_threads
调整虚拟机对于将来发现此问题的任何人。问题的根源来自于对路径名使用 File.copy!
。当您这样做时,副本将通过 Erlang file_server 是造成极其难以诊断的巨大瓶颈的原因。不要将 File.copy/1
与路径名一起使用,而是使用打开的文件作为输入。像这样
source = "path/to/some/file"
destination = "path/to/destination/"
with {:ok, source} <- File.open(source, [:raw, :read]),
{:ok, destination} <- File.open(destination, [:raw, :write]),
{:ok, bytes} <- File.copy(source, destination),
:ok <- File.close(source),
:ok <- File.close(destination) do
{:ok, bytes}
end