Um cliente Redis flexível e completo para PHP 7.2 e mais recente.
Mais detalhes sobre este projeto podem ser encontrados nas perguntas frequentes.
EVALSHA
ou EVAL
.SCAN
, SSCAN
, ZSCAN
e HSCAN
(Redis >= 2.8) baseada em iteradores PHP.Esta biblioteca pode ser encontrada no Packagist para facilitar o gerenciamento de dependências de projetos usando o Composer. Arquivos compactados de cada versão estão disponíveis no GitHub.
composer require predis/predis
Predis conta com os recursos de carregamento automático do PHP para carregar seus arquivos quando necessário e está em conformidade com o padrão PSR-4. O carregamento automático é tratado automaticamente quando as dependências são gerenciadas através do Composer, mas também é possível aproveitar seu próprio carregador automático em projetos ou scripts sem qualquer recurso de carregamento automático:
// Prepend a base path if Predis is not available in your "include_path".
require ' Predis/Autoloader.php ' ;
Predis Autoloader:: register ();
Ao criar uma instância cliente sem passar nenhum parâmetro de conexão, o Predis assume 127.0.0.1
e 6379
como host e porta padrão. O tempo limite padrão para a operação connect()
é de 5 segundos:
$ client = new Predis Client ();
$ client -> set ( ' foo ' , ' bar ' );
$ value = $ client -> get ( ' foo ' );
Os parâmetros de conexão podem ser fornecidos na forma de strings URI ou matrizes nomeadas. A última é a forma preferida de fornecer parâmetros, mas as strings URI podem ser úteis quando os parâmetros são lidos de fontes não estruturadas ou parcialmente estruturadas:
// 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 ' );
Servidores protegidos por senha podem ser acessados adicionando password
aos parâmetros definidos. Quando as ACLs estão habilitadas no Redis >= 6.0, username
e password
são necessários para autenticação do usuário.
Também é possível conectar-se a instâncias locais do Redis usando soquetes de domínio UNIX, neste caso os parâmetros devem usar o esquema unix
e especificar um caminho para o arquivo de soquete:
$ client = new Predis Client ([ ' scheme ' => ' unix ' , ' path ' => ' /path/to/redis.sock ' ]);
$ client = new Predis Client ( ' unix:/path/to/redis.sock ' );
O cliente pode aproveitar a criptografia TLS/SSL para se conectar a instâncias remotas seguras do Redis sem a necessidade de configurar um proxy SSL como o stunnel. Isso pode ser útil ao conectar-se a nós executados em vários provedores de hospedagem em nuvem. A criptografia pode ser habilitada usando o esquema tls
e uma série de opções adequadas passadas por meio do parâmetro 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 ' );
Os esquemas de conexão redis
(alias de tcp
) e rediss
(alias de tls
) também são suportados, com a diferença de que as strings URI contendo esses esquemas são analisadas seguindo as regras descritas em seus respectivos documentos de registro provisórios da IANA.
A lista real de parâmetros de conexão suportados pode variar dependendo de cada back-end de conexão, portanto, é recomendável consultar a documentação ou implementação específica para obter detalhes.
O Predis pode agregar múltiplas conexões ao fornecer uma matriz de parâmetros de conexão e a opção apropriada para instruir o cliente sobre como agregá-los (clustering, replicação ou uma lógica de agregação personalizada). Matrizes nomeadas e strings URI podem ser misturadas ao fornecer configurações para cada nó:
$ client = new Predis Client ([
' tcp://10.0.0.1?alias=first-node ' , [ ' host ' => ' 10.0.0.2 ' , ' alias ' => ' second-node ' ],
], [
' cluster ' => ' predis ' ,
]);
Consulte a seção de conexões agregadas deste documento para obter mais detalhes.
As conexões com o Redis são preguiçosas, o que significa que o cliente se conecta a um servidor somente se e quando necessário. Embora seja recomendado deixar o cliente fazer suas próprias coisas nos bastidores, pode haver momentos em que ainda é desejado ter controle de quando a conexão é aberta ou fechada: isso pode ser facilmente alcançado invocando $client->connect()
e $client->disconnect()
. Observe que o efeito desses métodos nas conexões agregadas pode diferir dependendo de cada implementação específica.
Muitos aspectos e comportamentos do cliente podem ser configurados passando opções específicas do cliente para o segundo argumento de PredisClient::__construct()
:
$ client = new Predis Client ( $ parameters , [ ' prefix ' => ' sample: ' ]);
As opções são gerenciadas usando um contêiner semelhante a um mini DI e seus valores podem ser inicializados lentamente apenas quando necessário. As opções de cliente suportadas por padrão no Predis são:
prefix
: string de prefixo aplicada a cada chave encontrada nos comandos.exceptions
: se o cliente deve lançar ou retornar respostas em caso de erros do Redis.connections
: lista de back-ends de conexão ou uma instância de connection factory.cluster
: especifica um backend de cluster ( predis
, redis
ou callable).replication
: especifica um backend de replicação ( predis
, sentinel
ou callable).aggregate
: configura o cliente com uma conexão agregada personalizada (chamável).parameters
: lista de parâmetros de conexão padrão para conexões agregadas.commands
: especifica uma instância de fábrica de comandos para usar por meio da biblioteca.Os usuários também podem fornecer opções personalizadas com valores ou objetos que podem ser chamados (para inicialização lenta) que são armazenados no contêiner de opções para uso posterior por meio da biblioteca.
As conexões agregadas são a base sobre a qual o Predis implementa clustering e replicação e são usadas para agrupar várias conexões em nós únicos do Redis e ocultar a lógica específica necessária para tratá-las adequadamente, dependendo do contexto. As conexões agregadas geralmente exigem uma série de parâmetros de conexão junto com a opção de cliente apropriada ao criar uma nova instância de cliente.
O Predis pode ser configurado para funcionar em modo de cluster com uma abordagem tradicional de fragmentação do lado do cliente para criar um cluster de nós independentes e distribuir o keyspace entre eles. Esta abordagem precisa de algum tipo de monitoramento externo da saúde dos nós e exige que o keyspace seja reequilibrado manualmente quando os nós são adicionados ou removidos:
$ parameters = [ ' tcp://10.0.0.1 ' , ' tcp://10.0.0.2 ' , ' tcp://10.0.0.3 ' ];
$ options = [ ' cluster ' => ' predis ' ];
$ client = new Predis Client ( $ parameters );
Junto com o Redis 3.0, um novo tipo de cluster supervisionado e coordenado foi introduzido na forma de redis-cluster. Esse tipo de abordagem usa um algoritmo diferente para distribuir os espaços-chave, com os nós Redis coordenando-se comunicando-se por meio de um protocolo de fofoca para lidar com o status de integridade, reequilíbrio, descoberta de nós e redirecionamento de solicitação. Para se conectar a um cluster gerenciado pelo redis-cluster, o cliente requer uma lista de seus nós (não necessariamente completa, pois descobrirá automaticamente novos nós, se necessário) e as opções do cliente cluster
definidas como 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 );
O cliente pode ser configurado para operar em uma configuração de mestre único/escravos múltiplos para fornecer melhor disponibilidade de serviço. Ao usar a replicação, o Predis reconhece comandos somente leitura e os envia para um escravo aleatório a fim de fornecer algum tipo de balanceamento de carga e muda para o mestre assim que detecta um comando que executa algum tipo de operação que acabaria modificando o keyspace ou o valor de uma chave. Em vez de gerar um erro de conexão quando um escravo falha, o cliente tenta retornar para um escravo diferente dentre os fornecidos na configuração.
A configuração básica necessária para usar o cliente no modo de replicação requer que um servidor Redis seja identificado como mestre (isso pode ser feito através de parâmetros de conexão definindo o parâmetro role
como master
) e um ou mais escravos (neste caso definindo role
como slave
para escravos é opcional):
$ 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 );
A configuração acima possui uma lista estática de servidores e depende inteiramente da lógica do cliente, mas é possível contar com redis-sentinel
para um ambiente de HA mais robusto, com servidores sentinela atuando como fonte de autoridade para clientes para descoberta de serviço. A configuração mínima exigida pelo cliente para trabalhar com redis-sentinel é uma lista de parâmetros de conexão apontando para várias instâncias sentinela, a opção replication
definida como sentinel
e a opção service
definida como o nome do serviço:
$ 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 );
Se os nós mestre e escravo estiverem configurados para exigir autenticação dos clientes, uma senha deverá ser fornecida através da opção de cliente parameters
globais. Esta opção também pode ser usada para especificar um índice de banco de dados diferente. A matriz de opções do cliente ficaria assim:
$ options = [
' replication ' => ' sentinel ' ,
' service ' => ' mymaster ' ,
' parameters ' => [
' password ' => $ secretpassword ,
' database ' => 10 ,
],
];
Embora o Predis seja capaz de distinguir comandos que executam operações de gravação e somente leitura, EVAL
e EVALSHA
representam um caso extremo em que o cliente muda para o nó mestre porque não pode dizer quando um script Lua é seguro para ser executado em escravos. Embora este seja de fato o comportamento padrão, quando certos scripts Lua não executam operações de gravação, é possível fornecer uma dica para dizer ao cliente para usar escravos para sua execução:
$ 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.
O diretório de examples
contém alguns scripts que demonstram como o cliente pode ser configurado e usado para aproveitar a replicação em cenários básicos e complexos.
O pipeline pode ajudar no desempenho quando muitos comandos precisam ser enviados a um servidor, reduzindo a latência introduzida pelos tempos de ida e volta da rede. Pipelining também funciona com conexões agregadas. O cliente pode executar o pipeline dentro de um bloco que pode ser chamado ou retornar uma instância do pipeline com a capacidade de encadear comandos graças à sua interface fluente:
// 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 ();
O cliente fornece uma abstração para transações Redis baseadas em MULTI
e EXEC
com uma interface semelhante para comandar pipelines:
// 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 ();
Essa abstração pode realizar operações de verificação e configuração graças a WATCH
e UNWATCH
e fornece novas tentativas automáticas de transações abortadas pelo Redis quando as teclas WATCH
ed são tocadas. Para obter um exemplo de transação usando CAS, você pode ver o exemplo a seguir.
Embora tentemos atualizar o Predis para nos mantermos atualizados com todos os comandos disponíveis no Redis, talvez você prefira ficar com uma versão antiga da biblioteca ou fornecer uma maneira diferente de filtrar argumentos ou analisar respostas para comandos específicos. Para conseguir isso, o Predis oferece a capacidade de implementar novas classes de comando para definir ou substituir comandos na fábrica de comandos padrão usada pelo cliente:
// 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 ();
Também existe um método para enviar comandos brutos sem filtrar seus argumentos ou analisar respostas. Os usuários devem fornecer a lista de argumentos do comando como uma matriz, seguindo as assinaturas definidas pela documentação do Redis para comandos:
$ response = $ client -> executeRaw ([ ' SET ' , ' foo ' , ' bar ' ]);
Embora seja possível aproveitar o script Lua no Redis 2.6+ usando diretamente EVAL
e EVALSHA
, o Predis oferece comandos de script como uma abstração de nível superior construída sobre eles para simplificar as coisas. Os comandos de script podem ser registrados na fábrica de comandos usada pelo cliente e são acessíveis como se fossem comandos simples do Redis, mas definem scripts Lua que são transmitidos ao servidor para execução remota. Internamente, eles usam EVALSHA
por padrão e identificam um script por seu hash SHA1 para economizar largura de banda, mas EVAL
é usado como alternativa quando necessário:
// 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 ());
O Predis pode usar diferentes back-ends de conexão para se conectar ao Redis. A integração interna do Relay aproveita a extensão Relay para PHP para obter grandes ganhos de desempenho, armazenando em cache uma réplica parcial do conjunto de dados Redis na memória de tempo de execução compartilhada do PHP.
$ client = new Predis Client ( ' tcp://127.0.0.1 ' , [
' connections ' => ' relay ' ,
]);
Os desenvolvedores podem criar suas próprias classes de conexão para oferecer suporte a back-ends de rede totalmente novos, estender classes existentes ou fornecer implementações completamente diferentes. As classes de conexão devem implementar PredisConnectionNodeConnectionInterface
ou estender 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 ' ],
]);
Para obter uma visão mais aprofundada sobre como criar novos back-ends de conexão, você pode consultar a implementação real das classes de conexão padrão disponíveis no namespace PredisConnection
.
As contribuições para o Predis são muito apreciadas na forma de solicitações pull para novos recursos, correções de bugs ou apenas relatórios de bugs. Pedimos apenas que você siga os modelos de emissão e pull request.
ATENÇÃO : Nunca execute o conjunto de testes fornecido com o Predis em instâncias do Redis em execução em ambientes de produção ou contendo dados de seu interesse!
O Predis possui um conjunto de testes abrangente que cobre todos os aspectos da biblioteca e que pode opcionalmente realizar testes de integração em uma instância do Redis em execução (obrigatório> = 2.4.0 para verificar o comportamento correto da implementação de cada comando. Testes de integração para não suportados Os comandos do Redis são ignorados automaticamente. Se você não tiver o Redis instalado e em execução, os testes de integração poderão ser desativados.
Predis usa GitHub Actions para integração contínua e o histórico de compilações anteriores e atuais pode ser encontrado em sua página de ações.
O código do Predis é distribuído sob os termos da licença do MIT (ver LICENÇA).