Spring Cloud GateWay是Spring Cloud的?個全新項?,?標是取代Netflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux(基于?性能的Reactor模式響應式通信框架Netty,異步?阻塞模型)等技術開發,性能?于Zuul,官?測試,GateWay是Zuul的1.6倍,旨在為微服務架構提供?種簡單有效的統?的API路由管理方式。
Spring Cloud GateWay不僅提供統?的路由?式(反向代理)并且基于 Filter(定義過濾器對請求過濾,完成?些功能) 鏈的?式提供了網關基本的功能,例如:鑒權、流量控制、熔斷、路徑重寫、?志監控等。
說明:負載均衡一般使用軟負載均衡器Nginx,可以搭建高可用的Nginx集群,經過負載均衡將請求轉發到網關層,這里的網關也成為API網關,再由網關路由到各個微服務進行執行。
Zuul1.x 阻塞式IO 2.x 基于Netty
Spring Cloud GateWay天生就是異步?阻塞的,基于Reactor模型。
請求到網關,根據?定的條件匹配,匹配成功之后可以將請求轉發到指定的服務地址;?在這個過程中,我們可以進??些?較具體的控制(限流、日志、黑名單等)
其中,Predicates斷?就是我們的匹配條件,而Filter就可以理解為?個?所不能的攔截器,有了這兩個元素,結合?標URL,就可以實現?個具體的路由轉發。
說明:客戶端向Spring Cloud GateWay發出請求,然后在GateWay Handler Mapping中找到與請求相匹配的路由,將其發送到GateWay Web Handler;Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務執?業務邏輯,然后返回。過濾器之間?虛線分開是因為過濾器可能會在發送代理請求之前(pre)或者之后(post)執?業務邏輯。
Filter在“pre”類型過濾器中可以做參數校驗、權限校驗、流量監控、?志輸出、協議轉換等,在“post”類型的過濾器中可以做響應內容、響應頭的修改、?志的輸出、流量監控等。
GateWay核?邏輯:路由轉發+執行過濾器鏈
<dependencyManagement>
<!--spring cloud依賴版本管理-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--GateWay 網關-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--引入webflux-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!--日志依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!--測試依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!--引入Jaxb,開始-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.10-b140310.1920</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--引入Jaxb,結束-->
<!-- Actuator可以幫助你監控和管理Spring Boot應用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--鏈路追蹤-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>-->
</dependencies>
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication9001 {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication9001.class,args);
}
}
server:
port: 9001
eureka:
client:
serviceUrl: # eureka server的路徑
#把 eureka 集群中的所有 url 都填寫了進來,也可以只寫一臺,因為各個 eureka server 可以同步注冊表
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
instance:
#使用ip注冊,否則會使用主機名注冊了(此處考慮到對老版本的兼容,新版本經過實驗都是ip)
prefer-ip-address: true
#自定義實例顯示格式,加上版本號,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
# 路由可以有多個
routes:
- id: service-consumer # 我們自定義的路由 ID,保持唯一
uri: http://127.0.0.1:8090 # 目標服務地址 自動投遞微服務(部署多實例) 動態路由:uri配置的應該是一個服務名稱,而不應該是一個具體的服務實例的地址
predicates: # 斷言:路由條件,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默 認方法來將 Predicate 組合成其他復雜的邏輯(比如:與,或,非)。
- Path=/consumer/**
注意:
1、不能使用內置的web容器tomcat
2、gateway只是請求轉發,uri的地址 還是原來路徑的地址
Spring Cloud GateWay 幫我們內置了很多 Predicates功能,實現了各種路由匹配規則(通過 Header、請求參數等作為條件)匹配到對應的路由。
predicates:
- After=2021-04-20T17:42:47.789-07:00[America/Denver] #美國時間
predicates:
- Before=2021-04-20T17:42:47.789-07:00[America/Denver] #美國時間
predicates:
- Between=2021-01-20T17:42:47.789-07:00[America/Denver],2021-04-21T17:42:47.789-07:00[America/Denver] #美國時間
predicates:
- Cookie=chocolate, ch.p #key, value value可以是正則表達式
predicates:
- Header=X-Request-Id, \d+ #key, value value可以是正則表達式
predicates:
- Host=**.somehost.org,**.http://anotherhost.org #key, value value可以是正則表達式
predicates:
- Method=GET,POST #key, value value可以是正則表達式
predicates:
- Path=/red/{segment},/blue/{segment}
predicates:
- Query=green
predicates:
- Query=red, gree.
predicates:
- RemoteAddr=192.168.1.1/24
GateWay?持?動從注冊中?中獲取服務列表并訪問,即所謂的動態路由
1)pom.xml中添加注冊中?客戶端依賴(因為要獲取注冊中?服務列表,eureka客戶端已經引?)
2)動態路由配置
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
# 路由可以有多個
routes:
- id: service-consumer # 我們自定義的路由 ID,保持唯一
#uri: http://127.0.0.1:8090 # 目標服務地址 自動投遞微服務(部署多實例) 動態路由:uri配置的應該是一個服務名稱,而不應該是一個具體的服務實例的地址
uri: lb://service-consumer # gateway網關從服務注冊中心獲取實例信息然后負載后路由
predicates: # 斷言:路由條件,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默 認方法來將 Predicate 組合成其他復雜的邏輯(比如:與,或,非)。
- Path=/consumer/**
- id: service-provider # 我們自定義的路由 ID,保持唯一
uri: lb://service-provider
predicates:
- Path=/provider/**
注意:動態路由設置時,uri以 lb: //開頭(lb代表從注冊中?獲取服務),后?是需要轉發到的服務名稱
從過濾器?命周期(影響時機點)的角度來說,主要有兩個pre和post:
生命周期時機點 | 作用 |
pre | 這種過濾器在請求被路由之前調?。我們可利?這種過濾器實現身份驗證、在集群中選擇 請求的微服務、記錄調試信息等。 |
post | 這種過濾器在路由到微服務以后執?。這種過濾器可?來為響應添加標準的 HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等。 |
從過濾器類型的角度,Spring Cloud GateWay的過濾器分為GateWayFilter和GlobalFilter兩種
過濾器類型 | 影響范圍 |
GateWayFilter | 應?到單個路由路由上 |
GlobalFilter | 應?到所有的路由上 |
單個Filter配置 - StripPrefix=1(比較常用):
spring:
cloud:
gateway:
routes:
- id: service-provider # 我們自定義的路由 ID,保持唯一
#uri: http://127.0.0.1:8080 #目標服務地址
uri: lb://service-provider
predicates:
- Path=/provider/**
filters:
- StripPrefix=1 #在請求的時候會去掉provider這個前綴在把剩下的url轉發到對應的微服務上
全局過濾器:通過自定義已給Filter進行過濾。
需求:拒絕黑名單訪問
@Component
public class BlackListFilter implements GlobalFilter, Ordered {
//模擬本機地址
private List<String> blackList = Arrays.asList("0:0:0:0:0:0:0:1");
/**
* 全局過濾器順序
*
* @param exchange 上下文對象封裝了request和response對象
* @param chain 執行器鏈
* @return 返回
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
InetSocketAddress remoteAddress = request.getRemoteAddress();
String clientIp = remoteAddress.getHostString();
if (blackList.contains(clientIp)) {
ServerHttpResponse response = exchange.getResponse();
//狀態碼
response.setStatusCode(HttpStatus.UNAUTHORIZED);
String data = "request be denied";
DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
return response.writeWith(Mono.just(wrap));
}
return chain.filter(exchange);
}
/**
* 定義Filter順序數值越小優先級越高
*/
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
}
?關作為?常核?的?個部件,如果掛掉,那么所有請求都可能?法路由處理,因此我們需要做GateWay的?可?。
GateWay的?可?很簡單:可以啟動多個GateWay實例來實現?可?,在GateWay的上游使?Nginx等負載均衡設備進?負載轉發以達到?可?的?的。啟動多個GateWay實例(假如說兩個,?個端?9002,?個端?9003),剩下的就是使?Nginx等完成負載代理即可。示例如下:
#配置多個GateWay實例upstream gateway {server 127.0.0.1:9002;server 127.0.0.1:9003;}location / {proxy_pass http://gateway;} |
我們使?配置?件管理?些配置信息,?如application.yml。
單體應用架構,配置信息的管理、維護并不會顯得特別麻煩,?動操作就可以,因為就?個?程;
微服務架構,因為我們的分布式集群環境中可能有很多個微服務,我們不可能?個?個去修改配置然后重啟?效,在?定場景下我們還需要在運?期間動態調整配置信息,?如:根據各個微服務的負載情況,動態調整數據源連接池大小,我們希望配置內容發?變化的時候,微服務可以?動更新。
常用的場景:
1)集中配置管理,?個微服務架構中可能有成百上千個微服務,所以集中配置管理是很重要的(?次修改、到處?效)
2)不同環境不同配置,?如數據源配置在不同環境(開發dev,測試test,?產prod)中是不同的
3)運?期間可動態調整。例如,可根據各個微服務的負載情況,動態調整數據源連接池??等配置修改后可?動更新
4)如配置內容發?變化,微服務可以?動更新配置
那么,我們就需要對配置文件進?集中式管理,這也是分布式配置中心的作用。
Spring Cloud Config是?個分布式配置管理?案,包含了 Server端和 Client端兩個部分。
說明:Config Server是集中式的配置服務,用于集中管理應用程序各個環境下的配置。 默認使?Git存儲配置?件內容,也可以SVN。
在遠程github或者gitee上創建一個倉庫+文件【在gitee上進行演示】
注意:創建配置文件名,{application}-{profile}.yml 或者 {application}-{profile}.properties
其中,application為應?名稱,profile指的是環境(dev、test、uat、pro等)
<dependencies>
<!--eureka client 客戶端依賴引入-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--config配置中心服務端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
</dependencies>
Application
@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class ConfigApplication9000 {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication9000.class, args);
}
}
配置文件
server:
port: 9000
#注冊到Eureka服務中心
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
instance:
prefer-ip-address: true #服務實例中顯示ip,而不是顯示主機名(兼容老的eureka版本)
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
spring:
application:
name: config-service
cloud:
config:
server:
git:
uri: https://gitee.com/kangkang53535/springcloudconfig-demo.git #配置git服務地址
username: 你的賬號#配置git用戶名
password: 你的密碼 #配置git密碼
#倉庫名字
search-paths:
- springcloudconfig-demo
# 讀取分支
label: master
POM
<!--Config 客戶端依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
bootstrap.yml配置文件(bootstrap配置文件加載優先于application配置文件)
spring:
cloud:
# config客戶端配置,和ConfigServer通信,并告知ConfigServer希望獲取的配置信息在哪個文件中
config:
name: demo-config #配置文件名稱
profile: dev #后綴名稱
label: master #分支名稱
uri: http://localhost:9000 #ConfigServer配置中心地址
使用
@Value("${http://messange.info}")
private String messageInfo;
@GetMapping("/config")
public String getConfig(){
return messageInfo;
}
問題:
如果我修改git上的配置文件了,對應的服務端獲取到的配置內容也會隨之改變,但是客戶端的內容就不會發生變化了,該如何解決?
客戶端暴露refresh接口
# 暴露regfresh接口
management:
endpoints:
web:
exposure:
include: refresh #暴露refresh接口也可以暴露 也可以配置成*暴露所有
在對應使用的類上貼上@RefreshScope注解
通過Post請求訪問http://localhost:8080/actuator/refresh
當配置發生變化時,通過調用服務端接口,服務端發送MQ消息,各個客戶端接收到MQ消息刷新配置信息。
這里需要使用到消息總線Bus、RabbitMQ。
所謂消息總線Bus,即我們經常會使?MQ消息代理構建?個共?的Topic,通過這個Topic連接各個微服務實例,MQ?播的消息會被所有在注冊中?的微服務實例監聽和消費。換?之就是通過?個主題連接各個微服務,打通脈絡。
Spring Cloud Bus(基于MQ的,支持RabbitMq/Kafka) 是Spring Cloud中的消息總線?案,Spring Cloud Config + Spring Cloud Bus 結合可以實現配置信息的?動更新。
https://blog.csdn.net/weixin_42914989/article/details/113187058 rabbitmq安裝教程
服務端改造
引入POM
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
暴露端口和rabbitMQ配置
#引入rabbitMq
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
#暴露端口
management:
endpoints:
web:
exposure:
include: bus-refresh
客戶端改造
引入POM
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置rabbitMQ即可
#引入rabbitMq
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
Post請求訪問:http://localhost:9000/actuator/bus-refresh
假如我只修改部分客戶端的機器可以在請求的時候定向刷新
http://localhost:9000/actuator/bus-refresh/consumer-provider:8080
Spring Cloud Stream 消息驅動組件幫助我們更快速,更?便,更友好的去構建消息驅動微服務的。
定時任務和消息驅動的?個對比。(消息驅動:基于消息機制做?些事情)MQ:消息隊列/消息中間件/消息代理,產品有很多,ActiveMQ RabbitMQ RocketMQ Kafka
不同的MQ消息中間件內部機制包括使??式都會有所不同,?如RabbitMQ中有Exchange(交換機/交換器)這?概念,kafka有Topic、Partition分區這些概念,MQ消息中間件的差異性不利于我們上層的開發應?,當我們的系統希望從原有的RabbitMQ切換到Kafka時,我們會發現?較困難,很多要操作可能重來(因為應?程序和具體的某?款MQ消息中間件耦合在?起了)。
Spring Cloud Stream進?了很好的上層抽象,可以讓我們與具體消息中間件解耦合,屏蔽掉了底層具體MQ消息中間件的細節差異,就像Hibernate屏蔽掉了具體數據庫(Mysql/Oracle?樣)。如此?來,我們學習、開發、維護MQ都會變得輕松。
目前Spring Cloud Stream?持RabbitMQ和Kafka。
本質就是屏蔽掉了底層不同MQ消息中間件之間的差異,統?了MQ的編程模型,降低了學習、開發、維護MQ的成本。
SpringCloud Stream是?個構建消息驅動微服務的框架。應?程序通過inputs(相當于消息消費者consumer)或者outputs(相當于消息?產者producer)來與Spring Cloud Stream中的binder對象交互,而Binder對象是用來屏蔽底層MQ細節的,它負責與具體的消息中間件交互。
說?了:對于我們來說,只需要知道如何使?Spring Cloud Stream與Binder對象交互即可
說明:Middleware代表中間件,inputs和outputs代表管道,Binder抽取了一層為了屏蔽底層的MQ。
Binder綁定器是SpringCloudStream 中?常核?的概念,就是通過它來屏蔽底層不同MQ消息中間件的細節差異,當需要更換為其他消息中間件時,我們需要做的就是更換對應的Binder綁定器?不需要修改任何應?邏輯(Binder綁定器的實現是框架內置的,Spring Cloud Stream?前?持Rabbit、Kafka兩種消息隊列)
Stream屏蔽了與MQ交互的細節,更加與MQ之間解耦了。
Stream中的消息通信?式遵循了發布—訂閱模式。
在Spring Cloud Stream中的消息通信?式遵循了發布-訂閱模式,當?條消息被投遞到消息中間件之 后,它會通過共享的 Topic 主題進行廣播,消息消費者在訂閱的主題中收到它并觸發?身的業務邏輯處理。這?所提到的 Topic 主題是SpringCloud Stream中的?個抽象概念,?來代表發布共享消息給消 費者的地?。在不同的消息中間件中, Topic 可能對應著不同的概念,?如:在RabbitMQ中的它對應了Exchange、在Kakfa中則對應了Kafka中的Topic。
都是站在應用程序的角度來分析的。
注解 | 描述 |
@Input(在消費者?程中使?) | 注解標識輸?通道,通過該輸?通道接收到的消息進?應?程序 |
@Output(在?產者?程中使?) | 注解標識輸出通道,發布的消息將通過該通道離開應?程序 |
@StreamListener(在消費者?程中使?,監聽message的到來) | 監聽隊列,?于消費者的隊列的消息的接收(有消息監聽.....) |
@EnableBinding | 把Channel和Exchange(對于RabbitMQ)綁定在?起 |
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--spring cloud stream 依賴(rabbit)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
@SpringBootApplication
@EnableDiscoveryClient
public class StreamProducerApplication7070 {
public static void main(String[] args) {
SpringApplication.run(StreamProducerApplication7070.class, args);
}
}
server:
port: 7070
spring:
application:
name: stream-producer
cloud:
stream:
bindings: # 關聯整合通道和binder對象
output: # output是我們定義的通道名稱,此處不能亂改
destination: myExchange # 要使用的Exchange名稱(消息隊列主題名稱)
content-type: text/plain # application/json # 消息類型設置,比如json
binder: rabbitBinder # 關聯MQ服務>>>>>>>>>>
binders: # 綁定MQ服務信息(此處我們是RabbitMQ)
rabbitBinder: # 給Binder定義的名稱,用于后面的關聯<<<<<<<<<<<<<<<<<<<<
type: rabbit # MQ類型,如果是Kafka的話,此處配置kafka
environment: # MQ環境配置(用戶名、密碼等)
spring:
rabbitmq:
host: 192.168.186.10
port: 5672
username: guest
password: guest
eureka:
client:
serviceUrl: # eureka server的路徑
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
instance:
prefer-ip-address: true #使用ip注冊
import com.stream.demo.service.IMessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
// Source.class里面就是對輸出通道的定義(這是Spring Cloud Stream內置的通道封裝)
@EnableBinding(Source.class)
public class MessageProducerImpl {
// 將MessageChannel的封裝對象Source注入到這里使用
@Autowired
private Source source;
@Override
public void sendMessage(String data) {
// 向mq中發送消息(并不是直接操作mq,應該操作的是spring cloud stream)
// 使用通道向外發出消息(指的是Source里面的output通道)
source.output().send(MessageBuilder.withPayload(data).build());
}
}
POM依賴跟生產者一樣
server:
port: 7080
spring:
application:
name: stream-consumer
cloud:
stream:
bindings: # 關聯整合通道和binder對象
input: # output是我們定義的通道名稱,此處不能亂改
destination: myExchange # 要使用的Exchange名稱(消息隊列主題名稱)
content-type: text/plain # application/json # 消息類型設置,比如json
binder: rabbitBinder # 關聯MQ服務>>>>>>>>>>
binders: # 綁定MQ服務信息(此處我們是RabbitMQ)
rabbitBinder: # 給Binder定義的名稱,用于后面的關聯<<<<<<<<<<<<<<<<<<<<
type: rabbit # MQ類型,如果是Kafka的話,此處配置kafka
environment: # MQ環境配置(用戶名、密碼等)
spring:
rabbitmq:
host: 192.168.159.128
port: 5672
username: guest
password: guest
eureka:
client:
serviceUrl: # eureka server的路徑
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
instance:
prefer-ip-address: true #使用ip注冊
@EnableBinding(Sink.class)
public class MessageConsumer {
@StreamListener(Sink.INPUT)
public void consumerMessage(Message<String> message) {
System.out.println(message.getPayload());
}
}
public interface CustomeChannel {
String INPUT_CHANNEL = "inputChannel";
String OUTPUT_CHANNEL = "outputChannel";
//輸入通道
@Input(INPUT_CHANNEL)
SubscribableChannel intputChannel();
//輸出通道
@Output(OUTPUT_CHANNEL)
MessageChannel outputChannel();
}
@EnableBinding(CustomeChannel.class)
public class CustomerMessageProducer {
// 將MessageChannel的封裝對象Source注入到這里使用
@Autowired
private CustomeChannel customeChannel;
public void sendMessage(String data) {
// 向mq中發送消息(并不是直接操作mq,應該操作的是spring cloud stream)
// 使用通道向外發出消息(指的是Source里面的output通道)
customeChannel.outputChannel().send(MessageBuilder.withPayload(data).build());
}
}
@EnableBinding(CustomeChannel.class)
public class CustomerMessageConsumer {
@StreamListener(CustomeChannel.INPUT_CHANNEL)
public void consumerMessage(Message<String> message) {
System.out.println(message.getPayload());
}
}
spring:
application:
name: stream-producer
cloud:
stream:
bindings: # 關聯整合通道和binder對象
outputChannel:
destination: customeExchange
content-type: text/plain
binder: rabbitBinder
inputChannel:
destination: customeExchange
content-type: text/plain
binder: rabbitBinder
binders: # 綁定MQ服務信息(此處我們是RabbitMQ)
rabbitBinder: # 給Binder定義的名稱,
type: rabbit # MQ類型,如果是Kafka的話,此處配置kafka
environment: # MQ環境配置(用戶名、密碼等)
spring:
rabbitmq:
host: 192.168.159.128
port: 5672
username: guest
password: guest
消息分組主要解決兩個問題
1)消息被重復消費問題,處于同一組中的消費者只有一個可以消費到消息
2)消息持久化問題,配置到消息組中,消息會被持久化
配置
outputChannel:
destination: customeExchange
content-type: text/plain
binder: rabbitBinder
group: messageGroup1
inputChannel:
destination: customeExchange
content-type: text/plain
binder: rabbitBinder
group: messageGroup1
問題場景:
上線?個新的服務實例,但是服務消費者?感知,過了?段時間才知道
某?個服務實例下線了,服務消費者?感知,仍然向這個服務實例在發起請求
問題分析:
這其實就是服務發現的?個問題,當我們需要調?服務實例時,信息是從注冊中?Eureka獲取的,然后通過Ribbon選擇?個服務實例發起調?,如果出現調?不到或者下線后還可以調?的問題,原因肯定是服務實例的信息更新不及時導致的。
Eureka 服務發現慢的原因主要有兩個,?部分是因為服務緩存導致的,另?部分是因為客戶端緩存導致的。
Eureka服務端分為2級緩存,一級緩存只讀緩存【ConcurrentHashMap來存儲數據】每30s同步1次,二級緩存【readWriteCacheMap采?Guava來實現緩存】讀寫緩存每180s同步1次,Eureka這樣子設計實際是為了服務端高可用但是在實際使用中一級緩存很雞肋。
解決:我們可以縮短只讀緩存的更新時間(eureka.server.response-cache-update-interval-ms)讓服務發現
變得更加及時,或者直接將只讀緩存關閉(eureka.server.use-read-only-response-cache=false),多級緩存也導致C層?(數據?致性)很薄弱。
Eureka Server 中會有定時任務去檢測失效的服務,將服務實例信息從注冊表中移除,也可以將這個失效檢測的時間縮短,這樣服務下線后就能夠及時從注冊表中清除。
EurekaClient負責跟EurekaServer進?交互,在EurekaClient中的com.netflix.discovery.DiscoveryClient.
initScheduledTasks() ?法中,初始化了?個 CacheRefreshThread 定時任務專??來拉取 Eureka Server 的實例信息到本地。
所以我們需要縮短這個定時拉取服務信息的時間間隔(eureka.client.registryFetchIntervalSeconds)來快速發現新的服務。
Ribbon會從EurekaClient中獲取服務信息,ServerListUpdater是Ribbon中負責服務實例更新的組件,默認的實現是PollingServerListUpdater,通過線程定時去更新實例信息。定時刷新的時間間隔默認是30秒,當服務停?或者上線后,這邊最快也需要30秒才能將實例信息更新成最新的。我們可以將這個時間調短
?點,?如 3 秒。
刷新間隔的參數是通過 getRefreshIntervalMs ?法來獲取的,?法中的邏輯也是從Ribbon 的配置中進?取值的。
將這些服務端緩存和客戶端緩存的時間全部縮短后,跟默認的配置時間相?,快了很多。我們通過調整參數的?式來盡量加快服務發現的速度,但是還是不能完全解決報錯的問題,間隔時間設置為3秒,也還是會有間隔。所以我們?般都會開啟重試功能,當路由的服務出現問題時,可以重試到另?個服務來保證這次請求的成功。
在SpringCloud中,應?的組件較多,只要涉及通信,就有可能會發?請求超時。那么如何設置超時時間? 在 Spring Cloud 中,超時時間只需要重點關注 Ribbon 和Hystrix 即可。
Ribbon如果采?的是服務發現?式,就可以通過服務名去進?轉發,需要配置Ribbon的超時。Rbbon的超時可以配置全局的ribbon.ReadTimeout和ribbon.ConnectTimeout。也可以在前?指定服務名,為每個服務單獨配置,?如user-service.ribbon.ReadTimeout。
其次是Hystrix的超時配置,Hystrix的超時時間要?于Ribbon的超時時間,因為Hystrix將請求包裝了起來,特別需要注意的是,如果Ribbon開啟了重試機制,?如重試3 次,Ribbon 的超時為 1 秒,那么 Hystrix 的超時時間應該?于 3 秒,否則就會出現 Ribbon 還在重試中,? Hystrix 已經超時的現象。
Hystrix全局超時配置就可以?default來代替具體的command名稱。hystrix.command.default.execution.
isolation.thread.timeoutInMilliseconds=3000 如果想對具體的 command 進?配置,那么就需要知道 command 名稱的?成規則,才能準確的配置。
如果我們使? @HystrixCommand 的話,可以?定義 commandKey。如果使?FeignClient的話,可以為FeignClient來指定超時時間:hystrix.command.UserRemoteClient.execution.isolation.thread.timeoutInMillis
econds = 3000
如果想對FeignClient中的某個接?設置單獨的超時,可以在FeignClient名稱后加上具體的?法:
hystrix.command.UserRemoteClient#getUser(Long).execution.isolation.thread.timeoutInMilliseconds = 3000
Feign本身也有超時時間的設置,如果此時設置了Ribbon的時間就以Ribbon的時間為準,如果沒設置Ribbon的時間但配置了Feign的時間,就以Feign的時間為準。Feign的時間同樣也配置了連接超時時間(feign.client.config.服務名稱.connectTimeout)和讀取超時時間(feign.client.config.服務名稱.readTimeout)。
建議,我們配置Ribbon超時時間和Hystrix超時時間即可。
IT之家 10 月 13 日消息,除了宣布一大堆 Azure 功能、Teams 功能和 Edge 升級之外,微軟還在 Ignite 2022 會議上公布了 Microsoft 365 的新功能和即將推出的功能。
首先,Mac 版 Outlook 現在支持蘋果公司提供的重點配置文件和重點過濾器。這些配置文件可以在每個賬戶的基礎上進行配置,并將適用于所有相關元素,如通知和主題。
此外,微軟還透露了 Outlook 的其他功能。這些功能包括:工作時間和地點,以便對何時適合與某人安排會議有更多的了解;會議回顧,以便直接從日歷事件中找到記錄和相關信息;電子郵件信息反應,以及由 Context IQ 提供的編輯器(現在正在預覽中推出,以便在 Web Outlook 中顯示相關信息和人物。所有這些都將在今年年底前普遍推出。
說到微軟 Editor 編輯器,在預覽版中也有一些新的功能,包括語氣建議、大型文件摘要和 Web Word 的簡潔性。同樣,Word、Excel 和 PowerPoint 也將獲得包含其最常用命令的個人工具條。
此外,微軟已經宣布了 Microsoft Project Web 版的一系列新功能。到今年年底,該軟件將獲得短期活動和聯系人視圖,以監測任務分配和工作量。而在 2023 年開始,與 Viva 目標、項目中的目標、分配給我的任務、任務歷史、高級依賴關系和高達 1000 的任務限制的連接也將變得可用。
微軟也正在使在 Stream 中創建和查看視頻內容變得更加容易。背景模糊、墨跡、文字和效果已經普遍可用,而 Teams 會議記錄現在也可以從 Teams 移動應用中訪問。其他功能還包括個性化的時間線標記、自動生成的章節和智能搜索。所有這些都將使人們更容易找到重要的內容,特別是在聽取冗長的錄音時。
IT之家獲悉,微軟還宣布了 Microsoft Syntex。這是由人工智能驅動的應用程序和服務的集合,可以使分析和組織非結構化內容更加容易。它可以自動化基于內容的工作流程,如電子簽名,支持注釋和編輯,并與微軟搜索緊密結合。其他功能包括數據管理和保護、場景加速器、與 Dynamics 365 等商業應用的整合以及容器。Syntex 功能已經開始逐步推出,從今天開始一直到 2023 年初。
在將近一年前宣布之后,微軟全新協作平臺 Loop 現在可以推出了私密預覽版。Loop 是新的 Microsoft 365 應用程序,還提供可與其他服務(如 Teams、Outlook 和 OneNote)一起使用的便攜式組件。《微軟發布了個“圈”,官方詳解 Microsoft Loop 全新協作平臺:組件、頁面和工作空間,集成全部微軟 365 應用程序》
未來幾個月,Loop 組件的擴展計劃包括如下:
將投票、核對表或任務清單組件插入 Web Word 中 —— 在 2022 年底前進行私密預覽
復制現有的 Loop 組件并將其粘貼到 Teams、Web 和桌面的白板中 —— 在 2022 年底前全面推出
由微軟表格驅動的民意調查與 Web Outlook 和 Word 同步 ——2022 年底前進行私密預覽
問答 —— 現在可以在 Web Outlook 中預覽,今年晚些時候可普遍使用
敏感性標簽 —— 今年年底在 Teams 聊天中可用
數據丟失防護(DLP)—— 今年年底在 Teams 聊天中可用
一款新的 Microsoft 365 應用程序也在醞釀之中。微軟將其描述為 Office 應用的進化,基本上允許用戶在一個地方訪問所有的東西,同時還有 AI 驅動的智能功能。新的應用程序將在下個月開始推出,它將包含一些新的功能,如跟蹤共享文件活動和趨勢 Feed 流,訪問任何 Microsoft 365 或相關第三方應用程序的應用模塊,以及標記你的內容以更好地組織。
在 Viva 方面也有一些更新,下面是一些介紹:
Viva Insights 普遍具有的新功能
會議效果調查
來自 Viva Insights 的日程表發送建議
新的專注模式體驗
靜默時間設置
Viva Learning 新功能
學習路徑 —— 私密預覽
學習集合 —— 私密預覽
權限 —— 私密預覽
Viva Learning 移動應用程序新功能
1、新的主頁 - 私密預覽
2、通知
3、在應用程序中完成學習課程
4、搜索和過濾連接的學習提供者的目錄
Viva Engage Storyline 普遍可用,而 Stories 則處于私密預覽階段
Viva Goals 正在獲得新的第一和第三方集成,包括 Slack、Google Sheets、Jira on-presmises、Microsoft Teams、Power BI、Microsoft Project 等。
Viva Topics 的新功能,現在處于預覽階段
1、利用 Context IQ
2、微軟 Syntex 連接器
3、主題卡將在 Windows 的 Outlook 和 Viva Connections 儀表盤中出現
4、使用 Viva Engage 查找相關內容并自動回答問題
5、主題上的徽章圖標以及瀏覽量