Laravel框架中使用Redis作为cache和session的驱动

Laravel 框架提供了开箱即用的 cache 和 session。不过,Laravel 默认驱动都是利用 file 来实现,生产环境中,file 驱动显然不能满足多机器架构,现在将 cache 和 session 写入 Redis 集群中,以满足多机之间的 cache 和 session 共享。

Redis键名命名规则

在开始前,先声明一下我采用的Redis键名命名规则:

域名前缀:业务前缀:键名

示例

larabbs.com:session:user1

Redis 驱动包使用的是 predis。

配置哨兵连接

这里使用Redis哨兵进行演示,单机Redis比Redis哨兵配置更简单,这里不赘述。

生产环境中,采用的一主两备的架构,一个节点服务器上配置了一个哨兵,也就是三节点三哨兵。

我们在程序中需要连接哨兵,哨兵会告诉我们三个节点中哪个是主节点,并且在主节点挂掉后会票选出新的主节点。对于一主的情况,就不需要考虑 hash 计算往那台主节点写入和去哪查的问题。

database.php 下配置Redis哨兵模式。

  • options

    • cluster 设置使用的驱动
    • replication 设置使用的模式
    • service 设置主节点的服务名
    • parameters 关联数组,配置一些相关参数
    • prefix 设置 Redis 键名前缀(在我的命名规则里,配置的是域名前缀
  • clusters

    • default 默认集群,其中配置的多组Redis节点
// database.php
……

'redis' => [

        'client' => env('REDIS_CLIENT', 'predis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'predis'),
            'replication' => 'sentinel', // 设置使用哨兵模式
            'service' =>  env('REDIS_SERVICE', 'mymaster'), // 设置主节点的服务名
            'parameters' => [
                'password' => env('REDIS_CLUSTER_PASSWORD', '') // 设置 Redis 密码(若有)
            ],
            'prefix' => env('REDIS_PREFIX'), // 设置 Redis 键名前缀

        ],

        'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_FIRST_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_FIRST_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_SECOND_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_SECOND_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_THIRD_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_THIRD_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
            ]
        ]
]

……

对于上面的配置,我们增加一些环境变量,需要在 .env 增加,并记得也把它新增到 .env.example 中作为示例配置。

// .env
REDIS_PREFIX=
REDIS_SERVICE=
# Redis 各节点地址
REDIS_FIRST_HOST=
REDIS_SECOND_HOST=
REDIS_THIRD_HOST=
# Redis 各节点端口
REDIS_FIRST_CLUSTER_PORT=
REDIS_SECOND_CLUSTER_PORT=
REDIS_THIRD_CLUSTER_PORT=
# Redis 密码
REDIS_CLUSTER_PASSWORD=

配置完 Redis 哨兵之后,在程序中使用 Redis 便会走 default 的配置。

Redis::set('test', '1');

配置cache

Redis 的哨兵模式是前置工作,配置好后,我们将 cache 改为 Redis 驱动。

修改 .env 文件的 CACHE_DRIVER 配置。

CACHE_DRIVER=redis

config/database.php中 redis.clusters 下增加一组单独的配置(cache),提供给缓存使用。

// config/database.php
……
'redis' => [
    ……
    'clusters' => [
            'default' => [
                [
                    'host' => env('REDIS_FIRST_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_FIRST_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_SECOND_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_SECOND_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_THIRD_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_THIRD_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
            ],
            // 新增配置
            'cache' => [
                [
                    'host' => env('REDIS_FIRST_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_FIRST_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_SECOND_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_SECOND_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_THIRD_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_THIRD_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
            ]
    ]
]
……

配好之后,在 Laravel 使用 Cache

Cache::put('topic_count', 1234, $expiredAt)

Redis中会产生如下记录,Laravel 贴心的给加上了laravel_cache业务前缀,此配置前缀名可在 config/cache.php 中修改。

Redis> get larabbs.com:laravel_cache:topic_count
1234

配置session

session 修改本质上于 cache 相同,但又有一些小不同。

同样地,像cache配置一样,修改 .env 文件的 SESSION_DRIVER 配置。

SESSION_DRIVER=redis

config/database.php中 redis.clusters 下增加一组单独的配置(session),提供给session使用。

// config/database.php
……
'redis' => [
    ……
    'clusters' => [
            'default' => [
                ……
            ],
            'cache' => [
                ……
            ],
            // 新增
            'session' => [
                [
                    'host' => env('REDIS_FIRST_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_FIRST_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_SECOND_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_SECOND_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
                [
                    'host' => env('REDIS_THIRD_HOST', 'localhost'),
                    'password' => env('REDIS_CLUSTER_PASSWORD', null),
                    'port' => env('REDIS_THIRD_CLUSTER_PORT', 6379),
                    'database' => 0,
                ],
            ]
    ]
]
……

如此修改完在,Laravel 使用 session 时,就会存入 Redis 中。

larabbs.com:laravel_cache:1WeqRUrnKatLrqqskG1FNjLBv51HOaa8GTLPTmdW

只不过会有一些小问题,session 存入 Redis 也是以 laravel_cache 作为业务前缀,这样不方便区别缓存和session,我们需要把他们区别开,这样更方便管理。

继续修改!

database/cache.php 中 stores 下增加配置

// database/cache.php

'stores' => [
……
        'redis' => [
            'driver' => 'redis',
            'connection' => 'cache',
        ],

        // 增加此段配置
        'redis:session' => [
            'driver' => 'redis',
            'connection' => 'session',
            'prefix' => 'session', 
        ],
……
],

.env 文件中,增加 session 相关环境变量

SESSION_CONNECTION=session
SESSION_STORE=redis:session

此时再使用session时,Redis中便会有如下数据,session 和 cache 可以通过键名来区别。

larabbs.com:session:1WeqRUrnKatLrqqskG1FNjLBv51HOaa8GTLPTmdW

参考 https://laracasts.com/discuss/channels/laravel/redis-sessions-prefix?page=1&replyId=434917

配置queue

TODO: queue