主页 > PHP > 让laravel的cache支持用connection选择redis服务

让laravel的cache支持用connection选择redis服务

2014 年 01 月 10 日 没有评论

前两篇文章都有提到这个cache和session选择redis作为存储机制的时候遇到的一些问题,今天这里着重说明下。
先看下我的database.php中关于redis的配置:

    /*
	|--------------------------------------------------------------------------
	| Redis Databases
	|--------------------------------------------------------------------------
	|
	| Redis is an open source, fast, and advanced key-value store that also
	| provides a richer set of commands than a typical key-value systems
	| such as APC or Memcached. Laravel makes it easy to dig right in.
	|
	*/
	'redis' => array(
		'cluster' => false,
		'default' => array(
			'host'     => '192.168.1.120',
			'port'     => 6379,
			'database' => 0,
		),
		'cache' => array(
			'host'     => '192.168.1.120',
			'port'     => 6379,
			'database' => 1,
		),
		'session' => array(
			'host'     => '192.168.1.120',
			'port'     => 6379,
			'database' => 2,
		),
	),

我这么配置的意图就是想在缓存的时候使用cache这个配置项,session的数据存储在session这个配置项。
那么我们先来看下我在app/config/cache.php中的相关配置

   'driver' => 'redis',
    //.......
   'path' => storage_path().'/cache',
	/*
	|--------------------------------------------------------------------------
	| Database Cache Connection
	|--------------------------------------------------------------------------
	|
	| When using the "database" cache driver you may specify the connection
	| that should be used to store the cached items. When this option is
	| null the default database connection will be utilized for cache.
	|
	*/
	'connection' => 'cache',

然后再来看下我在app/config/session.php中的相关配置

    'driver' => 'redis',
    //.......
    'files' => storage_path().'/sessions',
	/*
	|--------------------------------------------------------------------------
	| Session Database Connection
	|--------------------------------------------------------------------------
	|
	| When using the "database" session driver, you may specify the database
	| connection that should be used to manage your sessions. This should
	| correspond to a connection in your "database" configuration file.
	|
	*/
	'connection' => 'session',

这里我把两者的驱动都设置为redis。
经过对以上的设置进行测试,发现一个问题:session的数据可以正常存储到指定的服务中,而cache的数据并没有按照预期的进行了存储,而是存储在了session的服务中。这是为什么呢?请继续往下看。
现在我们换种方法,我们稍微修改下上面的配置,我们把session的驱动改成非redis,比如memcache等,这时我们再进行测试,效果如下:
缓存的数据存储到了default上面,并非我们期望的cache服务。这又是为什么呢?
通过上面我们发现了两个问题,暂且按顺序叫问题A和问题B吧。
这里我们先来解决问题B。
问题B的产生原因是laravel的cache并不支持redis的connection(也就是说当缓存的驱动是redis时,connection的设置没有意义的),只有database驱动时才支持,那么我们怎么改,才能支持呢?,修改起来很简单。
既然是cache那么肯定找cacheManager了: Laravel/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php
修改一下方法的代码为一下:

    /**
	 * Create an instance of the Redis cache driver.
	 *
	 * @return \Illuminate\Cache\RedisStore
	 */
	protected function createRedisDriver()
	{
		$redis = $this->app['redis'];
		// 增加一行获取cache connection值的代码
		$connection = $this->app['config']['cache.connection'];
		// 为RedisStore设置第三个参数
		return $this->repository(new RedisStore($redis, $this->getPrefix(), $connection));
	}

OK,改完了,是不是很简单呢。
这样子一改,就能解决我们的问题B,可以保证当我们的cache的驱动为redis时,缓存的数据是存在connection(cache)指定的服务中的。
那么我们这样子改了之后能否解决A问题呢?很抱歉,不能!!!
那按照酱紫我测试了下,结果还是跟上面没改之前的结果一样(session的数据可以正常存储到指定的服务中,而cache的数据并没有按照预期的进行了存储,而是存储在了session的服务中。)
目前我还没有发现有好的解决方案,为什么,请看下面分析。
其实我们大家都知道,session其实也一种缓存,那么既然是一种缓存,那么肯定是按照缓存的流程来处理的(其实laravel的部分session驱动(redis,memcache,memcached)走的就是缓存的存储流程)
具体来看代码:
文件是:Laravel/vendor/laravel/framework/src/Illuminate/Session/SessionManager.php

    /**
	 * Create an instance of the Redis session driver.
	 *
	 * @return \Illuminate\Session\Store
	 */
	protected function createRedisDriver()
	{
                // 这里会设置当前redis的connection为cache
		$handler = $this->createCacheHandler('redis');
                // 这里会设置当前redis的connection为session(也就是说覆盖了上面的)
		$handler->getCache()->getStore()->setConnection($this->app['config']['session.connection']);
		return $this->buildSession($handler);
	}

这段代码是在应用启动的时候通过booting callbacks启动session时调用的一个方法,这个方法的功能是创建一个redis的session驱动。
我们不妨看下createCacheHandler这个方法:

    /**
	 * Create the cache based session handler instance.
	 *
	 * @param  string  $driver
	 * @return \Illuminate\Session\CacheBasedSessionHandler
	 */
	protected function createCacheHandler($driver)
	{
		$minutes = $this->app['config']['session.lifetime'];
                // 这里最终会调用下面的CacheManager的createRedisDriver方法
		return new CacheBasedSessionHandler($this->app['cache']->driver($driver), $minutes);
	}

我们来看下CacheManager的createRedisDriver方法
文件是: Laravel/vendor/laravel/framework/src/Illuminate/Cache/CacheManager.php

    /**
	 * Create an instance of the Redis cache driver.
	 *
	 * @return \Illuminate\Cache\RedisStore
	 */
	protected function createRedisDriver()
	{
		$redis = $this->app['redis'];
		
		$connection = $this->app['config']['cache.connection'];
		// 这里我们设置我们cache的redis connection
		return $this->repository(new RedisStore($redis, $this->getPrefix(), $connection));
	}

这段代码是我们改过之后的代码,但是没关系。通过上面的分析,我们发现,其实在cache和session同时使用一个驱动的时候最终的驱动是由session的配置文件中的connection值决定的,因为它覆盖了cache设定的驱动值。那么造成这个问题的原因就是我们上面说的,session的所有数据处理是根据cache的流程处理的,因为session也是一种cache。=.=
其实这个要说是个问题,其实也是个问题,因为它没有按照我们的要求进行处理。
要是不是个问题,其实也不是个问题,因为session从某种意义上来说也是缓存,当然后面设置的覆盖了前面设置的。
那么有没有办法解决呢?提供两个侧面的解决方案:
1:两者不要同时使用一种驱动,可以交替者。比如cache用memcache,session用redis等。
2:就是用上次我提到的方案:

$redisCache = App::make('cache'); // Assumes "redis" set as your cache
$redisCache->setConnection('cache'); // Your redis cache connection
$redisCache->put('testtCacheIndex', 'fbbinValue', 10000);

// 或者

$redis = Redis::connection('cache');
$redis->set('fbbin', 'fbbinValue');
var_dump($redis->get('fbbin'))

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>