Skip to content

Commit

Permalink
[RU] Add the 'libraries/poolboy' lesson translation (#892)
Browse files Browse the repository at this point in the history
  • Loading branch information
nscyclone committed Jan 5, 2017
1 parent 03bb6d5 commit fb991df
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
1 change: 1 addition & 0 deletions GLOSSARY.md
Expand Up @@ -37,6 +37,7 @@ Class names and proper nouns do not get translated.
- match operator - оператор сопоставления
- pin operator - фиксирующий оператор
- pipe operator - оператор конвейера
- pool - пул
- sigil - строковая метка
- schema - структура
- tuple - кортеж
Expand Down
140 changes: 140 additions & 0 deletions ru/lessons/libraries/poolboy.md
@@ -0,0 +1,140 @@
---
layout: page
title: Poolboy
category: libraries
order: 2
lang: ru
---

Если позволить параллельным процессам выполняться произвольно, то с лёгкостью можно израсходовать все системные ресурсы. Poolboy предотвращает возможность возникновения чрезмерной нагрузки с помощью пула процессов-обработчиков, ограничивающих количество параллельных процессов.

{% include toc.html %}

## Зачем использовать Poolboy?

Возьмём конкретный пример. Вам надо создать приложение для сохранения профилей пользователей в базу данных. Если бы вы создавали по процессу на регистрацию каждого пользователя, вы бы генерировали неограниченное количество соединений. В определённый момент эти соединения начали бы соперничать за ограниченные ресурсы сервера базы данных. В итоге в приложении стали бы возникать таймауты и различные ошибки из-за перегрузки, появившейся вследствие такой конкуренции.

Решение такой проблемы — использовать пул процессов-обработчиков для ограничения количества одновременных соединений вместо создания процессов для регистрации каждого пользователя. Так можно с лёгкостью избежать истощения системных ресурсов.

Для этого и нужен Poolboy. Он создаёт пул процессов-обработчиков, управляемых супервизором без необходимости делать что-либо вручную. Очень многие библиотеки используют Poolboy под капотом. Например, так работают пулы соединений в `postgrex` *(который предоставляется Ecto при использовании PostgreSQL)* и `redis_poolex`.

## Установка

Благодаря mix установка очень проста. Нужно всего лишь добавить Poolboy в список зависимостей в `mix.exs`.

Для начала создадим приложение:

```
$ mix new poolboy_app --sup
$ mix deps.get
```

Добавим Poolboy в список зависимостей `mix.exs`.

```elixir
defp deps do
[{:poolboy, "~> 1.5.1"}]
end
```

Добавим Poolboy в приложение OTP:

```elixir
def application do
[applications: [:logger, :poolboy]]
end
```

## Настройка

Перед тем как начать пользоваться Poolboy, надо ознакомиться с возможностями его настройки:

* `:name` — наименование пула. Область видимости может быть `:local`, `:global` или `:via`.
* `:worker_module` — модуль, представляющий рабочий процесс.
* `:size` — максимальный размер пула.
* `:max_overflow` — максимальное количество процессов-обработчиков, создаваемых, если в пуле закончились свободные процессы. (необязательно)
* `:strategy` — `:lifo` или `:fifo`, определяет, в начало или в конец списка доступных процессов-обработчиков должен быть помещён создаваемый процесс. По умолчанию `:lifo`. (необязательно)

## Настройка Poolboy

Для примера создадим пул процессов-обработчиков, ответственных за обработку запросов на расчёт квадратного корня числа. Пример намеренно выбран попроще, чтобы мы могли сфокусироваться на Poolboy.

Опишем модуль настройки Poolboy и добавим его как дочерний рабочий процесс при запуске нашего приложения.

```elixir
defmodule PoolboyApp do
use Application

defp poolboy_config do
[{:name, {:local, :worker}},
{:worker_module, Worker},
{:size, 5},
{:max_overflow, 2}]
end

def start(_type, _args) do
import Supervisor.Spec, warn: false

children = [
:poolboy.child_spec(:worker, poolboy_config, [])
]

opts = [strategy: :one_for_one, name: PoolboyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
```

Первое, что мы сделали — объявили настройки для пула. Присвоили уникальное имя `:name`, установили локальную область видимости (`:scope`) и ограничили размер пула (`:size`) пятью процессами. Также в опции `:max_overflow` мы указали, что в случае, если все процессы-обработчики будут заняты, то можно создавать два дополнительных процесса, чтобы помочь разобраться с нагрузкой. *(`overflow`-процессы завершаются как только они выполнят свою работу.)*

Затем мы добавили функцию `poolboy.child_spec/3` в список дочерних процессов, чтобы пул запускался при запуске нашего приложения.

Функция `child_spec/3` принимает три аргумента: имя пула, настройки и третий аргумент, передаваемый в функцию `worker.start_link`. В нашем случае это пустой список.

## Создание рабочего процесса

Модуль рабочего процесса будет простым GenServer'ом, который считает квадратный корень числа, затем останавливается на секунду и выводит pid процесса:

```elixir
defmodule Worker do
use GenServer

def start_link(_) do
GenServer.start_link(__MODULE__, nil, [])
end

def init(_) do
{:ok, nil}
end

def handle_call({:square_root, x}, _from, state) do
IO.puts "процесс #{inspect self} считает квадратный корень из #{x}"
:timer.sleep(1000)
{:reply, :math.sqrt(x), state}
end
end
```

## Использование Poolboy

Теперь, когда у нас есть `Worker`, мы можем тестировать Poolboy. Создадим простой модуль, генерирующий задачи при помощи функции `:poolboy.transaction`:

```elixir
defmodule Test do
@timeout 60000

def start do
tasks = Enum.map(1..20, fn(i) ->
Task.async(fn -> :poolboy.transaction(:worker,
&(GenServer.call(&1, {:square_root, i})), @timeout)
end)
end)
Enum.each(tasks, fn(task) -> IO.puts(Task.await(task, @timeout)) end)
end
end

```

Если в пуле не останется свободных процессов, Poolboy вызовет таймаут после периода таймаута по умолчанию (пять секунд) и не будет принимать новые запросы. В нашем примере мы увеличили период таймаута до минуты, чтобы показать, как можно менять это значение.

Несмотря на то, что мы пытаемся создать много процессов *(всего двадцать в примере выше)*, функция `:poolboy.transaction` ограничит общее количество созданных процессов до пяти *(плюс два процесса для обработки перегрузки)*, как мы и указали в настройках. Все запросы будут обработаны пулом процессов вместо создания по процессу на каждый запрос.

0 comments on commit fb991df

Please sign in to comment.