Перловая обвязка для libiprotocluster. Помимо прочего поддерживаются:
- синхронный блокирующий режим работы при использовании внутреннего event loop (используется по умолчанию);
- синхронный неблокирующий режим работы при использовании внешнего event loop;
- асинхронный режим работы с возвратом результата через callback (разумно использовать только с внешним event loop);
- упаковка/распаковка данных при помощи
pack
/unpack
.
Объект класса MR::IProto::XS
представляет собой кластер iproto-серверов. Конструктор поддерживаются следующие параметры:
shards
- хэш шардов;masters
- мастера, если шард только один;replicas
- реплики, если шард только один;
В самом общем виде, создание объекта выглядит следующим образом:
my $iproto = MR::IProto::XS->new(
shards => {
1 => { masters => [['10.0.2.1:1002', '10.0.2.1:1012'], ['10.1.2.1:1002', '10.1.2.1:1012']], replicas => [['10.0.3.1:1003'], ['10.1.3.1:1013']] },
2 => { masters => ['10.0.2.2:2002', '10.0.2.2:2012'], replicas => ['10.0.3.2:2003'] },
3 => { masters => ['10.0.2.3:2002'], replicas => ['10.0.3.3:2003'] },
},
);
В хеше shards
ключами являются номера шардов от 1 до максимального, дырок быть не должно. В значениях - хэши с двумя ключами: masters
и replicas
, содержащими либо массивы строк host:port, либо массивы таких массивов. В первом случае, это будут равноправные серверы, обращение к которым будет выполняться в случайном порядке. Во втором случае, переход от одного массива к другому будет осуществляться только при недоступности всех серверов первого массива.
В случае только одного шарда запись можно упростить:
my $iproto = MR::IProto::XS->new(
masters => [['10.0.0.1:1000', '10.0.0.2:2000'], ['10.0.0.3:3000', '10.0.0.4:4000']],
replicas => [['10.0.1.1:1001', '10.0.1.2:2001'], ['10.0.1.3:3001', '10.0.1.4:4001']],
);
Для того, чтобы не таскать по коду переменную, можно создать класс-синглетон при помощи метода create_singleton
и выполнять все вызовы от имени класса:
package My::Super::Box;
use base 'MR::IProto::XS';
__PACKAGE__->create_singleton(masters => ["127.0.0.1:1234"]);
Впоследствии синглетон можно удалить методом remove_singleton
(хотя вряд ли это необходимо).
Собственно выполнение запросов осуществляется при помощи метода bulk
, либо его упрошенной формы do
:
my $resp = $iproto->bulk([
{
code => 17,
request => { method => 'pack', format => 'LL', data => [ 97, 10976 ] },
response => { method => 'unpack', format => 'L' },
},
{
code => 25,
request => { method => 'pack', format => 'CL$', data => [ 1, 15, "something" ] },
response => { method => 'unpack', format => 'L' },
},
]);
Метод bulk
вернет массив хешей, содержащих ключи error
и, если нет ошибок, data
. В error
содержится dualvar, который в числовом контексте содержит код ошибки, а в строковом - описание (подобно тому как работает $!
). В data
содержится либо необработанный ответ, либо, если указан способ распаковки ответа, результат этой распаковки. В случае, если ответ был получен от реплики, то будет также присутствовать ключ replica
со значением 1
.
Метод do
делает все ровно то же самое, но рассчитан на отправку одного запроса и принимает вместо массива хэш одного запроса и возвращает хэш одного ответа.
Для асинхронных запросов (содержащих ключ callback
) вместо результата функции вернут undef
, а собственно результат будет передан в callback-функцию.
Собственно хэш запроса может содержать следующие ключи:
code
- числовой код типа сообщений;request
- параметры упаковки запроса:method
- метод упаковки, поддерживается"raw"
,"pack"
и"sub"
;- если
method = "pack"
:format
- строка формата дляpack
;data
- массив данных дляpack
;
- если
method = "sub"
:sub
- функция-энкодер, должна возвращать строку с упакованными данными;data
- значение, передаваемое в нее первым параметром;
response
- параметры распаковки запроса:errcode
- длина кода ошибки (1, 2, 4, или 8), которая вырезается из начала ответа перед распаковкой;errstr
- если код ошибки ненулевой, то все оставшееся считается текстом ошибки;method
- метод распаковки, поддерживается"raw"
,"unpack"
и"sub"
;- если
method = "pack"
:format
- строка формата дляunpack
;
- если
method = "sub"
:sub
- функция-декодер, принимает на вход строку с упакованными данными;
shard_num
- номер шарда;max_tries
- максимальное количество попыток (по умолчанию 3);from
- порядок обращения к серверам при попытках:"master"
- только мастер (по умолчанию);"replica"
- только реплика;"master,replica"
- мастер, если не получилось, то реплика;"replica,master"
- реплика, если не получилось, то мастер;
early_retry
- выполнять ли ранние перепопытки;safe_retry
- выполнять перепопытки только если запрос не был отправлен на сервер (по умолчанию);retry_same
- выполнять перепопытки всегда к тому же серверу (во избежание дупликатов например);timeout
- таймаут на запрос (без учета времени на коннект) в секундах с плавающей точкой (по умолчанию 0.5);inplace
- модифицировать хэш запроса и дописать ответ прямо в него;callback
- функция, которая будет вызвана после выполнения запроса, результат будет передан в нее первым и единственным параметром;soft_retry_callback
- callback-функция, при помощи можно на раннем этапе определить неуспешные запросы и повторить их.
Для того, чтобы получить количество используемых шардов (например, чтобы отправить запрос во все шарды), можно использовать метод get_shard_count
.
После инициализации библиотека по умолчанию использует внутренний event loop для того, чтобы не было странных интерференций разных вызовов в синхронном коде (а также, чтобы сохранить поведение предыдущих версий). Изменить используемый event loop можно при помощи метода set_ev_loop
:
MR::IProto::XS->set_ev_loop(EV::default_loop);
- Coro
- EV
- libiprotocluster
perl Makefile.PL
make
make install