monospice/laravel-redis-sentinel-drivers

Laravel和Lumen的Redis Sentinel集成。

2.7.0 2020-03-19 20:47 UTC

This package is auto-updated.

Last update: 2024-09-08 15:25:20 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中使用Redis背后的Sentinel进行缓存和会话,我们不能像在没有Sentinel的标准单服务器Redis设置中那样为这两种类型的数据设置独立的Redis数据库。这在我们需要清除缓存时会导致问题,因为Laravel会同时删除存储的会话信息。

此包通过为Sentinel的Laravel广播、缓存、会话和队列API配置提供独立设置Redis服务选项的能力,封装了Laravel的配置。它为 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 与Laravel或使用 Lumen

安装

我们使用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分支上的功能发布。

如果项目尚未使用 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 (覆盖标准 Redis API)。有关所有可配置的环境变量,请参阅 附录。可选地,启用 RedisSentinel 门面

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

配置

根据应用需求,我们可以以三种方式配置该包

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

从版本 2.2.0 开始,该包支持通过环境变量进行简单配置,具有适合许多应用的默认配置结构。这特别减轻了 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'连接包括Sentinel服务器的地址或主机名以及应用程序连接到的端口号(通常是26379)。由于Sentinel不支持直接身份验证,我们将在'parameters'数组中设置Redis服务器的密码,该数组还包括用于连接的Redis数据库。'service'选项声明了在Sentinel中配置的服务集合的Redis服务器作为服务。

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

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

高级配置

上面的配置块几乎可以替换Laravel内置的'redis'连接配置,我们可以使用它来配置应用程序,而不需要此包即可使用Sentinel。然而,由于Laravel解析其Redis配置的方式有限制,我们不能配置Laravel的标准Redis连接,使其比基本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-enabled服务。请记住,我们不需要为所有这些服务设置Sentinel连接。如果我们需要一个标准的Redis连接和一个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... */ ]
    ]
];

...则当应用程序启动时,包会根据redis-sentinel.database.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'),
    ...
],

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

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

这使得开发人员在使用本地环境中的独立Redis服务器时更轻松,并在生产环境中切换到完整的Sentinel服务器组。

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

执行Redis命令(RedisSentinel外观)

如果我们需要将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 提供了一个通过调用 pubSubLoop()(不带参数)获得的 PUB/SUB 消费者。此 API 受 Sentinel 连接故障处理保护。对于高可用性,请使用通过传递闭包到 subscribe()psubscribe() 的 Laravel API。

Laravel Horizon

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

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

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

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

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

'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

该软件包提供了一个具有相同测试运行选项的docker-compose.yml文件。

$ 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)。有关更多信息,请参阅许可证文件

附录:环境变量

当使用默认的基于环境的配置时,该软件包会消耗以下环境变量。开发者只需要为其特定应用程序和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(Sentinel本身不支持密码认证)认证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.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服务器上为类似“feed”的东西创建一个数据库。为此设置,我们将配置多个'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'

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