标题:【Laravel系列4.7】连接redis以及缓存应用

文章目录
    分类:PHP 标签:Laravel,PHP框架

    连接redis以及缓存应用

    在现代的数据库应用中,Redis 已经占据了很重要的位置。关于 Redis 的优点相信也不用我多说了,快速的内容访问也能够充当缓存数据库来使用。早前几年还有不少的公司在使用 Memcached ,但是现在就已经屈指可数了。毕竟在同样的功能下,Redis 拥有更多的数据类型,也能适应更多的场景。Laravel 也是可以完美支持 Memcached 的,不过这个就不在我们的学习范围里了,有兴趣的同学可以自己研究一下。注意,是 Memcached 不是 Memcache 哦,Memcache 是已经相当于被淘汰的技术了。

    Redis 配置及使用

    同样地,在 config/database.php 中,我们就可以见到 Redis 的配置。

    'redis' => [
    
        'client' => env('REDIS_CLIENT', 'phpredis'),
    
        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        ],
    
        'default' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_DB', '0'),
        ],
    
        'cache' => [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', '6379'),
            'database' => env('REDIS_CACHE_DB', '1'),
        ],
    
    ],

    在这个配置中,我们能清楚地看到它同时还可以方便地配置 Redis Cluster ,这个是 Redis 自带的集群。在配置中有一个 default 和一个 cache 的配置,这个 cache 配置实际上是如果我们将 Laravel 默认的缓存目标设置为 Redis 的话,就会走这个配置,它会默认使用 Redis 的 1 库。这个缓存相关的配置我们将在后面马上看到。


    使用的话就很简单了。

    Route::get('redis/set', function(){
        \Illuminate\Support\Facades\Redis::connection('default')->client()->set('test', 1);
    });
    
    Route::get('redis/get', function(){
        echo \Illuminate\Support\Facades\Redis::connection('default')->client()->get('test');
    });

    使用 Redis 门面对象的 connection() 连接方法获得连接对象,然后调用 client() 方法获得连接客户端对象,到这一步,其实获取到的就是我们正常手写 Redis 扩展时的那个对象。接下来的操作相信不用多说大家也清楚了,其它的数据结构大家可以自己试试,我们再来看看队列怎么应用。

    Route::get('redis/lpush', function(){
        \Illuminate\Support\Facades\Redis::connection('default')->client()->rpush('LeftQueue', date('Y-m-d H:i:s'));
    });
    
    Route::get('redis/lpop', function(){
        echo \Illuminate\Support\Facades\Redis::connection('default')->client()->lpop('LeftQueue');
    });

    rpush() 右进,lpop() 左出,如果换成 lpush() 的话,就是一个栈式的操作了。非常地简单方便。


    其实 Redis 这一块的源码不用讲太多,大家也能够猜到,connection() 建立链接,client() 获得 Redis 对象。首先通过门面 Redis 对象,找到它的服务提供者也就是 laravel/framework/src/Illuminate/Redis/RedisManager.php 。在这个文件中就有 connection() 方法,下一步会调用到一个 connector() 方法。

    protected function connector()
    {
        $customCreator = $this->customCreators[$this->driver] ?? null;
    
        if ($customCreator) {
            return $customCreator();
        }
    
        switch ($this->driver) {
            case 'predis':
                return new PredisConnector;
            case 'phpredis':
                return new PhpRedisConnector;
        }
    }

    在这里,会有两种连接 Redis 的驱动可供我们使用,phpredis 就是我们通过 PECL 搜索到的那个源码编译安装的 PHP redis 扩展包,而 predis 则是纯 PHP 写的 Redis 驱动,好处是不用去服务器安装编译。这个其实很明显,predis 的效率是不及 phpredis 的。剩下的呢?真的没什么了,PhpRedisConnector 里面就是去实例化一个 Redis 对象了,这个就是我们的 client() 返回来的东西。

    缓存配置及应用

    我们在 Laravel 中,可以像上面那样去使用 redis 来充当缓存,不过大家的选择可不能只限于 redis 呀,在很多情况下,我们可能会用别的缓存工具,比如说 Memcached ,也有可能会需要直接的文件缓存。当然,这些现在虽说已经用得很少了,但是不排除有的项目会有特殊的需求。因此,Laravel 中也提供了一套缓存组件。


    首先,我们还是来看看缓存组件的配置文件。

    return [
        'default' => env('CACHE_DRIVER', 'file'),
    
        'stores' => [
    
            'apc' => [
                'driver' => 'apc',
            ],
    
            'array' => [
                'driver' => 'array',
                'serialize' => false,
            ],
    
            'database' => [
                'driver' => 'database',
                'table' => 'cache',
                'connection' => null,
                'lock_connection' => null,
            ],
    
            'file' => [
                'driver' => 'file',
                'path' => storage_path('framework/cache/data'),
            ],
    
            'memcached' => [
                'driver' => 'memcached',
                'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
                'sasl' => [
                    env('MEMCACHED_USERNAME'),
                    env('MEMCACHED_PASSWORD'),
                ],
                'options' => [
                    // Memcached::OPT_CONNECT_TIMEOUT => 2000,
                ],
                'servers' => [
                    [
                        'host' => env('MEMCACHED_HOST', '127.0.0.1'),
                        'port' => env('MEMCACHED_PORT', 11211),
                        'weight' => 100,
                    ],
                ],
            ],
    
            'redis' => [
                'driver' => 'redis',
                'connection' => 'cache',
                'lock_connection' => 'default',
            ],
    
            'dynamodb' => [
                'driver' => 'dynamodb',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
                'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
                'endpoint' => env('DYNAMODB_ENDPOINT'),
            ],
    
            'octane' => [
                'driver' => 'octane',
            ],
    
        ],
    
        'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
    
    ];

    在这个配置文件中,我们会看到 default 这个属性,它表示的其实和我们在数据库中的配置是一个意思,也就是指定的一个缓存驱动。根据 .env 文件中 CACHE_DRIVER 设置的值,来获取 stores 里的缓存驱动。stores 中有各种缓存数据库的驱动,apc 也是比较常见的一种缓存数据库,array 以数组的形式缓存在内存中和程序运行状态同生命周期,如果结束当前请求,缓存就失效了。dynamodb 是亚马逊的云缓存数据库的配置,octane 这个东西我也没接触过。


    在默认情况下,走得都是 file 。我们可以看到 stores 属性中 file 的配置,只需要指定 driver 为 file ,并且指定一个 path ,也就是缓存文件的保存路径。我们先来试试这个 file 缓存。

    Route::get('cache/default/set', function(){
        \Illuminate\Support\Facades\Cache::set('a', '1');
    });
    Route::get('cache/default/get', function(){
        echo \Illuminate\Support\Facades\Cache::get('a');
    });

    使用浏览器运行 /cache/default/set 路径之后,通过 /cache/default/get 路径就可以获取到刚刚我们保存在缓存中的数据。然后根据 path 路径去查找缓存文件,会发现在 storage/framework/cache/data 目录下多了 storage/framework/cache/data/86/f7/86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 这样一个文件,文件内容是

    9999999999s:1:"1";

    这就是我们默认的文件缓存生成的缓存文件。对于文件缓存来说,很多小型的网站,比如说一些在虚拟机上使用的企业官网非常有用。因为很多这样的小项目都不会去购买或者搭建专用的缓存服务器的,文件缓存对它们来说是最方便的一种缓存方式。


    接下来,我们修改 .env 中的配置,将 CACHE_DRIVER 换成 redis ,也就是使用 redis 数据库来作为缓存驱动,然后直接测试。

    Route::get('cache/redis/set', function(){
        \Illuminate\Support\Facades\Cache::set('a', '1');
    });
    Route::get('cache/redis/get', function(){
        dump(\Illuminate\Support\Facades\Cache::get('a')); // 1
    
        dump(\Illuminate\Support\Facades\Redis::connection('default')->client()->get('a'));
        dump(\Illuminate\Support\Facades\Redis::connection('cache')->client()->get('a'));
        dump(\Illuminate\Support\Facades\Redis::connection('cache')->client()->get('laravel_cache:a')); // 1
    });

    再次请求 /cache/redis/set ,文件缓存目录中就不会再生成新的缓存文件了,缓存数据现在被保存到了 Redis 中。在 /cache/redis/get 里面,我们通过 Cache 门面类可以方便地取得缓存的数据。这时,我们再测试去使用 Redis 的门面类获取缓存数据,会发现这个缓存数据是无法被读取到的。还记得我们最上面看到的 redis 配置中的 cache 配置吗?默认情况下,cahce 数据会被放到 redis 的 1 库中。


    接下来,我们再使用 redis 通过 cache 的 connection() 来获取数据,不过还是无法获取。同样的,这个也和 cache.php 的配置有关。仔细看配置文件,会发现有一个 prefix 属性,这里是指定 cache 会自动添加的前缀值,默认会加上 laravel_cache 这样一个前缀,于是,保存在 redis 中的键就需要使用 laravel_cache:a 这样的方式来获取内容。


    大家也可以向数据库连接中指定不同的 connection() 一样来指定使用的缓存驱动。

    Route::get('cache/store/set', function(){
        \Illuminate\Support\Facades\Cache::store('file')->set('a', '1');
        \Illuminate\Support\Facades\Cache::store('redis')->set('a', '2');
    });
    Route::get('cache/store/get', function(){
        dump(\Illuminate\Support\Facades\Cache::store('file')->get('a')); // 1
        dump(\Illuminate\Support\Facades\Cache::store('redis')->get('a')); // 2
    });

    Cahce 这个门面类中,通过服务容器实例化的是 laravel/framework/src/Illuminate/Cache/CacheManager.php 这个缓存管理对象。我们直接通过 get() 方法,查看到它会调用这个对象中的 resolve() 方法。

    protected function resolve($name)
    {
        $config = $this->getConfig($name);
    
        if (is_null($config)) {
            throw new InvalidArgumentException("Cache store [{$name}] is not defined.");
        }
    
        if (isset($this->customCreators[$config['driver']])) {
            return $this->callCustomCreator($config);
        } else {
            $driverMethod = 'create'.ucfirst($config['driver']).'Driver';
    
            if (method_exists($this, $driverMethod)) {
                return $this->{$driverMethod}($config);
            } else {
                throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");
            }
        }
    }

    注意看中间的 driverMethod 拼接出来的方法名称。如果是 redis 的话,那么它会拼接出来一个叫 createRedisDriver 的方法名,并在下面调用这个方法。

    protected function createRedisDriver(array $config)
    {
        $redis = $this->app['redis'];
    
        $connection = $config['connection'] ?? 'default';
    
        $store = new RedisStore($redis, $this->getPrefix($config), $connection);
    
        return $this->repository(
            $store->setLockConnection($config['lock_connection'] ?? $connection)
        );
    }

    在这里,$redis 对象同样是通过服务容器创建的,也就是我们的 phpredis 或者 predis 对象,然后在 RedisStore 中对 redis 对象进行连接设置之类的操作。


    其它的驱动大家可以自己查阅一下源代码,这块的源码还是比较简单的。

    总结

    对于现代化的开发来说,缓存真的是非常重要的应用。但是呢,由于缓存数据库都相对来说会比关系型数据库简单一些,因此这些组件在 Laravel 中的呈现反而相对来说会简单一些。我们今天主要是以 Redis 的学习为主,顺带也看了一下 Cache 组件的实现,主要也就是如何选择缓存驱动的实现。内容不多,也非常容易看明白源码。至此,数据库相关的内容也就学习完成了。接下来,我们就要进入前端相关的内容学习,不要落下了哦!


    参考文档:


    https://learnku.com/docs/laravel/8.x/cache/9389

    视频链接

    微信文章地址:http://mp.weixin.qq.com/s?__biz=MzIxODQyNTU1MA==&mid=2247486718&idx=1&sn=3a079e24c3d3fa3b13e3d477f81d1942&chksm=97ebfd5fa09c744966e3769a78af68912915fdb673a42b7138cb2aeb1b3bb5efb95feb7d9170&scene=27#wechat_redirect

    B站视频地址:https://www.bilibili.com/video/BV1zS4y1H7EU

    微信视频地址:https://mp.weixin.qq.com/s/tDhUmWSxJaRVy1l4lT5mDg

    搜索
    关注