天天看點

SpringCloud Eureka 服務治理

目錄

      • SpringCloud簡介
      • 搭建服務注冊中心 eureka-server
      • 服務提供者
      • 服務消費者
      • RestTemplate常用方法
      • 解決@ResponseBody、@RestController傳回xml而非json的問題
      • Eureka的架構
      • Eureka Server的服務保護機制
      • Eureka Client的緩存機制

技術棧

  • Eureka :服務治理
  • Ribbon :負載均衡
  • Feign :聲明式服務調用
  • Hystrix:斷路器,容錯保護
  • Zuul:網關(API Gateway),路由轉發、請求過濾
  • Config:配置中心,集中管理配置
  • Bus:總線
  • Sleuth+Zipkin:分布式鍊路追蹤

Eureka、Ribbon、Feign、Hystrix都是netflix的開源項目,SpringCloud都将它們內建進來了。

springcloud的版本

SpringCloud Eureka 服務治理

其它架構的版本是1.x,2.x…,SpringCloud的版本是Axx、Bxx、Cxx這樣命名走的。

ga是穩定版、通用版,snapshot是開發版。

springcloud需要自己寫一個服務(子產品),作為服務注冊中心。

1、建立子子產品eureka-server,建立時勾選 Spring Cloud Discovery -> Eureka Server ,或者手動添加依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
           

2、引導類上加 @EnableEurekaServer

3、application.yml

server:
  port: 8761

spring:
  application:
    name: eureka-server

eureka:
  instance:
    #所在機器的hostname或者ip
    hostname: 127.0.0.1
  client:
    #不注冊到其它eureka server上
    registerWithEureka: false
    #不從其它eureka server上拉取、同步注冊資訊
    fetchRegistry: false
  #此eureka server綁定的注冊中心位址
  serviceUrl:
    defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
           

如果要搭建Eureka Server叢集,将上面2個false改為true即可。

啟動應用,通路 127.0.0.1:8761 即可看到eureka server的頁面。

1、建立子子產品order-service,建立時勾選Spring Cloud Discovery -> Eureka Discovery Client,也可以手動添加依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
           

每個服務提供者、消費者都是Eureka Client

2、引導類上加 @EnableEurekaClient 或 @EnableDiscoveryClient

一個是eureka的注解、一個是springcloud的注解,效果一樣。也可以都不加,因為classpath中有eureka client的依賴 spring-cloud-starter-netflix-eureka-client 時,啟動應用時會自動在引導類上加 @EnableEurekaClient。

server:
  port: 8771

spring:
  application:
    name: order-service  #服務名稱

eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/  #注冊中心位址,如果是Eureka Server叢集,url之間逗号分隔
           

不用寫全部的Eureka Server的url,寫一部分即可。注冊時隻注冊到第一個url上,Eureka Server之間會同步資料,後面的url都是備胎,前面的故障時才會使用後一個。

4、model、service、controller

mdoel

@Getter
@Setter
public class Order implements Serializable {

}
           

service

public interface OrderService {
    List<Order> findOrdersByUserId(Integer userId);
}
           
@Service
public class OrderServiceImpl implements OrderService {
	
    @Override
    public List<Order> findOrdersByUserId(Integer userId) {
        
    }
	
}
           

controller

@Controller
@RequestMapping("/api/v1/order")
public class OrderController {
    @Autowired
    private OrderService orderService;
    
    @RequestMapping("/list/{user_id}")
    @ResponseBody
    public List<Order> findOrdersByUserId(@PathVariable("user_id") Long userId){

    }

}
           

1、建立子子產品user-service,建立時勾選Spring Cloud Discovery -> Eureka Discovery Client

2、引導類

@SpringBootApplication
@EnableEurekaClient  //非必需
public class UserServiceApplication {
    
    @Bean
    @LoadBalanced   
    public RestTemplate restTemplate() {  //建立RestTemplate這個bean
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }

}
           
server:
  port: 8781

spring:
  application:
    name: user-service  #服務名稱

eureka:
  client:
    serviceUrl:
      defaultZone: http://127.0.0.1:8761/eureka/  #注冊中心位址,如果是Eureka Server叢集,url之間逗号分隔
           

model

@Getter
@Setter
public class Order implements Serializable {

}
           

代碼備援多,如果要使用其它服務中的類,需要copy過去才能使用。可以用一個單獨的子產品寫公用的類,打包為jar,再要使用的服務中引用。

public interface UserService {
    List<Order> findOrdersById(Integer id);
}
           
@Service
public class UserServiceImpl implements UserService {
    @Autowired  //注入RestTemplate
    private RestTemplate restTemplate;

    @Override
    public List<Order> findOrdersById(Integer id){
        // 遠端調用
        return restTemplate.getForObject("http://order-service/api/v1/order/list/" + id, List.class);
    }

}
           

controller

@Controller
@RequestMapping("/api/v1/user")
public class UserController {
    @Autowired
    private UserService UserService;

    @RequestMapping("/{user_id}/order")
    @ResponseBody
    public List<Order> findOrdersById(@PathVariable("user_id") Integer id){
        return userService.findOrdersById(id);
    }

}
           

RestTemplate用于以restful方式遠端調用服務,常用方法如下

//參數:遠端服務接口,傳回值類型(目标類型)
List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class);

//url中的參數可以使用+号拼接,也可以使用占位符{1},{2}...,在目标類型後面寫參數值(Object...)
List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/{1}" + userId, List.class,1);

//可以用map向服務提供者傳遞資料
HashMap<String, Object> map = new HashMap<>();
List orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class,map);
           

xxxForObject(),get是查詢,post是建立,put是更新,delete是删除,用法都差不多。post、put可混用。

在controller上用produces指定為json格式,預設是xml

@RequestMapping(value = "/api/v1/user",produces = "application/json;charset=utf-8")
           

SpringCloud Eureka 服務治理

Eureka Server預設開啟了服務保護:

Eureka Server在90s内都未收到某個服務節點的心跳包時,會開啟為期15min的心跳檢測,這期間不會把該服務節點的資訊從服務注冊清單中删除。Eureka Server控制台也會用一段紅色文字提示:這個服務節點進入了服務保護模式。

如果15min内實際收到該節點的心跳數占應接收心跳數的比值小于0.85,就認為是該服務節點與Eureka Server之間的網絡故障導緻的心跳包丢失,該服務節點本身沒有問題,保留該節點的注冊資訊;如果比值大于0.85,就認為是該服務節點自身出了問題,從服務注冊清單中删除該服務節點的資訊。

造成的問題:某個服務節點可能真的出問題了,但依然被當做正常節點使用。

項目上線時一般也不關閉服務保護,公司的項目,服務節點數量往往成百上千,如果關閉服務保護,網絡不穩定時(網絡波動、延遲、斷線等)會導緻大量的服務反複注冊、删除、再注冊,會降低程式性能。開啟服務保護,某些服務節點故障時,無非就是注冊清單中有少量無效節點,不一定會調用叢集中的這些無效節點,就算調用了無效節點不能正确處理請求,使用者重新整理幾次,轉發給叢集中正常的節點處理就ok了。

開發、調試時可以關閉Eureka Server的服務保護,快速清理掉無效節點

eureka:
  server:
    #關閉Eureka Server的服務保護
    enableSelfPreservation: false
           

Eureka Client | ZK Client都會緩存Eureka Server | ZK Server傳回的服務節點清單,緩存一直有效,直到此Client下線。

繼續閱讀