Redis存儲(chǔ)經(jīng)緯度信息的實(shí)現(xiàn)
適應(yīng)場景
在一些向用戶提供天氣信息的業(yè)務(wù)場景中,我們通常會(huì)通過前端獲取用戶經(jīng)緯度信息,傳遞給后端作為參數(shù)進(jìn)行外部天氣接口調(diào)用,從而獲取用戶所在位置的天氣信息。
但是一旦用戶量級上來了或者該功能被頻繁觸發(fā)時(shí),調(diào)用外部天氣接口的成本會(huì)變得非常高昂。但是對于天氣信息來說,并不需要每次都實(shí)時(shí)調(diào)用外部接口獲取最新的天氣信息,因?yàn)樘鞖庑畔⒌淖兓l率并不是特別高,甚至相近位置的天氣信息也會(huì)非常相似。
因此我們可以通過在Redis中存儲(chǔ)經(jīng)緯度信息和對應(yīng)的天氣信息,在每次請求時(shí),先查詢Redis中是否存在相近位置的天氣信息,如果存在則直接返回緩存的天氣信息,如果不存在則調(diào)用外部天氣接口獲取最新的天氣信息,并將其存儲(chǔ)在Redis中以備下次使用。
設(shè)計(jì)思路
- 經(jīng)緯度信息存儲(chǔ):使用Redis的地理位置(GEO)數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)用戶的經(jīng)緯度信息。通過
GEOADD命令將經(jīng)緯度信息添加到Redis中。 - 天氣信息存儲(chǔ):將天氣信息存儲(chǔ)在Redis的字符串(STRING)數(shù)據(jù)結(jié)構(gòu)中,使用經(jīng)緯度信息作為鍵,天氣信息作為值。
- 查詢邏輯:
- 當(dāng)用戶請求天氣信息時(shí),首先使用
GEORADIUS命令查詢Redis中是否存在相近位置的經(jīng)緯度信息。 - 如果存在,則使用
GET命令獲取對應(yīng)的天氣信息。- 若天氣信息存在且未過期,則直接返回該信息。
- 若天氣信息不存在或已過期,則調(diào)用外部天氣接口獲取最新的天氣信息,并刪除舊的經(jīng)緯度信息,然后重新存儲(chǔ)新的經(jīng)緯度和天氣信息。
- 如果不存在,則調(diào)用外部天氣接口獲取最新的天氣信息,并使用
SET命令將其存儲(chǔ)在Redis中,同時(shí)使用GEOADD命令將經(jīng)緯度信息添加到Redis中。
- 當(dāng)用戶請求天氣信息時(shí),首先使用
- 過期策略:為了確保天氣信息的時(shí)效性,可以為存儲(chǔ)的天氣信息設(shè)置過期時(shí)間(TTL),例如30分鐘或1小時(shí),超過該時(shí)間后需要重新調(diào)用外部接口獲取最新的天氣信息。由于Redis的GEO數(shù)據(jù)結(jié)構(gòu)不支持直接設(shè)置過期時(shí)間,可以在發(fā)現(xiàn)天氣信息過期時(shí),刪除對應(yīng)的經(jīng)緯度信息。
代碼實(shí)現(xiàn)
示例代碼選用Java語言實(shí)現(xiàn),使用Spring Boot框架。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.2.5</version>
</dependency>
spring:
redis:
host: localhost
port: 6379
引入Spring Data Redis依賴,并在application.yml中配置Redis連接信息。
@Service
public class WeatherService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String WEATHER_GEO_KEY = "weather:locations";
private static final String WEATHER_KEY_PREFIX = "weather:";
private static final long WEATHER_TTL = 3600; // 天氣信息過期時(shí)間,單位秒
public String getWeather(String latitude, String longitude) {
// 查詢8公里內(nèi)最近的經(jīng)緯度信息
double lon = Double.parseDouble(longitude);
double lat = Double.parseDouble(latitude);
Point point = new Point(lon, lat);
Distance distance = new Distance(8, Metrics.KILOMETERS);
Circle circle = new Circle(point, distance);
var geoResults = redisTemplate.opsForGeo().radius(WEATHER_GEO_KEY, circle,
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().sortAscending().limit(1));
if (geoResults != null && !geoResults.getContent().isEmpty()) {
var nearestLocation = geoResults.getContent().get(0);
String locationKey = nearestLocation.getContent().getName();
// 獲取對應(yīng)的天氣信息
String weatherKey = WEATHER_KEY_PREFIX + locationKey;
String cachedWeather = redisTemplate.opsForValue().get(weatherKey);
if (cachedWeather != null) {
return cachedWeather; // 返回緩存的天氣信息
} else {
// 天氣信息過期,刪除舊的經(jīng)緯度信息
redisTemplate.opsForGeo().remove(WEATHER_GEO_KEY, locationKey);
}
}
// 調(diào)用外部天氣接口獲取最新的天氣信息
String newWeatherInfo = fetchWeatherFromExternalApi(latitude, longitude);
// 存儲(chǔ)新的經(jīng)緯度和天氣信息
String locationKey = latitude + ":" + longitude;
redisTemplate.opsForGeo().add(WEATHER_GEO_KEY, new Point(lon, lat), locationKey);
String weatherKey = WEATHER_KEY_PREFIX + locationKey;
redisTemplate.opsForValue().set(weatherKey, newWeatherInfo, Duration.ofSeconds(WEATHER_TTL));
return newWeatherInfo;
}
private String fetchWeatherFromExternalApi(String latitude, String longitude) {
// 這里實(shí)現(xiàn)調(diào)用外部天氣接口的邏輯
}
}
在上述代碼中,我們定義了一個(gè)WeatherService類,包含了獲取天氣信息的邏輯。首先通過GEORADIUS命令查詢8公里內(nèi)最近的經(jīng)緯度信息,如果找到則嘗試獲取對應(yīng)的天氣信息;如果天氣信息不存在或已過期,則調(diào)用外部天氣接口獲取最新的天氣信息,并將其存儲(chǔ)在Redis中,同時(shí)更新經(jīng)緯度信息。
通過這種方式,我們可以有效地減少對外部天氣接口的調(diào)用頻率,提高系統(tǒng)的響應(yīng)速度和穩(wěn)定性。
到此這篇關(guān)于Redis存儲(chǔ)經(jīng)緯度信息的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Redis存儲(chǔ)經(jīng)緯度信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Redis中的List是如何實(shí)現(xiàn)的
List 的 Redis 中的 5 種主要數(shù)據(jù)結(jié)構(gòu)之一,它是一種序列集合,可以存儲(chǔ)一個(gè)有序的字符串列表,順序是插入的順序,本文將給大家介紹了一下Redis中的List是如何實(shí)現(xiàn)的,需要的朋友可以參考下2024-05-05
Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn)
本文主要介紹了Redis鍵值設(shè)計(jì)的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06
redis列表類型_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了redis列表類型的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
淺談RedisTemplate和StringRedisTemplate的區(qū)別
本文主要介紹了RedisTemplate和StringRedisTemplate的區(qū)別及個(gè)人見解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
Redis安裝啟動(dòng)及常見數(shù)據(jù)類型
這篇文章主要介紹了Redis安裝啟動(dòng)及常見數(shù)據(jù)類型,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
虛擬機(jī)linux安裝redis實(shí)現(xiàn)過程解析
這篇文章主要介紹了虛擬機(jī)linux安裝redis實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Redis使用ZSET實(shí)現(xiàn)消息隊(duì)列使用小結(jié)
這篇文章主要介紹了Redis使用ZSET實(shí)現(xiàn)消息隊(duì)列使用總結(jié),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03

