通过缓存构建高性能 Laravel 应用

由 学院君 创建于3年前, 最后更新于 11个月前

版本号 #2

20678 views

9 likes

1 collects

配置

Laravel 为不同的缓存系统提供了统一的 API。缓存配置位于 config/cache.php。在该文件中你可以指定在应用中默认使用哪个缓存驱动。Laravel 开箱支持主流的缓存后端如 Memcached和 Redis 等。

缓存配置文件还包含其他文档化的选项,确保仔细阅读这些选项。默认情况下,Laravel 被配置成使用文件缓存,这会将序列化数据和缓存对象存储到文件系统。对于大型应用,建议使用内存缓存如 Memcached 或 APC,你甚至可以为同一驱动配置多个缓存配置。

驱动预备知识

数据库

使用 database 缓存驱动时,你需要设置一张表存储缓存项。下面是该表的 Schema 声明:

Schema::create('cache', function($table) {

$table->string('key')->unique();

$table->text('value');

$table->integer('expiration');

});

注:你还可以使用 Artisan 命令 php artisan cache:table 通过相应的 schema 生成迁移。

Memcached

使用 Memcached 缓存要求安装了Memcached PECL 包,即 PHP Memcached 扩展。你可以在配置文件 config/cache.php 中列出所有 Memcached 服务器:

'memcached' => [

[

'host' => '127.0.0.1',

'port' => 11211,

'weight' => 100

],

],

你还可以设置 host 选项为 UNIX socket 路径,如果你这样做,port 选项应该置为 0:

'memcached' => [

[

'host' => '/var/run/memcached/memcached.sock',

'port' => 0,

'weight' => 100

],

],

Redis

使用 Laravel 的 Redis 缓存之前,你需要通过 Composer 安装 predis/predis 包(~1.0)。

想要了解更多关于 Redis 的配置,查看 Larave 的 Redis 文档。

缓存使用

获取缓存实例

Illuminate\Contracts\Cache\Factory 和 Illuminate\Contracts\Cache\Repository 契约提供了访问 Laravel 缓存服务的方法。Factory 契约提供了所有访问应用定义的缓存驱动的方法。Repository 契约通常是应用中 cache 配置文件中指定的默认缓存驱动的一个实现。

不过,你还可以使用 Cache 门面,这也是我们在整个文档中使用的方式,Cache 门面提供了简单方便的方式对底层 Laravel 缓存契约实现进行访问:

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller

{

/**

* 显示应用所有用户列表.

*

* @return Response

*/

public function index()

{

$value = Cache::get('key');

//

}

}

访问多个缓存存储

使用 Cache 门面,你可以使用 store 方法访问不同的缓存存储器,传入 store 方法的键就是 cache 配置文件中 stores 配置数组里列出的相应的存储器:

$value = Cache::store('file')->get('foo');

Cache::store('redis')->put('bar', 'baz', 10);

从缓存中获取数据

Cache 门面的 get 方法用于从缓存中获取缓存项,如果缓存项不存在,返回 null。如果需要的话你可以传递第二个参数到 get 方法指定缓存项不存在时返回的自定义默认值:

$value = Cache::get('key');

$value = Cache::get('key', 'default');

你甚至可以传递一个闭包作为默认值,如果缓存项不存在的话闭包的结果将会被返回。传递闭包允许你可以从数据库或其它外部服务获取默认值:

$value = Cache::get('key', function() {

return DB::table(...)->get();

});

检查缓存项是否存在

has 方法用于判断缓存项是否存在,如果值为 null 或 false 该方法会返回 false:

if (Cache::has('key')) {

//

}

数值增加/减少

increment 和 decrement 方法可用于调整缓存中的整型数值。这两个方法都可以接收第二个参数来指明缓存项数值增加和减少的数目:

Cache::increment('key');

Cache::increment('key', $amount);

Cache::decrement('key');

Cache::decrement('key', $amount);

获取&存储

有时候你可能想要获取缓存项,但如果请求的缓存项不存在时给它存储一个默认值。例如,你可能想要从缓存中获取所有用户,或者如果它们不存在的话,从数据库获取它们并将其添加到缓存中,你可以通过使用 Cache::remember 方法实现:

$value = Cache::remember('users', $minutes, function() {

return DB::table('users')->get();

});

如果缓存项不存在,传递给 remember 方法的闭包被执行并且将结果存放到缓存中。

你还可以使用 rememberForever 方法从缓存中获取数据或者将其永久存储起来:

$value = Cache::rememberForever('users', function() {

return DB::table('users')->get();

});

获取&删除

如果你需要从缓存中获取缓存项然后删除,你可以使用 pull 方法,和 get 方法一样,如果缓存项不存在的话返回 null:

$value = Cache::pull('key');

在缓存中存储数据

你可以使用 Cache 门面上的 put 方法在缓存中存储数据。当你在缓存中存储数据的时候,需要指定数据被缓存的时间(分钟数):

Cache::put('key', 'value', $minutes);

除了传递缓存项失效时间,你还可以传递一个代表缓存项有效时间的 PHP Datetime 实例:

$expiresAt = Carbon::now()->addMinutes(10);

Cache::put('key', 'value', $expiresAt);

缓存不存在时存储数据

add 方法只会在缓存项不存在的情况下添加数据到缓存,如果数据被成功添加到缓存返回 true,否则,返回false:

Cache::add('key', 'value', $minutes);

永久存储数据

forever 方法用于持久化存储数据到缓存,这些值必须通过 forget 方法手动从缓存中移除:

Cache::forever('key', 'value');

注:如果你使用的是 Memcached 驱动,当缓存数据达到上限后永久存储的数据就会被移除。

从缓存中移除数据

你可以使用 Cache 门面上的 forget 方法从缓存中移除缓存项数据:

Cache::forget('key');

还可以使用 flush 方法清除所有缓存:

Cache::flush();

注:清除缓存并不管什么缓存键前缀,而是从缓存系统中移除所有数据,所以在使用这个方法时如果其他应用与本应用有共享缓存时需要格外注意。

缓存辅助函数

除了使用 Cache 门面或缓存契约,还可以使用全局的 cache 函数来通过缓存获取和存储数据。当带有一个字符串参数的 cache 函数被调用时,会返回给定键对应的缓存值(取值):

$value = cache('key');

如果你提供了键值对数组和一个过期时间给该函数,则会在指定的有效期内存储缓存值(存储):

cache(['key' => 'value'], $minutes);

cache(['key' => 'value'], Carbon::now()->addSeconds(10));

测试调用 cache 函数时,可以像测试门面一样使用 Cache::shouldReceive 方法。

缓存标签

注:缓存标签目前不支持 file 或 database 缓存驱动,此外,当使用多标签的缓存被设置为永久存储时,使用 memcached 驱动的缓存有着最佳性能表现,因为 Memcached 会自动清除陈旧记录。

存储被打上标签的缓存项

缓存标签允许你给相关缓存项打上同一个标签以便于后续清除这些缓存值,被打上标签的缓存可以通过传递一个被排序的标签数组来访问。例如,我们可以通过以下方式在添加缓存的时候设置标签:

Cache::tags(['people', 'artists'])->put('John', $john, $minutes);

Cache::tags(['people', 'authors'])->put('Anne', $anne, $minutes);

你可以给多个缓存项打上相同标签,这是没有数目限制的。

访问被打上标签的缓存项

要获取被打上标签的缓存项,传递同样的有序标签数组到 tags 方法然后使用你想要获取的key来调用 get 方法:

$john = Cache::tags(['people', 'artists'])->get('John');

$anne = Cache::tags(['people', 'authors'])->get('Anne');

移除被打上标签的数据项

你可以同时清除被打上同一标签/标签列表的所有缓存项,例如,以下语句会移除被打上 people 或 authors 标签的所有缓存:

Cache::tags(['people', 'authors'])->flush();

这样,上面设置的 Anne 和 John 缓存项都会从缓存中移除。

相反,以下语句只移除被打上 authors 标签的语句,所以只有 Anne 会被移除而 John 不会:

Cache::tags('authors')->flush();

添加自定义缓存驱动

编写驱动

要创建自定义的缓存驱动,首先需要实现 Illuminate\Contracts\Cache\Store 契约,所以,我们的 MongoDB 缓存实现看起来会像这样子:

namespace App\Extensions;

use Illuminate\Contracts\Cache\Store;

class MongoStore implements Store

{

public function get($key) {}

public function many(array $keys);

public function put($key, $value, $minutes) {}

public function putMany(array $values, $minutes);

public function increment($key, $value = 1) {}

public function decrement($key, $value = 1) {}

public function forever($key, $value) {}

public function forget($key) {}

public function flush() {}

public function getPrefix() {}

}

我们只需要使用一个 MongoDB 连接来实现其中的每一个方法,想要看如何实现每个方法的示例,可以参考 Laravel 底层源码 Illuminate\Cache\MemcachedStore,实现完成后,我们就可以完成自定义驱动注册:

Cache::extend('mongo', function($app) {

return Cache::repository(new MongoStore);

});

注:如果你在担心将自定义缓存驱动代码放到哪,可以在 app 目录下创建一个Extensions 命名空间。不过,记住 Laravel 并没有一个严格的应用目录结构,你可以基于你的需要自由的组织目录结构。

注册驱动

要通过 Laravel 注册自定义的缓存驱动,可以使用 Cache 门面上的 extend 方法。对 Cache::extend 的调用可以在 Laravel 自带的 App\Providers\AppServiceProvider 提供的 boot 方法中完成,或者,你也可以创建自己的服务提供者来存放扩展——只是别忘了在配置文件 config/app.php 中注册服务提供者到 providers 数组:

namespace App\Providers;

use App\Extensions\MongoStore;

use Illuminate\Support\Facades\Cache;

use Illuminate\Support\ServiceProvider;

class CacheServiceProvider extends ServiceProvider

{

/**

* Perform post-registration booting of services.

*

* @return void

* @translator laravelacademy.org

*/

public function boot()

{

Cache::extend('mongo', function($app) {

return Cache::repository(new MongoStore);

});

}

/**

* Register bindings in the container.

*

* @return void

*/

public function register()

{

//

}

}

传递给 extend 方法的第一个参数是驱动名称。该值对应配置文件 config/cache.php 中的 driver 选项。第二个参数是返回 Illuminate\Cache\Repository 实例的闭包。该闭包中被传入一个 $app 实例,也就是服务容器的一个实例。

扩展被注册后,只需简单更新配置文件 config/cache.php 的 driver 选项为自定义扩展名称即可。

缓存事件

要在每次缓存操作时执行代码,你可以监听缓存触发的事件,通常,你可以将这些缓存处理器代码放到 EventServiceProvider 中:

/**

* The event listener mappings for the application.

*

* @var array

*/

protected $listen = [

'Illuminate\Cache\Events\CacheHit' => [

'App\Listeners\LogCacheHit',

],

'Illuminate\Cache\Events\CacheMissed' => [

'App\Listeners\LogCacheMissed',

],

'Illuminate\Cache\Events\KeyForgotten' => [

'App\Listeners\LogKeyForgotten',

],

'Illuminate\Cache\Events\KeyWritten' => [

'App\Listeners\LogKeyWritten',

],

];

php redis 传递闭包,通过缓存构建高性能 Laravel 应用相关推荐

  1. 《构建高性能web站点》随笔 无处不在的性能问题

    前言– 追寻大牛的足迹,无处不在的"性能"问题. 最近在读郭欣大牛的<构建高性能Web站点>,读完收益颇多.作者从HTTP.多级缓存.服务器并发策略.数据库.负载均衡. ...

  2. spring boot 缓存_Spring Boot 集成 Redis 实现数据缓存

    Spring Boot 集成 Redis 实现数据缓存,只要添加一些注解方法,就可以动态的去操作缓存了,减少代码的操作. 在这个例子中我使用的是 Redis,其实缓存类型还有很多,例如 Ecache. ...

  3. Redis学习、缓存、持久化、哨兵模式

    个人博客欢迎访问 总结不易,如果对你有帮助,请点赞关注支持一下 微信搜索程序dunk,关注公众号,获取博客源码 我写代码是为了更好的表达自我,这是艺术创作,而不单单是为了把事情搞定. -Antirez ...

  4. redis的基本操作And数据持久化方式以及redis实现mybatis缓存

    Redis 1.NoSql # NoSql(Not Only Sql),不仅仅是sql,泛指非关系型数据库 2.NoSql的诞生 随着互联网web2.0网站的兴起,传统的关系型数据库在高并发和特大规模 ...

  5. 构建高性能微服务架构(网易)

    随着移动互联网时代的兴起,提供高性能.高可用性.高扩展性的服务已经不仅仅是大公司的专利,而逐渐成为所有互联网+公司的标配需求.本文介绍网易如何利用多年的互联网架构经验和网易蜂巢的平台,帮助客户进行架构 ...

  6. SD2C:CSDN产品总监范凯——用Rails构建高性能Web应用

    2010年的SD大会已经结束两个星期了,官方的PPT说是出来了,却不让下载(提示用户名密码错误),让人感觉这1800大洋花的很有些怨气.最可恨的是,官方提供的现场演讲实录整理的实在不敢恭维,要想在团队 ...

  7. 构建高性能微服务架构 【摘自刘超】

    随着移动互联网时代的兴起,提供高性能.高可用性.高扩展性的服务已经不仅仅是大公司的专利,而逐渐成为所有互联网+公司的标配需求.本文介绍网易如何利用多年的互联网架构经验和网易蜂巢的平台,帮助客户进行架构 ...

  8. 构建高性能的ASP.NET应用(五)-如何开始寻找性能瓶颈

    既然我们讲的是如何构建高性能的ASP.NET站点应用,那么我们就开始涉及网站方面的东西.我们说过,我们会把关注点放在"调优"上面. 在调优的时候,我们没有必要把事情搞的很复杂,要& ...

  9. 微服务实战(五):落地微服务架构到直销系统(构建高性能大并发系统)

    在现代系统中,特别是互联网软件,通常会涉及到大量用户的并发访问,我们的系统一定要在架构上支持高性能.大并发的访问.一个高性能的系统通常由很多的方面组成,包括数据库高性能.Web服务器高性能.负载均衡. ...

最新文章

  1. react控制组件的显示或隐藏, 根据state判断元素显示隐藏 , setState不实时生效解决方法
  2. Transformer新型神经网络在机器翻译中的应用 | 公开课笔记
  3. [转载] 百科全说——何裕民:性格影响疾病(10-12-20)
  4. “分库分表 ?选型和流程要慎重,否则会失控
  5. [zz]grep 命令的使用
  6. 在deepin上安装YouCompleteMe
  7. Sql Server之旅——第四站 你必须知道的非聚集索引扫描
  8. 天池 在线编程 最佳利用率(二分查找 + 哈希)
  9. 计算机原理语言方框图,计算机原理整理原版1.10.docx
  10. mysql主从有关参数_mysql主从复制配置
  11. 白板机器学习笔记 P9-P12线性回归
  12. 京东智能硬件平台Alpha 让零售“无界限”
  13. 下载VCForPython27.msi
  14. 基于随机森林的特征选择算法
  15. 医院信息化建设重点工作
  16. AD16 禁止联网操作
  17. WPF 加载PDF文件
  18. 中国计算机学会推荐国际学术会议和期刊目录 2015
  19. Apple开发账号添加团队成员
  20. Google版 “AirDrop” 姗姗来迟,万能联播缘何超越Nearby Sharing?

热门文章

  1. 【图解分布式架构】看不懂直接面壁
  2. 要闻君说:FaceTime的服务究竟坑有多大?CNCF 技术监督委员会首添中国面孔,来自阿里!高通华为暂和解……...
  3. python连等号_Python比较2列表和2元组用等号
  4. 初二物理模型有哪些_暑假新初二、新初三的数学该怎么学,教辅怎么买,题该怎么刷?看这里~...
  5. linux 环境 RocketMQ 4.8.0 安装、部署控制台
  6. Flowable 数据库表结构 ACT_HI_IDENTITYLINK
  7. linux 创建用户和修改新增用户默认的家目录
  8. 第15篇: Flowable-BPMN操作流程之排他网关
  9. ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘192.168.1.165‘ (113)
  10. mysql一些基本sql操作_MySql数据库的一些基本操作---------------SQL语法