glukkkk / laravel-redis-sentinel-drivers
Redis Sentinel integration for Laravel and Lumen.
Requires
- php: >=5.6.4
- illuminate/cache: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/contracts: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/queue: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/redis: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/session: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- illuminate/support: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- predis/predis: ^2.0
- s-borchev/spicy-identifiers: ^0.1.1
Requires (Dev)
- laravel/framework: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- laravel/horizon: ^1.0 || ^2.0 || ^3.0 || ^4.0
- laravel/lumen-framework: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0
- mockery/mockery: ^1.3
- phpunit/phpunit: ^5.0
README
Redis Sentinel integration for Laravel and Lumen.
Redis Sentinel facilitates high-availability, monitoring, and load-balancing for Redis servers configured for master-slave replication. Laravel includes built-in support for Redis, but we cannot configure Sentinel setups flexibly out-of-the-box. This limits configuration of Sentinel to a single service.
For instance, if we wish to use Redis behind Sentinel for both the cache and session in Laravel's API, we cannot set separate Redis databases for for both types of data like we can in a standard, single-server Redis setup without Sentinel. This causes issues when we need to clear the cache, because Laravel erases stored session information as well.
This package wraps the configuration of Laravel's broadcasting, cache, session, and queue APIs for Sentinel with the ability to set options for our Redis services independently. It adds Sentinel support for Laravel Horizon and fixes other compatibility issues.
We configure the package separately from Laravel's standard Redis configuration so we can choose to use the Sentinel connections as needed by the environment. A developer may use a standalone Redis server in their local environment, while production environments operate a Redis Sentinel set of servers.
Contents
- Quickstart (TL;DR)
- Requirements
- Installation
- Configuration Options
- Override the Standard Redis API
- Executing Redis Commands (RedisSentinel Facade)
- Other Sentinel Considerations
- Laravel Horizon
- Testing
- License
- Appendix: Environment Variables
- Appendix: Configuration Examples
Requirements
- PHP 5.4 or greater
- Redis 2.8 or greater (for Sentinel support)
- Predis 1.1 or greater (for Sentinel client support)
- Laravel or Lumen 5.0 or greater (4.x doesn't support the required Predis version)
Note: Laravel 5.4 introduced the ability to use the PhpRedis extension as a Redis client for the framework. This package does not yet support the PhpRedis option.
This Readme assumes prior knowledge of configuring Redis for Redis Sentinel and using Redis with Laravel or Lumen.
Installation
We're using Laravel, so we'll install through Composer, of course!
For Laravel/Lumen 5.4 and above:
composer require monospice/laravel-redis-sentinel-drivers
For Laravel/Lumen 5.3 and below:
composer require monospice/laravel-redis-sentinel-drivers:^1.0
Note: According to the Laravel release schedule, all Laravel versions prior
to 5.4 exited their active development and support periods in August of 2017.
After December, 2017, this package will no longer provide feature releases on
the 1.x
branch for Laravel versions earlier than 5.4.
If the project does not already use Redis with Laravel, this will install the Predis package as well.
Register the Service Provider
Laravel 5.5 brings package discovery! No service provider registration required in Laravel 5.5+.
To use the drivers in Laravel 5.4 and below, add the package's service provider to config/app.php:
'providers' => [ ... Monospice\LaravelRedisSentinel\RedisSentinelServiceProvider::class, ... ],
In Lumen, register the service provider in bootstrap/app.php:
$app->register(Monospice\LaravelRedisSentinel\RedisSentinelServiceProvider::class);
Quickstart (TL;DR)
After installing the package, set the following in .env:
CACHE_DRIVER=redis-sentinel SESSION_DRIVER=redis-sentinel QUEUE_CONNECTION=redis-sentinel # Laravel >= 5.7 QUEUE_DRIVER=redis-sentinel # Laravel <= 5.6 REDIS_DRIVER=redis-sentinel REDIS_HOST=sentinel1.example.com, sentinel2.example.com, 10.0.0.1, etc. REDIS_PORT=26379 REDIS_SENTINEL_SERVICE=mymaster # or your Redis master group name REDIS_CACHE_DATABASE=1 REDIS_SESSION_DATABASE=2 REDIS_QUEUE_DATABASE=3
The following should now use Redis Sentinel connections:
Redis::get('key'); Cache::get('key'); Session::get('key'); Queue::push(new Job());
This example configures the package through the environment. It
overrides Laravel's standard Redis API by setting
REDIS_DRIVER
to redis-sentinel
. See appendix for all of
the configurable environment variables. Optionally, enable the RedisSentinel
facade.
For those that need a quick development Sentinel server cluster, try the start-cluster.sh script included with the package's testing files.
Configuration
We can configure the package three ways depending on the needs of the application:
A hybrid configuration uses two or more of these methods.
With the release of version 2.2.0, the package supports simple configuration through environment variables with a default configuration structure suitable for many applications. This especially relieves Lumen users of the need to create several config files that may not already exist with an initial Lumen installation.
The package continues to support advanced configuration through standard config files without requiring changes for existing projects.
Environment-Based Configuration
For suitable applications, the package's ability to configure itself from the environment eliminates the need to create or modify configuration files in many scenarios. The package automatically configures Redis Sentinel connections and the application broadcasting, cache, session, and queue services for these connections using environment variables.
Developers may still configure the package through standard Laravel configuration files when the application requirements exceed the package's automatic configuration capacity.
Typically, we assign the application environment variables in the project's .env file during development. The configuration for a basic application may be as simple as setting the following values in this file:
REDIS_HOST=sentinel.example.com REDIS_PORT=26379 REDIS_SENTINEL_SERVICE=mymaster
This sets up the default Redis Sentinel connection for the package's services
that we can access through the RedisSentinel
facade (or by
resolving app('redis-sentinel')
from the container) like we would for
Laravel's standard Redis API. To use this Sentinel
connection for Laravel's broadcasting, cache, session, or queue services,
change the following values as well:
BROADCAST_DRIVER=redis-sentinel CACHE_DRIVER=redis-sentinel SESSION_DRIVER=redis-sentinel QUEUE_CONNECTION=redis-sentinel # Laravel >= 5.7 QUEUE_DRIVER=redis-sentinel # Laravel <= 5.6
Connection-Specific Configuration
In many cases, we'd set different connection parameters for the application broadcasts, cache, session, and queue. We may configure different Redis databases for our cache and session (so that clearing the cache doesn't erase our user session information), and the Redis servers that contain the application queue may reside behind a different Sentinel service (master group name):
REDIS_CACHE_DATABASE=1 REDIS_SESSION_DATABASE=2 REDIS_QUEUE_SERVICE=queue-service
Specifying Multiple Hosts
To supply multiple hosts for a connection through environment variables, set
the value of any *_HOST
variable to a comma-seperated string of hostnames or
IP addresses:
REDIS_HOST=sentinel1.example.com, sentinel2.example.com, ... REDIS_CACHE_HOST=10.0.0.1, 10.0.0.2, 10.0.0.3 REDIS_QUEUE_HOST=tcp://10.0.0.4:26379, tcp://10.0.0.4:26380, ...
Hosts share the port set for the connection unless we explicitly include the port number after the hostname as shown.
Mixed Applications
The previous examples set the REDIS_HOST
and REDIS_PORT
variables, which
Laravel also reads to configure standard Redis connections. This enables
developers to use the same variables in development,
with a single Redis server, and in production, with a full set of Sentinel
servers. However, if an application contains code that sends requests to both
Redis and Sentinel connections in the same environment, we must assign one or
more of the Sentinel-specific variables instead:
REDIS_SENTINEL_HOST=sentinel.example.com REDIS_SENTINEL_PORT=26379 REDIS_SENTINEL_PASSWORD=secret REDIS_SENTINEL_DATABASE=0
Other Environment Configuration Options
We can change the value of REDIS_DRIVER
to redis-sentinel
to override the
standard Laravel Redis API.
For a full list of the environment variables this package consumes, see the appendix. Check out the package's internal configuration file or the environment-based configuration examples to better understand how the package uses environment variables.
Using Standard Configuration Files
In addition to environment-based configuration, the package allows developers to configure Redis Sentinel integration through Laravel's standard configuration files. This option exists for cases when applications require more advanced or specialized Sentinel configuration than the package's default environment-based configuration can provide.
For this configuration method, we'll modify the following config files:
- config/database.php - to define the Redis Sentinel connections
- config/broadcasting.php - to define the Redis Sentinel broadcaster
- config/cache.php - to define a Redis Sentinel cache store
- config/session.php - to set the Redis Sentinel connection for sessions
- config/queue.php - to define a Redis Sentinel queue connection
Note: Lumen users may create a package config file instead to avoid the need to create all of the above files if they don't exist.
When environment-based configuration satisfies the needs of the application, we do not need to modify any config files. The code illustrated in the following sections overrides the package's automatic configuration.
Redis Sentinel Connection Configuration
We'll configure the Redis Sentinel database connections separately from
Laravel's default Redis database connection. This enables us to use Laravel's
standard Redis functionality side-by-side if needed, such as if a developer
runs a single Redis server in their local environment, while the production
environment operates a full set of Redis and Sentinel servers. We don't need to
remove the 'redis'
driver config block that ships with Laravel by default.
Note: Laravel passes these configuration options to the Predis client library, so we can include advanced configuration options here if needed. See the Predis documentation for more information.
Basic Configuration
For a simple setup with a single Sentinel server, add the following block to
config/database.php for the 'redis-sentinel'
database driver.
'redis-sentinel' => [ 'default' => [ [ 'host' => env('REDIS_HOST', 'localhost'), 'port' => env('REDIS_PORT', 26379), ], ], 'options' => [ 'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'), 'parameters' => [ 'password' => env('REDIS_PASSWORD', null), 'database' => 0, ], ], ],
As you can see, our 'default'
connection includes the address or hostname of
the Sentinel server and the port that the application connects to (typically
26379). Because Sentinel doesn't support authentication directly, we'll set the
password for our Redis server in the 'parameters'
array, which also includes
the Redis database to use for the connection. The 'service'
option declares
the service name of the set of Redis servers configured in Sentinel as a
service.
Take note of the sub-array in the top level array for the 'default'
connection. If we choose to add additional Sentinel servers to this
configuration, we'll wrap the definition of each host in another array, like we
can see in the following section.
Of course, be sure to add the environment configuration variables from the example above to .env.
Advanced Configuration
The configuration block above is almost a drop-in replacement for Laravel's
built-in 'redis'
connection configuration that we could use to configure an
application for Sentinel without this package. However, we cannot configure
Laravel's standard Redis connections for anything more complex than this basic
Sentinel setup because of limitations in the way Laravel parses its Redis
configuration. A single Sentinel server or connection is typically insufficient
for highly-available or complex applications. Read the examples in the
appendix for more robust configuration instructions:
Other Sentinel Connection Options
The Predis client supports some additional configuration options that determine
how it handles connections to Sentinel servers. We can add these to the global
'options'
array for all Sentinel connections or to a local 'options'
array
for a single connection. The default values are shown below:
'options' => [ ... // The default amount of time (in seconds) the client waits before // determining that a connection attempt to a Sentinel server failed. 'sentinel_timeout' => 0.100, // The default number of attempts to retry a command when the client fails // to connect to a Redis or Sentinel server. A value of 0 instructs the // client to throw an exception after the first failed attempt, while a // value of -1 causes the client to continue to retry commands indefinitely. 'retry_limit' => 20, // The default amount of time (in milliseconds) that the client waits before // attempting to contact another Sentinel server or retry a command if the // previous server did not respond. 'retry_wait' => 1000, // Instructs the client to query the first reachable Sentinel server for an // updated set of Sentinels each time the client needs to establish a // connection with a Redis master or replica. 'update_sentinels' => false, ],
Broadcasting, Cache, Session, and Queue Drivers
After configuring the Sentinel database connections, we can instruct Laravel to use these connections for the application's other redis-enabled services. Remember that we don't need to set Sentinel connections for all of these services. We could select a standard Redis connection for one and a Sentinel connection for another, if desired, but we likely want to take advantage of Sentinel for all of our Redis connections if it's available.
Note: We can omit (or remove) the following configuration blocks entirely and the package will configure these services for us. If we created custom Sentinel connections as above, we may need to declare those connection names.
Broadcasting
Add the following connection definition to config/broadcasting.php in the
'connections'
array:
'connections' => [ ... 'redis-sentinel' => [ 'driver' => 'redis-sentinel', 'connection' => 'default', ], ],
...and change the BROADCAST_DRIVER
environment variable to redis-sentinel
in .env.
If the application contains a specific connection in the 'redis-sentinel'
database configuration for the event broadcasting, replace 'default'
with its
name.
Cache
Add the following store definition to config/cache.php in the 'stores'
array:
'stores' => [ ... 'redis-sentinel' => [ 'driver' => 'redis-sentinel', 'connection' => 'default', ], ],
...and change the CACHE_DRIVER
environment variable to redis-sentinel
in
.env.
If the application contains a specific connection in the 'redis-sentinel'
database configuration for the cache, replace 'default'
with its name.
Session
Change the SESSION_DRIVER
environment variable to redis-sentinel
in .env.
Then, in config/session.php, set the 'connection'
directive to 'default'
,
or the name of the specific connection created for storing sessions from the
'redis-sentinel'
database configuration.
Queue
Add the following connection definition to config/queue.php in the
'connections'
array:
'connections' => [ ... 'redis-sentinel' => [ 'driver' => 'redis-sentinel', 'connection' => 'default', 'queue' => 'default', 'retry_after' => 90, // Laravel >= 5.4.30 'expire' => 90, // Laravel < 5.4.30 ], ],
...and change the QUEUE_CONNECTION
(Laravel 5.7+) or QUEUE_DRIVER
(Laravel
<= 5.6) environment variable to redis-sentinel
in .env.
If the application contains a specific connection in the 'redis-sentinel'
database configuration for the queue, replace 'connection' => 'default'
with
its name.
Using a Package Configuration File
Lumen projects don't include configuration files by default. Instead, by convention, Lumen reads configuration information from the environment. If we wish to configure this package through config files as described in the previous section, rather than using the environment-based configuration, we can add a single package configuration file: config/redis-sentinel.php. This alleviates the need to create several standard config files in Lumen.
The package configuration file contains elements that the package merges back into the main configuration locations at runtime. To illustrate, when the custom redis-sentinel.php file contains:
return [ 'database' => 'redis-sentinel' => [ /* ...Redis Sentinel connections... */ ] ] ];
...the package will set the database.redis-sentinel
configuration value from
the value of redis-sentinel.database.redis-sentinel
when the application
boots unless the key already exists.
We can customize the package's internal config file by copying it into our project's config/ directory and changing the values as needed. Lumen users may need to create this directory if it doesn't exist.
A custom package config file needs only to contain the top-level elements that developer wishes to customize: in the code shown above, the custom config file only overrides the package's default configuration for Redis Sentinel connections, so the package will still automatically configure the broadcasting, cache, session, and queue services using environment variables.
Hybrid Configuration
Although unnecessary in most cases, developers may combine two or more of the configuration methods provided by this package. For example, an application may contain a standard or package config file that defines the Redis Sentinel connections, but rely on the package's automatic environment-based configuration to set up the cache, session, queue, and broadcasting services for Sentinel.
The package uses configuration data in this order of precedence:
- Standard Laravel configuration files
- A custom package configuration file
- Automatic environment-based configuration
This means that package-specific values in the standard config files override values in a custom package config file, which, in turn, override the package's default automatic configuration through environment variables. In other words, a custom package config file inherits the values from the package's default configuration that it does not explicitly declare, and the main application configuration receives the values from both of these that it does not provide in a standard config file.
Override the Standard Redis API
This package adds Redis Sentinel drivers for Laravel's caching, session, and
queue APIs, and the developer may select which of these to utilize Sentinel
connections for. However, Laravel also provides an API
for interacting with Redis directly through the Redis
facade, or through
the Redis connection manager which we can resolve through the application
container (app('redis')
, dependency injection, etc.).
When installed, this package does not impose the use of Sentinel for all Redis requests. In fact, we can choose to use Sentinel connections for some features and continue to use Laravel's standard Redis connections for others. By default, this package does not replace Laravel's built-in Redis API.
As an example, we may decide to use Sentinel connections for the application's cache and sessions, but directly interact with a single Redis server using Laravel's standard Redis connections.
That said, this package provides the option to override Laravel's Redis API so
that any Redis commands use the Sentinel connection configuration defined by
the 'redis-sentinel'
database driver.
To use this feature, add the following configuration directive to the root of
the 'redis'
connection definition in config/database.php (if not using
environment-based configuration):
'redis' => [ ... 'driver' => env('REDIS_DRIVER', 'default'), ... ],
...and add the environment variable REDIS_DRIVER
to .env with the value
redis-sentinel
.
When enabled, Redis commands executed through the Redis
facade or the redis
service (app('redis')
, etc) will operate using the Sentinel connections.
This makes it easier for developers to use a standalone Redis server in their local environments and switch to a full Sentinel set of servers in production.
Note: When using the package with Laravel Horizon, this change will cause Horizon to run over a Sentinel connection as well.
Executing Redis Commands (RedisSentinel Facade)
If we need to send Redis commands to Redis instances behind a Sentinel server
directly, such as we can through the Redis
facade, but we don't want to
override Laravel's Redis API as above, we can use the
RedisSentinel
facade provided by this package or resolve the redis-sentinel
service from the application container:
// Uses the 'default' connection defined in the 'redis-sentinel' config block: RedisSentinel::get('some-key'); app('redis-sentinel')->get('some-key'); // Uses the 'default' connection defined in the standard 'redis' config block: Redis::get('some-key'); app('redis')->get('some-key');
This provides support for uncommon use cases for which an application may need to connect to both standard Redis servers and Sentinel clusters in the same environment. When possible, follow the approach described in the previous section to uniformly connect to Sentinel throughout the application to decouple the code from the Redis implementation.
The facade is not auto-aliased in Laravel 5.5+ for future compatibility with
the PhpRedis extension. To enable the facade in Laravel, add the following
alias to the 'aliases'
array in config/app.php:
'aliases' => [ ... 'RedisSentinel' => Monospice\LaravelRedisSentinel\RedisSentinel::class, ... ],
In Lumen, add the alias to bootstrap/app.php:
class_alias('Monospice\LaravelRedisSentinel\RedisSentinel', 'RedisSentinel');
Dependency Injection
For those that prefer to declare the Redis Sentinel manager as a dependency of a class rather than using the facade, we can type-hint the interface that the container will resolve when building an object from the container:
use Monospice\LaravelRedisSentinel\Contracts\Factory as RedisSentinel; ... public function __construct(RedisSentinel $sentinel) { $sentinel->get('some-key'); }
The above explicitly requests an instance of the package's Sentinel service. If we override the Redis API, we can use the standard Redis contract instead, and the application will inject the appropriate service based on the configuration:
use Illuminate\Contracts\Redis\Factory as Redis; ... public function __construct(Redis $redis) { // Either a Sentinel connection or a standard Redis connection depending on // the value of REDIS_DRIVER or config('database.redis.driver'): $redis->get('some-key'); }
Other Sentinel Considerations
The following sections describe some characteristics to keep in mind when working with Sentinel connections.
Read and Write Operations
To spread load between available resources, the client attempts to execute read operations on Redis slave servers when initializing a connection. Commands that write data will always execute on the master server.
Transactions
All commands in a transaction, even read-only commands, execute on the master Redis server. When it makes sense to do so, avoid calling read commands within a transaction to improve load-balancing.
If a transaction aborts because of a connection failure, the package attempts
to reconnect and retry the transaction until it exhausts the configured number
of allowed attempts (retry_limit
), or until the entire transaction succeeds.
Important: Predis provides a specialized MULTI/EXEC abstraction that we can
obtain by calling transaction()
with no arguments. This API is not
protected by Sentinel connection failure handling. For high-availability, use
the Laravel API by passing a closure to transaction()
.
Publish/Subscribe
For PUB/SUB messaging, the client publishes messages to the master server. When subscribing, the package attempts to connect to a slave server first before falling-back to the master. Like with read operations, this helps to distribute the load away from the master because messages published to the master propagate to each of the slaves.
Applications with long-running subscribers need to extend the timeout of the
connection or disable it by setting read_write_timeout
to 0
. Additionally,
we also need to extend or disable the timeout
configuration directive on the
Redis servers that the application subscribes to.
When a subscriber connection fails, the package will attempt to reconnect to
another server and resume listening for messages. We may want to set the value
of retry_limit
to -1
on connections with long-running subscribers so that
the client continues to retry forever. Note that a subscriber may miss messages
published to a channel while re-establishing the connection.
Important: Predis provides a PUB/SUB consumer that we can obtain by calling
pubSubLoop()
with no arguments. This API is not protected by Sentinel
connection failure handling. For high-availability, use the Laravel API by
passing a closure to subscribe()
or psubscribe()
.
Laravel Horizon
Versions 2.4.0 and greater of this package provide for the use of Sentinel connections with the Laravel Horizon queue management tool in compatible applications (Laravel 5.5+).
After installing Horizon, we need to update some configuration settings in config/horizon.php:
If needed, change 'use' => 'default'
to the name of the Sentinel connection
to use for the Horizon backend as configured in config/database.php.
Important: The standard 'redis'
connections array in config/database.php
must contain an element with the same key as the Sentinel connection specified
for the 'use'
directive or Horizon throws an exception. Currently, Horizon
does not provide a way for this package to handle this behavior, but an
(in-progress) pull request may eliminate this requirement in the future. This
element can contain any value (but a matching Redis connection config seems
most appropriate).
Change the backend driver for Horizon's internal metadata to 'redis-sentinel'
by adding the following element to the top-level array:
'driver' => env('HORIZON_DRIVER', 'redis');
...and assign the value of redis-sentinel
to HORIZON_DRIVER
in .env.
Then, add an entry to the 'waits'
array for any Sentinel queues:
'waits' => [ ... 'redis-sentinel:default' => 60, ],
Next, change the connection driver to redis-sentinel
for each of the queue
workers that should use Sentinel connections in the 'environments'
block:
... 'supervisor-1' => [ 'connection' => 'redis-sentinel', ... ], ...
Horizon will now use the application's Redis Sentinel connections to monitor and process our queues.
Note: If we already configured the package to override Laravel's standard
Redis API (by setting REDIS_DRIVER
to redis-sentinel
,
for example), we don't need to change HORIZON_DRIVER
to 'redis-sentinel'
.
The package already routes all Redis operations through Sentinel connections.
Testing
This package includes a PHPUnit test suite with unit tests for the package's classes and an integration test suite for Sentinel-specific functionality and compatibility fixes. These tests do not verify every Redis command because Predis and Laravel both contain full test suites themselves, and because the package code simply wraps these libraries.
$ phpunit --testsuite unit $ phpunit --testsuite integration
The unit tests do not require live Redis servers. Read the next section for integration testing environment suggestions.
Note: Composer does not download this package's testing files with a normal
installation. We need to clone the package repository directly or install it
with the --prefer-source
option.
Integration Tests
This package's integration test suite validates Sentinel- and Redis-specific functionality against real servers. These tests require at least one Sentinel server that monitors a Redis master. Additionally, at least one replica should synchronize with the master for optimal test coverage. Developers may supply their own servers or start an environment using the package's tools described below.
To customize the Sentinel connection settings used by the integration tests,
copy phpunit.xml.dist to phpunit.xml and change the constants defined in
the <php>...</php>
block.
We can run the start-cluster.sh script provided in the project's root directory to spin up Redis and Sentinel servers for a testing environment. Read the script help page for usage information.
$ ./start-cluster.sh help
Docker users may wish to use the script to start testing servers in a container:
$ docker run --name redis-sentinel \ -v "$(pwd):/project" \ -w /project \ -u "$(id -u):$(id -g)" \ -e BIND_ADDRESS=0.0.0.0 \ -e SENTINEL_PORTS='26379-26381' \ -e REDIS_GROUP_1='service1 6379-6381' \ -e REDIS_GROUP_2='service2 6382-6384' \ -e LOGGING=yes \ -p 6379-6384:6379-6384 \ -p 26379-26381:26379-26381 \ --entrypoint start-cluster.sh \ redis:alpine
The package provides a Compose file with the same options for running tests:
$ export CONTAINER_USER_ID="$(id -u):$(id -g)" $ docker-compose up -d cluster $ docker-compose run --rm tests [--testsuite ...]
Developers can also customize the Compose file by copying docker-compose.yml to docker-compose.override.yml.
License
The MIT License (MIT). Please see the LICENSE File for more information.
Appendix: Environment Variables
The package consumes the following environment variables when using the default environment-based configuration. Developers only need to supply values for the variables that apply to their particular application and Redis setup. The default values are sufficient in most cases.
REDIS_{HOST,PORT,PASSWORD,DATABASE}
The basic connection parameters used by default for all Sentinel connections.
To simplify environment configuration, this package attempts to read both the
REDIS_*
and the REDIS_SENTINEL_*
environment variables that specify values
shared by multiple Sentinel connections. If an application does not execute
commands through both Redis Sentinel and standard Redis connections at the same
time, this feature allows developers to use the same environment
variale names in development (with a single Redis server) and in production
(with a full set of Sentinel servers).
REDIS_HOST
- One or more hostnames or IP addresses. Defaults tolocalhost
when unset.REDIS_PORT
- The listening port of the Sentinel servers. Defaults to26379
for Sentinel connections when unset.REDIS_PASSWORD
- The password, if any, used to authenticate with the Redis servers behind Sentinel (Sentinels don't support password auth themselves).REDIS_DATABASE
- The number of the database to select when issuing commands to the Redis servers behind Sentinel (0
to15
in a normal Redis config). Defaults to0
.
REDIS_SENTINEL_{HOST,PORT,PASSWORD,DATABASE}
Set these variables instead of the above when the application uses both standard Redis and Redis Sentinel connections at the same time.
REDIS_SENTINEL_HOST
- SeeREDIS_HOST
.REDIS_SENTINEL_PORT
- SeeREDIS_PORT
.REDIS_SENTINEL_PASSWORD
- SeeREDIS_PASSWORD
.REDIS_SENTINEL_DATABASE
- SeeREDIS_DATABASE
.
REDIS_SENTINEL_SERVICE
The Redis master group name (as specified in the Sentinel server configuration
file) that identifies the default Sentinel service used by all Sentinel
connections. Defaults to mymaster
.
Set REDIS_CACHE_SERVICE
, REDIS_SESSION_SERVICE
, or REDIS_QUEUE_SERVICE
to
override this value for a service-specific connection.
REDIS_SENTINEL_{TIMEOUT,RETRY_LIMIT,RETRY_WAIT,DISCOVERY}
The Predis client supports some additional configuration options that determine how it handles connections to Sentinel servers.
REDIS_SENTINEL_TIMEOUT
- The amount of time (in seconds) the client waits before determining that a connection attempt to a Sentinel server failed. Defaults to0.100
.REDIS_SENTINEL_RETRY_LIMIT
- The number of attempts the client tries to contact a Sentinel server before it determines that it cannot reach all Sentinel servers in a quorum. A value of0
instructs the client to throw an exception after the first failed attempt, while a value of-1
causes the client to continue to retry connections to Sentinel indefinitely. Defaults to20
.REDIS_SENTINEL_RETRY_WAIT
- The amount of time (in milliseconds) the client waits before attempting to contact another Sentinel server if the previous server did not respond. Defaults to1000
.REDIS_SENTINEL_DISCOVERY
- Instructs the client to query the first reachable Sentinel server for an updated set of Sentinels each time the client needs to establish a connection with a Redis master or slave server. Defaults tofalse
.
REDIS_DRIVER
Set the value of this variable to redis-sentinel
to override Laravel's
standard Redis API.
BROADCAST_DRIVER
, CACHE_DRIVER
, SESSION_DRIVER
, QUEUE_CONNECTION
Laravel uses these to select the backends for the application broadcasting,
cache, session, and queue services. Set the value to redis-sentinel
for each
service that the application should use Sentinel connections for.
Note: Laravel 5.7 renamed QUEUE_DRIVER
to QUEUE_CONNECTION
in the
default configuration files.
REDIS_{BROADCAST,CACHE,SESSION,QUEUE}_{HOST,PORT,PASSWORD,DATABASE,SERVICE}
These variables configure service-specific connection parameters when they differ from the default Sentinel connection parameters for the broadcasting, cache, session, and queue connections. For example:
REDIS_BROADCAST_HOST
- OverridesREDIS_HOST
orREDIS_SENTINEL_HOST
for the default broadcasting connection.REDIS_CACHE_PORT
- OverridesREDIS_PORT
orREDIS_SENTINEL_PORT
for the default cache connection.REDIS_SESSION_PASSWORD
- OverridesREDIS_PASSWORD
orREDIS_SENTINEL_PASSWORD
for the default session connection.REDIS_QUEUE_DATABASE
- OverridesREDIS_DATABASE
orREDIS_SENTINEL_DATABASE
for the default queue connection.REDIS_QUEUE_SERVICE
- OverridesREDIS_SENTINEL_SERVICE
for the default queue connection.
BROADCAST_REDIS_CONNECTION
, BROADCAST_REDIS_SENTINEL_CONNECTION
The name of the Sentinel connection to select for application broadcasting when
BROADCAST_DRIVER
equals redis-sentinel
. It defaults to the package's
internal, auto-configured broadcasting connection when unset.
CACHE_REDIS_CONNECTION
, CACHE_REDIS_SENTINEL_CONNECTION
The name of the Sentinel connection to select for the application cache when
CACHE_DRIVER
equals redis-sentinel
. It defaults to the package's internal,
auto-configured cache connection when unset.
QUEUE_REDIS_CONNECTION
, QUEUE_REDIS_SENTINEL_CONNECTION
The name of the Sentinel connection to select for the application queue when
QUEUE_CONNECTION
(Laravel 5.7+) or QUEUE_DRIVER
(Laravel <= 5.6) equals
redis-sentinel
. It defaults to the package's internal, auto-configured
queue connection when unset.
SESSION_CONNECTION
The name of the Sentinel connection to select for storing application sessions
when SESSION_DRIVER
equals redis-sentinel
. It defaults to the package's
internal, auto-configured session connection when unset unless the
application configuration already contains a value for session.connection
.
REDIS_SENTINEL_AUTO_BOOT
When set to true
, this flag instructs the package to boot the package after
it registers its services without waiting for the application boot phase. This
provides a way for applications that use Sentinel connections in other service
providers to initialize the package immediately.
Appendix: Configuration Examples
Environment-based Configuration Examples
Supplemental examples for environment-based-configuration.
Development vs. Production
This example shows how we might change the values of environment variables between environments when we run a single Redis server in development and a full set of Sentinel servers in production.
# Development: # Production:
CACHE_DRIVER=redis CACHE_DRIVER=redis-sentinel
SESSION_DRIVER=redis SESSION_DRIVER=redis-sentinel
QUEUE_CONNECTION=redis QUEUE_CONNECTION=redis-sentinel
REDIS_HOST=localhost REDIS_HOST=sentinel1, sentinel2, sentinel3
REDIS_PORT=6379 REDIS_PORT=26379
REDIS_SENTINEL_SERVICE=null REDIS_SENTINEL_SERVICE=mymaster
Don't forget to run the artisan config:cache
command in production when
possible. This dramatically improves the configuration loading time for the
application and this package.
Best practice suggests that we avoid using the development .env file in production environments. Consider other means to set environment variables:
"phpdotenv is made for development environments, and generally should not be used in production. In production, the actual environment variables should be set so that there is no overhead of loading the .env file on each request. This can be achieved via an automated deployment process with tools like Vagrant, chef, or Puppet, or can be set manually with cloud hosts..."
Configuration File Examples
These examples demonstrate how to setup Laravel's standard configuration files to configure the package for more-advanced setups. For an introduction to using configuration files, read the config file documentation.
Multi-Sentinel Connection Configuration
In a true highly-available Redis setup, we'll run more than one Sentinel server
in a quorum. This adds redundancy for a failure event during which one or more
Sentinel servers become unresponsive. We can add multiple Sentinel server
definitions to our 'default'
connection in config/database.php:
... 'redis-sentinel' => [ 'default' => [ [ 'host' => 'sentinel1.example.com', 'port' => 26379, ], [ 'host' => 'sentinel2.example.com', 'port' => 26379, ], [ 'host' => 'sentinel3.example.com' 'port' => 26379, ], ], 'options' => [ 'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'), 'parameters' => [ 'password' => env('REDIS_PASSWORD', null), 'database' => 0, ], ], ],
With this configuration, we declare three Sentinel servers that can handle
requests for our Redis service, mymaster
(the master group name as specified
in the Sentinel server configuration file). If one of the Sentinel servers
fails, the Predis client will select a different Sentinel server to send
requests to.
Typically, in a clustered environment, we don't want to hard-code each server
into our configuration like above. We may install some form of load balancing
or service discovery to route requests to a Sentinel server through an
aggregate hostname, such as sentinels.example.com
, for flexible deployment
and arbritrary scaling.
Multi-service Connection Configuration
As we mentioned previously, we likely want to separate the Redis connections
Laravel uses for each of our services. For instance, we'd use separate databases
on a Redis server for our cache and session storage. In this example, we may
also want to create a database on a different set of Redis servers managed by
Sentinel for something like a feed. For this setup, we'll configure multiple
'redis-sentinel'
connections:
... 'redis-sentinel' => [ 'cache' => [ [ 'host' => env('REDIS_HOST', 'localhost'), 'port' => env('REDIS_PORT', 26379), ], 'options' => [ 'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'), 'parameters' => [ 'password' => env('REDIS_PASSWORD', null), 'database' => 0, ], ], ], 'session' => [ [ 'host' => env('REDIS_HOST', 'localhost'), 'port' => env('REDIS_PORT', 26379), ], 'options' => [ 'service' => env('REDIS_SENTINEL_SERVICE', 'mymaster'), 'parameters' => [ 'password' => env('REDIS_PASSWORD', null), 'database' => 1, ], ], ], 'feed' => [ [ 'host' => env('REDIS_HOST', 'localhost'), 'port' => env('REDIS_PORT', 26379), ], 'options' => [ 'service' => env('REDIS_SENTINEL_FEED_SERVICE', 'feed-service'), 'parameters' => [ 'password' => env('REDIS_PASSWORD', null), 'database' => 0, ], ], ], ],
Notice that we removed the global 'options'
array and created a local
'options'
array for each connection. In this example setup, we store the
application cache and sessions on one Redis server set, and feed data in
another set. In the first connection block, we set the Redis database for
storing cache data to 0
, and the database for session data to 1
, which
allows us to clear our application cache without erasing user sessions.
This example setup includes a second set of Redis servers for storing feed data.
The example Sentinel servers contain configuration for the first set with the
service name, mymaster
, and for the secord set with the service name,
feed-service
. The local connection options allow us to specify which service
(Redis master group name) the connection makes requests for. In particular, we
set the service name of the 'feed'
connection to 'feed-service'
.
For more information about Sentinel service configuration, see the Redis Sentinel Documentation.