SpringCloud分布式开发理解
谈到SpringCloud最新接触到的可能就是那五大"神兽",之前最先接触分布式开发是通过dubbo的RPC远程过程调用,而dubbo给我得感觉就是:虽然所有的主机物理上分布了,但是对于用户而言就仿佛是一个整体。而对我们的java开发人员而言,分布式开发的意义又是什么呢?也就是说哪里需要去使用分布式开发呢,其实在任何一个项目里面(MVC设计模式),业务操作是最为核心的部分,而所有项目之中你的业务操作是否完成直接决定了你的项目本身是否健壮。之前太年轻...一直感觉业务对一个追求技术培养得学者来说意义不大,大不了是一套CRUD,后来才发现这种想法就像是一头还不知道自己猎物在哪里的狮子一样,还不清楚自己猎物得特性,就急着想去吃它身上的肉,但是什么事都没有绝对,如果真的是业务堆积,一堆技术含量很低的业务代码CRUD的堆积就另当别论了...
回到"五大神兽":
- 服务发现——Netflix Eureka
- 客服端负载均衡——Netflix Ribbon(Feign)
- 断路器——Netflix Hystrix
- 服务网关——Netflix Zuul
- 分布式配置——Spring Cloud Config
下面我们逐个研究一下SpingCloud分布式这五个重点:
Eureka:
一个RESTful风格的服务,用来定位运行在业务流程管理开发平台(AWS Enterprise BPM Platform)层的中间层服务。 1.Eureka服务器用作服务的注册中心。(对比dubbo的注册中心:zk redis等); 2.Eureka客户端其实就是一个java客户端,负责与服务器的交互,用作轮询负责均衡,故障切换支持等。 Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。
依赖:
<!--eureka server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency>
注解:
- @EnableEurekaServer:这个注解需要在springboot工程的启动application类上加,表示启动一个服务注册中心;
- @EnableEurekaClient:表明自己是一个eurekaclient;
配置:
- 注册中心服务器:
server: port: 8761 # 默认情况下erureka server也是一个eureka client ,必须要指定一个 server。eureka server的配置文件appication.yml 通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明自己是一个eureka server. eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- 客户端服务器:
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8762 spring: application: name: service-hi
Ribbon:
主要提供客户侧的软件负载均衡算法。 Ribbon客户端组件提供一系列完善的配置选项,比如连接超时、重试、重试算法等。 Ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为。Feign默认集成了Ribbon。 Ribbon内置可插拔、可定制的负载均衡组件。 一些常用的负载均衡策略: 1. 简单轮询负载均衡 2. 加权响应时间负载均衡 3. 区域感知轮询负载均衡 4. 随机负载均衡 Ribbon中还包括一下功能: 1. 易于与服务发现组件(比如Netflix的Eureka)集成 2. 使用Archaius完成运行时配置 3. 使用JMX暴露运维指标,使用Servo发布 4. 多种可插拔的序列化选择 5. 异步和批处理操作(即将推出) 6. 自动SLA框架(即将推出) 7. 系统管理/指标控制台(即将推出)
依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency>
注解:
- @EnableDiscoveryClient:向服务中心注册;
- @LoadBalanced:结合入职restRemplate的@Bean一起使用,开始负载均衡功能;
配置:
application.yml:
#指定服务的注册中心地址为http://localhost:8761/eureka/ eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ #程序端口为8764 server: port: 8764 #程序名称为 service-ribbon spring: application: name: service-ribbon
Feign:
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。 简而言之: Feign 采用的是基于接口的注解 Feign 整合了ribbon
依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
注解:
- @EnableFeignClients:开启Feign功能;
- @FeignClient:在feign接口上加入此注解,通过@FeignClient("服务名"),来指定调用哪个服务。(类似controller的@RequestMapping(value = "访问路径"))
配置:
application.yml
#服务注册地址为http://localhost:8761/eureka/ eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ #端口号为8765 server: port: 8765 #指定程序名为service-feign spring: application: name: service-feign
Hystrix:
Netflix开源了Hystrix组件,实现了断路器模式,SpringCloud对这一组件进行了整合。较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystric 是5秒20次)断路器将会被打开。断路打开后,可用避免连锁故障,fallback方法可以直接返回一个固定值。 断路器的特点: 1.断路器可以防止一个应用程序多次试图执行一个操作,即很可能失败,允许它继续而不等待故障恢复或者浪费 CPU 周期,而它确定该故障是持久的. 2.断路器模式也使应用程序能够检测故障是否已经解决。如果问题似乎已经得到纠正,应用程序可以尝试调用操作。 3.断路器增加了稳定性和灵活性,以一个系统,提供稳定性,而系统从故障中恢复,并尽量减少此故障的对性能的影响。它可以帮助快速地拒绝对一个操作,即很可能失败,而不是等待操作超时(或者不返回)的请求,以保持系统的响应时间。如果断路器提高每次改变状态的时间的事件,该信息可以被用来监测由断路器保护系统的部件的健康状况,或以提醒管理员当断路器跳闸,以在打开状态。
依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
注解:
- @EnableHystrix:开启Hystrix;
- @HystrixCommand:在Service层的方法上加入,对方法创建熔断器的功能,并指定了fallbackMethod熔断方法,书写对应名称的方法;
PS:Feign中的断路器:
Feign是自带断路器的,在D版本的SpringCloud中,它没有默认打开。需要在配置文件中配置打开它,在配置文件加入配置:feign.hystrix.enabled=true
注解:
- @FeignClient:在FeignClient的接口的注解中加上fallback属性指定类,此类实现FeignClient的接口,并注入到IOC容器中(@Component),实现熔断方法即可。
Hystrix Dashboard (断路器:Hystrix 仪表盘):
依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency>
注解:
- @EnableHystrixDashboard:配置到主程序启动类中,开启hystrixDashboard;
Zuul:
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。在SpringCloud微服务系统中,一种常见的负载均衡方式是:客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服。,服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改配置。类似nginx,反向代理的功能,不过netflix自己增加了一些配合其他组件的特性。Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。
依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
注解:
- @EnableZuulProxy:一般应用在入口applicaton类加上注解@EnableZuulProxy,开启zuul的功能;
配置:
#指定服务注册中心的地址为http://localhost:8761/eureka/ eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ #服务的端口为8769 server: port: 8769 #服务名为service-zuul spring: application: name: service-zuul #以/api-a/ 开头的请求都转发给service-ribbon服务 #以/api-b/ 开头的请求都转发给service-feign服务 zuul: routes: api-a: path: /api-a/** serviceId: service-ribbon api-b: path: /api-b/** serviceId: service-feign
zuul的服务过滤:zuul不仅只是路由,并且还能过滤,做一些安全验证。(实现:继承ZuulFilter)
filterType:返回一个字符串代表过滤器的类型, 在zuul中定义了四种不同生命周期的过滤器类型,具体如下: pre:路由之前 routing:路由之时 post: 路由之后 error:发送错误调用 filterOrder:过滤的顺序 shouldFilter:这里可以写逻辑判断,是否要过滤,本文true,永远过滤。 run:过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
SpringCloudConfig:
1.SpringCloudConfig就是我们通常意义上说的分布式配置中心,将应用原本放在本地文件的配置抽取出来放在中心服务器上,从而能够提供更好的管理,发布能力。 2.SpringCloudConfig分为服务端和客户端,服务端负责将git(或者svn)上存储的配置文件发布成REST接口,客户端可以从服务端RESTjie接口获取配置。但客户端并不能主动感知配置文件的变化,从而主动去获取新的配置,它需要每个客户端通过POST方法触发各自的/refresh请求,SpringCloudBus就通过一个轻量级消息代理连接分布式系统节点。 3.可以用于广播状态更改,(如配置更改)或者管理指令。 4.SpringCloudBus提供了通过POST方法访问的endpoint/bus/refresh,这个接口通常由git的钩子功能调用,用以通知各个SpringCloudConfig的客户端去服务端更新配置。
依赖:
<!-- 服务端开始 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!-- 服务端结束 --> <!-- 客户端开始 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- 客户端结束 -->
注解:
- @EnableConfigServer:应用在程序的入口Application类上,表示开启配置服务器的功能;
配置:
服务端:application.properties
spring.application.name=config-server server.port=8888 #配置git仓库地址 spring.cloud.config.server.git.uri=https://github.com/forezp/SpringcloudConfig/ #配置仓库路径 spring.cloud.config.server.git.searchPaths=respo #配置仓库的分支 spring.cloud.config.label=master #访问git仓库的用户名(如果Git仓库为公开仓库,可以不填写用户名和密码) spring.cloud.config.server.git.username=your username #访问git仓库的用户密码 spring.cloud.config.server.git.password=your password
客户端:bootstrap.properties
spring.application.name=config-client spring.cloud.config.label=master spring.cloud.config.profile=dev spring.cloud.config.uri= http://localhost:8888/ server.port=8881
- spring.cloud.config.label 指明远程仓库的分支
- spring.cloud.config.profile
- dev开发环境配置文件
- test测试环境
- pro正式环境
-
spring.cloud.config.uri= http://localhost:8888/指明配置服务中心的网址。
http请求地址和资源文件映射如下: · /{application}/{profile}[/{label}] · /{application}-{profile}.yml · /{label}/{application}-{profile}.yml · /{application}-{profile}.properties · /{label}/{application}-{profile}.properties
PS:高可用配置中心:当服务实例很多时,都从配置中心读取文件,这时可以考虑将配置中心做成一个微服务,将其集群化,从而达到高可用;
依赖:
<!-- 服务注册中心依赖开始 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <!-- 服务注册中心依赖结束 --> <!-- 配置服务端依赖开始 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!-- 配置服务端依赖结束 -->
配置:
注册中心:application.yml
#服务端口为8889 server: port: 8889 # 作为服务注册中心的基本配置 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
服务端:bootstrap.properties
spring.application.name=config-client spring.cloud.config.label=master spring.cloud.config.profile=dev #spring.cloud.config.uri= http://localhost:8888/ #加上服务注册地址为http://localhost:8889/eureka/ eureka.client.serviceUrl.defaultZone=http://localhost:8889/eureka/ #是从配置中心读取文件 spring.cloud.config.discovery.enabled=true #配置中心的servieId,即服务名 spring.cloud.config.discovery.serviceId=config-server server.port=8881
暂时先记录这些;感谢网络上大神方志鹏的帖子:
https://gitee.com/liudongyang/SpringCloudLearning