SpringCloud总结

Spring Cloud基础

一、业务场景介绍

假设咱们现在开发⼀个电商⽹站,要实现⽀付订单的功能,流程 如下:

  • 创建⼀个订单之后,如果⽤户⽴刻⽀付了这个订单,我们需要将订单状态更新为 “已⽀付”

  • 扣减相应的商品库存

  • 通知仓储中⼼,进⾏发货

  • 给⽤户的这次购物增加相应的积分

针对上述流程,我们需要有订单服务、库存服务、仓储服务、积分服务。整个流程的⼤ 体思路如下:

  • ⽤户针对⼀个订单完成⽀付之后,就会去找订单服务,更新订单状态
  • 订单服务调⽤库存服务,完成相应功能
  • 订单服务调⽤仓储服务,完成相应功能
  • 订单服务调⽤积分服务,完成相应功能

⼆、Spring Cloud 核⼼组件:Eureka

Eureka 是微服务架构中的注册中⼼,专⻔负责服务的注册与发现。

Eureka Client 组件,这个组件专⻔负责将这个服务的信息注册到 Eureka Server 中。就是告诉 Eureka Server,⾃⼰在哪台机 器上,监听着哪个端⼝。

Eureka Client负责将这个服务的信息注册到 Eureka Server 中

Eureka Server:注册中⼼,⾥⾯有⼀个注册表,保存了各个服务所在的机器和端⼝号

三、Spring Cloud 核心组件:Feign

Feign Client 会在底层根据你的注解,跟你指定的服务建⽴连接、构造请求、发起靕求、获取响应、解析响应,等等。Feign 的⼀个关键机制就是使用了动态代理。

  • ⾸先,如果你对某个接⼝定义了 @FeignClient 注解,Feign 就会针对这个接⼝创建⼀个动态 代理
  • 接着你要是调⽤那个接⼝,本质就是会调⽤ Feign 创建的动态代理,这是核⼼中的核⼼
  • Feign 的动态代理会根据你在接⼝上的 @RequestMapping 等注解,来动态构造出你要请求的服务的地址
  • 最后针对这个地址,发起请求、解析响应。

四、Spring Cloud 核⼼组件:Ribbon

Ribbon 就是专⻔解决这个问题的。它的作⽤是负载均衡,会帮你在每次请求时选择⼀台机器,均匀的把请求分发到各个机器上

Ribbon 的负载均衡默认使⽤的最经典的 Round Robin 轮询算法:订单服务对库存服务发起 10 次请求,那就先让你请求第 1 台机器、然后是第 2 台机 器、第 3 台机器、第 4 台机器、第 5 台机器,接着再来—个循环,第 1 台机器、第 2 台机 器。。。以此类推。

五、Spring Cloud 核心组件:Hystrix

服务雪崩问题

现在假设订单服务⾃⼰最多只有 100 个线程可以处理请求,然后呢, 积分服务不幸的挂了,每次订单服务调⽤积分服务的时候,都会卡住⼏秒钟,然后抛出—个超时异常。如果系统处于⾼并发的场景下,⼤量请求涌过来的时候,订单服务的 100 个线程都会卡在请求积分服务这块。导致订单服务没有⼀个线程可以处理请求然后就会导致别⼈请求订单服务的时候,发现订单服务也挂了,不响应任何请求了。

Hystrix 是隔离、熔断以及降级的⼀个框架。

隔离

Hystrix 会搞很多个⼩⼩的线程池⽐如订单服务请求库存服务是⼀个线程池,请求仓储服 务是⼀个线程池,请求积分服务是⼀个线程池。每个线程池⾥的线程就仅仅⽤于请求那个服务。

熔断

所以我们直接对积分服务熔断不就得了, ⽐如在 5 分钟内请求积分服务直接就返回了,不要去⾛⽹络请求卡住⼏秒钟,这个过程,就是 所谓的熔断!

降级

每次调⽤积分服务,你就在数据库⾥记录⼀条消息,说给某某⽤户增加了多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,你可以 根据这些记录⼿⼯加⼀下积分。这个过程,就是所谓的降级。

六.Spring Cloud 核⼼组件:Zuul

可以根据请求的特征,将请求转发给后端的各个服务。

⽹关之后,还有很多好处,⽐如可以做统⼀的降级、限流、认证授权、安全,等等。

七.总结

  1. Eureka:各个服务启动时,Eureka Client 都会将服务注册到 Eureka Server,并且 Eureka Client 还可以反过来从 Eureka Server 拉取注册表,从⽽知道其他服务在哪⾥
  2. Ribbon:服务间发起请求的时候,基于 Ribbon 做负载均衡,从⼀个服务的多台机器中选择 ⼀台
  3. Feign:基于 Feign 的动态代理机制,根据注解和选择的机器,拼接请求 URL 地址,发起请求
  4. Hystrix:发起请求是通过 Hystrix 的线程池来⾛的,不同的服务⾛不同的线程池,实现了不 同服务调⽤的隔离,避免了服务雪崩的问题
  5. Zuul:如果前端、移动端要调⽤后端系统,统⼀从 Zuul ⽹关进⼊,由 Zuul ⽹关转发请求给 对应的服务

Spring Cloud基础进阶

一.问题

  1. Eureka 注册中⼼使⽤什么样的⽅式来储存各个服务注册时发送过来的机器地址和端⼝号?
  2. 各个服务找 Eureka Server 拉取注册表的时候,是什么样的频率?
  3. 各个服务是如何拉取注册表的?
  4. ⼀个⼏百服务,部署上千台机器的⼤型分布式系统,会对 Eureka Server 造成多⼤的访问压 ⼒?
  5. Eureka Server 从技术层⾯是如何抗住⽇千万级访问量的?

各个服务内的 Eureka Client 组件,默认情况下,每隔 30 秒会发送⼀个请求到Eureka Server,来拉取最近有变化的服务信息

心跳机制:Eureka 还有⼀个⼼跳机制,各个 Eureka Client 每隔 30 秒会发送⼀次⼼跳到 Eureka Server。

⼆、Eureka Server 设计精妙的注册表存储结构

现在咱们假设⼿头有⼀套⼤型的分布式系统,⼀共 100 个服务,每个服务部署在 20 台机器上, 机器是 4 核 8G 的标准配置。

Eureka 源码:

  1. 做 registry 的 CocurrentHashMap,就是注册表的核⼼结构。看完之后忍不住先赞叹⼀下,精妙的设计!
  2. 各个服务的注册、服务下线、服务故障,全部会在内存⾥维护和更新这个注册表。
  3. 各个服务每隔 30 秒拉取注册表的时候,Eureka Server 就是直接提供内存⾥存储的有变化的注册表数据给他们就可以了。
  4. 同样,每隔 30 秒发起⼼跳时,也是在这个纯内存的 Map 数据结构⾥更新⼼跳时间。

维护注册表、拉取注册表、更新⼼跳时间,全部发⽣在内存⾥!这是 Eureka Server ⾮常核⼼的⼀个点

Map<String, Lease<InstanceInfo>>
  1. 这个 Map 的 key 就是服务实例的 id
  2. value 是⼀个叫做 Lease 的类,它的泛型是⼀个叫做 InstanceInfo 的东东
  3. ⾸先说下 InstanceInfo,这个 InstanceInfo 就代表了服务实例的具体信息,⽐如机器的 ip 地址、hostname 以及端⼝号。
  4. ⽽这个 Lease,⾥⾯则会维护每个服务最近⼀次发送⼼跳的时间

三、Eureka Server 端优秀的多级缓存机制

避免同时读写内存数据结构造成的并发冲突问题,还采⽤了多级缓存机制来进⼀步提升服务请求的响应速度。

在拉取注册表的时候
  1. 首先从 ReadOnlyCacheMap ⾥查缓存的注册表。
  2. 若没有,就找 ReadWriteCacheMap ⾥缓存的注册表。
  3. 如果还没有,就从内存中获取实际的注册表数据。
在注册表发⽣变更的时候:
  1. 会在内存中更新变更的注册表数据,同时过期掉 ReadWriteCacheMap。
  2. 此过程不会影响 ReadOnlyCacheMap 提供⼈家查询注册表。
  3. ⼀段时间内(默认 30 秒),各服务拉取注册表会直接读 ReadOnlyCacheMap 30 秒过后,
  4. Eureka Server 的后台线程发现 ReadWriteCacheMap 已经清空了,也会清空 ReadOnlyCacheMap 中的缓存
  5. 下次有服务拉取注册表,⼜会从内存中获取最新的数据了,同时填充各个缓存。
多级缓存机制的优点是什么?
  1. 尽可能保证了内存注册表数据不会出现频繁的读写冲突问题。
  2. 并且进⼀步保证对 Eureka Server 的⼤量请求,都是快速从纯内存⾛,性能极⾼。

四.总结

Eureka 作为微服务注册中⼼可以承载⼤规模系统每天千万级访问量的原理:

  1. 通过上⾯的分析可以看到,Eureka 通过设置适当的请求频率(拉取注册表 30 秒间隔,发送 ⼼跳 30 秒间隔),可以保证⼀个⼤规模的系统每秒请求 Eureka Server 的次数在⼏百次。
  2. 同时通过纯内存的注册表,保证了所有的请求都可以在内存处理,确保了极⾼的性能
  3. 另外, 多级缓存机制,确保了不会针对内存数据结构发⽣频繁的读写并发冲突操作,进⼀步 提升性能。

每秒上万并发下的 Spring Cloud 参数优化实 战

问题:高并发到来,因为每个线程都会在一个服务卡住几秒,那么有可能回一下把线程池里的线程都hang死。没法再响应任何请求。

一.优化SQL

数据库就执⾏简单的单表查询和更新,然后复杂的业务逻辑全部放在 java 系统中来执⾏。

二.超时时间

ribbon 和 hystrix 的超时时间设置,⼀个接⼝,理论的最佳响应速度应该在 200ms 以内,或者慢点的接⼝就⼏百毫秒。

三.网络抖动,偶然超时

Spring Cloud 中的 Feign + Ribbon 的组合,在进⾏服务调⽤的时候,如果发 现某台机器超时请求失败,会⾃动重试这台机器,如果还是不⾏会换另外⼀台机器重试。

四.接口的幂等性保障机制

  1. 可以在数据库⾥建⼀个唯⼀索引,插⼊数据的时候如果唯⼀索引冲突了就不会插⼊重复数据
  2. 通过 redis ⾥放⼀个唯⼀ id 值,然后每次要插⼊数据,都通过 redis 判断⼀下,那个 值如果已经存在了,那么就不要插⼊重复数据了。

微服务架构的99.99%可用(主要是基础设施的故障)

Redis 集群挂了,Elasticsearch 集群故障了,MySQL 宕机。

  1. 是基于 Hystrix 做资源隔离以及熔断;
  2. 做备⽤降级⽅案。 如果资源隔离和降级都做的很完善,那么在双 11 这种⾼并发场景下,也许可能会出现个别 的服务故障,但是绝不会蔓延到整个系统全部宕机。

设置Hystrix 线程池大小

假设你的服务 A,每秒钟会接收 30 个请求,同时会向服务 B 发起 30 个请求,然后每个请求的响应时长经验值⼤概在 200ms,那么你的 hystrix 线程池需要多少个线程呢?

30(每秒请求数量) * 0.2(每个请求的处理秒数) + 4(给点缓冲 buffer) = 10。

如何设置请求超时时间

300毫秒

服务降级

如果你的某个服务挂了,那么你的 hystrix 会⾛熔断器,然后就会降级

  1. 如果查询数据的服务挂了,你可以查本地的缓存
  2. 如果写⼊数据的服务挂了,你可以先把这个写⼊操作记录⽇志到⽐如 mysql ⾥,或者写⼊ MQ ⾥,后⾯再慢慢恢复
  3. 如果 redis 挂了,你可以查 mysql
  4. 如果 mysql 挂了,你可以把操作⽇志记录到 es ⾥去,后⾯再慢慢恢复数据。

总结

1.⾸先你的 hystrix 资源隔离以及超时这块,必须设置合理的参数,避免⾼峰期,频繁的 hystrix 线程卡死。
2. 其次,针对个别的服务故障,要设置合理的降级策略,保证各个服务挂了,可以合理的降 级,系统整体可⽤!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值