boomerangmessaging / laravel-redis-sentinel-drivers
为Laravel和Lumen提供Redis Sentinel集成。
Requires
- php: >=5.6.4
- illuminate/cache: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- illuminate/contracts: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- illuminate/queue: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- illuminate/redis: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- illuminate/session: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- illuminate/support: ^5.4 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
- monospice/spicy-identifiers: ^0.1
- predis/predis: ^1.1
Requires (Dev)
- laravel/framework: ^5.4 || ^6.0 || ^7.0 || ^8.0
- laravel/horizon: ^1.0 || ^2.0 || ^3.0 || ^4.0
- laravel/lumen-framework: ^5.4 || ^6.0 || ^7.0 || ^8.0
- mockery/mockery: ^1.3
- phpunit/phpunit: ^5.0
This package is not auto-updated.
Last update: 2024-09-27 12:02:19 UTC
README
为Laravel和Lumen提供Redis Sentinel集成。
Redis Sentinel(Redis高可用、监控和负载均衡解决方案)为配置了主从复制的Redis服务器提供了高可用性、监控和负载均衡。Laravel内置了对Redis的支持,但我们无法直接灵活地配置Sentinel。这限制了Sentinel配置为单个服务。
例如,如果我们希望在Laravel的API中同时使用Redis和Sentinel来处理缓存和会话,我们无法像在未配置Sentinel的单服务器Redis环境中那样为两种数据类型设置独立的Redis数据库。这在我们需要清除缓存时会导致问题,因为Laravel会同时清除存储的会话信息。
此包通过允许独立设置我们的Redis服务选项,包装了Laravel的广播、缓存、会话和队列API的Sentinel配置。它为Laravel Horizon添加了Sentinel支持,并修复了其他兼容性问题。
我们独立于Laravel的默认Redis配置来配置此包,以便可以根据环境需要选择使用Sentinel连接。开发者可能在本地环境中使用独立的Redis服务器,而生产环境可能运行Redis Sentinel服务器集。
内容
- 快速入门 (简化版)
- 要求
- 安装
- 配置选项
- 覆盖标准Redis API
- 执行Redis命令(RedisSentinel外观)
- 其他Sentinel注意事项
- Laravel Horizon
- 测试
- 许可证
- 附录:环境变量
- 附录:配置示例
要求
- PHP 5.4或更高版本
- Redis 2.8或更高版本(用于Sentinel支持)
- Predis 1.1或更高版本(用于Sentinel客户端支持)
- Laravel 或 Lumen 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
分支上提供功能更新。
如果项目尚未使用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
这设置了包服务的默认 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_HOST
和REDIS_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文档。
基本配置
对于使用单个哨兵服务器的简单设置,将以下代码块添加到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)。因为哨兵不支持直接认证,所以我们将Redis服务器的密码设置在'parameters'
数组中,该数组还包括用于连接的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启用服务。请记住,我们不需要为所有这些服务设置哨兵连接。如果我们像上面那样创建了自定义哨兵连接,我们可能需要声明这些连接名称。
注意:我们可以完全省略(或删除)以下配置块,并且包将为我们配置这些服务。如果我们创建了如上所示的自定义哨兵连接,我们可能需要声明那些连接名称。
广播
将以下连接定义添加到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的缓存、会话、队列和广播服务。
此包按照以下优先级使用配置数据
- 标准Laravel配置文件
- 自定义包配置文件
- 自动基于环境的配置
这意味着标准配置文件中的特定包值覆盖了自定义包配置文件中的值,而自定义包配置文件又通过环境变量覆盖了包的默认自动配置。换句话说,自定义包配置文件从没有明确声明的包默认配置中继承值,而主应用程序配置从这两个配置中接收它没有在标准配置文件中提供的值。
覆盖标准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'), ... ],
...并在.env中添加环境变量REDIS_DRIVER
,其值为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实现解耦。
外观在Laravel 5.5+中不会自动别名,以实现与PhpRedis扩展的向后兼容性。要在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 未经 哨兵连接失败处理 保护。为了高可用性,使用 Laravel API 通过传递闭包到 transaction()
。
发布/订阅
对于 PUB/SUB 消息,客户端将消息发布到主服务器。在订阅时,客户端首先尝试连接到从服务器,然后回退到主服务器。就像读取操作一样,这有助于将负载从主服务器分散出去,因为发布到主服务器的消息会传播到每个从服务器。
具有长时间运行订阅器的应用程序需要扩展连接超时或通过将 read_write_timeout
设置为 0
来禁用它。此外,还需要扩展或禁用应用程序订阅的 Redis 服务器上的 timeout
配置指令。
当订阅器连接失败时,包将尝试连接到另一个服务器并继续监听消息。我们可能希望在具有长时间运行订阅器的连接上将 retry_limit
的值设置为 -1
,以便客户端无限期地继续重试。请注意,在重新建立连接期间,订阅器可能会错过发布到频道的消息。
重要: Predis 提供了一个 PUB/SUB 消费者,可以通过不带参数调用 pubSubLoop()
来获取。此 API 未经 哨兵连接失败处理 保护。为了高可用性,使用 Laravel API 通过传递闭包到 subscribe()
或 psubscribe()
。
Laravel Horizon
本包的 2.4.0 版本及以上支持与 Laravel Horizon 队列管理工具(Laravel 5.5+)在兼容应用程序中使用 Sentinel 连接。
安装 Horizon 后,我们需要更新 config/horizon.php 中的某些配置设置。
如果需要,将 'use' => 'default'
更改为用于 Horizon 后端配置的 Sentinel 连接名称,如 config/database.php 中配置。
重要: config/database.php 中的标准 'redis'
连接数组必须包含一个与 'use'
指令中指定的 Sentinel 连接相同的键的元素。否则,Horizon 将引发异常。目前,Horizon 没有提供一种方法来处理这种行为,但一个(正在进行的)拉取请求可能在未来消除此要求。此元素可以包含任何值(但匹配的 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'
。该包已通过哨兵连接路由所有 Redis 操作。
测试
本软件包包括一个PHPUnit测试套件,用于对包的类进行单元测试,以及一个针对Sentinel特定功能和兼容性修复的集成测试套件。由于Predis和Laravel都包含完整的测试套件,并且该包的代码仅对这些库进行封装,因此这些测试并不验证每个Redis命令。
$ 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_DATABASE
- 向Sentinel后面的Redis服务器发出命令时要选择的数据库编号(正常Redis配置中的0
到15
)。默认为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_SERVICE
、REDIS_SESSION_SERVICE
或 REDIS_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_DRIVER
、CACHE_DRIVER
、SESSION_DRIVER
、QUEUE_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_HOST
或REDIS_SENTINEL_HOST
。REDIS_CACHE_PORT
- 覆盖默认 缓存 连接的REDIS_PORT
或REDIS_SENTINEL_PORT
。REDIS_SESSION_PASSWORD
- 覆盖默认 会话 连接的REDIS_PASSWORD
或REDIS_SENTINEL_PASSWORD
。REDIS_QUEUE_DATABASE
- 覆盖默认 队列 连接的REDIS_DATABASE
或REDIS_SENTINEL_DATABASE
。REDIS_QUEUE_SERVICE
- 覆盖默认 队列 连接的REDIS_SENTINEL_SERVICE
。
BROADCAST_REDIS_CONNECTION
、BROADCAST_REDIS_SENTINEL_CONNECTION
当 BROADCAST_DRIVER
等于 redis-sentinel
时,选择应用程序广播的Sentinel连接名称。如果没有设置,则默认为包的内部、自动配置的 广播 连接。
CACHE_REDIS_CONNECTION
、CACHE_REDIS_SENTINEL_CONNECTION
当 CACHE_DRIVER
等于 redis-sentinel
时,选择应用程序缓存的Sentinel连接名称。如果没有设置,则默认为包的内部、自动配置的 缓存 连接。
QUEUE_REDIS_CONNECTION
、QUEUE_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文档。