随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢?
单体架构:简单方便,高度耦合,扩展性差,适合小型项目。例如:学生管理系统
分布式架构:松耦合,扩展性好,但架构复杂,难度大。适合大型互联网项目,例如:京东、淘宝
微服务:一种良好的分布式架构方案
①优点:拆分粒度更小、服务更独立、耦合度更低
②缺点:架构非常复杂,运维、监控、部署难度提高
SpringCloud是微服务架构的一站式解决方案,集成了各种优秀微服务功能组件
现有微服务userservice,orderservice,orderservice需要发起服务间远程调用userservice来获取用户的信息,目前userservice服务部署了多个实例,对外暴露的端口分别是8081、8082、8083,存在以下几个问题:
回答之前的各个问题。
问题1:order-service如何得知user-service实例地址?
获取地址信息的流程如下:
问题2:order-service如何从多个user-service实例中选择具体的实例?
问题3:order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?
在解决上述问题时候我们看到,Eureka通过负载均衡算法实现了从众多实例中选中一个实例,实际上SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的。
LoadBalancerInterceptor.class
这个类会在对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
继续跟踪this.loadBalancer.execute
方法
RibbonLoadBalancerClient.class
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); // 根据服务名获取该服务的一个负载均衡器
Server server = this.getServer(loadBalancer, hint);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
} else {
RibbonServer ribbonServer = new RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
}
}
其中:loadBalancer包含allServerList,从这三个服务列表中,按照负载均衡规则选择一台实例执行业务逻辑
继续跟踪this.getServer(loadBalancer, hint)方法,默认使用ZoneAwareLoadBalancer,但是由于我们的区域设置都是default,因此跳转到其父类执行choose方法,在choose方法中,执行this.rule.choose(key),可以看到是按照某种规则来执行选择的,定义规则的接口即IRule。
public Server chooseServer(Object key) {
if (this.counter == null) {
this.counter = this.createCounter();
}
this.counter.increment();
if (this.rule == null) {
return null;
} else {
try {
return this.rule.choose(key);
} catch (Exception var3) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3});
return null;
}
}
}
发现protected IRule rule = DEFAULT_RULE; private final static IRule DEFAULT_RULE = new RoundRobinRule();
可以指定轮询规则。
内置负载均衡规则类** | 规则描述 |
---|---|
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询【默认规则】 |
BestAvailableRule | 忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
RetryRule | 重试机制的选择逻辑 |
SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改。
基本流程如下:
Nacos与eureka的共同点
Nacos与Eureka的区别