目录
一、Spring Cloud中的服务发现框架——Eureka
二、Spring Cloud中的负载均衡器—— Ribbon
三、Spring Cloud中的声明式Rest客户端——Open Feign
Spring Cloud是最常见的分布式系统模式,提供了一种简单且易于接受的编程模型。Spring cloud构建于Spring boot之上。
SpringCloud 中的组件包括:
- Eureka 服务发现框架
- Ribbon 进程内负载均衡器
- Open Feign 服务调用映射
- Hystrix 服务降级熔断器
- Zuul 微服务网关
- Config 微服务统一配置中心
- Bus 消息总线
一、Spring Cloud中的服务发现框架——Eureka
1、Eureka中的角色:
- 服务提供者:提供一些自己能够执行的服务给外界
- 服务消费者:需要使用某些服务的“用户”
- 服务中介:其实就是服务提供者 和 服务消费者 之间的一个桥梁,服务提供者将服务注册到服务中介那里,然后服务消费者需要该服务的时候,就可以到中介这里找已经注册过的服务。
2、Eureka提供的功能:
- 服务注册 Register:Eureka客户端 向 Eureka Server注册时,客户端需要提供自己的元数据,例如:ip地址,端口,url 等。
- 服务续约 Renew:Eureka客户端 会每隔30秒向 Eureka Server发送一次心跳来续约,通过续约来告诉Server,客户端仍然存在,没有出现问题。正常情况下,Server 90s 未收到客户端的续约,就会将其从注册表中删除。
- 服务下线 Cancel :Eureka客户端 在程序关闭时候会向 Eureka Server 发送取消请求。发送请求后,该客户端的信息会从注册表中删除掉。
- 服务剔除 Eviction :在默认情况下,如果 Eureka 客户端 90s(连续三个周期)未向 Server 发送续约请求,及心跳。服务端会将该 客户端 从注册表中剔除。
- 获取注册列表信息 Fetch Registries:Eureka客户端 从服务器获取注册表,并将其缓存到本地,客户端 会根据 注册信息查找所需服务,进行远程调用。该注册信息定期(每 30秒)更新一次。每次返回的注册信息可能和已存的不一致,客户端会自动处理。Server 缓存的注册表信息,包括整个注册表以及每个应用程序的信息进行压缩,通过xml / json的方式和客户端进行通讯。
可以充当服务发现的组件有:Zookeeper
,Consul
, Eureka
等。
二、Spring Cloud中的负载均衡器—— Ribbon
Ribbon 是 开源的 负载均衡 项目,一个客户端 / 进程内 的负载均衡器,运行在消费者端。其工作原理就是 客户端 获取到了所有服务列表以后,在其内部使用 负载均衡算法,进行对多个系统的调用。
Nginx 和 Ribbon 的对比:
Nginx 与 Ribbon的区别在于,它是一个 集中式 的负载均衡器。简单理解就是:他会将所有请求都集中起来,然后统一进行负载均衡。
Ribbon 的几种负载均衡算法:
Ribbon中有多种负载均衡算法,默认情况使用的是 轮询策略 。
- RoundRobinRule:轮询策略,若经过一轮轮询没有找到可用的
provider
,其最多轮询 10 轮。若最终还没有找到,则返回 null。 - RandomRule: 随机策略,从所有可用的 provider 中随机选择一个。
- RetryRule: 重试策略。先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内重试。默认的时限为 500 毫秒。
在 Ribbon
中你还可以自定义负载均衡算法,你只需要实现 IRule
接口,然后修改配置文件或者自定义 Java Config
类。
三、Spring Cloud中的声明式Rest客户端——OpenFeign
有了 Eureka
,RestTemplate
,Ribbon
我们就可以 愉快地进行服务间的调用了,但是使用 RestTemplate
还是不方便,我们每次都要进行这样的调用。
@Autowired
private RestTemplate restTemplate;
// 这里是提供者A的ip地址,但是如果使用了 Eureka 那么就应该是提供者A的名称
private static final String SERVICE_PROVIDER_A = "http://localhost:8081";
@PostMapping("/judge")
public boolean judge(@RequestBody Request request) {
String url = SERVICE_PROVIDER_A + "/service1";
// 是不是太麻烦了???每次都要 url、请求、返回类型的
return restTemplate.postForObject(url, request, Boolean.class);
}
这样每次都调用 RestRemplate
的 API
是否太麻烦,我能不能像 调用原来代码一样进行各个服务间的调用呢?OpenFeign 提供了声明式调用服务的方式。OpenFeign 也是运行在消费者端的,使用 Ribbon 进行负载均衡,所以 OpenFeign 直接内置了 Ribbon。
在导入了 Open Feign
之后我们就可以进行愉快编写 Consumer
端代码了。
@RestController
public class TestController {
// 这里就相当于原来自动注入的 Service
@Autowired
private TestClient testClient;
// controller 调用 service 层代码
@RequestMapping(value = "/test", method = RequestMethod.POST)
public CommonResponse<List<Plan>> get(@RequestBody planGetRequest request) {
return testClient.getPlans(request);
}
}
然后就可以在Controller
就可以像调用自身 Service
层代码一样调用它了。
@RestController
public class TestController {
// 这里就相当于原来自动注入的 Service
@Autowired
private TestClient testClient;
// controller 调用 service 层代码
@RequestMapping(value = "/test", method = RequestMethod.POST)
public CommonResponse<List<Plan>> get(@RequestBody planGetRequest request) {
return testClient.getPlans(request);
}
}
四、Spring Cloud中的熔断机制——Hystrix
在分布式环境中,不可避免的会有许多服务依赖项中的某些服务失败。Hystrix是一个库,可以通过添加等待时间容限和容错逻辑来控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备来实现该目的,提高系统的整体弹性。
总体来说Hystrix就是一个 熔断 和 降级 的库。
由于某个服务节点崩溃了,可能会导致相互调用的所有服务同时崩溃,称为服务雪崩。
1、熔断
所谓的 熔断 就是解决 服务雪崩 的有效解决方案,当指定时间内请求失败次数达到了设定的阀值,系统将通过 断路器 直接将此请求链路断开。
熔断 指的是 Hystrix中的 断路器模式 。
你可以使用简单的 @HystrixCommand
注解来标注某个方法,这样 Hystrix
就会使用 断路器 来“包装”这个方法,每当调用时间超过指定时间时(默认为1200ms),断路器将会中断对这个方法的调用。
@HystrixCommand(
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1200")}
)
public List<Xxx> getXxxx() {
// ...省略代码逻辑
}
2、降级
降级 是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复。
降级 指得是 Hystrix中的 后备处理模式。
你可以通过设置 fallbackMethod
来给一个方法设置备用的代码逻辑。
// 指定了后备方法调用
@HystrixCommand(fallbackMethod = "getHystrixNews")
@GetMapping("/get/news")
public News getNews(@PathVariable("id") int id) {
// 调用新闻系统的获取新闻api 代码逻辑省略
}
//
public News getHystrixNews(@PathVariable("id") int id) {
// 做服务降级
// 返回当前人数太多,请稍后查看
}
五、Spring Cloud中的微服务网关——Zuul
网关是系统唯一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权、限流、 路由、监控等功能。Zuul基本可以实现网关的基本功能。
而 Zuul
中最关键的就是 路由 和 过滤器 。
1、Zuul的路由功能
当我们已经向 Eureka Server
注册了两个 Consumer
、三个 Provicer
,这个时候我们再加个 Zuul
网关,系统应该变成这样子了。
Zuul需要向Eureka进行注册,因为Consumer都注册到了Eureka上,所以当Zuul注册到了Eureka上的时候,就可以拿到 consumer的 元数据 了。
路由映射:获取 Consumer的 元数据,则可以 直接做 路由映射 。
统一前缀:通过Zuul的配置,统一请求调用的前缀
路由策略配置:直接使用服务名的访问方式,需要将微服务名称暴露给用户,会存在安全性问题。所以,可以自定义路径来替代微服务名称,即自定义路由策略。
服务名屏蔽:在配置完 路由策略 之后使用微服务名称还是可以访问的,这个时候你需要将服务名屏蔽。
路径屏蔽:指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将无法访问到指定的服务。通过该方式可以限制用户的权限。
敏感请求头屏蔽:默认情况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,我们可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。
2、过滤器
所有请求都经过网关(Zuul),那么我们可以进行各种过滤,这样我们就能实现 限流,灰度发布,权限控制等等。
要实现自己定义的 Filter
我们只需要 继承 ZuulFilter
然后将这个过滤器类以 @Component
注解加入 Spring 容器中就行了。
过滤器类型:Pre、Routing、Post。
- 前置Pre就是在请求之前进行过滤
- 路由Routing过滤器就是我们上面所讲的路由策略
- 后置Post过滤器就是在
Response
之前进行过滤的过滤器。
例子:服务请求时间日志打印。
Zuul
作为网关肯定也存在 单点问题 ,如果我们要保证 Zuul
的高可用,我们就需要进行 Zuul
的集群配置,这个时候可以借助额外的一些负载均衡器比如 Nginx
。
六、Spring Cloud中的分布式配置——Config
SpringCloud config 就是能将各个 应用/系统/模块 的配置文件存放到 统一的地方然后进行管理(Git 或者 SVN)。从而实现既能对配置文件统一地进行管理,又能在各个项目运行时动态修改配置文件。
存在一个问题:如应用A在运行时动态修改了配置文件,那么对于依赖于这个配置文件的已启动的应用B会不会进行其相应配置的更改?
答案:不会的。
为了解决这种情况一般我们会使用 Bus
消息总线 + SpringCloud config
进行配置的动态刷新。
七、Spring Cloud中的消息总线——BUS
SpringCloud BUS 的作用就是 管理 和 广播 分布式系统中的消息,也就是消息引擎系统中的广播模式。例如实现:客户端的配置刷新功能。
拥有了 SpringCloud Bus 之后,我们只需要创建一个简单的请求,并且加上 @ResfreshScope
注解就能进行配置的动态修改了。