使用 Redis 实现高并发天气查询的优化方案
1. 项目背景
随着互联网应用的普及和用户量的增长,高并发成为现代 Web 系统设计中的一项关键挑战。如何应对高并发、如何优化性能,尤其是在高并发环境下对外部 API 的查询,已成为开发者们不可忽视的问题。本文将介绍如何在高并发场景下,使用 Redis 和令牌桶限流等策略优化天气查询系统,避免缓存穿透、缓存雪崩等常见问题。
2. 项目需求
假设我们正在开发一个天气查询系统,用户通过发送 HTTP 请求查询天气信息。为了保证系统的高效性,特别是在高并发的场景下,我们需要:
- 使用 Redis 缓存天气数据,避免重复查询。
- 实现限流功能,防止频繁访问外部天气接口,避免接口被打爆。
- 使用分布式锁,确保同一时刻只有一个请求能访问某个城市的天气数据。
- 遇到高并发时,使用熔断、回退等策略来确保系统稳定。
3. 系统设计
3.1 系统架构
为了应对高并发查询,我们需要在系统设计中考虑以下几个模块:
- Redis 缓存:将天气查询的结果缓存到 Redis 中,减少频繁的数据库或外部 API 调用。
- 限流策略:使用令牌桶限流,控制每秒可以处理的请求数量,避免外部天气接口超载。
- 分布式锁:通过分布式锁,防止多个并发请求同时查询同一城市的天气数据,避免缓存穿透。
- 熔断与回退:使用 Resilience4j 来实现请求失败后的回退机制,当外部服务不可用时,返回默认值。
系统架构图:

3.2 主要技术栈
- Spring Boot:作为框架来构建应用程序。
- Redis:作为缓存数据库来存储天气数据。
- Redisson:用于实现分布式锁。
- Resilience4j:实现限流、熔断和回退机制。
4. 关键技术实现
4.1 使用 Redis 实现缓存
首先,我们使用 Redis 来缓存天气查询的结果。每次查询时,我们先检查 Redis 中是否有缓存的数据。如果有,直接返回缓存数据;如果没有,才去外部 API 获取数据,并将结果缓存到 Redis 中。
String weatherData = (String) redisTemplate.opsForValue().get(cacheKey);
if (weatherData != null) {return weatherData;
}
weatherData = "Sunny 25°C"; // 模拟从外部 API 获取天气数据
redisTemplate.opsForValue().set(cacheKey, weatherData, 60); // 设置缓存过期时间为 60 秒
return weatherData;
4.2 限流
为了防止过多的请求同时访问外部天气 API,我们实现了令牌桶限流。每秒生成一定数量的令牌,当令牌桶中有令牌时,允许请求通过;如果没有令牌,则拒绝请求。
public boolean tryAcquire() {Long tokenCount = redisTemplate.opsForList().size(TOKEN_BUCKET_KEY);if (tokenCount != null && tokenCount > 0) {redisTemplate.opsForList().leftPop(TOKEN_BUCKET_KEY); // 消费令牌return true; // 请求通过} else {return false; // 请求被拒绝}
}
4.3 分布式锁
为防止多个请求同时查询同一城市的天气数据,我们使用 Redis 分布式锁来确保同一时刻只有一个请求能去访问外部 API。我们使用 Redisson 来实现这一分布式锁。
RLock lock = redissonClient.getLock("lock:weather:" + cityId);
if (lock.tryLock()) {// 执行业务逻辑lock.unlock();
}
4.4 熔断与回退
当外部天气 API 由于高并发而无法提供服务时,我们使用 Resilience4j 实现熔断和回退机制。具体的做法是,当外部服务不可用时,返回一个默认的错误提示,而不是直接崩溃。
@RateLimiter(name = "weatherQuery", fallbackMethod = "weatherFallback")
public String getWeather(String cityId) {// 请求天气数据的逻辑
}public String weatherFallback(String cityId, Throwable t) {return "Weather service is temporarily unavailable, please try again later.";
}
5. 性能测试与优化
在实现了上述功能后,我们进行了压力测试。测试模拟了 20 个请求的并发访问,测试结果如下:
- 测试 1:首次请求时,天气数据会从外部 API 获取,并成功缓存。
- 测试 2:在接下来的请求中,缓存命中率高,几乎没有请求访问外部 API。
- 测试 3:当请求过多时,令牌桶限流会限制请求频率,保证外部 API 不会被过载。
6. 总结与未来优化方向
在本次项目中,我们成功实现了一个高并发天气查询系统,并通过 Redis 缓存、令牌桶限流、分布式锁以及熔断与回退机制等技术,解决了高并发下的常见问题。然而,仍有优化的空间:
- 缓存优化:为避免缓存穿透,可以进一步加强对缓存空值的管理,并合理配置缓存过期时间。
- 限流算法:除了令牌桶和滑动窗口,还可以考虑漏桶算法来控制流量。
- 分布式架构:随着访问量的增加,可以考虑将服务拆分成多个微服务,进一步提高可扩展性。
GitHub 项目地址:https://github.com/Wilsoncyf/weather-query.git
