相对概念,生产者:被调用方;消费者:调用方
服务生产:
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置:
server:
port: 2000
spring:
application:
name: provider-server
profiles:
active: dev
cloud:
config:
label: master
profile: ${spring.profiles.active}
discovery:
service-id: config-server
enabled: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
启动类:
/**
* 不用再声明开启注册中心,自动配置了
*/
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
服务:
@RestController
@RequestMapping("/api/v1/provider")
public class ProviderController {
@Value("${server.port}")
private String port;
@GetMapping("/port")
public String port() {
return port;
}
}
服务消费(Ribbon):
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置:
server:
port: 3000
spring:
application:
name: consumer-server-ribbon
profiles:
active: dev
cloud:
config:
label: master
profile: ${spring.profiles.active}
discovery:
service-id: config-server
enabled: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@SpringBootApplication
public class ConsumerRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerRibbonApplication.class, args);
}
// 加载Ribbon,应用负载均衡
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@RestController
@RequestMapping("/api/v1/consumer")
class ProviderController {
private static final String SERVICE_NAME = "provider-server";
private static final String GET_PORT = "/api/v1/provider/port";
@Resource
private RestTemplate restTemplate;
@GetMapping
public String consumer() {
// 调用生产者服务
ResponseEntity<String> forEntity = restTemplate
.getForEntity("http://" + SERVICE_NAME + GET_PORT, String.class, (Object) null);
return forEntity.getBody();
}
}
}
验证:
访问消费者:http://localhost:3000/api/v1/consumer
获得响应:2000
Ribbon主要包含如下组件:
IRule:
根据特定算法中从服务列表中选取一个要访问的服务
- RoundRobinRule:轮询规则,默认规则。同时也是更高级rules的回退策略
- AvailabilityFilteringRule:优先过滤掉由于多次访问故障而处于断路器跳闸状态,并发的连接数量超过阈值
- WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快,服务权重越重、被选中的概率越高
- RetryRule:先按照RoundRobinRule的策略获取服务,如果获取服务失败,则在指定时间内会进行重试,获取可用的服务
- BestAvailableRule:此负载均衡器会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- RandomRule:随机获取一个服务
IPing:
在后台运行的一个组件,用于检查服务列表是否都可用
- NIWSDiscoveryPing:不执行真正的ping。如果Discovery Client认为是在线,则程序认为本次心跳成功,服务可用
- PingUrl:此组件会使用HttpClient调用服务的一个URL,如果调用成功,则认为本次心跳成功,表示此服务活着
- NoOpPing:永远返回true, 即认为服务永远活着
- DummyPing:默认实现,默认返回true,即认为服务永远活着
ServerList:
存储服务列表。分为静态和动态。如果是动态的,后台有个线程会定时刷新和过滤服务列表
- ConfigurationBasedServerList:从配置文件中获取所有服务列表
sample-client.ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
- DiscoveryEnabledNIWSServerList:从服务注册表中获取服务列表。此值必须通过属性中的VipAddress来标识服务器集群。DynamicServerListLoadBalancer会调用此对象动态获取服务列表
- DomainExtractingServerList:代理类,根据ServerList的值实现具体的逻辑
ServerListFilter:
该接口允许过滤配置或动态获取的具有所需特性的服务器列表。ServerListFilter是DynamicServerListLoadBalancer用于过滤从ServerList实现返回的服务器的组件。
- ZoneAffinityServerListFilter:过滤掉所有的不和客户端在相同zone的服务,如果和客户端相同的zone不存在,才不过滤不同zone有服务。
<clientName>.ribbon.EnableZoneAffinity=true
- ZonePreferenceServerListFilter:是比较的zone是发布环境里面的zone。过滤掉所有和客户端环境里的配置的zone的不同的服务,如果和客户端相同的zone不存在,才不进行过滤。
- ServerListSubsetFilter:此过滤器确保客户端仅看到由ServerList实现返回的整个服务器的固定子集。 它还可以定期用新服务器替代可用性差的子集中的服务器
其他配置:
consumer-server-ribbon:
ribbon:
# 请求连接的超时时间
ConnectTimeout: 250
# 请求处理的超时时间
ReadTimeout: 1000
# 对所有操作请求都进行重试
OkToRetryOnAllOperations: true
# 切换实例的重试次数
MaxAutoRetriesNextServer: 2
# 对当前实例的重试次数
MaxAutoRetries: 1
# 定义负载均衡规则
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
服务消费(Feign):
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
配置:
server:
port: 3001
spring:
application:
name: consumer-server-feign
profiles:
active: dev
cloud:
config:
label: master
profile: ${spring.profiles.active}
discovery:
service-id: config-server
enabled: true
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
声明调用生产者的接口:
@FeignClient(name = "provider-server")
@RequestMapping("/api/v1/provider")
public interface ProviderClient {
@GetMapping("/port")
String port();
}
启动类:
@EnableFeignClients:开启Feign功能
@SpringBootApplication
@EnableFeignClients
public class ConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerFeignApplication.class, args);
}
@RestController
@RequestMapping("/api/v1/consumer")
public class OrderController {
@Resource
private ProviderClient providerClient;
@GetMapping
public String productInfo() {
return providerClient.port();
}
}
}
# feign 配置
feign:
hystrix:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
# 请求和响应GZIP压缩支持
compression:
request:
enabled: true
response:
enabled: true
验证:
访问消费者:http://localhost:3000/api/v1/consumer
获得响应:2000
配置:
1、请求响应压缩配置
feign.compression.request.enabled=true
feign.compression.response.enabled=true
# 设置支持的 mime-types
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 选择压缩介质类型和最小请求阈值长度。
feign.compression.request.min-request-size=2048
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
min-request-size: 2048
response:
enabled: true
日志:
记录器的名称是用于创建Feign客户端的接口的完整类名。Feign日志记录仅响应
DEBUG
级别。
logging:
level:
project.user.UserClient: DEBUG
Logger.Level配置:
NONE
,没有记录(DEFAULT)。BASIC
,仅记录请求方法和URL以及响应状态代码和执行时间。HEADERS
,记录基本信息以及请求和响应标头。FULL
,记录请求和响应的标题,正文和元数据。
@Configuration
public class FooConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
@QueryMap:
OpenFeign @QueryMap
注释为POJO提供了对用作GET参数映射的支持。不幸的是,默认的OpenFeign QueryMap注释与Spring不兼容,因为它缺少value
属性。
Spring Cloud OpenFeign提供等效@SpringQueryMap
注释,用于将POJO或Map参数注释为查询参数映射。
@FeignClient("demo")
public class DemoClient {
@GetMapping(path = "/demo")
String demoEndpoint(@SpringQueryMap Params params);
}