为了对Spring Cloud框架中的组件进行说明,我们先准备一个微服务系统(该例子来源于Spring Cloud微服务架构开发实战一书))。整个系统可以分为天气数据采集微服务、天气数据API微服务、城市数据API微服务、天气预报微服务四个微服务。其中,每个微服务又可以由不同的组件组成,其中:
- 天气数据采集微服务包含数据采集组件、数据存储组件。数据采集组件是通用的用于采集天气数据的组件。数据存储组件是用于存储天气数据的组件;
- 天气数据API微服务包含了天气数据查询组件。天气数据查询组件提供了天气数据查询的接口;
- 城市数据API微服务包含了城市数据查询组件。城市数据查询组件提供了城市数据查询的接口;
- 天气预报微服务包含了数据展示组件。数据展示组件用于将数据模型展现为用户能够理解的UI界面。
微服务代码的拆分
对于代码而言,每个微服务都是一个独立的SpringBoot工程。针对上述的四个微服务,代码可以分为如下4个工程:
- msa-weather-collection-server: 天气数据采集微服务
- msa-weather-data-server:天气数据API微服务
- msa-weather-city-server:城市数据API微服务
- msa-weather-report-server:天气预报微服务
代码结构和项目界面如下图。msa-weather-collection-server微服务会定时去抓取某城市的天气数据,并将其存入到redis中;msa-weather-data-server微服务提供按城市ID及城市名称查询天气的功能;msa-weather-city-server微服务提供城市信息查询功能;msa-weather-report-server微服务提供数据展示及数据处理的功能。
思考
目前,我们的系统实现了模块的拆分,各模块之间也可以通过restful接口进行调用,但他还有很多的问题。例如,调用天气数据API,用户将发送一个GET请求到所发布的URI。
http://127.0.0.1:8082/weather/cityId/{cityId}
在我们的天气预报微服务中依赖了天气数据API微服务,那么在调用方的代码里面,增加了REST客户端来调用服务。
@Service public class WeatherReportServiceImpl implements WeatherReportService { @Autowired private RestTemplate restTemplate; @Override public Weather getDataByCityId(String cityId) { String uri = "http://127.0.0.1:8082/weather/cityId/" + cityId; ResponseEntity<String> response = restTemplate.getForEntity(uri,String.class); String data = response.getBody(); ...
通过代码可以看到,我们是通过IP来访问服务的。但是通过IP直接访问服务是有一定的弊端的。
首先,一个比较大的问题是,IP是与一台特定的主机关联的。IP必须唯一,不然会产生混淆。
其次,要让服务的调用方记住服务方的IP地址很难。特别是当双方都还没有正式上线部署的时候,根本无法提前获知服务提供方的IP地址。IP地址是相对变化的。
最后一点是,通过IP地址很难做到负载均衡。设想下,服务提供方提供了两个服务实例,分别部署到两台主机里面,那么用户要访问哪个IP呢?固定一个IP,也无法实现负载均衡。
Spring Cloud框架提供了Eureka组件,已经解决了这个问题。具体请参照下一篇博客“Spring Cloud(三)Spring Cloud Eureka 微服务的注册和发现
注:本系列文章为本人总结的《Spring Cloud微服务架构开发实战》一书学习笔记