Гибкий и полнофункциональный клиент Redis для PHP 7.2 и новее.
Более подробную информацию о проекте можно найти в часто задаваемых вопросах.
EVALSHA
или EVAL
.SCAN
, SSCAN
, ZSCAN
и HSCAN
(Redis >= 2.8) на основе итераторов PHP.Эту библиотеку можно найти на Packagist, чтобы упростить управление зависимостями проектов с помощью Composer. Сжатые архивы каждого выпуска доступны на GitHub.
composer require predis/predis
Predis использует функции автозагрузки PHP для загрузки файлов при необходимости и соответствует стандарту PSR-4. Автозагрузка обрабатывается автоматически, когда зависимости управляются через Composer, но также можно использовать собственный автозагрузчик в проектах или сценариях, в которых отсутствует какая-либо возможность автозагрузки:
// Prepend a base path if Predis is not available in your "include_path".
require ' Predis/Autoloader.php ' ;
Predis Autoloader:: register ();
При создании экземпляра клиента без передачи каких-либо параметров подключения Predis предполагает 127.0.0.1
и 6379
в качестве хоста и порта по умолчанию. Тайм-аут по умолчанию для операции connect()
составляет 5 секунд:
$ client = new Predis Client ();
$ client -> set ( ' foo ' , ' bar ' );
$ value = $ client -> get ( ' foo ' );
Параметры соединения могут быть предоставлены либо в виде строк URI, либо в виде именованных массивов. Последний способ предоставления параметров является предпочтительным, но строки URI могут быть полезны, когда параметры считываются из неструктурированных или частично структурированных источников:
// Parameters passed using a named array:
$ client = new Predis Client ([
' scheme ' => ' tcp ' ,
' host ' => ' 10.0.0.1 ' ,
' port ' => 6379 ,
]);
// Same set of parameters, passed using an URI string:
$ client = new Predis Client ( ' tcp://10.0.0.1:6379 ' );
Доступ к серверам, защищенным паролем, можно получить, добавив password
в набор параметров. Если списки управления доступом включены в Redis >= 6.0, для аутентификации пользователя требуются username
и password
.
Также возможно подключение к локальным экземплярам Redis с использованием доменных сокетов UNIX, в этом случае параметры должны использовать схему unix
и указывать путь к файлу сокета:
$ client = new Predis Client ([ ' scheme ' => ' unix ' , ' path ' => ' /path/to/redis.sock ' ]);
$ client = new Predis Client ( ' unix:/path/to/redis.sock ' );
Клиент может использовать шифрование TLS/SSL для подключения к защищенным удаленным экземплярам Redis без необходимости настраивать прокси-сервер SSL, например stunnel. Это может быть полезно при подключении к узлам, работающим на различных провайдерах облачного хостинга. Шифрование можно включить с помощью схемы tls
и массива подходящих опций, передаваемых через параметр ssl
:
// Named array of connection parameters:
$ client = new Predis Client ([
' scheme ' => ' tls ' ,
' ssl ' => [ ' cafile ' => ' private.pem ' , ' verify_peer ' => true ],
]);
// Same set of parameters, but using an URI string:
$ client = new Predis Client ( ' tls://127.0.0.1?ssl[cafile]=private.pem&ssl[verify_peer]=1 ' );
Схемы подключения redis
(псевдоним tcp
) и rediss
(псевдоним tls
) также поддерживаются с той разницей, что строки URI, содержащие эти схемы, анализируются в соответствии с правилами, описанными в соответствующих документах о предварительной регистрации IANA.
Фактический список поддерживаемых параметров подключения может варьироваться в зависимости от каждого механизма подключения, поэтому рекомендуется обратиться к их конкретной документации или реализации для получения подробной информации.
Predis может агрегировать несколько соединений, предоставляя массив параметров соединения и соответствующую опцию, чтобы проинструктировать клиента о том, как их агрегировать (кластеризация, репликация или пользовательская логика агрегирования). Именованные массивы и строки URI можно смешивать при настройке конфигурации для каждого узла:
$ client = new Predis Client ([
' tcp://10.0.0.1?alias=first-node ' , [ ' host ' => ' 10.0.0.2 ' , ' alias ' => ' second-node ' ],
], [
' cluster ' => ' predis ' ,
]);
Дополнительные сведения см. в разделе совокупных соединений этого документа.
Подключения к Redis являются ленивыми, что означает, что клиент подключается к серверу только в случае необходимости. Хотя рекомендуется позволить клиенту делать свою собственную работу «под капотом», могут быть случаи, когда все же желательно иметь контроль над тем, когда соединение открывается или закрывается: этого можно легко добиться, вызвав $client->connect()
и $client->disconnect()
. Обратите внимание, что влияние этих методов на совокупные соединения может различаться в зависимости от каждой конкретной реализации.
Многие аспекты и поведение клиента можно настроить, передав определенные параметры клиента во второй аргумент PredisClient::__construct()
:
$ client = new Predis Client ( $ parameters , [ ' prefix ' => ' sample: ' ]);
Параметры управляются с помощью мини-контейнера, подобного DI, и их значения могут быть лениво инициализированы только при необходимости. Параметры клиента, поддерживаемые по умолчанию в Predis:
prefix
: строка префикса, применяемая к каждой клавише, найденной в командах.exceptions
: должен ли клиент выдавать или возвращать ответы при ошибках Redis.connections
: список серверов соединений или экземпляр фабрики соединений.cluster
: указывает серверную часть кластера ( predis
, redis
или callable).replication
: указывает серверную часть репликации ( predis
, sentinel
или Callable).aggregate
: настраивает клиент с помощью специального агрегатного соединения (вызываемого).parameters
: список параметров соединения по умолчанию для совокупных соединений.commands
: указывает экземпляр фабрики команд, который будет использоваться через библиотеку.Пользователи также могут предоставлять пользовательские параметры со значениями или вызываемыми объектами (для отложенной инициализации), которые хранятся в контейнере параметров для последующего использования через библиотеку.
Агрегатные соединения являются основой, на которой Predis реализует кластеризацию и репликацию, и они используются для группировки нескольких подключений к отдельным узлам Redis и скрытия конкретной логики, необходимой для их правильной обработки, в зависимости от контекста. Для агрегатных подключений обычно требуется массив параметров подключения и соответствующий параметр клиента при создании нового экземпляра клиента.
Predis можно настроить для работы в режиме кластеризации с традиционным подходом сегментирования на стороне клиента для создания кластера независимых узлов и распределения пространства ключей между ними. Этот подход требует своего рода внешнего мониторинга работоспособности узлов и требует ручной перебалансировки пространства ключей при добавлении или удалении узлов:
$ parameters = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' cluster ' => ' predis ' ];
$ client = new Predis Client ( $ parameters );
Вместе с Redis 3.0 был представлен новый контролируемый и скоординированный тип кластеризации — redis-cluster. В таком подходе используется другой алгоритм для распределения пространств ключей, при этом узлы Redis координируют себя, взаимодействуя через протокол сплетен для обработки состояния работоспособности, ребалансировки, обнаружения узлов и перенаправления запросов. Чтобы подключиться к кластеру, управляемому redis-cluster, клиенту требуется список его узлов (не обязательно полный, поскольку при необходимости он автоматически обнаруживает новые узлы) и параметры клиента cluster
установленные на redis
:
$ parameters = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' cluster ' => ' redis ' ];
$ client = new Predis Client ( $ parameters , $ options );
Клиент может быть настроен для работы в режиме «один главный / несколько подчиненных», чтобы обеспечить лучшую доступность услуг. При использовании репликации Predis распознает команды только для чтения и отправляет их случайному ведомому устройству, чтобы обеспечить своего рода балансировку нагрузки, и переключается на ведущее устройство, как только обнаруживает команду, выполняющую любую операцию, которая в конечном итоге может привести к изменению пространство ключей или значение ключа. Вместо того, чтобы выдавать ошибку соединения при сбое ведомого устройства, клиент пытается вернуться к другому ведомому устройству из числа тех, которые предусмотрены в конфигурации.
Базовая конфигурация, необходимая для использования клиента в режиме репликации, требует, чтобы один сервер Redis был идентифицирован как главный (это можно сделать с помощью параметров соединения, установив для параметра role
значение master
) и один или несколько подчиненных серверов (в данном случае установив role
в качестве slave
для рабов необязательно):
$ parameters = [ ' tcp://10.0.0.1?role=master ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => ' predis ' ];
$ client = new Predis Client ( $ parameters , $ options );
Приведенная выше конфигурация имеет статический список серверов и полностью полагается на логику клиента, но можно положиться на redis-sentinel
для создания более надежной среды высокой доступности, где дозорные серверы будут выступать в качестве источника полномочий для клиентов при обнаружении сервисов. Минимальная конфигурация, необходимая клиенту для работы с redis-sentinel, — это список параметров подключения, указывающий на группу экземпляров Sentinel, опция replication
установленная на sentinel
, и опция service
, установленная на имя службы:
$ sentinels = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => ' sentinel ' , ' service ' => ' mymaster ' ];
$ client = new Predis Client ( $ sentinels , $ options );
Если главный и подчиненный узлы настроены на требование аутентификации от клиентов, необходимо указать пароль с помощью опции клиента глобальных parameters
. Эту опцию также можно использовать для указания другого индекса базы данных. Тогда массив параметров клиента будет выглядеть так:
$ options = [
' replication ' => ' sentinel ' ,
' service ' => ' mymaster ' ,
' parameters ' => [
' password ' => $ secretpassword ,
' database ' => 10 ,
],
];
Хотя Predis способен различать команды, выполняющие операции записи и только чтения, EVAL
и EVALSHA
представляют собой крайний случай, в котором клиент переключается на главный узел, поскольку он не может определить, когда сценарий Lua безопасно выполнять на подчиненных устройствах. Хотя это действительно поведение по умолчанию, когда определенные сценарии Lua не выполняют операции записи, можно предоставить подсказку, чтобы клиент придерживался подчиненных устройств для их выполнения:
$ parameters = [ ' tcp://10.0.0.1?role=master ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' replication ' => function () {
// Set scripts that won't trigger a switch from a slave to the master node.
$ strategy = new Predis Replication ReplicationStrategy ();
$ strategy -> setScriptReadOnly ( $ LUA_SCRIPT );
return new Predis Connection Replication MasterSlaveReplication ( $ strategy );
}];
$ client = new Predis Client ( $ parameters , $ options );
$ client -> eval ( $ LUA_SCRIPT , 0 ); // Sticks to slave using `eval`...
$ client -> evalsha ( sha1 ( $ LUA_SCRIPT ), 0 ); // ... and `evalsha`, too.
Каталог examples
содержит несколько сценариев, демонстрирующих, как можно настроить клиент и использовать его для использования репликации как в базовых, так и в сложных сценариях.
Конвейерная обработка может помочь повысить производительность, когда на сервер необходимо отправить много команд, за счет уменьшения задержки, вызванной временем прохождения в сети. Конвейерная обработка также работает с агрегатными соединениями. Клиент может выполнить конвейер внутри вызываемого блока или вернуть экземпляр конвейера с возможностью связывания команд благодаря гибкому интерфейсу:
// Executes a pipeline inside the given callable block:
$ responses = $ client -> pipeline ( function ( $ pipe ) {
for ( $ i = 0 ; $ i < 1000 ; $ i ++) {
$ pipe -> set ( " key: $ i " , str_pad ( $ i , 4 , ' 0 ' , 0 ));
$ pipe -> get ( " key: $ i " );
}
});
// Returns a pipeline that can be chained thanks to its fluent interface:
$ responses = $ client -> pipeline ()-> set ( ' foo ' , ' bar ' )-> get ( ' foo ' )-> execute ();
Клиент предоставляет абстракцию для транзакций Redis на основе MULTI
и EXEC
с интерфейсом, аналогичным командным конвейерам:
// Executes a transaction inside the given callable block:
$ responses = $ client -> transaction ( function ( $ tx ) {
$ tx -> set ( ' foo ' , ' bar ' );
$ tx -> get ( ' foo ' );
});
// Returns a transaction that can be chained thanks to its fluent interface:
$ responses = $ client -> transaction ()-> set ( ' foo ' , ' bar ' )-> get ( ' foo ' )-> execute ();
Эта абстракция может выполнять операции проверки и установки благодаря WATCH
и UNWATCH
и обеспечивает автоматические повторы транзакций, прерванных Redis при касании клавиш WATCH
ed. Пример транзакции с использованием CAS вы можете увидеть в следующем примере.
Хотя мы стараемся обновлять Predis, чтобы быть в курсе всех команд, доступных в Redis, вы можете предпочесть использовать старую версию библиотеки или предоставить другой способ фильтрации аргументов или анализа ответов для определенных команд. Для этого Predis предоставляет возможность реализовывать новые классы команд для определения или переопределения команд в фабрике команд по умолчанию, используемой клиентом:
// Define a new command by extending PredisCommandCommand:
class BrandNewRedisCommand extends Predis Command Command
{
public function getId ()
{
return ' NEWCMD ' ;
}
}
// Inject your command in the current command factory:
$ client = new Predis Client ( $ parameters , [
' commands ' => [
' newcmd ' => ' BrandNewRedisCommand ' ,
],
]);
$ response = $ client -> newcmd ();
Существует также метод отправки необработанных команд без фильтрации их аргументов и анализа ответов. Пользователи должны предоставить список аргументов команды в виде массива, следуя сигнатурам, определенным в документации Redis для команд:
$ response = $ client -> executeRaw ([ ' SET ' , ' foo ' , ' bar ' ]);
Хотя в Redis 2.6+ можно использовать сценарии Lua напрямую, используя EVAL
и EVALSHA
, Predis предлагает команды сценариев как абстракцию более высокого уровня, построенную на их основе, чтобы упростить задачу. Команды сценария могут быть зарегистрированы в фабрике команд, используемой клиентом, и доступны, как если бы они были простыми командами Redis, но они определяют сценарии Lua, которые передаются на сервер для удаленного выполнения. Внутри они по умолчанию используют EVALSHA
и идентифицируют скрипт по его хешу SHA1 для экономии пропускной способности, но EVAL
используется в качестве запасного варианта при необходимости:
// Define a new script command by extending PredisCommandScriptCommand:
class ListPushRandomValue extends Predis Command ScriptCommand
{
public function getKeysCount ()
{
return 1 ;
}
public function getScript ()
{
return <<<LUA
math.randomseed(ARGV[1])
local rnd = tostring(math.random())
redis.call('lpush', KEYS[1], rnd)
return rnd
LUA ;
}
}
// Inject the script command in the current command factory:
$ client = new Predis Client ( $ parameters , [
' commands ' => [
' lpushrand ' => ' ListPushRandomValue ' ,
],
]);
$ response = $ client -> lpushrand ( ' random_values ' , $ seed = mt_rand ());
Predis может использовать разные серверные части подключения для подключения к Redis. Встроенная интеграция Relay использует расширение Relay для PHP для значительного повышения производительности за счет кэширования частичной копии набора данных Redis в общей памяти времени выполнения PHP.
$ client = new Predis Client ( ' tcp://127.0.0.1 ' , [
' connections ' => ' relay ' ,
]);
Разработчики могут создавать свои собственные классы подключения для поддержки совершенно новых сетевых серверов, расширять существующие классы или предоставлять совершенно другие реализации. Классы подключения должны реализовывать PredisConnectionNodeConnectionInterface
или расширять PredisConnectionAbstractConnection
:
class MyConnectionClass implements Predis Connection NodeConnectionInterface
{
// Implementation goes here...
}
// Use MyConnectionClass to handle connections for the `tcp` scheme:
$ client = new Predis Client ( ' tcp://127.0.0.1 ' , [
' connections ' => [ ' tcp ' => ' MyConnectionClass ' ],
]);
Для более глубокого понимания того, как создавать новые серверные части соединений, вы можете обратиться к фактической реализации стандартных классов соединений, доступных в пространстве имен PredisConnection
.
Вклад в Predis высоко ценится либо в виде запросов на включение новых функций, исправлений ошибок, либо просто отчетов об ошибках. Мы только просим вас придерживаться шаблонов задач и запросов на включение.
ВНИМАНИЕ : Никогда не запускайте набор тестов, поставляемый с Predis, на экземплярах Redis, работающих в производственных средах или содержащих интересующие вас данные!
Predis имеет комплексный набор тестов, охватывающий все аспекты библиотеки, который при необходимости может выполнять интеграционные тесты для работающего экземпляра Redis (требуется >= 2.4.0 для проверки правильности поведения реализации каждой команды. Интеграционные тесты для неподдерживаемых Команды Redis автоматически пропускаются. Если Redis не запущен, интеграционные тесты можно отключить. Дополнительные сведения о тестировании этой библиотеки см. в файле README тестов.
Predis использует GitHub Actions для непрерывной интеграции, а историю прошлых и текущих сборок можно найти на странице действий.
Код для Predis распространяется на условиях лицензии MIT (см. ЛИЦЕНЗИЯ).