今天繼續來把我們的玩具爬蟲加入新的元素
D17 - 團隊觀戰區爬蟲 v3 ft. AWS S3 時,我們把爬蟲的結果上傳到 S3,作為一種減少爬蟲次數的解法,並讓 S3 來替我們扛流量,
那如果我只是想要減少爬蟲次數,但依然開 API 讓 Client 使用、而不是上傳到其他地方的話,可以怎麼做呢?
我們可以加入 Cache 的機制,把結果暫存起來繼續使用,
就讓我們來看看要怎麼做。
什麼是 Cache 的機制?
當我們的爬蟲,每次爬完資料後,就先把結果暫存到 Cache,
當下一次 Request 進來時,會先檢查 Cache 內是不是有我要的資料,如果沒有,才會重新執行爬蟲,
藉著 Cache 的機制,我們可以讓爬蟲爬回來的結果不是僅限於單次的 Response,而是可以被重複使用,
另外,稍微釐清一點,有時,Cache
跟 Cache 機制
並不完全相等,
Cache 有時指的是 CPU快取 或 記憶體,是電腦中用來加速的一個硬體零件,
Cache 機制則是廣泛地指把會常用的資料暫存起來供重複利用,以達到加速或節省資源的方式。
說到 Cache 的工具,Redis 幾乎是最知名的,
可以把它想成是一個很快的 Server、Database、或單純的一張表,
寫入索引跟要儲存的值,下次查找時則輸入索引,看是否存在值,
除了暫存以外,Redis 會把資料放在電腦的記憶體內,使儲存跟查找的速度非常快,
但同時,當伺服器 (或開發電腦) 關機後,Redis 中的資料就會遺失,
因此,Redis 這樣的工具是來強化效能、加速用的,
關鍵的資料請避免放在 Redis,而是要放在資料庫。
接下來,讓我們直接送上,加入了 Redis 的程式碼:
每次 Request 進來時,會先檢查 Cache,
如果有 Cache,就直接回傳,
如果沒有 Cache,就執行爬蟲,並把爬蟲結果寫回 Cache,
我把 Cache 設定為 1 分鐘就會過期,也就是,在一分鐘後,下一個 Request 就會需要重新爬蟲,抓取最新的鐵人賽資料。
// src/router.js
import Router from 'express';
import { createClient } from 'redis';
import { getMembersWithPostInfo } from './ithelp-crawler.js';
const router = Router();
const client = createClient({
url: process.env.REDIS_URL,
});
router.get('/team/:teamId/members', async (req, res) => {
const teamId = parseInt(req.params.teamId);
if (!Number.isInteger(teamId)) {
return res.status(400).json({
error: 'teamId is not an integer'
});
}
await client.connect();
const cacheKey = `team_${teamId}`;
const cache = await client.get(cacheKey);
const members = cache
? JSON.parse(cache)
: await getMembersWithPostInfo(teamId);
await client.setEx(cacheKey, 20, JSON.stringify(members));
await client.disconnect();
return res.json({ data: members });
});
export default router;
依然透過方便的 Docker compose 來定義 container:
# docker-compose.yml
version: "3"
services:
redis:
image: redis
crawler:
build: .
ports:
- 3000:3000
environment:
- REDIS_URL=redis://redis
執行:
$ sudo docker compose up -d
接著就可以使用我們的 API 了,
一樣,如果是雲端平台,記得要在後台打開 Server 的防火牆,
好的,我們的玩具箱越來越豐富了,那今天就到這邊。