myqaa/laravel-redis-sentinel-drivers

Laravel 和 Lumen 的 Redis Sentinel 集成。

2.x-dev 2024-06-17 15:20 UTC

This package is auto-updated.

Last update: 2024-09-17 16:11:13 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 会同时清除存储的会话信息。

此包使用 Sentinel 对 Laravel 的广播、缓存、会话和队列 API 进行配置,并允许我们独立设置 Redis 服务选项。它为 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 以及使用 Redis 与 LaravelLumen

安装

由于我们使用 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 版本提供功能发布。

如果项目尚未使用 Redis 与 Laravel 配合使用,此安装将安装 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。有关所有可配置的环境变量,请参阅附录。可选地,启用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

这为包的服务设置了 默认 Redis Sentinel 连接,我们可以通过 RedisSentinel 门面(或从容器解析 app('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 连接配置

我们将单独配置 Redis Sentinel 数据库连接,而不是 Laravel 的默认 Redis 数据库连接。这使我们可以在需要时使用 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'连接包括哨兵服务器的地址或主机名以及应用程序连接到的端口号(通常是26379)。由于哨兵不支持直接认证,我们将在'parameters'数组中设置Redis服务器的密码,该数组还包括连接所使用的Redis数据库。'service'选项声明了哨兵中配置的Redis服务器组的服务名称。

请注意顶层数组中'default'连接的子数组。如果我们选择向此配置添加更多的哨兵服务器,我们将像下面章节中看到的那样,将每个主机的定义包装在另一个数组中。

当然,务必将上面的示例中的环境配置变量添加到.env文件中。

高级配置

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

其他哨兵连接选项

Predis客户端支持一些额外的配置选项,这些选项决定了它如何处理与哨兵服务器的连接。我们可以将这些选项添加到全局'options'数组中,用于所有哨兵连接,或者添加到单个连接的本地'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,
],

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

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

注意:我们可以完全省略(或删除)以下配置块,并且包会为我们配置这些服务。如果我们像上面那样创建了自定义哨兵连接,我们可能需要声明这些连接名称

广播

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

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

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

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

缓存

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

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

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

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

会话

SESSION_DRIVER环境变量在.env中更改为redis-sentinel。然后,在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)环境变量在.env中更改为redis-sentinel

如果应用程序包含针对队列的'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')、依赖注入等)解析它。

安装此包后,它不会强制使用Sentinel来处理所有Redis请求。实际上,我们可以选择为某些功能使用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'),
    ...
],

...并将环境变量REDIS_DRIVER添加到.env中,值为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_timeout0。此外,我们还需要扩展或禁用应用程序订阅的Redis服务器上的timeout配置指令。

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

重要: Predis提供了一个PUB/SUB消费者,我们可以通过不带参数调用pubSubLoop()来获取。此API不通过哨兵连接故障处理来保护。对于高可用性,通过传递闭包到subscribe()psubscribe()使用Laravel API。

Laravel Horizon

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

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

如有必要,将'use' => 'default'更改为用于Horizon后端的哨兵连接名称,如config/database.php中配置。

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

将Horizon内部元数据的后端驱动程序更改为'redis-sentinel',通过向顶级数组添加以下元素实现:

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

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

然后,为任何哨兵队列添加'waits'数组条目。

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

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

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

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

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

测试

本软件包包括一个PHPUnit测试套件,包含对软件包类进行单元测试,以及一个针对哨兵特定功能和兼容性修复的集成测试套件。这些测试并不验证每个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 服务器的监听端口。未设置时默认为 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使用这些选项来选择应用程序广播、缓存、会话和队列服务的后端。对于应使用Sentinel连接的应用程序服务,将每个服务的值设置为redis-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服务器。示例哨兵服务器包含第一组配置,服务名为mymaster,以及第二组配置,服务名为feed-service。本地连接选项允许我们指定连接请求哪个服务(Redis主节点组名)。特别是,我们将'feed'连接的服务名设置为'feed-service'

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