numesia/laravel-redis-sentinel-drivers

Laravel 和 Lumen 的 Redis Sentinel 集成。

2.8.1 2022-08-09 14:33 UTC

This package is auto-updated.

Last update: 2024-09-30 01:19:51 UTC


README

Build Status Scrutinizer Code Quality Latest Stable Version Total Downloads License

Laravel 和 Lumen 的 Redis Sentinel 集成。

Redis Sentinel 为配置了主从复制的 Redis 服务器提供高可用性、监控和负载均衡。 Laravel 内置了对 Redis 的支持,但我们无法直接灵活地配置 Sentinel 环境。这限制了 Sentinel 的配置只能针对单个服务。

例如,如果我们希望在 Laravel API 中使用 Sentinel 背后的 Redis 同时进行缓存和会话,我们无法像没有 Sentinel 的标准单服务器 Redis 设置那样为这两种类型的数据设置单独的 Redis 数据库。这在我们需要清除缓存时会导致问题,因为 Laravel 会清除存储的会话信息。

此包通过允许独立设置 Redis 服务的选项,包装了 Laravel 的广播、缓存、会话和队列 API 的 Sentinel 配置。它为 Laravel Horizon 添加了 Sentinel 支持,并修复了其他兼容性问题。

我们单独配置此包与 Laravel 的标准 Redis 配置,以便我们可以根据环境需要选择使用 Sentinel 连接。开发人员可以在本地环境中使用独立的 Redis 服务器,而生产环境则运行 Redis Sentinel 服务器组。

内容

要求

  • PHP 5.4 或更高版本
  • Redis 2.8 或更高版本(用于 Sentinel 支持)
  • Predis 1.1 或更高版本(用于 Sentinel 客户端支持)
  • LaravelLumen 5.0 或更高版本(4.x 不支持所需的 Predis 版本)

注意: Laravel 5.4 引入了使用 PhpRedis 扩展作为框架 Redis 客户端的能力。此包尚不支持 PhpRedis 选项。

此 Readme 假设您已经了解如何为 Redis 配置 Redis Sentinel 以及如何在 Laravel 或 Lumen 中使用 Redis。

安装

由于我们使用 Laravel,所以当然将通过 Composer 进行安装!

对于 Laravel/Lumen 5.4 及以上版本

composer require monospice/laravel-redis-sentinel-drivers

对于 Laravel/Lumen 5.3 及以下版本

composer require monospice/laravel-redis-sentinel-drivers:^1.0

注意: 根据 Laravel 发布计划,所有在 2017 年 8 月之前发布的 Laravel 版本都已停止活跃开发和支持。2017 年 12 月之后,此包将不再为 5.4 以下的 Laravel 版本提供功能发布在 1.x 分支上。

如果项目尚未使用 Laravel 的 Redis,此操作还将安装 Predis 包。

注册服务提供者

Laravel 5.5 引入了 包发现Laravel 5.5 及以上版本不需要注册服务提供者。

要使用 Laravel 5.4 及以下版本的驱动程序,请将包的服务提供者添加到 config/app.php

'providers' => [
    ...
    Monospice\LaravelRedisSentinel\RedisSentinelServiceProvider::class,
    ...
],

在 Lumen 中,在 bootstrap/app.php 中注册服务提供者

$app->register(Monospice\LaravelRedisSentinel\RedisSentinelServiceProvider::class);

快速入门(TL;DR)

安装 后,在 .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

现在应该使用 Redis Sentinel 连接

Redis::get('key');
Cache::get('key');
Session::get('key');
Queue::push(new Job());

以下示例通过环境配置该包 (环境配置)。通过将 REDIS_DRIVER 设置为 redis-sentinel 来覆盖 Laravel 的标准 Redis API (覆盖标准 Redis API)。有关所有可配置的环境变量,请参阅 附录。可选地,启用 RedisSentinel 门面

对于需要快速开发 Sentinel 服务器集群的开发者,请尝试包测试文件中包含的 start-cluster.sh 脚本。

配置

根据应用程序的需求,我们可以通过三种方式配置该包

混合配置使用两种或多种这些方法。

从版本 2.2.0 发布以来,该包支持通过环境变量进行简单配置,并提供适合许多应用程序的默认配置结构。这特别减轻了 Lumen 用户在初始 Lumen 安装中可能不需要创建的多个配置文件的需求。

该包继续支持通过标准配置文件进行高级配置,而无需对现有项目进行更改。

基于环境的配置

对于合适的应用程序,该包从环境配置自身的能力消除了在许多情况下创建或修改配置文件的需求。该包自动使用环境变量配置 Redis Sentinel 连接以及应用程序广播、缓存、会话和队列服务。

当应用程序需求超过包的自动配置能力时,开发人员仍然可以通过标准 Laravel 配置文件 (使用标准配置文件) 配置该包。

通常,我们在开发期间在项目的 .env 文件 中分配应用程序环境变量。基本应用程序的配置可能只需在此文件中设置以下值

REDIS_HOST=sentinel.example.com
REDIS_PORT=26379
REDIS_SENTINEL_SERVICE=mymaster

这为通过 RedisSentinel 门面(或从容器中解析 app('redis-sentinel'))访问的包的服务设置了 默认 Redis Sentinel 连接,就像我们使用 Laravel 的 标准 Redis API 一样。要使用此 Sentinel 连接为 Laravel 的广播、缓存、会话或队列服务,请更改以下值

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

连接特定配置

在许多情况下,我们会为应用程序的广播、缓存、会话和队列设置不同的连接参数。我们可能为缓存和会话配置不同的 Redis 数据库(以便清除缓存不会擦除我们的用户会话信息),并且包含应用程序队列的 Redis 服务器可能位于不同的 Sentinel 服务(主组名)之后

REDIS_CACHE_DATABASE=1
REDIS_SESSION_DATABASE=2
REDIS_QUEUE_SERVICE=queue-service

指定多个主机

通过环境变量为连接提供多个主机,将任何*_HOST变量的值设置为以逗号分隔的主机名或IP地址的字符串

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, ...

除非我们像这样显式地在主机名后包含端口号,否则主机共享连接设置的端口号

混合应用程序

之前的示例设置了REDIS_HOSTREDIS_PORT变量,Laravel也会读取这些变量来配置标准Redis连接。这允许开发者使用相同的变量进行开发,使用单个Redis服务器,以及在生产中使用一组完整的Sentinel服务器。然而,如果一个应用程序包含在同一环境中发送请求到Redis和Sentinel连接的代码,我们必须分配一个或多个Sentinel特定的变量

REDIS_SENTINEL_HOST=sentinel.example.com
REDIS_SENTINEL_PORT=26379
REDIS_SENTINEL_PASSWORD=secret
REDIS_SENTINEL_DATABASE=0

其他环境配置选项

我们可以将REDIS_DRIVER的值更改为redis-sentinel覆盖标准Laravel Redis API

有关该包消耗的所有环境变量的完整列表,请参阅附录。查看该包的内部配置文件基于环境的配置示例,以更好地理解该包如何使用环境变量。

使用标准配置文件

除了基于环境的配置之外,该包还允许开发人员通过Laravel的标准配置文件配置Redis Sentinel集成。此选项存在于需要比该包的默认基于环境的配置更高级或特殊化的Sentinel配置的应用程序中。

对于此配置方法,我们将修改以下配置文件

  • config/database.php - 定义Redis Sentinel连接
  • config/broadcasting.php - 定义Redis Sentinel广播器
  • config/cache.php - 定义Redis Sentinel缓存存储
  • config/session.php - 设置Redis Sentinel会话连接
  • config/queue.php - 定义Redis Sentinel队列连接

注意: Lumen用户可以创建一个包配置文件,以避免创建上述所有文件(如果它们不存在的话)。

基于环境的配置满足应用程序的需求时,我们不需要修改任何配置文件。以下章节中所示代码覆盖了包的自动配置。

Redis Sentinel连接配置

我们将独立于Laravel的默认Redis数据库连接来配置Redis Sentinel数据库连接。这使我们能够在需要时使用Laravel的标准Redis功能,例如,如果开发者在本地环境中运行单个Redis服务器,而生产环境运行一组完整的Redis和Sentinel服务器。我们不需要删除Laravel默认提供的'redis'驱动程序配置块。

注意: Laravel将这些配置选项传递给Predis客户端库,因此如果需要,我们可以在此处包含高级配置选项。有关更多信息,请参阅Predis文档

基本配置

对于具有单个Sentinel服务器的简单设置,将以下块添加到config/database.php中,以定义'redis-sentinel'数据库驱动程序。

'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,
        ],
    ],

],

如您所见,我们的 'default' 连接包括 Sentinel 服务器的地址或主机名以及应用程序连接到的端口号(通常是 26379)。由于 Sentinel 不支持直接认证,我们将在 'parameters' 数组中设置 Redis 服务器的密码,该数组还包括连接所使用的 Redis 数据库。'service' 选项声明了 Sentinel 配置的 Redis 服务器集的服务名称。

请注意顶层数组中的 'default' 连接的子数组。如果我们选择向此配置添加额外的 Sentinel 服务器,我们将像以下部分所示,在每个主机定义中包装另一个数组。

当然,请确保将上面的示例中的环境配置变量添加到 .env

高级配置

上面的配置块几乎可以替代 Laravel 内置的 'redis' 连接配置,我们可以用它来配置应用程序以使用 Sentinel 而不使用此包。然而,由于 Laravel 解析 Redis 配置的方式有限制,我们无法配置 Laravel 的标准 Redis 连接以执行比基本 Sentinel 设置更复杂的操作。单个 Sentinel 服务器或连接通常不足以满足高可用性或复杂应用程序的需求。请参阅附录中的示例以获取更稳健的配置说明

其他 Sentinel 连接选项

Predis 客户端支持一些额外的配置选项,用于确定它如何处理对 Sentinel 服务器的连接。我们可以将这些选项添加到全局 'options' 数组中的所有 Sentinel 连接,或添加到单个连接的本地 'options' 数组中。以下显示默认值

'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,
],

广播、缓存、会话和队列驱动程序

配置 Sentinel 数据库连接后,我们可以指示 Laravel 使用这些连接为应用程序的其他 redis 启用的服务。请记住,我们不需要为所有这些服务设置 Sentinel 连接。如果需要,我们可以为其中一个选择标准 Redis 连接,为另一个选择 Sentinel 连接,但如果我们有 Sentinel 可用,我们可能希望利用 Sentinel 为所有 Redis 连接提供服务。

注意:我们可以完全省略(或删除)以下配置块,并且包将为我们配置这些服务。如果我们创建了如上所示的定制 Sentinel 连接,我们可能需要声明这些连接名称

广播

将以下连接定义添加到 config/broadcasting.php 中的 'connections' 数组

'connections' => [
    ...
    'redis-sentinel' => [
        'driver' => 'redis-sentinel',
        'connection' => 'default',
    ],
],

...并将 BROADCAST_DRIVER 环境变量更改为 redis-sentinel.env

如果应用程序包含针对事件广播的 'redis-sentinel' 数据库配置中的特定连接,请将 'default' 替换为其名称。

缓存

将以下存储定义添加到 config/cache.php 中的 'stores' 数组

'stores' => [
    ...
    'redis-sentinel' => [
        'driver' => 'redis-sentinel',
        'connection' => 'default',
    ],
],

...并将 CACHE_DRIVER 环境变量更改为 redis-sentinel.env

如果应用程序包含针对缓存的 'redis-sentinel' 数据库配置中的特定连接,请将 'default' 替换为其名称。

会话

SESSION_DRIVER 环境变量更改为 redis-sentinel.env。然后,在 config/session.php 中,将 'connection' 指令设置为 'default' 或为从 'redis-sentinel' 数据库配置存储会话而创建的特定连接的名称。

队列

将以下连接定义添加到 config/queue.php 中的 'connections' 数组

'connections' => [
    ...
    'redis-sentinel' => [
        'driver' => 'redis-sentinel',
        'connection' => 'default',
        'queue' => 'default',
        'retry_after' => 90, // Laravel >= 5.4.30
        'expire' => 90,      // Laravel < 5.4.30
    ],
],

...并将环境变量 QUEUE_CONNECTION(Laravel 5.7+)或QUEUE_DRIVER(Laravel <= 5.6)修改为redis-sentinel,在.env文件中进行修改。

如果应用在队列数据库配置中包含了特定的'redis-sentinel'连接,将'connection' => 'default'替换为其名称。

使用包配置文件

Lumen项目默认不包含配置文件。相反,按照惯例,Lumen从环境中读取配置信息。如果我们希望通过如前所述的配置文件来配置此包,而不是使用基于环境的配置,我们可以添加一个单独的包配置文件:config/redis-sentinel.php。这避免了在Lumen中创建多个标准配置文件的需要。

包配置文件包含在运行时合并回主配置位置的元素。例如,当自定义的redis-sentinel.php文件包含

return [
    'database' =>
        'redis-sentinel' => [ /* ...Redis Sentinel connections... */ ]
    ]
];

...包将在应用启动时将database.redis-sentinel配置值设置为redis-sentinel.database.redis-sentinel的值,除非该键已存在。

我们可以通过将其复制到我们项目的config/目录并按需更改值来自定义包的内部配置文件。Lumen用户可能需要创建此目录,如果它不存在的话。

自定义包配置文件只需要包含开发人员希望自定义的最顶层元素:在上面的代码中,自定义配置文件仅覆盖了包的Redis Sentinel连接默认配置,因此包仍会自动使用环境变量配置广播、缓存、会话和队列服务。

混合配置

尽管在大多数情况下是不必要的,但开发人员可以将此包提供的两种或多种配置方法结合起来。例如,一个应用可能包含一个定义Redis Sentinel连接的标准或包配置文件,但依赖于包的自动基于环境的配置来设置Sentinel的缓存、会话、队列和广播服务。

此包按照以下优先级使用配置数据

  1. 标准Laravel配置文件
  2. 自定义包配置文件
  3. 自动基于环境配置

这意味着标准配置文件中的特定包值覆盖了自定义包配置文件中的值,而自定义包配置文件又覆盖了通过环境变量设置的包的默认自动配置。换句话说,自定义包配置文件继承了未显式声明的包默认配置的值,而主应用配置从这两个来源接收它未在标准配置文件中提供的值。

覆盖标准 Redis API

此包为Laravel的缓存、会话和队列API添加了Redis Sentinel驱动程序,开发人员可以选择使用Sentinel连接利用其中哪些。然而,Laravel也提供了一个API,可以直接通过Redis外观或通过Redis连接管理器与Redis进行交互,我们可以通过应用容器(如app('redis')、依赖注入等)解析它。

当安装此包时,它不会强制所有Redis请求都使用Sentinel。实际上,我们可以选择为某些功能使用Sentinel连接,同时继续使用Laravel的标准Redis连接。默认情况下,此包不会替换Laravel内置的Redis API。

例如,我们可能会决定为应用程序的缓存和会话使用Sentinel连接,但直接使用Laravel的标准Redis连接与单个Redis服务器交互。

话虽如此,此包提供了覆盖Laravel Redis API的选项,以便所有Redis命令都使用由'redis-sentinel'数据库驱动程序定义的Sentinel连接配置。

要使用此功能,请将以下配置指令添加到config/database.php'redis'连接定义的根目录(如果不使用基于环境的配置)

'redis' => [
    ...
    'driver' => env('REDIS_DRIVER', 'default'),
    ...
],

...并在.env中添加环境变量REDIS_DRIVER,其值为redis-sentinel

启用后,通过Redis外观或redis服务(例如app('redis'))执行的Redis命令将使用Sentinel连接。

这使得开发者在本地环境中使用独立Redis服务器,并在生产环境中切换到完整的Sentinel服务器集更容易。

注意:当与Laravel Horizon一起使用时,此更改将使Horizon也通过Sentinel连接运行。

执行 Redis 命令 (RedisSentinel Facade)

如果我们需要将Redis命令直接发送到Sentinel服务器后面的Redis实例,例如我们可以通过Redis外观完成,但不想像上面那样覆盖Laravel的Redis API,我们可以使用此包提供的RedisSentinel外观或从应用程序容器解析redis-sentinel服务

// 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');

这为那些可能需要在同一环境中连接到标准Redis服务器和Sentinel集群的应用程序提供了支持。当可能时,遵循上一节中描述的方法,在整个应用程序中统一连接到Sentinel,以将代码与Redis实现解耦。

由于与PhpRedis扩展的向后兼容性,外观在Laravel 5.5+中没有自动别名。为了在Laravel中启用外观,请将以下别名添加到config/app.php中的'aliases'数组

'aliases' => [
    ...
    'RedisSentinel' => Monospice\LaravelRedisSentinel\RedisSentinel::class,
    ...
],

在Lumen中,将别名添加到bootstrap/app.php

class_alias('Monospice\LaravelRedisSentinel\RedisSentinel', 'RedisSentinel');

依赖注入

对于那些更喜欢将Redis Sentinel管理器作为类的依赖项而不是使用外观来声明,我们可以对容器在从容器构建对象时将解析的接口进行类型提示

use Monospice\LaravelRedisSentinel\Contracts\Factory as RedisSentinel;
...
public function __construct(RedisSentinel $sentinel)
{
    $sentinel->get('some-key');
}

上述内容明确请求实例化包的Sentinel服务。如果我们覆盖Redis API,我们可以使用标准的Redis契约,并且应用程序将根据配置注入适当的服务

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');
}

其他 Sentinel 考虑

以下部分描述了在使用Sentinel连接时需要注意的一些特性。

读写操作

为了在可用资源之间分配负载,客户端在初始化连接时尝试在Redis从服务器上执行读操作。写入数据的命令将始终在主服务器上执行。

事务

事务中的所有命令,即使是只读命令,都在主Redis服务器上执行。当这样做有意义时,避免在事务中调用读命令,以提高负载均衡。

如果事务因连接失败而中止,包将尝试重新连接并重试事务,直到耗尽配置的允许尝试次数(retry_limit),或者直到整个事务成功。

重要: Predis 提供了一个特殊的 MULTI/EXEC 抽象,我们可以在没有任何参数的情况下调用 transaction() 来获得。此 API 受 Sentinel 连接失败处理保护。为了高可用性,通过将闭包传递给 transaction() 来使用 Laravel API。

发布/订阅

对于 PUB/SUB 消息传递,客户端将消息发布到主服务器。在订阅时,包首先尝试连接到从服务器,然后再回退到主服务器。与读取操作类似,这有助于将负载从主服务器分散开来,因为发布到主服务器的消息会传播到每个从服务器。

对于长时间运行的订阅者,需要扩展连接超时或通过将 read_write_timeout 设置为 0 来禁用它。此外,我们还需要扩展或禁用应用程序订阅的 Redis 服务器上的 timeout 配置指令。

当订阅者连接失败时,包将尝试连接到另一个服务器并继续监听消息。我们可能希望将具有长时间运行的订阅者的连接上的 retry_limit 的值设置为 -1,以便客户端无限期地继续重试。请注意,在重新建立连接的过程中,订阅者可能会错过发布到通道的消息。

重要: Predis 提供了一个 PUB/SUB 消费者,我们可以在没有任何参数的情况下调用 pubSubLoop() 来获得。此 API 受 Sentinel 连接失败处理保护。为了高可用性,通过将闭包传递给 subscribe()psubscribe() 来使用 Laravel API。

Laravel Horizon

此包的版本 2.4.0 及更高版本支持与 Laravel Horizon 队列管理工具(Laravel 5.5+)兼容的应用程序(Laravel Horizon)使用 Sentinel 连接。

安装 Horizon 之后,我们需要更新 config/horizon.php 中的某些配置设置。

如果需要,将 'use' => 'default' 更改为用于 Horizon 后端的 Sentinel 连接的名称,该连接在 config/database.php 中配置。

重要: config/database.php 中的标准 'redis' 连接数组必须包含一个与 'use' 指令中指定的 Sentinel 连接具有相同键的元素。如果 Horizon 抛出异常,则 Horizon 不提供一种方法来处理这种行为,但一个(正在进行中的)拉取请求可能会在将来消除此要求。此元素可以包含任何值(但一个匹配的 Redis 连接配置似乎最合适)。

通过添加以下元素来更改 Horizon 内部元数据的后端驱动程序

'driver' => env('HORIZON_DRIVER', 'redis');

...并将 redis-sentinel 的值分配给 .env 中的 HORIZON_DRIVER

然后,为任何 Sentinel 队列添加 'waits' 数组中的条目

'waits' => [
    ...
    'redis-sentinel:default' => 60,
],

接下来,在 'environments' 块中为每个应使用 Sentinel 连接的队列工作者更改连接驱动程序为 redis-sentinel

...
'supervisor-1' => [
    'connection' => 'redis-sentinel',
    ...
],
...

现在,Horizon 将使用应用程序的 Redis Sentinel 连接来监控和处理我们的队列。

注意:如果我们已经配置了包以 覆盖 Laravel 的标准 Redis API(例如,通过将 REDIS_DRIVER 设置为 redis-sentinel),则不需要将 HORIZON_DRIVER 更改为 'redis-sentinel'。该包已经通过 Sentinel 连接路由所有 Redis 操作。

测试

本包包含一个PHPUnit测试套件,其中包括对包中类的单元测试以及针对Sentinel特定功能和兼容性修复的集成测试套件。这些测试并不验证每个Redis命令,因为Predis和Laravel本身都包含完整的测试套件,并且该包代码只是简单地封装了这些库。

$ phpunit --testsuite unit
$ phpunit --testsuite integration

单元测试不需要真实的Redis服务器。请阅读下一节获取集成测试环境建议。

注意:Composer在正常安装过程中不会下载此包的测试文件。我们需要直接克隆包的仓库或使用--prefer-source选项来安装。

集成测试

本包的集成测试套件验证了Sentinel和Redis特定功能与真实服务器的兼容性。这些测试至少需要一个监控Redis主节点的Sentinel服务器。此外,至少应该有一个从节点与主节点同步,以实现最佳测试覆盖率。开发者可以提供自己的服务器或使用下面描述的包工具启动环境。

要自定义集成测试使用的Sentinel连接设置,将phpunit.xml.dist复制到phpunit.xml,并更改<php>...</php>块中定义的常量。

我们可以运行项目根目录中提供的start-cluster.sh脚本来启动Redis和Sentinel服务器,以创建测试环境。请阅读脚本帮助页面以获取使用信息。

$ ./start-cluster.sh help

使用Docker的用户可能希望使用该脚本在容器中启动测试服务器

$ 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

该包提供了一个具有相同测试运行选项的Compose文件

$ export CONTAINER_USER_ID="$(id -u):$(id -g)"
$ docker-compose up -d cluster
$ docker-compose run --rm tests [--testsuite ...]

开发者也可以通过将docker-compose.yml复制到docker-compose.override.yml来自定义Compose文件。

许可证

MIT许可证(MIT)。请参阅LICENSE文件以获取更多信息。

附录:环境变量

当使用默认的基于环境的配置时,该包会消耗以下环境变量。开发者只需要为适用于其特定应用程序和Redis设置的变量提供值。在大多数情况下,默认值是足够的。

REDIS_{HOST,PORT,PASSWORD,DATABASE}

默认情况下用于所有Sentinel连接的基本连接参数。

为了简化环境配置,该包尝试读取指定多个Sentinel连接共享值的REDIS_*REDIS_SENTINEL_*环境变量。如果一个应用程序不是同时通过Redis Sentinel和标准Redis连接执行命令,则此功能允许开发者在开发(使用单个Redis服务器)和生产(使用完整的Sentinel服务器集)中使用相同的环境变量名。

  • REDIS_HOST - 一个或多个主机名或IP地址。如果没有设置,默认为localhost
  • REDIS_PORT - 监听Sentinel服务器端口的端口。如果没有设置,Sentinel连接默认为26379
  • REDIS_PASSWORD - 如果有的话,用于在Sentinel后(Sentinels本身不支持密码认证)与Redis服务器进行认证的密码。
  • REDIS_DATABASE - 发送命令到Sentinel后Redis服务器时选择的数据库编号(在正常Redis配置中为015)。默认为0

REDIS_SENTINEL_{HOST,PORT,PASSWORD,DATABASE}

当应用程序同时使用标准Redis和Redis Sentinel连接时,请设置这些变量而不是上面的变量。

  • REDIS_SENTINEL_HOST - 见REDIS_HOST
  • REDIS_SENTINEL_PORT - 见REDIS_PORT
  • REDIS_SENTINEL_PASSWORD - 见REDIS_PASSWORD
  • REDIS_SENTINEL_DATABASE - 见REDIS_DATABASE

REDIS_SENTINEL_SERVICE

Redis主节点组名称(在Sentinel服务器配置文件中指定),用于标识所有Sentinel连接使用的默认Sentinel服务。默认为mymaster

REDIS_CACHE_SERVICEREDIS_SESSION_SERVICEREDIS_QUEUE_SERVICE设置为此值以覆盖特定服务的连接。

REDIS_SENTINEL_{TIMEOUT,RETRY_LIMIT,RETRY_WAIT,DISCOVERY}

Predis客户端支持一些额外的配置选项,这些选项决定了它如何处理与Sentinel服务器的连接。

  • REDIS_SENTINEL_TIMEOUT - 客户端在确定连接到Sentinel服务器的尝试失败之前等待的时间(以秒为单位)。默认为0.100
  • REDIS_SENTINEL_RETRY_LIMIT - 客户端在确定无法连接到法定多数中的所有Sentinel服务器之前尝试联系Sentinel服务器的次数。值为0指示客户端在第一次尝试失败后抛出异常,而值为-1则导致客户端无限期地重试连接。默认为20
  • REDIS_SENTINEL_RETRY_WAIT - 客户端在尝试联系另一个Sentinel服务器之前等待的时间(以毫秒为单位),如果先前的服务器没有响应。默认为1000
  • REDIS_SENTINEL_DISCOVERY - 指示客户端在每次需要与Redis主服务器或从服务器建立连接时,查询第一个可到达的Sentinel服务器以获取更新的Sentinel集合。默认为false

REDIS_DRIVER

将此变量的值设置为redis-sentinel覆盖Laravel的标准Redis API

BROADCAST_DRIVERCACHE_DRIVERSESSION_DRIVERQUEUE_CONNECTION

Laravel使用这些变量来选择应用程序广播、缓存、会话和队列服务的后端。将值设置为redis-sentinel,以便应用程序应使用Sentinel连接。

注意: Laravel 5.7将默认配置文件中的QUEUE_DRIVER重命名为QUEUE_CONNECTION

REDIS_{BROADCAST,CACHE,SESSION,QUEUE}_{HOST,PORT,PASSWORD,DATABASE,SERVICE}

这些变量配置了与广播、缓存、会话和队列连接的默认Sentinel连接参数不同的服务特定连接参数。例如

  • REDIS_BROADCAST_HOST - 覆盖默认广播连接的REDIS_HOSTREDIS_SENTINEL_HOST
  • REDIS_CACHE_PORT - 覆盖默认缓存连接的REDIS_PORTREDIS_SENTINEL_PORT
  • REDIS_SESSION_PASSWORD - 覆盖默认会话连接的REDIS_PASSWORDREDIS_SENTINEL_PASSWORD
  • REDIS_QUEUE_DATABASE - 覆盖默认队列连接的REDIS_DATABASEREDIS_SENTINEL_DATABASE
  • REDIS_QUEUE_SERVICE - 覆盖默认队列连接的REDIS_SENTINEL_SERVICE

BROADCAST_REDIS_CONNECTIONBROADCAST_REDIS_SENTINEL_CONNECTION

BROADCAST_DRIVER等于redis-sentinel时,选择用于应用程序广播的Sentinel连接名称。未设置时,默认为包内部自动配置的广播连接。

CACHE_REDIS_CONNECTIONCACHE_REDIS_SENTINEL_CONNECTION

CACHE_DRIVER等于redis-sentinel时,选择用于应用程序缓存的Sentinel连接名称。未设置时,默认为包内部自动配置的缓存连接。

QUEUE_REDIS_CONNECTIONQUEUE_REDIS_SENTINEL_CONNECTION

QUEUE_CONNECTION(Laravel 5.7+)或QUEUE_DRIVER(Laravel <= 5.6)等于redis-sentinel时,选择用于应用程序队列的Sentinel连接名称。未设置时,默认为包内部自动配置的队列连接。

SESSION_CONNECTION

SESSION_DRIVER 等于 redis-sentinel 时,用于存储应用程序会话的 Sentinel 连接名称。如果未设置,默认使用包内部自动配置的 session 连接,除非应用程序配置已包含 session.connection 的值。

REDIS_SENTINEL_AUTO_BOOT

当设置为 true 时,此标志指示包在注册其服务后启动包,而不等待应用程序启动阶段。这为使用其他服务提供商中的 Sentinel 连接的应用程序提供了立即初始化包的方法。

附录:配置示例

基于环境的配置示例

基于环境的配置的补充示例。

开发与生产

此示例显示,当我们在开发环境中运行单个 Redis 服务器,在生产环境中运行一组完整的 Sentinel 服务器时,如何更改环境变量之间的值。

# 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

当可能时,不要忘记在生产环境中运行 artisan config:cache 命令。这极大地提高了应用程序和此包的配置加载时间。

最佳实践 建议我们在生产环境中避免使用开发环境的 .env 文件。考虑其他设置环境变量的方法

"phpdotenv 是为开发环境制作的,通常不应在生产环境中使用。在生产环境中,实际的环缄变量应设置,以便在每次请求时无需加载 .env 文件。这可以通过使用 Vagrant、chef 或 Puppet 等工具的自动化部署流程来实现,或者可以通过云主机手动设置..."

配置文件示例

这些示例演示了如何设置 Laravel 的标准配置文件来配置更高级的设置。有关使用配置文件的介绍,请参阅 配置文件文档

多 Sentinel 连接配置

在真正的高可用 Redis 设置中,我们将在法定人数中运行多个 Sentinel 服务器。这为在发生一个或多个 Sentinel 服务器变得无响应的故障事件时增加了冗余。我们可以在 config/database.php 中的 'default' 连接中添加多个 Sentinel 服务器定义

...
'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,
        ],
    ],

],

使用此配置,我们声明了三个可以处理对我们的 Redis 服务请求的 Sentinel 服务器,mymaster(如 Sentinel 服务器配置文件中指定的主组名称)。如果其中一个 Sentinel 服务器失败,Predis 客户端将选择另一个 Sentinel 服务器发送请求。

通常,在集群环境中,我们不想像上面那样将每个服务器硬编码到我们的配置中。我们可能需要安装某种形式的负载均衡或服务发现,以便通过聚合主机名(如 sentinels.example.com)将请求路由到 Sentinel 服务器,以实现灵活的部署和任意扩展。

多服务连接配置

如前所述,我们可能希望将 Laravel 为每个服务使用的 Redis 连接分开。例如,我们会在 Redis 服务器上为缓存和会话存储使用不同的数据库。在此示例中,我们可能还希望在由 Sentinel 管理的不同 Redis 服务器集上为类似订阅等功能创建数据库。为此设置,我们将配置多个 'redis-sentinel' 连接

...
'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,
            ],
        ],
    ],

],

请注意,我们已删除全局的'options'数组,并为每个连接创建了一个本地的'options'数组。在这个示例配置中,我们将应用程序缓存和会话存储在一个Redis服务器集中,并将数据喂入另一个集中。在第一个连接块中,我们将用于存储缓存数据的Redis数据库设置为0,将用于会话数据的数据库设置为1,这使我们能够在不删除用户会话的情况下清除应用程序缓存。

这个示例配置还包括用于存储推文数据的第二个Redis服务器集。示例Sentinel服务器包含第一个服务集的配置,服务名为mymaster,以及第二个服务集的配置,服务名为feed-service。本地连接选项允许我们指定连接请求哪个服务(Redis主组名)。特别是,我们将'feed'连接的服务名设置为'feed-service'

有关Sentinel服务配置的更多信息,请参阅Redis Sentinel 文档