PHP项目气象数据如何缓存减少接口调用频次

wen PHP项目 29

本文目录导读:

PHP项目气象数据如何缓存减少接口调用频次

  1. 文件缓存(简单直接)
  2. Redis缓存(高性能推荐)
  3. Memcached缓存(分布式场景)
  4. 数据库缓存(持久化方案)
  5. 多级缓存策略(最优化)
  6. 懒加载与预缓存策略
  7. 最佳实践建议
  8. 推荐方案

在PHP项目中缓存气象数据是减少API调用、提升性能的重要手段,以下是几种常见的实现方案,按复杂度从低到高排列:

文件缓存(简单直接)

<?php
class WeatherCache {
    private $cacheDir = './cache/weather/';
    private $cacheTime = 1800; // 30分钟缓存
    public function getWeatherData($city) {
        $cacheFile = $this->cacheDir . md5($city) . '.json';
        // 检查缓存是否有效
        if (file_exists($cacheFile) && time() - filemtime($cacheFile) < $this->cacheTime) {
            return json_decode(file_get_contents($cacheFile), true);
        }
        // 调用真实API
        $data = $this->fetchFromApi($city);
        // 写入缓存
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
        file_put_contents($cacheFile, json_encode($data));
        return $data;
    }
    private function fetchFromApi($city) {
        // 实际API调用代码
        $apiUrl = "https://api.weather.com/v1/location/{$city}";
        $response = file_get_contents($apiUrl);
        return json_decode($response, true);
    }
}

Redis缓存(高性能推荐)

<?php
use Predis\Client;
class WeatherRedisCache {
    private $redis;
    private $ttl = 1800; // 30分钟过期
    public function __construct() {
        $this->redis = new Client([
            'scheme' => 'tcp',
            'host'   => '127.0.0.1',
            'port'   => 6379,
        ]);
    }
    public function getWeather($city) {
        $key = "weather:{$city}";
        // 检查Redis缓存
        if ($this->redis->exists($key)) {
            return json_decode($this->redis->get($key), true);
        }
        // 从API获取
        $data = $this->fetchWeather($city);
        // 存入Redis
        $this->redis->setex($key, $this->ttl, json_encode($data));
        return $data;
    }
    private function fetchWeather($city) {
        // API调用
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, "https://api.openweathermap.org/data/2.5/weather?q={$city}&appid=YOUR_API_KEY");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response, true);
    }
}

Memcached缓存(分布式场景)

<?php
class WeatherMemcachedCache {
    private $memcached;
    private $expiration = 1800;
    public function __construct() {
        $this->memcached = new Memcached();
        $this->memcached->addServer('localhost', 11211);
    }
    public function getWeatherData($city) {
        $key = "weather_data_{$city}";
        // 尝试从缓存获取
        $cachedData = $this->memcached->get($key);
        if ($cachedData !== false) {
            return $cachedData;
        }
        // 获取新数据
        $data = $this->callWeatherApi($city);
        // 存入缓存
        $this->memcached->set($key, $data, $this->expiration);
        return $data;
    }
}

数据库缓存(持久化方案)

-- 创建缓存表
CREATE TABLE weather_cache (
    id INT PRIMARY KEY AUTO_INCREMENT,
    city VARCHAR(100) UNIQUE,
    weather_data JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_city (city)
);
<?php
class WeatherDBCache {
    private $db;
    private $cacheTime = 1800;
    public function getWeather($city) {
        // 查询数据库缓存
        $stmt = $this->db->prepare("SELECT weather_data, updated_at FROM weather_cache WHERE city = ?");
        $stmt->execute([$city]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($result) {
            $updatedAt = strtotime($result['updated_at']);
            if (time() - $updatedAt < $this->cacheTime) {
                return json_decode($result['weather_data'], true);
            }
        }
        // 获取新数据
        $data = $this->fetchFromApi($city);
        // 更新数据库
        $jsonData = json_encode($data);
        if ($result) {
            $updateStmt = $this->db->prepare("UPDATE weather_cache SET weather_data = ? WHERE city = ?");
            $updateStmt->execute([$jsonData, $city]);
        } else {
            $insertStmt = $this->db->prepare("INSERT INTO weather_cache (city, weather_data) VALUES (?, ?)");
            $insertStmt->execute([$city, $jsonData]);
        }
        return $data;
    }
}

多级缓存策略(最优化)

<?php
class MultiLevelWeatherCache {
    private $redis;
    private $fileCache;
    private $config = [
        'file_ttl' => 3600,    // 文件缓存1小时
        'redis_ttl' => 1800,   // Redis缓存30分钟
        'db_ttl' => 7200       // 数据库缓存2小时
    ];
    public function getWeatherData($city, $forceRefresh = false) {
        $key = "weather_{$city}";
        // 1. 检查Redis缓存(最快)
        if (!$forceRefresh) {
            $data = $this->getFromRedis($key);
            if ($data) return $data;
        }
        // 2. 检查文件缓存
        if (!$forceRefresh) {
            $data = $this->getFromFile($key);
            if ($data) {
                // 异步更新Redis
                $this->setRedisCache($key, $data);
                return $data;
            }
        }
        // 3. 从API获取
        $data = $this->fetchFromApi($city);
        // 4. 更新所有缓存层
        $this->setRedisCache($key, $data);
        $this->setFileCache($key, $data);
        return $data;
    }
    private function getFromRedis($key) {
        // Redis获取逻辑
    }
    private function getFromFile($key) {
        // 文件缓存获取
    }
    private function setRedisCache($key, $data) {
        // 设置Redis缓存
    }
    private function setFileCache($key, $data) {
        // 设置文件缓存
    }
}

懒加载与预缓存策略

<?php
class WeatherPreloadCache {
    // 热门城市列表
    private $hotCities = ['北京', '上海', '广州', '深圳', '杭州'];
    public function preloadHotCities() {
        // 系统启动或定时任务预加载热门城市数据
        foreach ($this->hotCities as $city) {
            $this->getWeatherData($city);
        }
    }
    public function getWeatherData($city, $lazyLoad = true) {
        // 懒加载:仅在请求时获取
        if ($lazyLoad) {
            return $this->lazyGet($city);
        }
        // 提前加载
        return $this->fetchFromApi($city);
    }
    private function lazyGet($city) {
        $cache = new WeatherRedisCache();
        return $cache->getWeather($city);
    }
}

最佳实践建议

缓存时间设置参考

// 根据不同数据类型设置不同缓存时间
$cacheConfig = [
    'current_weather' => 1800,   // 当前天气 30分钟
    'hourly_forecast' => 3600,   // 小时预报 1小时
    'daily_forecast'  => 7200,   // 日报预报 2小时
    'weekly_forecast' => 86400,  // 周预报 24小时
    'air_quality'     => 3600,   // 空气质量 1小时
];

错误处理与降级

public function getWeatherWithFallback($city) {
    try {
        // 尝试从缓存获取
        return $this->getFromCache($city);
    } catch (Exception $e) {
        // 缓存失败,从API获取
        $data = $this->fetchFromApi($city);
        // 尝试写入缓存(非关键操作)
        try {
            $this->setCache($city, $data);
        } catch (Exception $cacheError) {
            // 记录日志但不影响主流程
            error_log("Cache write failed: " . $cacheError->getMessage());
        }
        return $data;
    }
}

监控缓存命中率

class WeatherCacheMonitor {
    private static $hitCount = 0;
    private static $missCount = 0;
    public function recordHit() {
        self::$hitCount++;
    }
    public function recordMiss() {
        self::$missCount++;
    }
    public function getHitRate() {
        $total = self::$hitCount + self::$missCount;
        return $total > 0 ? (self::$hitCount / $total) * 100 : 0;
    }
}

推荐方案

对于大多数PHP项目:

  1. 小项目:使用文件缓存 + Redis(如果可用)
  2. 中型项目:Redis缓存 + 数据库持久化
  3. 大型项目:多级缓存(Redis + 文件 + CDN)
  4. 高并发场景:Redis集群 + 本地缓存(APCu)

选择合适的缓存方案时,要考虑:

  • 数据更新频率
  • 用户访问分布
  • 系统资源限制
  • 运维复杂度

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