提升微服务的并发访问能力

有时,为了提升整个网站的性能,我们会将经常需要访问数据缓存起来,这样,在下次查询的时候,能快速的找到这些数据。

缓存的使用与系统的时效性有着非常大的关系。当我们的系统时效性要求不高时,则选择使用缓存是极好的。当,系统要求的时效性比较高时,则并不适合用缓存。

本章节,我们将演示如何通过集成Redis服务器来进行数据的缓存,以提高微服务的并发访问能力。

天气数据接口,本身时效性不是很高,而且又因为是Web服务,在调用过程中,本身是存在延时的。所以,采用缓存,一方面可以有效减轻访问天气接口服务带来的延时问题,另一方面,也可以减轻天气接口的负担,提高并发访问量。

micro-weather-basic的基础上,我们构建了一个micro-weather-redis项目,作为示例。

开发环境

项目配置

添加 Spring Data Redis 的依赖。

  1. // 依赖关系
  2. dependencies {
  3. //...
  4. // 添加 Spring Data Redis 依赖
  5. compile('org.springframework.boot:spring-boot-starter-data-redis')
  6. //...
  7. }

下载安装、运行 Redis

安装后,默认运行在 地址端口。

修改 WeatherDataServiceImpl

增加了 StringRedisTemplate 用于操作 Redis。

  1. @Service
  2. public class WeatherDataServiceImpl implements WeatherDataService {
  3. @Autowired
  4. private RestTemplate restTemplate;
  5. @Autowired
  6. private StringRedisTemplate stringRedisTemplate;
  7. private final String WEATHER_API = "http://wthrcdn.etouch.cn/weather_mini";
  8. @Override
  9. public WeatherResponse getDataByCityId(String cityId) {
  10. String uri = WEATHER_API + "?citykey=" + cityId;
  11. return this.doGetWeatherData(uri);
  12. }
  13. @Override
  14. public WeatherResponse getDataByCityName(String cityName) {
  15. String uri = WEATHER_API + "?city=" + cityName;
  16. return this.doGetWeatherData(uri);
  17. }
  18. /**
  19. * 获取天气数据
  20. * @param uri
  21. * @return
  22. */
  23. private WeatherResponse doGetWeatherData(String uri) {
  24. ValueOperations<String, String> ops = this.stringRedisTemplate.opsForValue();
  25. String key = uri;
  26. WeatherResponse weather = null;
  27. String strBody = null;
  28. if (!this.stringRedisTemplate.hasKey(key)) {
  29. System.out.println("Not Found key " + key);
  30. ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
  31. if (response.getStatusCodeValue() == 200) {
  32. strBody = response.getBody();
  33. }
  34. ops.set(key, strBody, 10L, TimeUnit.SECONDS);
  35. } else {
  36. System.out.println("Found key " + key + ", value=" + ops.get(key));
  37. strBody = ops.get(key);
  38. }
  39. ObjectMapper mapper = new ObjectMapper();
  40. try {
  41. weather = mapper.readValue(strBody, WeatherResponse.class);
  42. } catch (IOException e) {
  43. e.printStackTrace();
  44. }
  45. return weather;
  46. }
  47. }

修改了 doGetWeatherData 方法,增加了 Redis 数据的判断。

  • 当存在某个key(天气接口的uri,是唯一代表某个地区的天气数据)时,我们就从 Redis 里面拿缓存数据;
  • 当不存在某个key(没有初始化数据或者数据过期了),从去天气接口里面去取最新的数据,并初始化到 Redis 中;
  • 由于天气数据更新频率的特点(基本上一个小时或者半个小时更新一次),或者,我们在Redis里面设置了 30分钟的超时时间。

运行

多次访问某个天气接口时,来测试效果。

  1. Not Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601
  2. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  3. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  4. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  5. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  6. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  7. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  8. Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601, value={"data":{"yesterday":{"date":"5日星期二","high":"高温 32℃","fx":"无持续风向","low":"低温 27℃","fl":"<![CDATA[<3级]]>","type":"中雨"},"city":"深圳","aqi":"34","forecast":[{"date":"6日星期三","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"中雨"},{"date":"7日星期四","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"小雨"},{"date":"8日星期五","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"雷阵雨"},{"date":"9日星期六","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 27℃","fengxiang":"无持续风向","type":"多云"},{"date":"10日星期天","high":"高温 32℃","fengli":"<![CDATA[<3级]]>","low":"低温 26℃","fengxiang":"无持续风向","type":"多云"}],"ganmao":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","wendu":"27"},"status":1000,"desc":"OK"}
  9. Not Found key http://wthrcdn.etouch.cn/weather_mini?citykey=101280601

可以看到,第一次访问接口时,没有找到 Redis 里面的数据,所以,就初始化了数据。
后面几次访问,都是访问 Redis 里面的数据。最后一次,由于超时了,所以 Redis 里面又没有数据了,所以又会拿天气接口的数据。

源码

本章节的源码,在micro-weather-redis目录下。