??各位小伙伴們大家好,歡迎來到這個小扎扎的spring cloud專欄,在這個系列專欄中我對B站尚硅谷陽哥的spring cloud教程進行一個總結,鑒于 看到就是學到、學到就是賺到 精神,這波依然是血賺 ┗|`O′|┛
💡服務調用知識點速覽
- 🍑 Ribbon
- 🍏 初識Ribbon
- 🥭 Ribbon是什么?
- 🥭 Ribbon能干什么?
- 🍏 使用Ribbon實現負載均衡
- 🥭 RestTemplate三步走
- 🥭 負載均衡算法
- 🍑 OpenFeign
- 🍏 初識OpenFeign
- 🥭 什么是OpenFeign?
- 🥭 如何使用OpenFeign?
- 🍏 OpenFeign超時控制
- 🍏 OpenFeign日志打印
🍑 Ribbon
🍏 初識Ribbon
🥭 Ribbon是什么?
??Ribbon是Netflix發布的開源項目,主要功能是提供對客戶端進行負載均衡算法的一套工具,將Netflix的中間層服務連接在一起。Ribbon客戶端組件提供一系列完善的配置項如連接超時,重試等。簡單的說,就是在配置文件中列出Load Balancer(簡稱LB)后面所有的機器,Ribbon會自動的幫助你基于某種規則(如簡單輪詢,隨即連接等)去連接這些機器。我們也可以使用Ribbon實現自定義的負載均衡算法。
🥭 Ribbon能干什么?
??前面提到說Ribbon的作用就是向客戶端提供負載均衡算法的工具,那么什么是負載均衡呢?負載均衡就是將用戶發來的請求通過算法均攤到多個服務上,從而達到系統的HA(高可用性)
??其中,負載均衡又可分為本地負載均衡(進程內LB)和服務端負載均衡(集中式LB),服務端負載均衡以Nginx為例,用戶的所有請求都會交給Nginx,由其決定請求將被轉發到哪個服務器;Ribbon是本地負載均衡,在調用接口的時候從 eureka 注冊中心服務器端上獲取服務注冊信息列表緩存到本地,從而可以在本地實現RPC遠程調用服務
🍏 使用Ribbon實現負載均衡
??實際上Ribbon可以簡單的理解為負載均衡算法 + RestTemplate的調用,也就是說想要使用Ribbon實現負載均衡,就可以通過這兩個技術加以實現。
🥭 RestTemplate三步走
??第一步: 引入Ribbon場景啟動器依賴,但是之前使用eureka的時候我們在pom文件中導入過netflix-eureka-server的依賴,其中就默認引入了ribbon的場景啟動器依賴(netflix-eureka-client也會默認導入),如果再引一次也可以,但是真沒那必要。
??第二步: 使用配置文件開啟 RestTemplate
/*** @ClassName: ApplicationContextConfig* @Description: 程序配置類,用于開啟RestTemplate服務,以供后面使用* @author: chenhao* @date: 2022/7/17*/
@Configuration
public class ApplicationContextConfig {@Bean@LoadBalancedpublic RestTemplate getRestTemplate() {return new RestTemplate();}
}
??第三步: 使用RestTemplate的API實現負載均衡,RestTemplate的API根據請求方式的不同可以被分為get和post,根據返回類型又可以分為Object(響應體轉化成的json串)和Entity(響應的重要信息,包括響應頭、狀態碼、響應體等,可以使用對應的get方法獲取到值),所以說最主要的四個API是getForObject、postForObject、getForEntity、postForEntity,這里我把四種API的使用方法都向大家介紹一下
@RestController
@Slf4j
@RequestMapping("consumer")
@Api("消費者的訂單管理類")
public class OrderController {// 先注入RestTemplate對象@Resourceprivate RestTemplate restTemplate;// 使用API實現負載均衡@ApiOperation(value = "創建一條支付記錄", tags = ApiVersionConstant.v1_0)@PostMapping(value = "/payment/create", produces = {"application/json;charset=UTF-8"})public CommonResult<Integer> create(@RequestBody Payment payment) {return restTemplate.postForObject(UrlConstant.CLUSTER_PAYMENT_URL + "/payment/create", payment, CommonResult.class);}@ApiOperation(value = "根據ID查詢支付記錄", tags = ApiVersionConstant.v1_0)@GetMapping(value = "/payment/get/{id}", produces = {"application/json;charset=UTF-8"})public CommonResult<Payment> getPayment(@PathVariable("id") Integer id) {return restTemplate.getForObject(UrlConstant.CLUSTER_PAYMENT_URL + "/payment/get/" + id, CommonResult.class);}@ApiOperation(value = "根據ID查詢支付記錄Entity", tags = ApiVersionConstant.v1_0)@GetMapping(value = "/payment/getForEntity/{id}", produces = {"application/json;charset=UTF-8"})public CommonResult<Payment> getPaymentEntity(@PathVariable("id") Integer id) {ResponseEntity<CommonResult> entity = restTemplate.getForEntity(UrlConstant.CLUSTER_PAYMENT_URL + "/payment/get/" + id, CommonResult.class);if (entity.getStatusCode().is2xxSuccessful()) {return entity.getBody();} else {return new CommonResult<>(444, "操作失敗");}}@ApiOperation(value = "創建一條支付記錄Entity", tags = ApiVersionConstant.v1_0)@PostMapping(value = "/payment/createEntity", produces = {"application/json;charset=UTF-8"})public CommonResult<Integer> createEntity(@RequestBody Payment payment) {return restTemplate.postForEntity(UrlConstant.CLUSTER_PAYMENT_URL + "/payment/create", payment, CommonResult.class).getBody();}
}
🥭 負載均衡算法
??經過我們上面的嘗試,不難發現使用RestTemplate實現的負載均衡算法是輪詢機制,實際上IRule中不僅僅只提供了一種算法
IRule實現算法切換
??第一步: 新建一個package,在官方文檔中聲明了IRule的配置類不能放到@ComponentScan注解所能掃描到的當前包以及子包下,否則自定義的配置類就會被Ribbon的所有客戶端所共享,以至于失去客戶端定制化的可能性。主程序入口上的@SpringBootApplication注解是復合注解,其中就包含@ComponentScan注解,而且是直接掃描主程序入口所在的當前包以及子包,也就是說配置類必須放到主程序入口之外的包下,于是需要新建一個package
??第二步: 在新建的包中新建一個MySelfRule規則類,用于設置輪詢算法,如果不設置的話就默認為輪詢
@Configuration
public class MySelfRule {@Beanpublic IRule myRule() {// 修改輪詢算法為隨機算法return new RandomRule();}
}
??第三步: 主啟動類上使用@RibbonClient(name = “CLOUD-PAYMENT-SERVICE”, configuration = MySelfRule.class)注解,用于指定應用服務和自定義算法規則的配置類
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class, args);}
}
輪詢算法
??所謂的輪詢算法就是根據所有的服務,依次將請求均攤到所有的服務依次訪問,它的算法實現就是用RestTemplate接收到的請求數量對服務器集群的數量進行取模運算,余數就是服務在服務列表中對應的索引位置,所以說可以實現輪詢。但是如果中途服務器關掉的話接收到的請求數量就會從1重新計數
🍑 OpenFeign
🍏 初識OpenFeign
🥭 什么是OpenFeign?
??openFeign是要聲明式的web服務客戶端,或叫做聲明式REST客戶端,它讓編寫web服務客戶端變得簡單。它將提供者的restful服務偽裝成接口進行消費,消費者只需要通過feign接口+注解就可以直接調用提供者的服務接口,也就是可以實現接口對接口的調用,而無需像ribbon一樣通過restTemplate方式對提供者的服務進行調用
??值得注意的一點是,openFeign內置了負載均衡器-Ribbon,所以說openfeign也可以使用負載均衡算法
🥭 如何使用OpenFeign?
??第一步: 引入相關依賴
<!--openfeign-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
??第二步: 配置配置文件,只是基本配置和注冊,沒有OpenFeign獨有的配置
server:port: 80eureka:client:register-with-eureka: falseservice-url:#服務端的地址,服務端為集群版,向所有的模塊都注冊defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka,http://localhost:7003/eureka
??第三步: 主啟動類開啟OpenFeign客戶端
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {public static void main(String[] args) {SpringApplication.run(OrderFeignMain80.class, args);}
}
??第四步: 之前使用ribbon是直接在controller里調用payment服務的controller,但是openfeign則是通過service調用,于是第三步就是創建一個service接口用于調用payment服務的接口
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") // 用于指定服務名,可在eureka或者服務的配置文件中查看
public interface PaymentFeignService {@GetMapping(value = "/payment/get/{id}", produces = {"application/json;charset=UTF-8"})CommonResult<Payment> getPaymentById(@PathVariable("id") Integer id);
}
??第五步: controller層調用service接口
@RestController
@RequestMapping("consumer")
public class OrderFeignController {@Autowiredprivate PaymentFeignService paymentFeignService;@GetMapping(value = "/payment/get/{id}", produces = {"application/json;charset=UTF-8"})public CommonResult<Payment> getPaymentById(@PathVariable("id") Integer id) {return paymentFeignService.getPaymentById(id);}
}
??如此操作也可實現order服務對payment服務的調用,而且由于OpenFeign默認引入Ribbon,去進行order服務訪問的時候,后端會默認輪詢名為是“CLOUD-PAYMENT-SERVICE”的微服務,也就是兩個payment服務
🍏 OpenFeign超時控制
??使用OpenFeign調用服務接口,默認等待時間為1秒,超時就會直接報錯。如果有些服務的調用確實會花費超過1s的時間,就需要我們在服務調用方(也就是order服務)的配置文件中進行配置
??由于OpenFeign的超時控制由其底層的ribbon實現,于是配置文件中的超時控制也由ribbon進行配置
#設置feign客戶端超時時間(OpenFeign默認支持ribbon)
ribbon:#指的是建立連接所用的時間,適用于網絡狀況正常的情況下, 兩端連接所用的時間ReadTimeout: 5000#指的是建立連接后從服務器讀取到可用資源所用的時間ConnectTimeout: 5000
🍏 OpenFeign日志打印
??OpenFeign提供了日志打印的功能,我們可以通過日志的打印監控接口的調用情況,從而了解接口調用時HTTP請求的具體細節,具體的使用分
??第一步: 使用配置類配置日志級別
@Configuration
public class FeignConfig {/*** 日志級別* NONE:默認的,不顯示任何日志* BASIC:僅記錄請求方法、URL、響應狀態碼以及執行時間* HEADERS:請求方法、URL、響應狀態碼、執行時間、請求和響應的頭信息* FULL:請求方法、URL、響應狀態碼、執行時間、請求和響應的頭信息、正文以及元數據*/@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}
??第二步: 配置文件開啟日志打印,并指定監控的接口和級別
logging:level:# feign日志以 debug 級別監控 com.atguigu.springcloud.service.PaymentFeignService 接口com.xiaochen.springcloud.service.PaymentFeignService: debug
打印出來的日志如下: