分布式和微服务区别_深度解析spring cloud分布式微服务的实现

01948c642287459f5ac30ddc67d495d8.png

分布式系统

微服务就是原来臃肿的项目拆分为多个模块互不关联。如:按照子服务拆分、数据库、接口,依次往下就更加细粒度,当然运维也就越来越难受了。

分布式则是偏向与机器将诺大的系统划分为多个模块部署在不同服务器上。

微服务和分布式就是作用的“目标不一样”。

微服务与Cloud

微服务是一种概念,spring-cloud是微服务的实现。

微服务也不一定必须使用cloud来实现,只是微服务中有许多问题,如:负载均衡、服务注册与发现、路由等等。

而cloud则是将这些处理问题的技术整合了。

Spring-Cloud 组件

Eureka

Eureka是Netifix的子模块之一,Eureka有2个组件,一个EurekaServer 实现中间层服务器的负载均衡和故障转移,一个EurekaClient它使得与server交互变得简单。

Spring-Cloud封装了Netifix公司开发的Eureka模块来实现服务注册和发现。

通过Eureka的客户端 Eureka Server维持心跳连接,维护可以更方便监控各个微服务的运行。

角色关系图

885025c15e7df13f0edd974c674c2785.png

Eureka使用

客户端

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
server:
port: 4001
eureka:
client:
serviceUrl:
defaultZone: http://localhost:3000/eureka/ #eureka服务端提供的注册地址 参考服务端配置的这个路径
instance:
instance-id: admin-1 #此实例注册到eureka服务端的唯一的实例ID
prefer-ip-address: true #是否显示IP地址
leaseRenewalIntervalInSeconds: 10 #eureka客户需要多长时间发送心跳给eureka服务器,表明它仍然活着,默认为30 秒 (与下面配置的单位都是秒)
leaseExpirationDurationInSeconds: 30 #Eureka服务器在接收到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除,默认为90秒spring:
application:
name: server-admin #此实例注册到eureka服务端的name

服务端

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-
netflix-eureka-server</artifactId>
</dependency>
yml文件声明 
server:
port: 3000
eureka:
server:
enable-self-preservation: false #关闭自我保护机制
eviction-interval-timer-in-ms: 4000 #设置清理间隔
(单位:毫秒 默认是60*1000)
instance:
hostname: localhost 
client:
registerWithEureka: false #不把自己作为一个客户端注册到自己身上
fetchRegistry: false #不需要从服务端获取注册信息
(因为在这里自己就是服务端,而且已经禁用自己注册了)
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
在SpringBoot 启动项目中加入注解:@EnableEurekaServer 
就可以启动项目了,访问对应地址就可以看到界面。

Eureka 集群

服务启动后Eureka Server会向其他服务server 同步,当消费者要调用服务提供者,则向服务注册中心获取服务提供者的地址,然后将提供者的地址缓存到本地,下次调用时候直接从本地缓存中获取

yml 服务端

server:
port: 3000
eureka:
server:
enable-self-preservation: false #关闭自我保护机制
eviction-interval-timer-in-ms: 4000 #设置清理间隔
(单位:毫秒 默认是60*1000)
instance:
hostname: eureka3000.com 
client:
registerWithEureka: false #不把自己作为一个客户端
注册到自己身上
fetchRegistry: false #不需要从服务端获取注册信息
(因为在这里自己就是服务端,而且已经禁用自己注册了)
serviceUrl:
defaultZone: http://eureka3001.com:3001/eureka,
http://eureka3002.com:3002/eureka
(这里不注册自己,注册到其他服务上面以为会同步。)

yml 客户端

server:
port: 4001
eureka:
client:
serviceUrl:
defaultZone:http://localhost:3000/eureka/,http://
eureka3001.com:3001/eureka,http://eureka3002.com:3 002
/eureka #eureka服务端提供的注册地址 参考服务端配置的这个路径
instance:
instance-id: admin-1 #此实例注册到eureka服务端的唯一的实例ID
prefer-ip-address: true #是否显示IP地址
leaseRenewalIntervalInSeconds: 10 #eureka客户需要多长时间发
送心跳给eureka服务器,表明它仍然活着,默认为30 秒 (与下面配置的单位都是秒)
leaseExpirationDurationInSeconds: 30 #Eureka服务器在
接收到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除,默认为90秒spring:
application:
name: server-admin #此实例注册到eureka服务端的name

CAP定理

C:Consistency 一致性
A:Availability 可用性
P:Partition tolerance 分区容错性
这三个指标不能同时达到

Partition tolerance

分区容错性,大多数分布式系统都部署在多个子网络。每一个网络是一个区。区间的通信是可能失败的如一个在本地,一个在外地,他们之间是无法通信的。分布式系统在设计的时候必须要考虑这种情况。

Consistency

一致性,写操作后的读取,必须返回该值。如:服务器A1和服务器A2,现在发起操作将A1中V0改为V1,用户去读取的时候读到服务器A1得到V1,如果读到A2服务器但是服务器

还是V0,读到的数据就不对,这就不满足一致性。

所以让A2返回的数据也对,的让A1给A2发送一条消息,把A2的V0变为V1,这时候不管从哪里读取都是修改后的数据。

Availability

可用性就是用户只要给出请求就必须回应,不管是本地服务器还是外地服务器只要接收到就必须做出回应,不管数据是否是最新必须做出回应,负责就不是可用性。

C与A矛盾

一致性和可用性不能同时成立,存在分区容错性,通信可能失败。

如果保证一致性,A1在写操作时,A2的读写只能被锁定,只有等数据同步了才能读写,在锁定期间是不能读写的就不符合可用性。

如果保持可用性,那么A2就不会被锁定,所以一致性就不能成立。

综上 无法做到一致性和可用性,所以系统在设计的时候就只能选其一。

Eureka与Zookeeper

Zookeeper遵循的是CP原则保持了一致性,所以在master节点因为网络故障与剩余“跟随者”接点失去联系时会重新选举“领导者”,选取“领导者”大概会持续30-120s的时间,且选举的时候整个zookeeper是不可用的。导致在选举的时候注册服务瘫痪。

Eureka在设计的时候遵循AP可用性。Eureka各个接点是公平的,没有主从之分,down掉几个几点也没问题,其他接点依然可以支持注册,只要有一台Eureka在,注册就可以用,只不过查询到的数据可能不是最新的。Eureka有自我保护机制,如果15分钟之内超过85%接点都没有正常心跳,那么Eureka认为客户端与注册中心出现故障,此时情况可能是

Eureka不在从注册列表移除因为长时间没有瘦到心跳而过期的服务。

Eureka仍然能够接收注册和查询,但不会同步到其他接点。

当网络稳定后,当前的 实例注册信息会更新到其他接点。

Ribbon

rebbon主要提供客户端的负载均衡,提供了一套完善的客户端的配置。Rebbin会自动帮助你基于某种规则(如:简单的轮询,随机链接等)。

服务端的负载均衡是一个url通过一个代理服务器,然后通过代理服务器(策略:轮询,随机 ,权重等等),反向代理到你的服务器。

客户端负载均衡是通过一个请求在客户端已经声明了要调用那个服务,然后通过具体算法来完成负载均衡。

Ribbon使用

引入依赖,Eureka以及把Ribbon集成在里面。

使用Ribbon只有在RestTemplate上面加入@LoadBalanced注解。

Feign负载均衡

feign是一个声明式的webService客户端,使用feign会让编写webService更简单,就是定义一个接口加上注解。

feign是为了编写java http客户端更加简单,在Ribbon+RestTemplate此基础上进一步封装,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。

Feign使用

引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类上加@EnableFeignClients
然后在接口上加@FeignClient("SERVER-POWER")注解其中参数就是服务的名字。

Feign集成Ribbon

利用Ribbon维护服务列表信息,融合了Ribbon的负载均衡配置,与Ribbon不同的是Feign只需要定义服务绑定接口以声明的方式,实现简答的服务调用。

hystrix断路器

是一种用于处理分布式系统延迟和容错的开源库。在分布式系统中许多依赖不可避免的会调用失败,比如超时、异常等,断路器保证出错不会导致整体服务失败,避免级联故障。

断路器其实就是一种开关设置,类似保险丝,像调用方返回一个符合预期的、可处理的备选响应,而不是长时间等待或者抛出无法处理的异常,保证服务调用方线程不会被长时间 不必要占用,从而避免了在分布式系统中蔓延,乃至雪崩。

微服务中 client->微服务A->微服务B->微服务C->微服务D,其中微服务B异常了,所有请求微服务A的请求都会卡在B这里,就会导致线程一直累积在这里,那么其他微服务就没有可用线程,导致整个服务器雪崩。

针对这方案有 服务限流、超时监控、服务熔断、服务降级

降级 超时

降级就是服务响应过长 ,或者不可用了,就是服务调用不了了,我们不能把错误信息返回出来,或者长时间卡在哪里,所以要准备一个策略当发生这种问题我们直接调用这个方法快速返回这个请求,不让他一直卡在那。

要在调用方做降级(要不然那个微服务都down掉了在做降级就没有意义)。

引入hystrix依赖

<dependency> 
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId> 
</dependency>
在启动类上加入@EnableHystrix 或者@EnableCircuitBreaker。
@RequestMapping("/feignPower.do") 
@HystrixCommand(fallbackMethod = "fallbackMethod") 
public Object feignPower(String name){ 
return powerServiceClient.power(); 
} 
fallbackMethod:
public Object fallbackMethod(String name){ 
System.out.println(name); 
return R.error("降级信息"); 
}
这里的降级信息具体内容根据业务需求来,比如返回一个默认的查询信息等等。
hystrix有超时监听,当你请求超过1秒 就会超时,这个是可以配置的

这里的降级信息具体内容根据业务需求来,比如返回一个默认的查询信息等等。

hystrix有超时监听,当你请求超过1秒 就会超时,这个是可以配置的

降级什么用

第一他可以监听服务有没有超时。第二报错了他这里直接截断了没有让请求一直卡在这个。

其实降级,当你系统迎来高并发的时候,这时候发现系统马上承载不了这个大的并发 ,可以先关闭一些不重要 的微服务(就是在降级方法返回一个比较友好的信息)把资源让出来给主服务,其实就是整体资源不够用了,忍痛关闭某些服务,待过渡后再打开。

熔断限流

熔断就像生活中的跳闸,比如电路故障了,为了防止事故扩大,这里切断你的电源以免意外发生。当一个微服务调用多次,hystrix就会采取熔断 机制,不在继续调用你的方法,会默认短路,5秒后试探性的先关闭熔断机制,如果在这时候失败一次会直接调用降级方法,一定程度避免雪崩,

限流,限制某个微服务使用量,如果线程占用超过了,超过的就会直接降级该次调用。

Feign整合hystrix

feign默认支持hystrix,需要在yml配置中打开。
feign: 
hystrix: 
enabled: true降级方法
@FeignClient(value = "SERVER-POWER", fallback = PowerServiceFallBack.class)
public interface PowerServiceClient {@RequestMapping("/power.do")
public Object power(@RequestParam("name") String name);
}在feign客户端的注解上 有个属性叫fallback 然后指向一个类 PowerServiceClient 
@Component
public class PowerServiceFallBack implements PowerServiceClient {
@Override
public Object power(String name) {
return R.error("测试降级");
}
}

Zuul 网关

zuul包含了对请求的路由和过滤两个主要功能

路由是将外部请求转发到具体的微服务实例上。是实现统一入口基础而过滤器功能负责对请求的处理过程干预,是实现请求校验等功能。

Zuul与Eureka进行整合,将zuul注册在Eureka服务治理下,同时从Eureka获取其他服务信息。(zuul分服务最终还是注册在Eureka上)

路由

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
最后要注册在Eureka上所以需要引入eureka依赖
YML
server:
port: 9000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:3000/eureka/ #eureka服务端提供的注册地址 参考服务端配置的这个路径
instance:
instance-id: zuul-0 #此实例注册到eureka服务端的唯一的实例ID
prefer-ip-address: true #是否显示IP地址
leaseRenewalIntervalInSeconds: 10 #eureka客户需要多长时间发送心跳给eureka服务器,表明它仍然活着,默认为30 秒 (与下面配置的单位都是秒)
leaseExpirationDurationInSeconds: 30 #Eureka服务器在接收到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除,默认为90秒spring:
application:
name: zuul #此实例注册到eureka服务端的name 
启动类 @EnableZuulProxy在实际开发当中我们肯定不会/server-power这样通过微服务调用,
可能只要一个/power就好了 
zuul: 
routes:
mypower: 
serviceId: server-power 
path: /power/** 
myorder: 
serviceId: server-order 
path: /order/**
注意/**代表是所有层级 /* 是代表一层。
一般我们会禁用服务名调用
ignored-services:server-order 这样就不能通过此服务名调用,
不过这个配置如果一个一个通微服务名字设置太复杂
一般禁用服务名 ignored-services:“*”
有时候要考虑到接口调用需要一定的规范,比如调用微服务URL需要前缀/api,可以加上一个prefix
prefix:/api 在加上strip-prefix: false /api前缀是不会出现在路由中
zuul:
prefix: /api
ignored-services: "*"
stripPrefix: false
routes:
product:
serviceId: server-product
path: /product/**
order:
serviceId: server-order
path: /order/**

过滤器

过滤器(filter)是zuul的核心组件,zuul大部分功能是通过过滤器实现的,zuul中定义了4种标准过滤器类型,这些过滤器类型对应与请求的生命周期,

PRE:这种过滤器在请求路由前被调用,可利用过滤器进行身份验证,记录请求微服务的调试信息等。

ROUTING:这种过滤器将请求路由到微服务,这种过滤器用于构建发送给微服务请求,并使用 Apache HttpClient或Netfix Ribbon请求微服务。

POST:这种过滤器在路由微服务后执行,可用来相应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端。

ERROR:在其他阶段发送错误时执行过滤器

继承ZuulFilter

@Component
public class LogFilter extends ZuulFilter { 
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER+1;
}@Override
public boolean shouldFilter() {
return true;
}@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
//被代理到的微服务
String proxy = (String)ctx.get("proxy");
//请求的地址
String requestURI = (String)ctx.get("requestURI");
//zuul路由后的url
System.out.println(proxy+"/"+requestURI);
HttpServletRequest request = ctx.getRequest();
String loginCookie = CookieUtil.getLoginCookie(request);
ctx.addZuulRequestHeader("login_key",loginCookie);
return null;
}
}

由此可知道自定义zuul Filter要实现以下几个方法。

filterType:返回过滤器类型,有pre、route、post、erro等几种取值

filterOrder:返回一个int值指定过滤器的顺序,不同过滤器允许返回相同数字。

shouldFilter:返回一个boolean判断过滤器是否执行,true执行,false不执行。

run:过滤器的具体实现。

Spting-Cloud默认为zuul编写并开启一些过滤器。如果要禁用部分过滤器,只需在application.yml里设置zuul…disable=true,例如zuul.LogFilter.pre.disable=true

zuul也整合了了hystrix和ribbon的, 提供降级回退,继承FallbackProvider 类 然后重写里面的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/289273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过Shell开发企业级专业服务启动脚本案例(MySQL)

老男孩教育Linux高端运维班Shell课后必会考试题:企业Shell面试题10&#xff1a;开发企业级MySQL启动脚本说明:MySQL启动命令为&#xff1a;/bin/sh mysqld_safe --pid-file$mysqld_pid_file_path 2>&1 >/dev/null &停止命令逻辑脚本为&#xff1a;mysqld_pidcat …

React Native之js调用Android原生使用Callback传递结果给js

如果不清楚js如何调用Android原生,可以先参考我的这篇博客React Native实现js调用安卓原生代码 1 问题 上面的文章只是调用安卓原生显示Toast,但是我们一般会需要调用安卓的代码然后去拿回结果给js,但是我们知道在android层js调用的这个函数返回值必须的void,所以我们需要用到…

ENVI帮助研究人员发现金矿

本文转自&#xff1a;http://www.esrichina-bj.cn/2012/0319/1663.html 遥感影像能让我们实时的获取地理区域的准确信息&#xff0c;这些为很多石油、天然气和矿产的开采提供关键的信息&#xff0c;节约实地测量的成本&#xff0c;提高工作效率。 美国圣路易斯大学的研究人员希…

C# 使用TCP创建HTTP客户程序

首先&#xff0c;创建一个控制台应用程序(包)&#xff0c;向 Web 服务器发送一个 HTTP 请求。以前用 HttpClient 类实现了这个功能&#xff0c;但使用 TcpClient 类需要深入 HTTP 协议。HttpClientUsingTcp 示例代码使用了以下名称空间:System System.IO System.Net.Sockets …

迅捷路由器 服务器无响应,如果路由器重启还是上不了网 几招搞定

如果网速很慢重启了路由器之后结果还是慢&#xff0c;而且甚至上不了网了那该怎么办。如果有这种情况原因其实有很多很多的可能&#xff0c;需要逐个排查&#xff0c;首先需要进入192.168.1.1路由器的管理设置界面&#xff0c;查看路由器的运行状态。路由器设置、路由器没有成功…

Azure DevOps 中 Dapr项目自动部署流程实践

注&#xff1a;本文中主要讨论 .NET6.0项目在 k8s 中运行的 Dapr 的持续集成流程, 但实际上不是Dapr的项目部署到K8s也是相同流程&#xff0c;只是k8s的yaml配置文件有所不同流程选择基于 Dapr 的项目持续集成包含以下流程编译并打包项目构建 Dockerfile,并推送镜像push image至…

React Native之js同步调用安卓原生方法@ReactMethod(isBlockingSynchronousMethod = true)

1 问题 之前的代码js调用安卓原生都是用的异步方法,比如callback, promiss,异步的话,我们一般是在安卓原生有耗时操作,才用异步,如果我要离开返回,就需要js调用安卓同步方法 利用callback实现js调用原生可以参考我的这篇博客 React Native实现js调用安卓原生代码 React Nat…

用POP动画引擎实现弹簧动画(POPSpringAnimation)

效果图: #import "ViewController.h" #import <POP.h>interface ViewController ()property (nonatomic, weak) UIView *testView;endimplementation ViewController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor [UIColor blackColor…

地理知识归纳:影响降水的九大因素

降水指大气中水汽凝结降落的过程,包括降雨、下雪、冰雹等形式,降水的多少要受很多因素的影响,但主要条件是三个:充足的水汽供应,气流上升达到过饱和状态,足够的凝结核。通常情况下,我们不需要考虑凝结核的问题,只是考虑有没有充足的水汽和促使气流上升的机制就可以,归…

linux 查看cpu_作为高级Java,你应该了解的Linux知识

作为一个javaer&#xff0c;我以前写过很多关于Linux的文章。但经过多年的观察&#xff0c;发现其实对于大部分人&#xff0c;有些东西压根就用不着。用的最多的&#xff0c;就是到线上排查个问题而已&#xff0c;这让人很是苦恼。那么&#xff0c;我们就将范围再缩小一下。最有…

layer和3D仿射变换

1、视图的显示基于图层&#xff0c;通过控制图层同样能控制显示效果&#xff0c;获取当前的视图的layer,并为其增加圆角边框。 //设置layer边框的宽度为2view.layer.borderWidth2;//如果需要为layer添加颜色需要转换为CGColor对象view.layer.borderColor[UIColor greenColor].C…

React Native之Android原生通过DeviceEventEmitter发送消息给js

1 问题 Android原生向js发消息,并且可以携带数据 2 实现原理 Android原生可以使用RCTEventEmitter来注册事件,然后这里需要指定事件的名字,然后在js那端进行监听同样事件的名字监听,就可以收到消息得到数据 Android注册关键代码 reactContext.getJSModule(DeviceEventManag…

CentOS安装JAVA JDK

普通情况下&#xff0c;我们都要将linux自带的OPENJDK卸载掉。然后安装SUN的JDK。首先查看Linux自带的JDK是否已安装。 输入例如以下命令&#xff0c;查看已经安装的JAVA版本号信息。 Linux代码 java -version 输入例如以下命令。查看JDK的信息。Linux代码 rpm -qa|grep j…

安装bigdesk后es无法启动_安装天正后,探索者无法双击启动?

用户经常会出现&#xff0c;安装天正后&#xff0c;探索者无法双击启动&#xff0c;或者是图纸无法拖拽入CAD中&#xff0c;如何解决&#xff1f;答&#xff1a;天正安装完成后&#xff0c;默认将CAD的acad.exe程序&#xff0c;添加了“以管理员身份运行此程序”而导致的&#…

服务器安全维护包含,服务器安全维护包含

服务器安全维护包含 内容精选换一换本章节介绍如何使用管理控制台向导创建裸金属服务器。创建裸金属服务器时&#xff0c;您需要配置规格、镜像、存储、网络、安全组等必备信息。同时&#xff0c;向导也提供了丰富的扩展配置功能&#xff0c;方便您进行个性化部署和管理。在创建…

C# 发出异步的Get请求

下列的下载代码示例是 HttpClientSample。它以不同的方式异步调用Web 服务。为了演示本例使用的不同方法&#xff0c;使用了命令行参数。示例代码使用了以下名称空间&#xff1a;System System.Linq System.Net System.Net.Http System.Net.Http.Headers System.Threading Sy…

React Native之Props(属性)和State(状态)和简单样式简单使用

1 Props(属性)和State(状态)和简单样式简单使用App.js代码如下 /*** Sample React Native App* https://github.com/facebook/react-native** format* flow*/import React, {Component} from react; import {Platform, StyleSheet, Text, View, NativeModules, DeviceEvent…

config kubectl_Kubernetes(k8s)中文文档 kubectl config set-context_Kubernetes中文社区

译者&#xff1a;hurf在kubeconfig配置文件中设置一个环境项。摘要在kubeconfig配置文件中设置一个环境项。 如果指定了一个已存在的名字&#xff0c;将合并新字段并覆盖旧字段。kubectl config set-context NAME [--clustercluster_nickname] [--useruser_nickname] [--namesp…

使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题

理想的代码优化方式团队日常协作中&#xff0c;自然而然的会出现很多重复代码&#xff0c;根据这些代码的种类&#xff0c;之前可能会以以下方式处理方式描述应用时可能产生的问题硬编码多数新手&#xff0c;或逐渐腐坏的项目会这么干&#xff0c;会直接复制之前实现的代码带来…

React Native之Flexbox布局和监测文本输入onChangeText

1 Flexbox布局 1) flexDirection 可以决定布局的主轴,子元素是应该沿着水平轴(row)方向排列&#xff0c;还是沿着竖直轴(column)方向排列 2) justifyContent 决定其子元素沿着次轴&#xff08;与主轴垂直的轴&#xff0c;比如若主轴方向为row&#xff0c;则次轴方向为…