PHP项目第三方接口数据如何缓存本地

wen PHP项目 26

本文目录导读:

PHP项目第三方接口数据如何缓存本地

  1. 文件缓存(简单场景)
  2. Redis缓存(高性能推荐)
  3. Memcached缓存(分布式场景)
  4. 最佳实践策略
  5. 框架集成方案
  6. 缓存清理策略
  7. 建议

为PHP项目的第三方接口数据实现本地缓存,常见方案及最佳实践如下:

文件缓存(简单场景)

基础实现

<?php
class FileCache {
    private $cacheDir;
    public function __construct($cacheDir = '/tmp/api_cache/') {
        $this->cacheDir = $cacheDir;
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
    }
    public function get($key) {
        $file = $this->cacheDir . md5($key) . '.cache';
        if (!file_exists($file)) {
            return false;
        }
        $data = unserialize(file_get_contents($file));
        if ($data['expire'] < time()) {
            unlink($file);
            return false;
        }
        return $data['value'];
    }
    public function set($key, $value, $ttl = 3600) {
        $data = [
            'expire' => time() + $ttl,
            'value' => $value
        ];
        file_put_contents(
            $this->cacheDir . md5($key) . '.cache', 
            serialize($data)
        );
    }
}

使用示例

$cache = new FileCache('/var/www/cache/');
$apiKey = 'weather_data';
if (!$data = $cache->get($apiKey)) {
    // 请求第三方接口
    $data = file_get_contents('https://api.weather.com/v1/...');
    $data = json_decode($data, true);
    // 缓存10分钟
    $cache->set($apiKey, $data, 600);
}
return $data;

Redis缓存(高性能推荐)

安装与配置

# 安装Redis扩展
pecl install redis
# 或使用composer
composer require predis/predis

封装缓存类

<?php
class RedisCache {
    private $redis;
    private $prefix = 'api_cache:';
    public function __construct($config = []) {
        $this->redis = new Redis();
        $this->redis->connect(
            $config['host'] ?? '127.0.0.1',
            $config['port'] ?? 6379
        );
        // 设置密码
        if (!empty($config['password'])) {
            $this->redis->auth($config['password']);
        }
    }
    public function get($key) {
        $data = $this->redis->get($this->prefix . $key);
        return $data ? unserialize($data) : false;
    }
    public function set($key, $value, $ttl = 3600) {
        $cacheKey = $this->prefix . $key;
        $this->redis->setex($cacheKey, $ttl, serialize($value));
    }
    public function delete($key) {
        $this->redis->del($this->prefix . $key);
    }
    public function exists($key) {
        return $this->redis->exists($this->prefix . $key);
    }
}

缓存策略封装

<?php
class ApiCacheManager {
    private $cache;
    private $defaultTTL = 300; // 默认5分钟
    public function __construct($cache) {
        $this->cache = $cache;
    }
    /**
     * 获取或缓存API数据
     */
    public function remember($key, $callback, $ttl = null) {
        $cacheKey = md5($key);
        // 1. 检查缓存
        if ($data = $this->cache->get($cacheKey)) {
            return $data;
        }
        // 2. 调用第三方API
        try {
            $data = call_user_func($callback);
            // 3. 缓存数据
            $this->cache->set(
                $cacheKey, 
                $data, 
                $ttl ?? $this->defaultTTL
            );
            return $data;
        } catch (Exception $e) {
            // 异常处理:降级策略
            return $this->handleFailure($cacheKey, $e);
        }
    }
    /**
     * 故障降级处理
     */
    private function handleFailure($key, $e) {
        // 1. 尝试返回过期缓存
        if ($oldData = $this->cache->get($key . ':stale')) {
            return $oldData;
        }
        // 2. 返回默认数据
        $default = $this->getDefaultResponse();
        // 3. 记录错误日志
        error_log("API Cache Error: {$e->getMessage()}");
        return $default;
    }
}

Memcached缓存(分布式场景)

基础实现

<?php
class MemcachedCache {
    private $memcached;
    public function __construct($servers = [['127.0.0.1', 11211]]) {
        $this->memcached = new Memcached();
        $this->memcached->addServers($servers);
        $this->memcached->setOption(Memcached::OPT_COMPRESSION, true);
    }
    public function get($key) {
        return $this->memcached->get($key);
    }
    public function set($key, $value, $ttl = 3600) {
        return $this->memcached->set($key, $value, $ttl);
    }
}

最佳实践策略

缓存降级策略

<?php
class CacheStrategy {
    // 阶梯缓存时间
    const CACHE_TIERS = [
        'high' => 60,     // 高频率更新:1分钟
        'medium' => 300,  // 中频率更新:5分钟
        'low' => 3600     // 低频率更新:1小时
    ];
    // 根据接口类型选择缓存策略
    public function getCacheTTL($apiType) {
        switch ($apiType) {
            case 'weather':
                return self::CACHE_TIERS['medium'];
            case 'stock':
                return self::CACHE_TIERS['high'];
            case 'country_code':
                return self::CACHE_TIERS['low'];
            default:
                return 600; // 10分钟默认
        }
    }
}

双重缓存机制

<?php
class DualCache {
    private $local;   // 本地文件缓存
    private $remote;  // Redis缓存
    public function __construct() {
        $this->local = new FileCache();
        $this->remote = new RedisCache();
    }
    public function get($key) {
        // 1. 先查本地缓存(最快)
        if ($data = $this->local->get($key)) {
            return $data;
        }
        // 2. 再查Redis缓存
        if ($data = $this->remote->get($key)) {
            // 同步到本地
            $this->local->set($key, $data, 60);
            return $data;
        }
        return false;
    }
    public function set($key, $value, $ttl = 300) {
        // 同时写入两级缓存
        $this->remote->set($key, $value, $ttl);
        $this->local->set($key, $value, min($ttl, 60));
    }
}

缓存穿透防护

<?php
class CachePenetrationProtection {
    public function getWithProtection($key, $callback, $ttl = 300) {
        // 1. 使用布隆过滤器快速判断
        if (!$this->bloomFilter->exists($key)) {
            return null;
        }
        // 2. 互斥锁防止缓存击穿
        $lockKey = "lock:{$key}";
        if ($this->cache->get($key) === false) {
            if ($this->lock($lockKey)) {
                try {
                    $data = call_user_func($callback);
                    $this->cache->set($key, $data, $ttl);
                    return $data;
                } finally {
                    $this->unlock($lockKey);
                }
            }
        }
        return $this->cache->get($key);
    }
}

框架集成方案

Laravel示例

// config/cache.php
'api_cache' => [
    'driver' => 'redis',
    'connection' => 'default',
    'prefix' => 'api_',
],
// 使用缓存
$weather = Cache::store('api_cache')->remember('weather', 300, function () {
    return Http::get('https://api.weather.com')->json();
});

ThinkPHP示例

use think\facade\Cache;
// 配置
Cache::store('redis')->set($key, $data, 300);
// 获取
if (Cache::has($key)) {
    return Cache::get($key);
}

缓存清理策略

<?php
class CacheCleaner {
    // 定时清理过期缓存
    public function cleanExpired() {
        $files = glob('/tmp/cache/*.cache');
        foreach ($files as $file) {
            if (filemtime($file) + 3600 < time()) {
                unlink($file);
            }
        }
    }
    // 按前缀批量清除
    public function cleanByPrefix($prefix) {
        $keys = $this->redis->keys("{$prefix}*");
        if (!empty($keys)) {
            $this->redis->del($keys);
        }
    }
    // 缓存预热(加载常用数据)
    public function warmup($apiList) {
        foreach ($apiList as $api => $config) {
            // 预请求并缓存
            $data = $this->fetchApi($api);
            $this->cache->set($api, $data, $config['ttl']);
        }
    }
}

建议

  1. 选择原则

    • 单机项目:文件缓存即可
    • 中等项目:Redis
    • 高并发:Redis + 本地缓存
  2. 缓存时间

    • 动态数据:30秒-5分钟
    • 静态数据:1-24小时
    • 极少变化:7天以上
  3. 异常处理

    • 必须包含降级策略
    • 记录缓存失败日志
    • 设置合理的过期时间

这样既保证了数据新鲜度,又提高了系统稳定性。

抱歉,评论功能暂时关闭!