佇列 是先進先出 (FIFO) 的線性資料結構,僅允許尾端插入、頭端移除。在 Web 開發中,佇列常用於:
<?php
class SimpleQueue {
private $data = [];
public function enqueue($value) { $this->data[] = $value; }
public function dequeue() { return array_shift($this->data); }
public function peek() { return $this->data[0] ?? null; }
public function size() { return count($this->data); }
public function isEmpty() { return empty($this->data); }
}
<?php
/**
* 基於緩存驅動的佇列實作
* 支援: Redis, Memcached, APCu, File 等實現 Cache 接口的驅動
*/
class Queue {
private $_queue = [];
protected $cache;
protected $cacheKey;
public function __construct(string $queueName, $cacheDriver = null) {
$this->cacheKey = 'queue_' . $queueName;
$this->cache = $cacheDriver ?? Cache::instance(); // 需自行實作 Cache 單例
$cached = $this->cache->get($this->cacheKey);
if (is_array($cached)) $this->_queue = $cached;
}
/** 入佇列 */
public function enQueue($value): self {
$this->_queue[] = $value;
$this->persist();
return $this;
}
/** 批量出佇列 (預設 1 筆) */
public function sliceQueue(int $num = 1): array {
$num = min($num, count($this->_queue));
$output = array_splice($this->_queue, 0, $num);
$this->persist();
return $output;
}
/** 單筆出佇列 */
public function deQueue() {
$entry = array_shift($this->_queue);
$this->persist();
return $entry;
}
/** 查看隊首 */
public function peek() { return $this->_queue[0] ?? null; }
/** 查看前 N 筆 */
public function peeks(int $num): array {
return array_slice($this->_queue, 0, min($num, count($this->_queue)));
}
/** 佇列長度 */
public function size(): int { return count($this->_queue); }
/** 銷毀佇列 */
public function destroy(): void { $this->cache->remove($this->cacheKey); }
private function persist(): void {
$this->cache->set($this->cacheKey, $this->_queue);
}
}
<?php
class RedisQueue {
private $redis;
private $key;
public function __construct(\Redis $redis, string $queueName) {
$this->redis = $redis;
$this->key = "queue:{$queueName}";
}
// LPUSH + RPOP = FIFO
public function push($data): int {
return $this->redis->lPush($this->key, json_encode($data));
}
public function pop(): ?array {
$raw = $this->redis->rPop($this->key);
return $raw ? json_decode($raw, true) : null;
}
// 阻塞式 pop (長輪詢,適合消費者)
public function bPop(int $timeout = 5): ?array {
$raw = $this->redis->bRPop($this->key, $timeout);
return $raw ? json_decode($raw[1], true) : null;
}
public function size(): int { return $this->redis->lLen($this->key); }
public function clear(): bool { return $this->redis->del($this->key) > 0; }
}
<?php
// 前端請求:快速寫入佇列 (毫秒級響應)
$queue = new RedisQueue($redis, 'page_views');
$queue->push(['page_id' => 123, 'time' => time()]);
echo "OK";
// 背景 Worker:批次處理 (每分鐘/每 1000 筆)
$batch = [];
while (($item = $queue->pop()) && count($batch) < 1000) {
$batch[] = $item;
}
if ($batch) {
// 聚合統計
$counts = [];
foreach ($batch as $item) {
$counts[$item['page_id']] = ($counts[$item['page_id']] ?? 0) + 1;
}
// 批次更新 DB
foreach ($counts as $pageId => $cnt) {
$pdo->prepare("UPDATE pages SET views = views + ? WHERE id = ?")
->execute([$cnt, $pageId]);
}
}
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| PHP 陣列 | 單請求生命週期、單元測試 | 零依賴、極快 | 進程結束資料消失 |
| File/Session | 簡單跨請求、低併發 | 無額外服務 | 鎖競爭、I/O 瓶頸 |
| Redis List | 高併發、分散式、需阻塞消費 | 高效能、原子操作、支援優先級 | 需維護 Redis |
| RabbitMQ/Kafka | 微服務、複雜路由、高可靠 | 企業級功能、持久化、ACK 機制 | 運維複雜、資源佔用大 |
| Laravel Queue / Symfony Messenger | 框架專案 | 整合好、驅動多、延遲任務 | 綁定框架生態 |
佇列是高併發架構的核心組件,合理引入能大幅提升系統彈性與響應速度,建議從 Redis List 起步,隨業務增長平滑遷移。