0%

为什么微服务需要网关

在微服务架构中,通常会有多个服务提供者。设想一个电商系统,可能会有商品、订单、支付、用户等多个类型的服务,而每个类型的服务数量也会随着整个系统体量的增大也会随之增长和变更。作为UI端,在展示页面时可能需要从多个微服务中聚合数据,而且服务的划分位置结构可能会有所改变。网关就可以对外暴露聚合API,屏蔽内部微服务的微小变动,保持整个系统的稳定性。

阅读全文 »

HystrixCommand.execute源码细节

HystrixCommand会将任务丢到异步线程池里去执行,通过Future获取执行完毕的结果。

1
2
3
4
5
6
7
8
// HystrixCommand.java
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw Exceptions.sneakyThrow(decomposeException(e));
}
}

queue()方法,是用来异步执行的command逻辑的,他会将command扔到线程池里去执行,但是这个方法不会等待线程执行完毕command,他会拿到一个Future对象,通过Future对象去获取command执行完毕的响应结果。

阅读全文 »

背景

在zuul网关中,有关于配置连接数量的配置:

1
2
3
4
zuul:
host:
max-per-route-connections: 20 #默认值
max-total-connections: 200 #默认值

这个是只是的zuul调用静态路由配置的Http连接池数量,按照实际情况设置就好(请注意不要和Tomcat的maxConnections搞混了)。

这个配置并不会对基于Ribbon的下游服务访问生效,如果要配置Ribbon相关的配置,需要配置以下的配置:

1
2
3
ribbon:
MaxConnectionsPerHost: 50 #默认值
MaxTotalConnections: 200 #默认值
阅读全文 »

Feign和Hystrix结合使用

在@FeignClient中增加fallback配置,指定降级方法的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
@FeignClient(name = "user",url = "${user.url}",fallback = UserFeignFallback.class
/*fallbackFactory = UserFeignFactory.class*/)
public interface UserFeign {

@PostMapping
void save(User user);

@GetMapping("/{id}")
User getUserByID(@PathVariable("id") String id);

@GetMapping
List<User> findAll();
}
阅读全文 »

Feign超时和重试

超时

在微服务架构中,一个服务对服务的访问至少得配置一个超时时间,不可能请求一个接口等了好几分钟都还没有返回,在设置超时时间后,超时后就认为这次接口请求失败了。

重试

服务B调用服务A,服务A部署了3台机器,现在服务B通过负载均衡的算法,调用到了服务A的机器1,因为服务A的机器1宕机了,请求超时了,可以让服务B再次请求一次服务A的机器1,如果还是不行,再请求服务A的机器2,如果还是不行,就再请求服务A的服务3,这就是重试机制。

阅读全文 »

接口方法与MethodHandler映射map的生成机制

在开始之前,先说一下FeignClient接口的上的SpringMVC注解是如何被解析的,回顾到之前生成动态代理的时候,有个nameToHandler的map,有一句非常关键的代码。

1
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

这里面就完成了SpringMVCContract对方法的解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ReflectiveFeign.java
public Map<String, MethodHandler> apply(Target key) {
// 这就用contract完成了方法上的SpringMVC注解的转换
// ServiceAClient的每一个方法都会被解析成MethodMetadata
// 对各种SpringMVC的注解进行解析,将解析出来的header,method,path,body,form param,返回值等等等,放入了MethodMetadata中
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
// 遍历方法元数据
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md);
}
// 在这里就创建了SynchronousMethodHandler,key就是方法名
// SynchronousMethodHandler就是所有的方法被代理后实际处理的处理器
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
阅读全文 »

动态代理创建FeignClient的实例

在做完前面的事情以后,FeignClientFactoryBean已经被注册到Spring上下文中,根据Spring的原理,FactoryBean是用于构造复杂对象实例的一种工厂,可定制创建,初始化,刷新,销毁的各个过程。重点需要去看getObject()方法,看对象实例是如何产生的。

阅读全文 »

Feign的组件简介

Feign负责简化接口调用,发起Http请求,Feign也包含了几个核心组件

  1. 编码器和解码器:Encoder和Decoder。
    Encoder:如果调用接口的时候,传递的参数是个对象,feign需要将这个对象进行encode解码,json序列化,把一个对象转成json格式。
    Decoder:json反序列化,收到json以后,将json转换成本地的一个Java对象。
  2. Logger:用于打印接口请求相关的调用日志
  3. Contract:feign注解和spring web mvc 支持的@PathVariable,@RequesstMapping,@RequestParam等注解结合起来使用了。feign本来是没法支持spring web mvc的注解的,但是有了contract(契约组件)支持后,这个组件负责解释其他的注解,让feign可以跟其他注解结合起来使用。
  4. Feign.Builder:Feign客户端的一个实例构造器,基于构建器模式的,Ribbon也有。
  5. FeignClient:最核心的入口,和RibbonLoadBalancerClient类似,包含以上这些核心的组件,基于这些组件去协作调用。
阅读全文 »

负载均衡

服务注册,就是在分布式系统中,将注册的ip和端口号等信息告诉注册中心。

服务发现就是客户端去注册中心获取服务列表,知道每一个服务实例的ip和端口是什么。

负载均衡就是在拿到了这个服务列表以后,从中要选取一个实例来进行调用,这里就需要用到负载均衡算法。在Spring Cloud中,Ribbon就是做负载均衡用的一个组件,在这边叫做客户端负载均衡。具体的概念咋回事和如何使用我这里就不介绍了,网上文章很多,用过SpringCloud的人也应该都用过,下面开始进入源码探索。

阅读全文 »