緩存是web開發中重要的一部分,我相信很多人和我一樣,經常忽略這個問題。 隨着工作經驗的累積,我已經意識到緩存是多么的重要,這里我通過 Scotch 來解釋一下它的重要性。
通過觀察發現,Scotch每天按照計划發布文章,然而,上一次發布文章的24小時內,新的文章不會被放出,因此,登陸頁面上的數據將保持24小時不變。 換句話說,在24小時內( 更准確的說是22-23個小時)向數據庫請求文章數據是沒有意義的。
緩存可以很好的解決這個問題,當遇到一個頁面請求時,我們可以把結果緩存22個小時,只要在這個時間內通過控制器請求的數據,都是緩存中的數據,直到緩存超時。
下面我們來看看Laravel 中緩存的基本用法,然后看一個簡單的例子,試試緩存到底能帶來多大的加速。
在 Laravel 中緩存的基本用法
Laravel 使得我們可以輕松地轉換出我們想要生成緩存的方式。我們很容易修改緩存驅動方式。只需到 config / cache.php
來查看可用的驅動程序:
- apc
- array
- database
- file
- memcached
- redis
你可以在 .env
文件中修改緩存驅動:
CACHE_DRIVER=file
你可以繼續嘗試修改它們而不用擔心配置,因為它默認驅動是
file
。
Cache
facade 暴露了很多靜態方法來創建,更新,獲取,刪除和檢查緩存內容的存在。讓我們在構建演示應用程序之前先了解一下這些方法。
建立/更新緩存值
我們使用 put()
方法來新增或更新緩存值。該方法必須使用 3 個參數:
鍵名
鍵值
過期時間
單位分鍾
例如:
Cache::put('key', 'value', 10);
鍵名
是緩存的唯一標識,需要時要用它來獲取值。
此外,我們也可以用 remember()
方法自動獲取和更新一個緩存值。該方法首先檢查 鍵名
是否存在,如果已經創建則返回結果。否則它會創建新的 鍵名
,並用閉包返回結果進行賦值,就象下面:
Cache::remember('articles', 15, function() {
return Article::all();
});
參數 15
是要緩存的分鍾數。這樣的話,我們甚至根本不必檢查緩存是否過期。Laravel 不僅會替我們打理,而且會獲取或重新生成該緩存,不需要我們顯式地告訴它如何操作。
檢索緩存值
緩存的值可以通過 get()
方法去獲取,這個方法接受一個參數 key
:
Cache::get('key');
檢查是否已存在key
有時候在更新或者取回緩存值之前判斷這個緩存的key是否存在是很有必要的,使用 has()
方法就可以實現:
if (Cache::has('key')){
Cache::get('key');
} else {
Cache::put('key', $values, 10);
}
刪除緩存值
刪除緩存值可以用 forget()
方法並把需要刪除的 key
作為參數傳進去:
Cache::forget('key');
我們也可以檢索緩存值並刪除它。我喜歡把這個稱為一次性緩存:
$articles = Cache::pull('key');
我們還可以使用以下命令在緩存過期前就把所有緩存清楚掉:
php artisan cache:clear
一個例子
這是一個簡單的演示,主要是為了說明是否使用緩存對請求響應所需要時間的影響,為了讓你能更直接的了解,我建議你跟着教程自己來 構建 一個 Laravel 例子。
模型和表遷移
使用下面命令新建一個 Article
模型:
php artisan make:model Article -m
-m
參數會自動創建一個 migration ,所以無需再使用 create migration 命令了,這個命令會創建 App/Article.php
和 database/migrations/xxxx_xx_xx_xxxxxx_create_articles_table.php
文件。
修改你的 migration 文件並添加以下兩行:
public function up() {
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
// add the following
$table->string("title");
$table->string("content");
$table->timestamps();
});
}
然后我們就可以用以下命令遷移我們的數據庫了:
php artisan migrate
填充數據庫
接下來我們需要填充文章的數據庫表,在 database/seeds/DatabaseSeeder.php
中,修改 run()
如下所示:
public function run() {
Model::unguard();
// use the faker library to mock some data
$faker = Faker::create();
// create 30 articles
foreach(range(1, 30) as $index) {
Article::create([
'title' => $faker->sentence(5),
'content' => $faker->paragraph(6)
]);
}
Model::reguard();
}
Laravel中包含 Faker
庫用以快速生成假數據,我們可以使用PHP的 range()
方法去生成30條假數據。
接下來我們就可以通過這條 artisan 命令去填充數據庫了:
php artisan db:seed
創建文章控制器
接下來,我們可以創建一個處理請求和緩存的控制器,首先它是空的:
php artisan make:controller ArticlesController
...然后我們增加一個路由 app/Http/routes.php
指向這個文章控制器的 index 方法:
Route::group(['prefix' => 'api'], function() {
Route::get('articles', 'ArticlesController@index');
});
現在我們的數據庫都是用樣本數據建立起來的,我們可以進行測試了。
未使用緩存的響應
讓我們看看我們傳統的控制器方法是什么樣的,沒有緩存,處理響應需要多長時間,在 index()
方法中,返回文章的資源數據:
public function index() {
$articles = Articles::all();
return response()->json($articles);
}
你也可以使用 Postman 去請求(http://localhost/api/articles) 或者直接用瀏覽器打開,你就可以看到如下所示。
請注意在本地開發服務器上完成此請求所花費的時間。
從緩存中返回的響應
現在讓我們嘗試使用緩存,看看數據響應所花費的時間是否會有顯着差異。修改 index()
方法為:
public function index() {
$articles = Cache::remember('articles', 22*60, function() {
return Article::all();
});
return response()->json($articles);
}
現在我們使用 remember()
方法緩存了文章,緩存時間為 22 小時,再次運行並觀察所花費的時間,可以看我的截圖:
結果和建議
在我的標准開發環境中測試得出,使用緩存時產生響應所需的時間比沒有使用的時候要少:
未使用緩存
Server Hits | Time |
---|---|
1st | 4478ms |
2nd | 4232ms |
3rd | 2832ms |
4th | 3428ms |
Avg | 3742ms |
使用緩存 (File 驅動)
Server Hits | Time |
---|---|
1st | 4255ms |
2nd | 3182ms |
3rd | 2802ms |
4th | 3626ms |
Avg | 3466ms |
使用緩存 (Memcached 驅動)
Server Hits | Time |
---|---|
1st | 3626ms |
2nd | 566ms |
3rd | 1462ms |
4th | 1978ms |
Avg | 1908ms 😃 |
使用緩存 (Redis 驅動)
這里需要通過 composer 安裝 predis/predis 包
Server Hits | Time |
---|---|
1st | 3549ms |
2nd | 1612ms |
3rd | 920ms |
4th | 575ms |
Avg | 1664ms 😃 |
是不是很酷呢?這里有兩點需要注意:
- 即使使用了緩存,第一次請求響應還是需要比較多的時間,因為當第一次請求的時候緩存里面還是空的。
- 與 file 驅動相比,Memcached 和 Redis 的速度更快,所以建議在項目較大時使用外部緩存驅動。
結論
使用文件、數據庫作為驅動,兩者在速度上沒有很明顯的區別。但是如果我們使用第三方服務作為驅動, 可以很明顯地看到性能提升。所以投資高速緩存是值得的。
更多現代化 PHP 知識,請加入 PHP / Laravel 知識社區 一起學習成長吧。