微服務架構入門
微服務 的概念最早產生於Martin Fowler在2014年的一篇論文中。
微服務架構是一種架構模式,他提倡將單一應用程序划分成一組小的服務,服務與服務之間互相協調、相互配合,為用戶提供最終價值。每個服務運行在獨立的進程中,服務與服務之間采用輕量級的通信機制相互合作(通常是基於HTTP協議的Restful API)。每個服務圍繞具體業務進行構建,並且能夠被獨立的部署到生產環境、類生產環境等。另外,應當盡量避免同一的、集中式的服務管理機制,對具有的一個服務而言,應當根據業務上下文,選擇合適的語言、工具對其進行構建。
Cloud組件停更
被動修復bug,停更不停用,不再github上接收新的合並請求,不再發布新的版本。
RestTemplate提供了多種邊界訪問遠程HTTP服務的方法,是一種簡單便捷的訪問restful服務模板類,是Spring提供的用於訪問Rest服務的客戶端模板工具集。
(URL,requestMap,ResponseBean.class)這三個參數分別代表REST請求地址,請求參數,HTTP響應轉換的對象類型。
服務注冊中心
Eureka服務注冊中心
什么是服務治理
SpringCloud封裝了Netflix公司開發的Eureka模塊來實現服務治理。
在傳統的RPC遠程調用框架中,管理每個服務於服務之間依賴關系比較復雜,管理比較復雜,所以需要使用服務治理來管理服務與服務之間的依賴關系,可以實現服務調用、負載均衡、容錯等,實現服務發現與注冊。
服務注冊與發現
Eureka采用來CS的設計架構,Eureka Server作為服務注冊功能的服務器,他是服務注冊中心。而系統中的其他微服務,使用Eureka客戶端連接到Eureka Server並維持心跳鏈接。這樣系統的維護人員可以通過Eureka Server來監控系統中各個微服務是否正常運行。
在服務注冊與發現中,有一個注冊中心,當服務器啟動的時候,會把當前自己服務器的信息,比如服務地址,通訊地址等以別名的方式注冊到注冊中心中,另一方(其實也就是消費者或者服務提供者),以別名的方式去注冊中心上獲取實際的服務通信地址,然后在實現本地RPC調用。
RPC遠程調用框架的思想在於:使用注冊中心管理服務與服務之間的依賴關系。在任何RPC遠程框架中都會有一個注冊中心。
Eureka Server和Eureka Client
Eureka Server提供服務注冊
各個微服務節點通過配置啟動后,會在Eureka Server中進行注冊,這樣Eureka Server中的服務注冊表中將會存儲所有可用的節點信息,服務節點信息可以在界面中直觀看到。
Eureka Client通過注冊中心進行訪問
這個客戶端是用來簡化Eureka Server的交互,客戶端同時具備一個內置的,使用輪詢負載算法的負載均衡器。在應用啟動后,將會向Eureka Server發送心跳(默認是30s一次),如果Serve在多個心跳周期內(默認90s)沒有接收到某個節點的心跳,那就會被Server除名(從服務注冊表中將節點移除)。
Eureka架構圖與Dubbo對比
Eureka Server模塊
1、創建模塊
2、導入依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>org.xzq.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<dependency>
<groupId>org.xzq.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--boot web actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
3、編寫配置文件
application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost # eureka服務端實例名稱
client:
register-with-eureka: false # 不向注冊中心注冊自己
fetch-registry: false # 表示自己就是注冊中心,不必檢索其他服務
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 設置與 Eureka Server 交互的地址,可用來查詢注冊的服務
4、創建主類
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
5、啟動server,訪問http://localhost:7001
Eureka集群原理
先啟動Eureka注冊中心,啟動服務提供者,支付服務啟動后會把自身信息以別名的方式注冊進Eureka,消費者order服務在需要調用接口時,使用服務別名去注冊中心獲取實際的遠程調用地址,消費者獲取調用地址后,底層使用的是HTPPClient技術實現遠程調用,消費者獲得服務地址后會魂村到本地JVM內存中,默認每隔30s更新一次服務調用地址。
要實現RPC遠程調用服務最核心的是高可用,但是如何實現高可用?
方法:搭建注冊中心集群,實現負載均衡+故障容錯。
服務注冊中心搭建集群,集群中的所有服務都相互注冊,例如server7001,server7002,7002的eureka.client.service-url.defaultZone=http://eureka7001.com:7001/eureka,而7001中的Eureka配置是eureka.client.service-url.defaultZone=http://eureka7002.com:7002/eureka。在主啟動類上添加@EnableEurekaServer
注解,先啟動這些注冊中心服務,再啟動服務提供者,最后啟動消費者。
服務發現Discovery
@RequestMapping("/payment")
@RestController
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
@Resource
private DiscoveryClient discoClient;
@GetMapping("/discover")
public Object discovery(){
List<String> services = discoClient.getServices();
for (String service : services) {
log.info("service===="+service);
}
List<ServiceInstance> instances = discoClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info(instance.getInstanceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return this.discoClient;
}
}
在主啟動類上添加@EnableDiscoveryClient
注解
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class Payment8002 {
public static void main(String[] args) {
SpringApplication.run(Payment8002.class,args);
}
}
通過瀏覽器訪問localhost:8001/payment/discover
Eureka的自我保護
所謂的保護模式就是用於一組客戶端和Eureka Server之間存在網絡分區場景下的保護。一旦進入保護模式,Eureka Server將會嘗試保護其服務注冊表中的信息,不再刪除服務注冊表中的數據,也就是不會注銷任何微服務。
如果在Eureka Server的首頁看到以下這段提示,則說明Eureka進入了保護模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
一句話:在某時刻一個微服務不可用,Eureka不會立刻清理,依舊會對改為服務的信息進行保護。
這是屬於CAP里面的AP分支。
怎樣禁止自我保護?
在Eureka-server中,修改配置文件,添加
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka服務端實例名稱
client:
register-with-eureka: false # 不向注冊中心注冊自己
fetch-registry: false # 表示自己就是注冊中心,不必檢索其他服務
service-url:
defaultZone: http://eureka7002.com:7002/eureka/ # 設置與 Eureka Server 交互的地址,可用來查詢注冊的服務
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka服務端實例名稱
client:
register-with-eureka: false # 不向注冊中心注冊自己
fetch-registry: false # 表示自己就是注冊中心,不必檢索其他服務
service-url:
defaultZone: http://eureka7002.com:7002/eureka/ # 設置與 Eureka Server 交互的地址,可用來查詢注冊的服務
server:
enable-self-preservation: false # 關閉自我檢測
eviction-interval-timer-in-ms: 2000 # 修改檢查心跳時間 默認是30s,現在改成2s。
enable-self-preservation: false # 關閉自我檢測,一旦關閉自我檢測,其中有任何一台微服務宕機,Eureka就會立刻將他從注冊中心除名。
將其中的一個服務提供者的配置也更改如下。
eureka:
client:
register-with-eureka: true # 默認是true表示將自己注冊進服務中心
fetch-registry: true # 默認是true表示抓取已有的注冊中心,如果是集群必須進行配置
service-url:
defaultZone: http://localhost:7001/eureka # 單機版
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: payment8001
prefer-ip-address: true # 代表路徑可以顯示IP地址信息
lease-expiration-duration-in-seconds: 2 #Eureka在收到最后一次心跳后,等待的時間默認是90s,如果超過等待時間,將會剔除服務
lease-renewal-interval-in-seconds: 1 # 客戶端默認間隔30s 向服務端發送心跳,現在每間隔1s向服務端發送心跳。
eureka.instance.lease-expiration-duration-in-seconds=2
eureka.instance.lease-renewal-interval-in-seconds=1
客戶端默認間隔是30s,向服務端發送心跳,改成每隔1s向服務端發送心跳。
啟動服務后,訪問http://eureka7001.com:7001/
當關閉payment8001服務提供者后,實例立即消失。
使用zookeeper作服務發現與注冊時,服務節點是臨時節點。當服務關閉時,zookeeper會立即去除實例。
導入zookeeper相關的依賴。
<dependencies>
<!-- SpringBoot整合Web組件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.xzq.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- SpringBoot整合zookeeper客戶端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自帶的zookeeper3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
server:
port: 8004
spring:
application:
name: cloud-provider-payment #微服務實例名
cloud:
zookeeper:
connect-string: localhost:2181 #zookeeper服務所在的IP地址,默認端口是2181
之后啟動zookeeper服務,並打開zkCli.sh,ls /services,會發現實例名成是cloud-provider-payment。
Consul簡介
官網地址:https://www.consul.io/docs
Consul是一套開源的分布式服務發現和配置管理系統,有HashiCorp
公司使用Go
語言開發。
提供了微服務系統中的服務治理、配置中心、控制總線等功能。
這些功能中的每一個否可以根據自己的需要單獨使用,也可以一起使用構成全方面的服務網格,總之Consul提供了一種完整的服務網格解決方案。
它具有很多優點。包括:基於raft協議,比較簡潔;支持健康檢查,同時支持HTTP和DNS協議支持擴數據中心的WAN集群,提供圖形界面 擴平台支持,例如Linux,Mac,Windows。
Consul安裝與配置
Consul下載地址: https://www.consul.io/downloads
選擇你所對應的版本,下載壓縮包后,直接解壓。
解壓完成后,只有一個consul.exe文件,通過cmd窗口,輸入consul agent -dev
啟動,然后通過瀏覽器訪問localhost:8500,得到以下界面,算是安裝完成了。
CAP原則
最多只能同時滿足兩個。
CAP理論的核心就是:一個分布式系統不可能同時很好的滿足一致性,可用性和分區容錯性,這三個需求。
因此,根據CAP原理將NoSQL數據庫分成了滿足CA原則,滿足CP原則和滿足AP原則三大類。
CA-單點集群,滿足一致性,可用性的系統,通常在可擴展性上不強大。
CP-滿足一致性,分區容錯性,通常性能上有所損失。(Zookeeper/Consul)
AP-滿足可用性,分區容錯性的系統,通常可能對一致性的要其余不是很嚴格。(Eureka)
組件名 | 語言 | CAP | 服務健康檢測 | 對外暴露接口 | SpringCloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客戶端 | 已集成 |
Ribbon簡單概述
SpringCloud Ribbon是基於Netflix Ribbon實現的一套客戶端。(負載均衡工具)
簡單的說,Ribbon是Netflix發布的開源項目,主要功能是提供客戶端的軟件負載均衡算法和服務調用。Ribbon客戶端主鍵提供一系列完善的配置項:如連接超時,重試等。簡單的說,就是在配置文件中列出Load Blance后面的所有機器,Ribbon會自動幫助你基於某種規則去連接這些機器。我們很容易使用Ribbon實現自定義的負載均衡算法。
雖然現在Ribbon已經停止維護,但是還是有不少人使用。
主要的模塊有Ribbon-HTTPClient,Ribbon-eureka,Ribbon-Loadbalance
所謂的負載均衡是什么?
簡單的說就是將用戶的請求分發到多個服務上,從而達到系統的高可用。
常見的負載均衡有Nginx,LVS,硬件F5等。
Ribbon
本地負載均衡VS Nginx
服務端負載均衡
Nginx是服務器負載均衡,客戶端所有請求都會交給Nginx,然后由Nginx實現轉發請求。即負載均衡是服務端實現的。
Ribbon是本地負載均衡,在調用微服務接口的時候,會在注冊中心上獲取注冊信息,緩存到JVM本地,從而在本地實現RPC遠程調用服務技術。
Ribbon負載均衡是客戶端本地的負載均衡,分為集中式和進程內。
集中式
在服務的消費方和提供方之間使用獨立的負載均衡設施(可以是硬件,如F5,也可以是軟件,如Nginx),由該設施負責訪問請求,通過某種策略轉發到服務的提供方。
進程式
將負載均衡的邏輯集成到消費方,消費方從服務注冊中心獲知有哪些地址可用,然后自己再從這些地址中選擇出一個合適的服務器。Ribbon屬於進程內的負載均衡。他是一個類庫,繼承消費方進程,消費方通過它來獲取到服務提供方的地址。
Ribbon是一個軟負載均衡的客戶端組件,它可以和其他所需請求的客戶端結合使用,例如Eureka,RestTemplate等。
Ribbon的工作原理:第一步先選擇EurekaServer,他會優先選擇在同一個區域內負載均衡較少的Server。
第二步再根據用戶指定的策略,從Server取到的服務注冊列表中選擇一個地址。
其中Ribbon提供了多種策略:比如輪詢,隨機,根據響應時間加權等。
Ribbon依賴如下。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.1.RELEASE</version>
<scope>compile</scope>
</dependency>
默認情況下,Eureka-client依賴中包含有ribbon的依賴,不需要再次引入。
RestTemplate中的getForEntity方法返回的是對象,getForObject方法返回的是JSON串。
Ribbon的核心組件IRule
Ribbon默認的負載均衡算法是輪詢,而IRule是根據特定的算法中從服務列表中選取其中一個要訪問的服務。
一共有7個方法。
修改負載均衡算法
將默認的輪詢改為隨機。
首先增加配置類,需要注意的是,自定義的配置類不能被@ComponentScan注解掃描到,所以自定義的IRule不要放在啟動類的子目錄,要與啟動類隔離開。
MySelfRule類
@Configuration
public class MySelfRule {
@Bean
public IRule getRule(){
// 負載均衡算法改為隨機
return new RandomRule();
}
}
第二步,需要在主啟動類上添加@RibbonClient
注解。然后再啟動。
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args );
}
}
啟動Eureka-server,啟動服務提供者payment8001,payment8002,啟動服務消費者consumer-order80.
訪問http://localhost/consumer/payment/getForEntity/1001,會發現被訪問的服務提供者的端口是隨機變化的,因此選取的服務也是隨機的。
Ribbon負載均衡算法原理
輪詢方法:rest接口第幾次請求數對服務集群總數量取余操作,得到結果就是實際調用服務器的下標,每次服務器重啟后rest接口計數從1開始。
例如有兩台服務提供者,instances[0] = 127.0.0.1:8001,instances[1] = 127.0.0.1:8002,兩台實例作為兩台機器,集群總數是2,按照輪詢算法原理。
當第1請求時, 1%2 = 1,所以獲取服務地址是127.0.0.1:8001;
當第2請求時, 2%2 = 0,所以獲取服務地址是127.0.0.1:8002;
當第3請求時, 3%2 = 1,所以獲取服務地址是127.0.0.1:8001;
當第4請求時, 4%2 = 0,所以獲取服務地址是127.0.0.1:8002;
以此類推…
手寫輪詢負載均衡算法
首先創建一個MyLoadBalance接口
public interface MyLoadBalance {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
接口的實現。
@Component
@Slf4j
public class MyLoadBalanceImpl implements MyLoadBalance {
// 原子操作類,底層使用的是CAS
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement(){
int current = 0;
int next;
do {
current = this.atomicInteger.get();
next = current > 2147483647 ? 0: current+1;
//如果CAS自增操作成功,就會退出循環(當期望值是current時才會更改稱為next,否則一直自旋)
}while (!this.atomicInteger.compareAndSet(current,next));
log.info("next= "+next);
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
// 服務提供者下標 = 自增的數據 % 服務提供者總數
int index = getAndIncrement() % serviceInstances.size();
// 選取成功后返回
return serviceInstances.get(index);
}
}
服務消費者使用這種輪詢方法,選取服務提供者。orderController
@GetMapping("/consumer/payment/lb")
public String getPaymentUrl(){
String serviceID = "CLOUD-PAYMENT-SERVICE";
List<ServiceInstance> instances = discoveryClient.getInstances(serviceID);
if (instances == null || instances.size() <=0){
return null;
}
ServiceInstance instances1 = loadBalance.instances(instances);
URI uri = instances1.getUri();
log.info("url= "+uri);
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
OpenFeign
的基本概念
Feign是一個聲明式WebService客戶端。使用Feign能讓編寫WebService客戶端更加簡單。
他的使用方法是:定義一個服務接口然后在上面添加注解。Feign也能支持可拔插式的編碼器和解碼器。Spring Cloud對Feign進行了封裝,使其能夠支持SpringMVC標准注解和HttpMessageConverters。Feign可以與Eureka和Ribbon組合使用完成負載均衡。
Feign旨在使Java Http客戶端變得更加容易。
前面在使用Ribbon+RestTemplate時,利用RestTemplate對Http請求做封裝處理,形成一套模板話的調用方法。但是在實際開發中,由於對服務依賴的調用可能不止一處,往往一個接口會被多處調用。所以,Feign在此基礎上做了進一步的封裝,由他來幫助我們定義和實現接口。在Feign的實現下,我們只需要使用注解配置接口,即可完成對服務提供方的接口綁定,簡化了使用Spring Cloud Ribbon時,自己封裝服務調用的工作量。
還有一點,默認Feign也已經集成了Ribbon。
OpenFeign的使用
1、新建cloud-consumer-fegin-order80模塊,
2、修改pom.xml
添加依賴
<dependencies>
<!--entity-->
<dependency>
<groupId>org.xzq.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基礎通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3、創建application.yml配置文件
server:
port: 80
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
register-with-eureka: false
4、寫主啟動類
注意是@Feign注解生效,需要在主啟動類上添加@EnableFeignClients。
@SpringBootApplication
@EnableFeignClients
public class OpenFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OpenFeignMain80.class,args);
}
}
5、編寫業務類
service
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
@Component
public interface PaymentFeignService {
@GetMapping("/payment/get/{id}")
CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
controller
@RestController
@Slf4j
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
6、測試feign功能
啟動兩個Eureka-server,啟動payment-8001,payment-8002,然后再啟動feign-order80.
OpenFeign的超時控制
問題描述:在消費者向服務提供者發起請求到最后完成響應的過程中,如果服務提供者在處理過程中消耗的時間大於客戶端消費者等待的時間,客戶端就會java.net.SocketTimeoutException: Read timed out
拋出異常。
解決方法:在配置文件中,修改客戶端讀取時間和連接時間盡量讓消費者等待的時間大於提供者處理的時間。這個也就是Feign的超時控制。
server:
port: 80
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
register-with-eureka: false
# s設置feign的超時時間,OpenFeign默認只此Ribbon
ribbon:
# 在兩端正常情況下,網絡連接所用的時間
ReadTimeout: 5000
# 建立連接后從服務器讀取到可用資源所用的時間
ConnectTimeout: 5000
OpenFeign的日志增強
支持的日志級別
- NONE:默認的,不顯示任何日志
- BASIC:僅僅記錄請求方法、URL、響應狀態碼以及執行時間
- HEADERS:除了BASIC中定義的信息之外,還有請求和響應的頭信息
- FULL:除了HEADERS中定義的信息之外,還有請求和響應的正文以及元數據。
要想在控制台中查看詳細日志,需要設置配置類。
@Configuration
public class FeginLogConfig {
@Bean
Logger.Level feignLogger(){
return feign.Logger.Level.FULL;
}
}
配置文件中添加需要打印日志的請求方法路徑。
logging:
level:
com.guigu.service.PaymentFeignService: debug
啟動服務后,向服務提供方發起請求,在控制台上可以看到以下日志。
未完待續…
下一篇:Hystrix