服务治理

Spring Cloud 封装了 Netflix公司开发的 Eureka 模块来实现服务治理。
在传统的rpc远程调用框架中,管理每个服务于服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

假如我们的服务提供者user-service部署了多个实例,如图:
image-20210713214925388.png
思考几个问题:

  • order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口?
  • 有多个user-service实例地址,order-service调用时该如何选择?
  • order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?

    Eureka的结构和作用

    上面这些问题都需要利用SpringCloud中的注册中心来解决,其中最广为人知的注册中心就是Eureka,其结构如下:
    image-20210713220104956.png
    服务提供者和服务消费者实例启动后,都会将自己的信息注册到Eureka注册中心。这个叫服务注册。Eureka保存服务名称到服务实例地址列表的映射关系。
    服务消费者,想要某个服务,就去Eureka注册中心请求,注册中心发现有这个服务,就把这个服务的列表给消费者。
    而消费者从Eureka获取的服务地址列表中通过负载均衡算法选中一个实例地址,向该实例地址发起远程调用。
    每个服务都会每隔一段时间(默认30秒)向Eureka注册中心发起请求,报告自己的状态,这种称为心跳。当超过一定时间没发送心跳时,Eureka会认为该服务实例故障,将该实例从服务列表中剔除。当消费者拉服务的时候就能排除故障了。

    搭建Eureka注册中心

    SpringCloud服务搭建,拆分,调用Demo
    根据这个demo,添加一个module,springboot项目。
  1. 引入依赖,没写版本号是因为之前的demo父模块里面有版本号

    老版本引入的eureka服务端依赖为:spring-cloud-starter-eureka 新版本使用的eureka服务端依赖为:spring-cloud-starter-netflix-eureka-server

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  4. </dependency>
  1. 启动类上加注解@EnableEurekaServer启动Eureka服务的功能 ```java package cn.itcast.eureka;

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }

  1. 3. 编写配置文件
  2. ```yaml
  3. server:
  4. port: 10086
  5. spring:
  6. application:
  7. name: eureka-server
  8. eureka:
  9. client:
  10. service-url:
  11. defaultZone: http://127.0.0.1:10086/eureka

最后启动了这个服务后,访问地址http://localhost:10086/就能看到Eureka的管理页面
image.png

服务注册

给需要注册服务的消费者或者提供者 引入依赖和改配置文件。
demo例子,我们给user-service和order-service注册一下。拿user-service举例子。

  1. 引入依赖,eureka那个是服务端,这个是客户端,注意后面的结尾,还有上面提到的新老版本

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    4. </dependency>
  2. 修改application.yml文件,添加服务名称、eureka地址:

    1. spring:
    2. application:
    3. name: userservice
    4. eureka:
    5. client:
    6. service-url:
    7. defaultZone: http://127.0.0.1:10086/eureka

    就这两步弄完了就重新启动服务就行了

同一个服务启动多个实例

我们模拟启动两次以上user-service服务。
在左下角服务窗格里面选中右键:
image.png
不一样的名字,还有设置新的端口-Dserver.port=9081
image.png

全部服务重新运行后访问,Eureka的地址就能看到注册的实例了
image.png

服务发现

下面,我们将order-service的逻辑修改:向eureka-server拉取user-service的信息,实现服务发现。

  1. 引入依赖

服务发现、服务注册统一都封装在eureka-client依赖,因此这一步与服务注册时一致。在order-service的pom文件中,引入下面的eureka-client依赖:

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  4. </dependency>
  1. 配置文件

服务发现也需要知道eureka地址,因此第二步与服务注册一致,都是配置eureka信息:在order-service中,修改application.yml文件,添加服务名称、eureka地址

  1. spring:
  2. application:
  3. name: orderservice
  4. eureka:
  5. client:
  6. service-url:
  7. defaultZone: http://127.0.0.1:10086/eureka
  1. 负载均衡

在配置文件中RestTemplate上在一个注解@LoadBalanced实现负载均衡

  1. package cn.itcast.order.config;
  2. @Configuration
  3. public class MyConfig {
  4. @Bean
  5. @LoadBalanced
  6. public RestTemplate restTemplate(){
  7. return new RestTemplate();
  8. }
  9. }
  1. 修改业务代码,修改访问的url路径,用服务名代替ip+端口。这样就能访问到用户数据了 ```java package cn.itcast.order.service;

@Service public class OrderService {

  1. @Autowired
  2. private OrderMapper orderMapper;
  3. @Autowired
  4. private RestTemplate restTemplate;
  5. @Autowired
  6. private DataSource druidDataSource;
  7. public Order queryOrderById(Long orderId) {
  8. // 1.查询订单
  9. Order order = orderMapper.findById(orderId);
  10. // 2.远程查询user localhost:8081
  11. String url = "http://userservice/user/"+order.getUserId();
  12. User user = restTemplate.getForObject(url, User.class);
  13. // 3.组合
  14. order.setUser(user);
  15. // 4.返回
  16. return order;
  17. }

}

```