微服务与分布式简介

  • 分布式系统是建立在web之上的 软件系统
  • 分布式的目的是解决普通的,单一的计算机无法独自处理一个任务
    • 首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。
    • 因为分布式增加了系统的复杂性

      应用架构

      下面的模块,应用,服务不是一回事,服务指能独立运行的才算服务,否则只是个模块

  1. 单一应用架构,即一个后端服务承载全部功能,这种模式orm是关键,主要是orm占用资源最多
    1. 协同开发问题(多个功能模块互相影响,一次部署打包需要所有功能都没问题才行,不利于升级维护,不利于扩展。一个功能出问题影响所有功能)
  2. 垂直应用架构:单一应用不足以承载越来越大的访问量,将后端服务进行拆分为更多的服务,通过一个统一的入口进行转发(如nginx),以提高效率。此时虽然多服务但是仍旧为一个物理机,这种mvc是关键,nginx也可以看成是mvc架构的一个部分
    1. 公用模块无法重复利用,开发性的浪费
  3. 分布式应用架构:垂直应用越来越多,每次增加服务模块都要重复性的写一些公用性的代码。此时应该将不同服务的公用代码提取出来 这种架构里提高业务复用及整合的分布式服务框架(RPC)是关键。
  4. 还有种流动计算架构:

    RPC HTTP RMI

  • rpc即远程调用,是一种进程间的通信,同一个服务里通常是线程间的调用。他是一种技术的思想,而不是规范。它允许程序直接调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数(不是一个内存地址通常不允许进行调用,现在通过网络来让服务自己调用自己,将结果传给另外一个服务,就相当于远程调用了),而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
    • http可以看成rpc的一种实现。他们底层都是Socket
  • http即超文本传输协议。与rpc一样跨语言,但是http协议数据量比rpc大得多(请求体里有很多各种头,cookie等) 而rpc更加简单高效
    • rpc一般用于内部请求(指的不是一个计算机内部,指的是公司内部),而对外接口一般是http
  • RMI:可以看成是只用于java之间的rpc。而rpc是跨语言的(但是要求互相之间是同一种rpc框架)

    CAP理论

  • 这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

    • 一致性(C):在分布式系统中,如果服务器集群,每个节点在同时刻访问必须要保持数据的一致性。
      • 这里的一致性是指强一致性。一般关系型数据库就具有强一致性特性。
    • 可用性(A):服务一直可用
    • 分区容错性(P):某个节点出错后仍旧对外提供一致性和可用性服务
      • 这是最基本的要求,我们在剩下2个中做取舍
  • 三个不能都得,三选二得情况下一般都是CP AP进行组合(为什么没有ca不清楚)
    • CP情况下:虽然我们服务可用性不高(可能一个挂了影响其他),但是必须要保证数据强一致性,如金融等业务这种偏多
    • AP情况下:可以短暂数据不一致,但是最终可以一致性,不管怎么样,要能够保证我们的服务可用
    • 一般除非要保证强一致性时使用CP,绝大多数情况我们都可以使用AP即可
  • Zookeeper是CP型得 Eureka是AP型的, Nacos是AP与CP可以切换使用某个,默认是AP

    BASE理论

  • BASE 是 Basically Available( 基本可用 )、Soft State( 软状态 )和 Eventually Consistency ( 最终一致性 )

  • BASE 理论是对 CAP 中的一致性及可用性进行权衡的结果,其核心思想是:无法做到强一致性,那么可以通过牺牲强一致性来获得可靠性。
    • 基本可用:在分布式系统出现不可预知故障时,允许损失部分可用性(如服务降级)
    • 软状态:允许系统在多个不同节点的数据副本上存在数据延时。
    • 通过牺牲强一致性来获得可用性,并允许一定时间内的不一致,但最终达到一致。
  • 我们可以借助消息队列实现分布式最终一致性事务链接

    微服务的组成简介

  • 服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。

  • 服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • 注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
  • 监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

    微服务组成之间的调用关系

  • l 服务容器负责启动,加载,运行服务提供者。

  • l 服务提供者在启动时,向注册中心注册自己提供的服务。
  • l 服务消费者在启动时,向注册中心订阅自己所需的服务。
  • l 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  • l 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  • l 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

    Spring Cloud简介

  • 早期的 Spring Cloud 五大组件包括:EurekaRibbonHystrixZuulConfig

  • Spring Cloud 基于 Spring Boot 框架,它不重复造轮子,而是将第三方实现的微服务应用的一些模块集成进去。准确的说,Spring Cloud 是一个概念上容器,它包含了一整套组件。
  • 服务之间通信本质还是HTTP通信,而服务之间一般采用Rest风格的API进行远程调用

    注册中心

  • 因为微服务各个模块可以动态扩展,所以固定的通信地址不可靠,因此需要一个中心化的组件各个微服务实例信息进行登记和管理,同时让各个微服务实例之间能够相互发现,从而互相调用。

  • 注册中心主要负责如下功能,eureka是微服务注册中心思想的实现

    • 服务注册:各个微服务(在启动时)连接到注册中心登记自己的相关信息(服务名、ip、端口等),并且在持续的运行过程中,与注册中心保持着连接,并周期性发送心跳,证明自己还健在
    • 服务发现:各个微服务会从注册中心下载注册表(其中包含了所有登记到注册中心的微服务的相关信息),通过注册表,各个微服务就能明确知道在网络环境中都有哪些服务存在,以及如何联系上它们。

      Eureka

  • Eureka 由两部分组成:

    • 一个是 Eureka Server,提供服务注册和发现功能,即,我们上述的服务器端;
    • 另一个是 Eureka Client,它简化了客户端与服务端之间的交互
  • Eureka Client 会定时将自己的注册信息登记到 Eureka Server 中,并从 Server 中下载包括了其它 Eurek Client 信息的注册表

    Zookeeper

  • Zookeeper 是一个分布式协调服务。这样我们就可以利 用 Zookeeper 来协调多个分布式进程之间的活动。比如在一个分布式环境中,为了提高可靠 性,我们的集群的每台服务器上都部署着同样的服务。但是,一件事情如果集群中的每个服 务器都进行的话,那相互之间就要协调,编程起来将非常复杂。而如果我们只让一个服务进 行操作,那又存在单点。

    • 通常还有一种做法就是使用分布式锁,在某个时刻只让一个服务去干活,当这台服务出问题的时候锁释放,立即 fail over 到另外的服务。
  • Zookeeper就相当于起到了个**注册中心**的作用

    Nacos(A)

  • Nacos是Alibaba 开源的一个使用 Java 语言开发的服务发现、配置管理中心服务

    • 早期eureka是springcloud实现注册中心的唯一选择。现在如Nacos,Consul比eureka还强大。它们的区别在于:
      • Eureka 是一个 jar 包,它不能独立运行,而无论是 Consul 还是 Nacos 它们都是独立的产品,可以独立运行。
      • Eureka 只能提供服务注册与发现功能,而无论是 Consul 还是 Nacos 它们都整合了配置中心性能的功能。
  • nacos集成了ribbon

    负载均衡

  • 负载均衡就算将用户访问请求,通过某种算法,尽可能平均的分发到集群中的节点。如nginx也算是负载均衡的一个应用

  • 负载均衡一般在配置远程调用时会自动集成进去。所以没有意识到时,其实Ribbon已经在起作用了

  • Ribbon

  • 默认的负载均衡策略是轮询

    Spring Cloud Loadbalancer

  • 目前ribbon已经逐渐停止维护,新版本的cloud已经移除了对ribbon的支持。Spring Cloud Loadbalancerribbon的官方推荐替代

    熔断器

  • 不同服务通过网络互相访问会容易碰到网络请求超时``微服务不可用等问题,一个服务有问题会引起依赖它的服务也出错。这就是**雪崩效应**

  • 针对上述错误有如下手段:
    • 对于超时有超时重试机制,超时时超过一定时间后我们(主调方)就会断开连接(不再等待被调方的响应)。同时超时后会设置重试,重试一定次数才彻底关闭
    • 对于微服务不可用有熔断器机制,如果请求出现异常,所有请求都会直接返回(不会再执行controller和service),而不会等待或阻塞,这样可以减少资源的浪费。(也称为快速失败)
      • 熔断器还有一种半开的状态,当熔断器发现异常后会进入半开状态,此时它会『放行一个请求』来检测被调系统是否已经恢复,如果请求调用成功,则代表被调系统已经恢复正常,那么就会关掉熔断器,否则继续打开。
    • 限流/流量限制:限流跟熔断类似,熔断是发生错误时自动触发直接返回。限流是主动强行直接返回。
  • 限流和熔断并非只有直接拒绝请求的操作,还有服务降级,特权优先,延时处理等处理方式
  • 快速失败的HTTP状态码为429 too many request

    Hystrix

  • Hystrix 封装了微服务调用过程中的每一个依赖,使每个依赖彼此隔离,当延迟情况发生时,它会被限制在资源中,并包含回退(fallback)逻辑,该逻辑决定在依赖发生任何类型故障时应做出何种响应。

  • Hystrix 的目标是阻止级联故障(级联故障就是一个错引起关联部分也错),对通过第三方客户端访问的依赖的延迟和故障进行保护和访问。Hystrix 实现这一目标的大致思路如下:
    • 将外部依赖的访问请求封装在独立的线程中,进行资源隔离。
    • 对于超出设定阈值的服务调用,直接进行超时处理,不允许其消耗过长时间而导致线程阻塞。
    • 每个依赖服务维护一个独立的线程池,一旦线程池满了,直接拒绝服务调用。
    • 统计依赖服务调用的成功次数、失败次数、拒绝次数、超时次数等结果。
    • 在一段时间内,如果服务调用的异常次数超过一定的阈值,就会触发熔断器,停止对特定服务的所有请求。在一定时间内对服务降级,一段时间之后自动尝试恢复。
    • 如果某个服务出现调用失败、被拒绝、超时等异常情况,就会自动调用 fallback 降级机制。
  • Hystrix作用于服务调用方

    Resilience4j

  • Hystrix 官方已经停止开发了,所以 Spring Cloud 社区又推出了一款新的熔断器:Resilience4j 。

  • Resilience4j 是spring和netflix官方共同推荐的替代Hystrix的产品。不过市场占有率提升缓慢就是

    Sentinel (A)

  • 阿里的,相较于Hystrix添加了限流功能

    • Sentinel的限流算法为滑动窗口算法
  • Sentinel以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

    网关

  • API网关封装了系统内部架构,类似于外观模式,对客户端友好,屏蔽不同服务的复杂性和差异性

    Zuul

  • Zuul 作为第一代网关,它相较于第二代网关 Gateway 而言,它最大的优势在于:它是基于 Servlet 的,因此学习曲线几乎为零。在并发量不高的情况下(仅在乎功能,而不在乎性能), Zuul 仍然是可选方案。

    Spring Cloud Gateway

  • Gateway(网关) 是 Java 微服务体系中的第二代服务网关,是Zuul的替代品。Gateway基于Springboot2.0

  • Gateway 旨在提供一种简单而有效的途径来转发请求,并为它们提供横切关注点。主要功能如下

    • 路由Route:路由就是一套『转发』规则。路由是网关最基础的部分,路由信息由一个 ID 、一个目的 URL 、一组断言工厂和一组 Filter 组成。如果路由断言为真,则说明请求的 URL 和配置的路由匹配。
    • 断言 Predicate:通过断言函数和请求信息可以自由的定义转发规则。路由的转发规则都是断言定义
      • Path 断言不会改变请求的 URI ,即,Gateway 收到的 URI 是什么样的,那么它将请求转给目标服务的时候,URI 仍然是什么。整个过程中只有 IP、端口部分会被『替换』掉 。
    • 过滤器 Filter:Spring Cloud Gateway 中的 Filter 分为两种类型:Gateway Filter 和 Global Filter 。过滤器 Filter 将会对请求和响应进行修改处理,ru修改url

      配置中心

  • 一个服务可能存在多个实例(即多个部署),如果服务需要修改配置,那么每个实例都要修改,不方便。因此需要一个中心的配置中心。

  • 个人理解就是配置中心就是统一进行配置,并把配置存到数据库里
  • 现在的趋势是将配置中心的功能和注册中心的功能合二为一,如nacosConsul都提供了配置中心的功能。因此spring Cloud Config用的比较少

    Spring Cloud Config

    消息总线

  • 方便服务被动接收其他服务的消息。如服务a往总线上发消息,订阅了消息总线的b也能收到消息。可以使用消息队列或者第三方消息总线实现作消息总线

    分布式事务

  • 常见的分布式事务框架是阿里的Seata

    Spring Cloud Alibaba

  • springCloud的大部分常用组件都是netflix开发的,netflix可以看成是springcloud的一个子框架。而alibaba依照springcloud的思想提供了一套对应netflix的组件。

  • Alibaba对于springcloud没有的功能也提供了组件,如分布式事务Seata,分布式消息RocketMQ
  • SpringCloud Alibaba 优于 SpringCloud Netflix,SpringCloud Netflix 核心组件停止维护
  • 阿里巴巴的这些也可以跟netflix的组件自由组合搭配使用。阿里的新组件并非完全替代netflix,如nacos内部也引入了ribbon。
    • spring cloud alibaba也遵循spring cloud的标准,所以能够与netflix自由组合 | | SpringCloud | SpringCloudAlibaba | | —- | —- | —- | | 注册中心 | Eureka | Nacos | | 负载均衡 | Ribbon | Dubbo LB | | 熔断器 | Hystrix | Sentinel | | 配置中心 | SpringCloudConfig | nacos | | 网关 | Zuul | - | | 配置中心 | Config | Nacos | | 服务调用 | Feign | Dubbo |

Cloud ,Cloud Alibb与Boot版本对应关系

  • lombok版本最好大于1.14 因为lombok需要配合idea的lombok插件才能起作用。idea的lombok插件一般是最新版本的,不一定兼容低版本的lombok依赖

链接

cloud项目实战

  • ruoyi
    • 登录模块单独作为一个服务
      • 当前登录信息获取得实现:在所有请求得token拦截器那里登录成功就往ThreadLocal里面存入map。map里存有该请求得用户名,用户id等(这些东西一般存于请求头里面)。ThreadLocal
    • 这个项目里redis,功能是否启用,路由规则等配置都配置到了nacos的配置文件里,这些可能容易变动或者一对多的组件(如redis) 就配置到配置中心方便管理
    • 服务发现注册等不容易变动的就配置到项目里的配置文件里.
    • 网关:单独作为单独一个项目,请求都到网关进行一系列过滤再转发给路由的相关服务。
    • 各种通用的配置可以提取为一个公共的模块。其中公共模块里每一个功能相关的配置再作为一个子模块。如redis相关的配置作为一个模块
      • 使用时直接像普通依赖一样引用其中具体的某个模块即可,父级common就是个普通的继承型pom,子项目都采用jar打包方式(无需配置,packing默认就是jar)
      • 会自动将引入模块的需要依赖一同传递过来,能直接使用引入模块定义的功能
    • image.png