springcloud学习-Eureka、Eureka高可用集群、Ribbon客户端负载均衡策略

【eureka】浏览器测试地址

服务提供者:http://127.0.0.1:9100/service/goods
{"statusCode":0,"statusMessage":"查询成功","data":[{"id":1,"name":"商品1","price":67.00,"store":12},{"id":2,"name":"商品2","price":168.00,"store":1},{"id":3,"name":"商品3","price":25.00,"store":50}]}

服务消费者(调用服务提供者):http://localhost:8080/cloud/goods
{"statusCode":0,"statusMessage":"查询成功","data":[{"id":1,"name":"商品1","price":67.0,"store":12},{"id":2,"name":"商品2","price":168.0,"store":1},{"id":3,"name":"商品3","price":25.0,"store":50}]}

第一台eureka server:http://127.0.0.1:8761/
第二台eureka server:http://localhost:8762/
第三台eureka server:http://localhost:8763/

linux 本地虚拟机内网变化ip:
之前的ip:192.168.182.130
http://192.168.227.128:8761/
http://192.168.227.128:8762/
http://192.168.227.128:8763/

SpringCloud|Spring Cloud Alibaba全套完整版框架开发教程-微服务项目实战【大牛亲授Spring Cloud Alibaba】

视频链接:https://www.bilibili.com/video/BV1or4y1F7Qa

p1~p18视频笔记

视频导读

接下来要学习两个课程,第一个是一站式微服务解决方案Spring Cloud Netflix,另外一个课程是一站式微服务解决方案Spring Cloud Alibaba。

Spring Cloud Netflix和Spring Cloud Alibaba都是微服务解决方案。

那么这里分成两个课程进行讲解,

做了一个分类。

它们之间有什么关系呢,那么这里有一张图可以看一下它的关系。

Spring生态下是有几十个项目的。

那么Spring生态下就包含了像Spring Boot、Spring框架(Spring Framework)、Spring Cloud…

Spring Cloud即微服务的开发框架。

那么Spring Cloud 当中包含了哪些内容呢?

Spring Cloud 当中包含了有Spring Cloud Netflix,Spring Cloud Netflix当中又包含了一些Netflix公司开源的一些组件,所以这个我们称之为Spring Cloud Netflix,Spring Cloud Netflix当中有包含Eureka、Hystrix、Hystrix Dashboard、Hystrix Turbine、Ribbon、Feign、Zuul。

另外一个即Spring Cloud Alibaba。Spring Cloud Alibaba开源的一些组件有Nacos Discovery、Nacos Config、Sentinel、RocketMQ、Seata、Dubbo Spring Cloud。都是用来进行微服务开发的。

所以当前课程分成两个部分来进行讲解。

  • Spring生态(https://spring.io)

    • Spring Web Services

    • Spring Web Flow

    • Spring Vault

    • Spring Statemachine

    • Spring Shell

    • Spring Roo

    • Spring Mobile

    • Spring LDAP

    • Spring for Apache Kafka

    • Spring Framework

    • Spring Cloud

      • Spring Cloud Netflix
        • Eureka
        • Hystrix
        • Hystrix Dashboard
        • Hystrix Turbine
        • Ribbon
        • Feign
        • Zuul
      • Spring Cloud Alibaba
        • 开源组件
          • Nacos Discovery
          • Nacos Config
          • Sentinel
          • RocketMQ
          • Seata
          • Dubbo Spring Cloud
        • 商业化组件
          • ANS
          • ACM
          • OSS
          • SMS
          • SchedulerX
      • Spring Cloud Azure
      • Spring Cloud for Amazon Web Services
      • Spring Cloud Bus
      • Spring Cloud CLI
      • Spring Cloud for Cloud Foundry
      • Spring Cloud - Cloud Foundry Service Broker
      • Spring Cloud Cluster
      • Spring Cloud Commons
      • Spring Cloud Config
    • Spring Data

    • Spring Cloud Data Flow

    • Spring Security

    • Spring Session

    • Spring Integration

    • Spring HATEOAS

第一个课程即Spring Cloud Netflix。

一站式微服务解决方案Spring Cloud Netflix

那么在这个课程当中会讲解哪些内容呢?

以下为大纲1~21点即为Spring Cloud Netflix课程。

这当中不光包括Netflix公司的一些开源组件,实际上还包含了一些别的东西,比如说Spring Cloud Config配置中心(用途、使用、加解密)、Spring Cloud Config配置中心(自动刷新、高可用、安全认证),再比如说Spring Cloud Sleuth分布式链路跟踪、Spring Cloud Sleuth整合Zipkin分布式链路跟踪,再比如说Spring Cloud 集成携程Apollo分布式配置中心也都包含在这当中。

这是第一个课程Spring Cloud Netflix,那么具体的课程详情就会逐一进行讲解。

  1. 分布式与微服务架构的理论梳理。
  2. 什么是Spring Cloud?
  3. Spring Cloud的整体架构(与Dubbo比较)
  4. 服务消费者Controller直连调用服务提供者Controller(http协议的restful)
  5. Spring Cloud的注册中心Eureka
  6. Spring Cloud Eureka与Zookeeper比较
  7. Spring Cloud Eureka高可用集群
  8. Spring Cloud Eureka自我保护机制
  9. Spring Cloud Ribbon 负载均衡
  10. Spring Cloud Feign声明式服务调用(与Dubbo接口层比较)
  11. Spring Cloud Hystrix服务熔断降级、服务限流
  12. Spring Cloud Hystrix DashBoard仪表盘监控
  13. Spring Cloud Hystrix Turbine聚合监控
  14. Spring Cloud Zuul网关(路由、过滤、异常、降级)
  15. Spring Cloud Config配置中心(用途、使用、加解密)
  16. Spring Cloud Config配置中心(自动刷新、高可用、安全认证)
  17. Spring Cloud Sleuth分布式链路跟踪
  18. Spring Cloud Sleuth整合Zipkin分布式链路跟踪
  19. Spring Cloud Stream消息驱动框架
  20. Spring Cloud 微服务安全机制
  21. Spring Cloud 集成携程Apollo分布式配置中心

第二个课程即Spring Cloud Alibaba。

那么这个课程当中我们会讲解哪些内容呢?

也列出了一个大纲。总共有58点。具体详细内容在后面也会进行详细的展开。

那么在这58点当中同样也不仅仅只包含了Spring Cloud Alibaba的开源组件,还包含了其他的内容,比如说Spring Cloud Stream,再比如说SkyWalking分布式链路跟踪,再比如说Spring Cloud Gateway网关等等,都是另外的一些内容。

一站式微服务解决方案 Spring Cloud Alibaba

  1. Spring家族开源项目梳理
  2. Spring Cloud下的开源项目梳理
  3. Spring Cloud Alibaba下的开源及商业项目梳理
  4. 微服务的基础模型:服务消费者-注册中心-服务提供者
  5. What is Nacos?
  6. Nacos的运行环境部署(Java写的,SpringBoot项目)
  7. Nacos的后台web管控台
  8. Nacos作为注册中心注册服务
  9. Nacos作为注册中心发现/订阅服务
  10. 服务消费者负载均衡调用服务提供者(ribbon)restTemplate、feign(openfeign)
  11. Nacos宕机时服务消费者缓存注册中心信息
  12. Nacos作为配置中心存储项目各种配置
  13. Nacos作为配置中心支持自动配置刷新(不需要重启应用)
  14. Nacos配置中心DataId+Group+Properties/yaml+配置内容(比较灵活)
  15. Nacos配置中心多环境配置(profile)即 s p r i n g . a p p l i c a t i o n . n a m e − {spring.application.name}- spring.application.name{profile}.${file-extension:properties}
  16. Nacos服务配置数据模型(命名空间、Group、Data Id)
  17. Nacos 数据持久化(mysql)
  18. Nacos集群部署(nginx)
  19. 主要调用方式:restTemplate、feign、ribbon(Spring Cloud)
  20. 流量控制Sentinel(流控、降级、热点、系统、授权规则)
  21. Sentinel DashBoard通信原理(与微服务通信)
  22. Sentinel 对应用保护的三种方式
  23. Sentinel整合RestTemplate流控熔断
  24. Sentinel整合Feign流控熔断
  25. Sentinel规则持久化(默认、pull模式、push模式)
  26. Spring Cloud Gateway网关(核心概念、如何工作、路由、谓词11个、过滤器31个)
  27. Spring Cloud Gateway自定义谓词
  28. Spring Cloud Gateway谓词不匹配404处理
  29. Spring Cloud Gateway自定义路由过滤器
  30. Spring Cloud Gateway全局过滤器(默认自动配置,无需单独配置)
  31. Spring Cloud Gateway集成ribbon复杂均衡
  32. Spring Cloud Gateway集成Sentinel
  33. Spring Cloud Gateway集成Sentinel规则持久化(文件、nacos)
  34. Spring Cloud Gateway内部流程源码分析
  35. Spring Cloud Gateway跨域CORS
  36. SkyWalking分布式链路跟踪
  37. SkyWalking主要功能特性和整体架构
  38. SkyWalking环境搭建部署
  39. SkyWalking Agent跟踪微服务
  40. IDEA中使用SkyWalking Agent跟踪运行的程序
  41. SkyWalking告警和回调处理
  42. SkyWalking持久化道elasticsearch
  43. SkyWalking跨多个微服务跟踪
  44. 自定义SkyWalking链路跟踪
  45. SkyWalking集成日志框架logback
  46. SkyWalking ui页面功能
  47. SkyWalking集群
  48. 什么是分布式事务
  49. What is Seata?
  50. Seata TC Server运行环境部署
  51. AT事务模型-单体应用多数据源应用
  52. AT事务模型-微服务应用
  53. AT事务模式工作机制
  54. Seata TC Server集群部署
  55. TCC事务模式执行机制
  56. 基于SpringBoot单体应用的TCC事务
  57. 基于Spring Cloud Alibaba的TCC分布式事务
  58. Spring Cloud Stream

分布式与微服务的那些高大上的理论梳理

微服务专题-一站式微服务架构Spring Cloud

接下来进行的专题是微服务专题。

微服务专题当中的第二个内容:一站式微服务架构Spring Cloud。这样一个微服务的解决方案叫Spring Cloud。

开始学习这样一个内容。

首先做一个简单了解:

接触过Spring Cloud、会使用Spring Cloud的、或者在公司的项目当中使用到过的打个1;

从未接触过的打个0;

接下来是重新开始学习这个内容,以后公司开发可能都会采用这种模式;

一点理论概念的梳理(也很重要)

在讲解之前先进行一点理论的梳理。虽然是理论但是也是非常重要的内容。稍微梳理下理论。

在系统架构与设计的实践中,从宏观上可以总结为三个阶段;(也就是系统架构经历了三个阶段)

第一个阶段即为传统、集中式的架构。比较早的时候,就一个项目,不管是在什么平台,做什么项目,就建一个工程,然后一帮程序员在其中进行开发,可能在这当中功能也很多,但是就只有一个项目,也就是在eclipse或者是idea当中就建立一个工程(单体应用),部署的时候就部署一个项目即可,有可能会部署到两到三台服务器,即集群的形式,但是其项目本身只有一个。

后续就发展成分布式架构。分布式架构就是拆分了。子项目之间相互调用共同对外提供服务。分布式架构有很多项目的原因在于由原来的一个项目根据不同的功能或者原因拆分成了很多个项目。整体的功能不是一个war包就可以完成的,而是多个war包一起去完成这个功能。

发展到第三个概念就是微服务架构。

最近几年来流行的一个概念叫做微服务架构。微服务架构实质上也属于分布式架构。可以认为是分布式架构的2.0版本,就相当于在这当中做了升级一样。

微服务架构在分布式架构的基础上做了升级,衍生、升华了一下。

集中式架构:就是把所有的功能、模块都集中到一个项目中,部署在一台服务器上,从而对外提供服务(单体架构、单体服务、单体应用)

直白一点:就是只有一个项目,只有一个war;

分布式架构:就是把所有的功能、模块拆分成不同的子项目,部署在多台不同的服务器上,这些子项目相互协作共同对外提供服务。

直白一点:就是有很多项目,有很多war包,这些项目相互协作完成需要的功能,不是一个war能完成的,一个war包完成不了。

比如:

Shop项目(电商平台):单体应用

Shop项目:拆分–>(user-center[用户中心],order-center[订单中心],trade-center[交易中心]…)分布式应用

微服务架构:分布式强调系统的拆分,微服务也是强调系统的拆分,微服务架构属于分布式架构的范畴。

并且到目前为止,微服务并没有一个统一的标准的定义,那么微服务究竟是什么?

微服务一词源于Martin Fowler(马丁·福勒)的名为Microsevices的博文,

可以在他的官方博客上找到这篇文章:

https://www.martinfowler.com/articles/microservices.html

中文翻译版本:

https://www.martinfowler.cn/articles/microservices.html

Martin Fowler国外知名的一名软件开发人员。

后面很多关于微服务的一些概念理念都基本上是以该文章作为基础参考。同时这篇文章国内有人将它翻译成为了中文。

了解即可。了解微服务的思想以及理念。


微服务

——讨论这个新架构风格名词的定义

原文[英]:http://martinfowler.com/articles/microservices.html

翻译[中]:http://martinfowler.cn/articles/microservices.html

摘要:

【微服务】这个词在过去的几年中传播开来,它用来描述一种将软件设计成一系列独立部署服务的特定方式。尽管目前尚没有对这种架构风格的明确定义,但是围绕组织结构、业务能力、自动化部署、终结点的智能化程度,编程语言和数据的去中心化控制这几个方面,这种架构风格有着某些共同的特征。

目录

  1. 微服务架构的特征
    1. 通过服务实现组件化
    2. 围绕业务能力组织
    3. 是产品而不是项目
    4. 智能终结点和哑管道
    5. 去中心化的管理
    6. 去中心化的数据管理
    7. 基础架构自动化
    8. 为容错设计
    9. 演进式设计
  2. 微服务是未来吗?

May 18,2016

詹姆斯·里维斯(James Lewis)

詹姆斯·里维斯是ThoughtWorks公司的首席顾问,并且是公司技术咨询委员会的成员。

詹姆斯对于使用相互协作的小服务来构建应用程序的兴趣源自他整合大规模企业系统的背景。

他使用微服务构建了大量系统,并且几年来一直都是正在兴起的微服务社区的积极参与者。

马丁·福勒(Martin Fowler)

martin@martinfowler.com(but if you do email me please read my FAQ first.)

马丁·福勒是一名作家,演讲者,还是软件开发领域的大嘴巴。

他一直苦苦思索如何组件化软件系统这一问题,听到了许多站不住脚的声称已解决这个问题的言论,但是却很少听到能令他满意的观点。

他希望微服务能够达到它的支持者对它的早期期望。

相关标签:

  • MICROSERVICES(微服务)
  • POPULAR(流行的)
  • APPLICATION ARCHITECTURE(应用程序架构)
  • WEB SERVICES(WEB 服务)

“微服务”

------在软件架构拥挤的街道出现的有一个新词。

尽管我们习惯性地投以这类事物轻蔑的一瞥,但是这个小小的词却描述了一种被发现越来越具有吸引力的软件架构风格。

在过去的几年中,我们已经看到了许多个项目使用了这种风格,目前为止这些项目的结果都是积极的,以至于对我的许多同事而言这已称为构建企业应用的默认风格。

然而,令人沮丧的是,没有大量的信息明确指出微服务是什么以及我们如何实现它。

简而言之,微服务架构风格[1]是以一组小服务来开发单个因供应程序的方法,每一个服务运行在自己独立的进程中并且使用轻量的方法通信,通常是一个HTTP API接口,这些服务围绕相关业务范围构建并且由全自动化部署机器独立部署。

这些服务只需要最低限度的管理,可以用不同的编程语言去编写并且使用不同的数据存储技术。

原站点边栏

我的微服务资源向导提供了有关微服务的文章,视频,书籍和播客的链接。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XOAufOeW-1621472077289)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511171340500.png)]

若要解释清楚微服务风格,将它与单块风格(一个单块应用程序作为单个单元构建)对比将会很有帮助。

企业应用程序通常由三个主要部分组成:一个客户端用户界面(由运行在用户机器上的浏览器中的HTML页面和JavaScript代码组合成),一个数据库(由多个插入到一种常见的,通常是关系型数据库管理系统中的数据表组合成),以及一个服务端应用程序。

这个服务端应用程序将会处理HTTP请求,执行领域逻辑,从数据库获取和更新数据,并且选择和填充发送给浏览器的HTML视图。

这个服务器端的应用程序就是单块——一个单一的可执行的逻辑[2]。

任何对这个系统的改动都需要重新构建和部署一个服务器端应用程序的新版本。

很自然地,这样的单块服务器是构建这样一个系统的一种方式。

处理一条请求的所有逻辑都在一个单一的进程中运行,这允许你使用编程语言的基本功能将应用程序拆分成类、函数和命名空间。

更谨慎的做法是,你可以在一个开发者的笔记本上运行和测试多个应用程序,并且使用一个部署管道来确保改动都被正确的测试并且部署到了生产环境中。

你可以通过在一个负载均衡器后运行多个实例的方式来横向缩放这个单块应用。

单块应用可以被成功运用,但是渐渐地人们对蛋快应用感到不满——尤其是当越来越多的应用程序被部署到云端。

任何改动都会牵一发动全身——哪怕是对应用程序一个小地方的改变都需要整个单块应用被重新构建和部署。

随着时间的推移通常会很难保持一个良好的模块结构使得控制变更仅影响模块内部变得越加困难。

如要实现缩放,需要缩放整个应用程序而不是应用程序的某一部分,这要求更多的资源。

一个单体应用将它所有的功能放到一个单一的进程…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AKRhMkUi-1621472077296)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511172552174.png)]

…并且通过在多台服务器上运行单块应用的副本来实现缩放

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ffk4PES-1621472077300)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511172614147.png)]

一个微服务架构将每一个功能放到独立的服务中…

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2JASfnEg-1621472077302)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511172655628.png)]

…并且通过跨服务器分发这些服务来实现缩放,按需创建副本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iHDCtqjX-1621472077304)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511172833929.png)]

以上为:单块架构和微服务架构的对比

这些不满催生了微服务架构风格:以一组服务来构建应用程序,除了使得服务能够被独立部署和缩放,每一个服务还提供了一个稳定的模块边界,甚至允许不同的服务使用不同的编程语言编写。

每个服务也可以由不同的团队来管理。

我们不想宣称微服务架构风格是新生的或者创新的,它的起源至少可以追溯到Unix的设计原则。

但是我们真的认为考虑使用微服务架构的人还不够多【Martin初次写作本文时才是2014年3月,随后的情况是微服务概念甚嚣尘上,以至于Martin又写了一篇《使用微服务的预备条件》来“降温”——译者著】,如果他们使用微服务架构的话,许多软件开发宫锁能够做得更好。

原站点脚注

[1] 2011年五月在威尼斯附近的一个软件架构师的工作室“微服务”这个词被用来形容大多数与会者近期正在探索的被视为通用的架构风格的架构。

在2012年的五月,同一支工作小组决定使用“微服务”这个词作为这种架构风格最合适的叫法。

在2012年3月克拉科夫市举办的“33rd Degree”技术大会上,James(本文作者之一)在其“Microservices - Java,the Unix Way”演讲中以案例的形式介绍了这些微服务的观点,在同一时间,Fred George也表达了相同观点。

Netflix公司的drian Cockcroft,将这种方法描述为“细粒度的SOA”,并且同本文中所提到的——Joe Walnes, Dan North,Evan Botcher and Graham Tackley这些人一样已经在web领域开展了实战。

[2] 单块这个词在Unix社区已经被使用了一段时间了。它出现在《UNIX编程艺术(The Art of UNIX Programming)》这本书中,用来形容过于巨大的系统。

微服务架构的特征

我们不能够说微服务有着一个正式地定义,但是我们可以尝试着描述那些被标上“微服务”标签架构的共同特征。

尽管可以列出共同特征,但并非所有的微服务架构都具备所有的特征,但是我们猜想绝大多数的微服务架构都显现出多数特征。

尽管我们两位作者已经成为微服务这个相当松散的社区的活跃成员,但我们的意愿是视图描述我们在自己和我们所指的团队中所了解的情况。

特别要指出,我们不会给出教条式的微服务的定义。

通过服务实现组件化

自软件工程诞生伊始,人们就有着通过将软件模块组合在一起来构建系统的愿望,就如同我们在现实生活中看到的事务被制造的方式。

在过去的几十年里,我们在公共组件库方面取得了长足的进展,这些大量的公共组件库已经成为多数编程语言平台的一部分。

当我们讨论组件时,我们首先得回答“什么是组件”。

我们的定义是:一个组件就是一个可以被独立替换和升级的软件单元。

微服务架构也会使用软件库,但是用来实现软件组件化的主要方式是将软件拆分成服务。

我们将被连接到一个程序并且通过内存函数调用的组件称为库,而服务确是进程外加载的组件,它通过例如web服务请求或者远程过程调用的方式通信。(各种OO语言程序中服务又是另一个概念了[3])

选择使用服务作为组件(而不是库)的一个主要原因是服务是可以独立部署的。

假设你有一个包含多个库的应用程序[4]跑在一个单一的进程里,对任何单一组件的变更都将导致整个应用程序的重新部署。

但是如果这个应用程序被分解成多个服务,那么你可以期望对单一服务的多项变更只需要重新部署那个服务。

这不是绝对的,某些变更可能会改变服务接口从而导致某些内容协商问题,但是微服务架构的目的就是要通过明确的服务边界和演进设计的服务契约来最小化这些变更。

使用服务作为组件的另一个好处是更加明确的组件接口。

许多语言在定义明确的公共接口方面表现得不好。

通常它只有一些文档来描述如何组织客户端破坏组件的封装,这将导致组件间过渡的耦合。

服务通过使用明确的远程调用方法轻松地避免了这个问题。

Using services like this does have downsides.

Remote calls are more expensice than in-process calls,

and thus remote APIs need to be coarser-grained,

which is often more awkward to use.

If you need to change the allocation of responsiblities between components,

such movements of behavior are harder to do when you’re crossing process boundaries.

像这样使用服务也会带来副作用。

远程调用比起进程内调用要昂贵得多,因此远程API需要是粗粒度的,这通常更加不便于使用。

At a first approximation,

we can observe that services map to runtime processes,

but that is only a first approximation.

A service may consist of multiple processes that will always be developed and deployed together,

such as an application process and a database that’s only use by that service.

原站点脚注

[3] 许多面向对象的设计者,包括我们自己,使用“服务”这个词来描述领域驱动设计中没有与实体绑定的执行一个重要业务过程的对象。

这与我们在此篇文章中探讨的“服务”是不同的概念。

糟糕的是“服务”这个词有着两个意思,并且我们不得不忍受多义【事实上正是因为“聚义”,人类的语言才得到长足的发展——译者】。

[4] 我们将一个应用程序看做由代码、功能集合以及架构组成的社会结构。

围绕业务能力组织

是产品而不是项目

智能终结点和哑管道

去中心化的管理

去中心化的数据管理

基础架构自动化

为容错设计

演进式设计

微服务是未来吗?

翻译: 一丘 翻译日志:

2016/09/07 完成“导语”部分文字翻译
2016/09/02 完成背景阅读
2016/08/23 开始背景阅读

以上为微服务最早的来源。

简单地说,微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP的RESTful API进行通信协作;(HTTP协议,RESTful 风格;在Dubbo当中是通过dubbo协议调用,将其称之为RPC,当然在微服务中基于HTTP的RESTful API进行通信协作也可以称之为RPC,RPC是一个整体的概念,仅仅是实现的方式不一致而已;那么微服务当中的RPC即基于HTTP协议的RESTful风格这种项目之间的调用;RESTful风格调用即简单理解就是Controller调用Controller,即一个SpringBoot的项目当中写有一个Controller,这个Controller可以调用另外一个Controller,那么另外一个Controller就相当于是服务的接口;RESTful API[controller --> 调用 controller]底层走HTTP协议)

被拆分后的每一个小型服务都专注于完成系统中某一项业务功能职责单一,并且每个服务都是一个独立的项目,可以进行独立的测试、开发和部署等;(与其他项目无关,不影响其他项目,比如说一个用户服务,那么该服务只进行专注于用户的注册登录,其他功能都不专注,就专注于这一个功能,职责比较单一,如果需要注册登录功能,那么这个时候就调用该用户服务的注册登录接口,去通过RESTful API进行调用)

由于各个独立的服务之间使用的是基于HTTP的JSON作为数据通信协作的基础,所以这些微服务也可以使用不同的语言来开发;

(微服务没有一个统一,是一个概念,一种思想)

比如说在PHP开发时,或者用Python或者其他什么语言开发时,也可以使用微服务这种理念,两个项目之间通过JSON来进行数据交互。因为RESTful风格用户两个接口之间,在它们进行交互的时候就是通过JSON。

一个Controller A返回一个JSON,另外一个Controller B调用另外一个Controller C拿Controller A返回的JSON数据,Controller C拿到JSON数据之后再进行业务逻辑处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXcd1bZc-1621472077305)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511220413196.png)]

客户端有PC端、手机端、还有H5等,它们在进行数据获取过程中会经过一个api网关服务(网关后续会有讲解到,微服务当中有很多的相关组件),再走到相关的产品服务、订单服务、用户服务…;

微服务和原来的分布式服务,架构是非常相似的,可能分布式服务也是进行拆分,比如说产品服务、订单服务、用户服务…,然后每一个服务下面都是属于该服务的数据库这种模式,它本身和分布式服务架构差不多。

微服务和分布式服务有什么区别?

比如:项目里面有User模块(用户模块)和Order模块(订单模块),但是User模块和Order模块并没有直接关系(微服务职责比较单一,每一个模块只专注该模块本身自己的事情),仅仅只是一些数据需要交互,那么就可以把这2个模块单独分开来(单独拆分,做两个微服务),当User需要调用Order的时候,Order是一个服务方(服务提供方),但是Order需要调用User的时候,User又是服务方了(User服务/Order服务既可以是消费方也可以是服务提供方),所以,他们并不在乎谁是服务方谁是调用方,它们都是2个独立的服务,这就是微服务的概念;(经过拆分之后,两个服务User服务和Order服务可以相互进行调用,两者都可以作为消费方或者服务方)

经典面试:分布式和微服务有什么区别?

相同部分

分布式,就是将巨大的一个系统(项目)划分为多个模块,这一点和微服务是一样的,都是要把系统进行拆分,部署到不同机器上,因为一台机器可能承受不了这么大的访问压力,或者说要支撑这么大的访问压力需要采购一台性能超级好的服务器,其财务成本非常高,有这些预算完全可以采购很多台普通的服务器了,分布式系统各个模块通过接口进行数据交互,其实分布式也是一种微服务,因为都是把模块拆分变为独立的单元,提供接口来调用,那么它们本质的区别是什么?

(微服务与分布式确实很相似,都是进行服务的拆分;它们之间有相同点也有不同点)

不同部分

它们的本质的区别体现在“目标”上,何为目标,就是你采用分布式架构或者微服务架构,你最终是为了什么,要达到什么目的?

分布式架构的目标是什么?

就是访问量很大,一台机器承受不了,或者是成本问题,不得不使用多台机器来完成服务的部署。(分布式架构将服务拆分是为了用一些普通的机器来进行部署项目/服务)

而微服务的目标是什么?

只是让各个模块拆分开来,不会被互相影响,比如模块的升级或者出现BUG或者是重构等等都不要影响到其他模块(因为微服务模块它比较职责单一,粒度比较细化职责单一,关注的是服务之间影响的程度),微服务它是可以在一台机器上部署(即拆分了多个微服务,但是多个微服务可以在一台机器上部署,分布式也是可以在一台机器上进行部署的);

从这个上面来说,分布式和微服务它们之间的不同点在于它们追求的目标不一样;分布式进行拆分缘故在于原来是一个单体应用,由于单体应用部署在一台机器上,在该机器上时,客户端在进行访问请求时,所有的功能都落在一台机器上,那么就有可能会造成这台机器的压力比较大,所以这个时候就会将这台机器上的该单体应用中的某些服务进行拆分出来放到其他的机器上去进行部署,这样就对该原来的机器或者某一台机器起到了一个分摊压力的作用;这是分布式架构追求的目标;

而微服务架构追求的目标即为,每个被拆分出来的微服务职责单一,它们之间的影响是最小化的,相互之间影响很小,依赖也很小,不会一个项目/服务A的改造升级重构对另外一个项目/服务B的影响度是很小很小的。

即这两者追求的目标不一样,这也是微服务和分布式之间的一个区别。从宏观上来说这两者没有什么很大的区别,都是为了拆分。

但是:分布式也是微服务的一种,微服务也属于分布式;

(它们两者之间你中有我,我中有你,但是它们的目标不一致,也是它们的区别)

面试:微服务与Spring-Cloud的关系或区别?

微服务只是一种项目的架构方式、架构理念,或者说是一种概念,就如同我们的MVC架构一样,那么Spring Cloud便是对这种架构方式的技术落地实现。

面试:微服务一定要使用Spring Cloud吗?

讲微服务时,可能首先想到的就是Spring Cloud。可能直接就对号入座是Spring Cloud,那么微服务不能直接说就是Spring Cloud。

微服务只是一种项目的架构方式、架构理念,所有任何技术都可以实现这种架构理念,只是微服务架构里面有很多问题需要我们去解决,比如:负载均衡,服务的注册与发现,服务调用,服务路由,服务熔断等等一系列问题,如果你自己从0开始实现微服务的架构理念,那头发都掉光了,所以Spring Cloud帮我们做了这些事情,Spring Cloud将处理这些问题的技术全部打包好了,我们只需要开箱即用。

微服务不光是Spring Cloud,还有其他技术也可以解决做微服务的功能,只是Spring Cloud是一整套的方案,帮我们解决了一系列的问题,这样的话我们进行开发就非常方便了,即很多的微服务问题都提供了有技术方案,不用自己去折腾。

What is Spring Cloud

官网:https://spring.io/projects/spring-cloud

版本:Greenwich SR3

出自官方:

OVERVIEW
Spring Cloud provides tools for developers to quickly build some of the common patterns in distributed systems(e.g. configuration management, service discovery, circuit breakers, intelligent routing, micro-proxy, controls bus, one-time tokens, global locks, leadership election, distributed sessions, cluster state).
Coordination of distributed systems leads to boiler plate patterns, and using Spring Cloud developers can quickly stand up services and applications that implement those patterns.
They will work well in any distributed environment, including the developer's own laptop, bare metal data centers, and managed platforms such as Cloud Foundry.

翻译:
Spring Cloud为开发人员提供了一些工具用来快速构建分布式系统中一些常见模式和解决一些常见问题(例如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)。
分布式系统的协调导致了很多样板式的代码(很多固定套路的代码),使用Spring Cloud开发人员可以快速建立实现这些模式的服务和应用程序。
它们在任何分布式环境中都能很好地运行,包括开发人员自己的笔记本电脑、裸机数据中心和云计算等托管平台。

(微服务也属于分布式,分布式也是微服务,它们你中有我我中有你,但是它们所追求的目标有区别;
distributed systems分布式系统,Spring Cloud解决了分布式系统开发中的一系列问题,然后我们使用这样一套方案,Spring Cloud可以称作一套组件,一套方案,它里面是由很多组件构成的。它就可以帮我们解决一些问题,开发时遇到的分布式问题例如领导选举、分布式会话等等都将有一套方案,倒是直接用即可。)

微服务有很多个问题需要进行解决,Spring Cloud下由多个子项目进行构成。

目前看到Spring Cloud下的组件有:

  • Spring Cloud
    • Spring Cloud Azure
    • Spring Cloud Alibaba
    • Spring Cloud for Amazon Web Services
    • Spring Cloud Bus
    • Spring Cloud Circuit Breaker
    • Spring Cloud CLI
    • Spring Cloud for Cloud Foundry
    • Spring Cloud - Cloud Foundry Service Broker
    • Spring Cloud Cluster
    • Spring Cloud Commons
    • Spring Cloud Config
    • Spring Cloud Connectors
    • Spring Cloud Consul
    • Spring Cloud Contract
    • Spring Cloud Function
    • Spring Cloud Gateway
    • Spring Cloud GCP
    • Spring Cloud Kubernetes
    • Spring Cloud Netflix
    • Spring Cloud Open Service Broker
    • Spring Cloud OpenFeign
    • Spring Cloud Pipelines
    • Spring Cloud Schema Registry
    • Spring Cloud Security
    • Spring Cloud Skipper
    • Spring Cloud Sleuth
    • Spring Cloud Stream
    • Spring Cloud Stream App Starters
    • Spring Cloud Stream Applications
    • Spring Cloud Task
    • Spring Cloud Task App Starters
    • Spring Cloud Vault
    • Spring Cloud Zookeeper
    • Spring Cloud App Broker

当前稳定版本Greenwich SR3 CURRENT GA

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aYdPnXWs-1621472089835)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511225849002.png)]

在国内,版本之间的称呼:

Greenwich SR3称之为G版;

Hoxton RC1称之为H版;

Finchley SR4称之为F版;

或者还有A版、B版、D版;

它是从A~Z这个顺序去进行发布的版本,看首字母。

下一个版本的字母会比上一个版本的字母大。

当下去看版本:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aYqVnFbr-1621472089836)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511230003975.png)]

Spring Cloud特性

Spring Cloud为分布式系统开发的 典型应用场景 提供良好的 开箱即用的功能。

比如:

分布式/版本化配置

服务注册和发现

路由

服务与服务间的调用

负载均衡

断路器

全局锁

领导选举与集群状态

分布式消息传递

由于要解决不止是以上的问题,Spring Cloud下提供了很多的组件来进行解决相关问题。

Spring Cloud下的主要项目

  • Spring Cloud Config
  • Spring Cloud Netflix
  • Spring Cloud Bus
  • Spring Cloud for Cloud Foundry
  • Spring Cloud Open Service Broker
  • Spring Cloud Cluster
  • Spring Cloud Consul
  • Spring Cloud Security
  • Spring Cloud Sleuth
  • Spring Cloud Data Flow
  • Spring Cloud Stream
  • Spring Cloud Stream App Starters
  • Spring Cloud Task
  • Spring Cloud Task App Starters
  • Spring Cloud Zookeeper
  • Spring Cloud AWS
  • Spring Cloud Connectors
  • Spring Cloud Starters
  • Spring Cloud CLI
  • Spring Cloud Contract
  • Spring Cloud Gateway
  • Spring Cloud OpenFeign
  • Spring Cloud Pipelines
  • Spring Cloud Function

Spring Cloud 的版本

Spring Cloud是由一系列独立项目组成的,每个独立的项目具有不同的发布节奏。

每次Spring Cloud发布版本时,就会组合这一系列的子项目,Spring Cloud为了避免大家对版本号的误解,避免与子项目版本号混淆,所以Spring Cloud发布的版本是一个按照字母顺序的伦敦地铁站的名字,

(“天使”是第一个版本,“布里克斯顿”是第二个)字母顺序是从A~Z,目前最新稳定版本Greenwich SR3,

当Spring Cloud里面的某些子项目出现关键性bug或重大更新,则发布序列将推出名称以".SRX"结尾的版本,其中“X”是一个数字,比如:Greenwich SR1、Greenwich SR2、Greenwich SR3;

因为Spring Cloud当中有多个子项目,比如说Spring Cloud Pipelines该子项目当中有一个重大的bug,在进行修改了之后进行发布了新版本,那么Spring Cloud是使用到了这个子项目的,该子项目发布了新版本,Spring Cloud的版本也是需要进行跟进的,如果不进行跟进的话,那么到时候Spring Cloud依赖Spring Cloud Pipelines该子项目的是之前的那个旧的版本,即有重大bug的版本,所以就不得不将Spring Cloud版本进行升级一下,那么在升级的时候,不想变化总版本,即变化字母的大版本,那么这个时候".SRX"的重要性就凸显出来了。

目前看到Greenwich SR3就说明有过三次的重大bug修复或者是更新,但是其总版本还是G版本不变,即G版本中依赖的某一个组件模块发生了重大的调整更新,所以就是用".SR"加“X”数值来进行实现版本的升级。

Spring Cloud是微服务开发的一整套解决方案,采用Spring Cloud开发,每个项目依然是使用Spring Boot;

所以在学习Spring Cloud之前先要进行学习Spring Boot;

由于底层是使用的Spring Boot,那么在使用时需要注意Spring Cloud和Spring Boot的兼容版本;

Spring Cloud与Spring Boot的兼容版本表格

Spring Cloud版本Spring Boot版本
Hoxton2.2.x
Greenwich2.1.x
Finchley2.0.x
Edgware1.5.x
Dalston1.5.x
Camden1.4.x 或 1.5.x
Brixton1.3.x 或 1.4.x
Angel1.2.x

Greenwich简称G版本需要使用Spring Boot的2.1.x版本,如果使用了Spring Boot的2.2.x版本的话,并不能保证不会报错或者启动运行这样类似的问题。

由于G版本 Greenwich只在2.1.x中做了严格测试是没有问题的。

G版本搭配Spring Boot除了2.1.x版本使用其他的版本是没有测试过的。所以最好是用测试过匹配的这个版本进行开发项目。

2.1.x即可以是2.1.0、2.1.1等等,2.1.x系列即可;

GA稳定版本;PRE预发布版本

搭建Spring Cloud服务提供者服务

下面看Spring Cloud如何进行开发。

开发之前,先看下Spring Cloud 的整体开发结构,它和Dubbo非常相似,所以有的时候经常会将Spring Cloud与Dubbo进行比较。

在原来讲解Dubbo的时候,会有一个注册中心,有一个服务提供者,以及一个服务消费者。

那么Spring Cloud大概也是这样一个模式。有一个服务提供方,一个服务消费方,以及一个注册中心。

服务提供方启动服务之后会在注册中心进行注册,而服务消费方在启动服务之后也会在注册中心进行注册,因为在微服务当中,Service Consumer或者是Service Provider都既可以是服务提供方也可以是服务消费方。所以这两个服务Service Consumer/Service Provider都会往注册中心Eureka Server进行注册,即Service Consumer可以进行调用Service Provider,而Service Provider也可以进行调用Service Consumer。(微服务之间是可以进行相互间的调用的。然后子微服务都会向注册中心注册自己的服务。)那么其整体结构即可以分为这三个部分,Service Consumer、Service Provider即服务,Eureka Server即注册中心,和Dubbo非常相似。

2、Spring Cloud的整体架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ch0Hw5Vk-1621472105040)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210511234948296.png)]

Service Provider:暴露服务的服务提供方。

Service Consumer:调用远程服务的服务消费方。

Eureka Server:服务注册中心和服务发现中心。

3、服务消费方直接调用服务提供方

我们知道,SpringCloud构建微服务是基于SpringBoot开发的。

搭建环境:有一个服务提供方和服务消费方,但是没有注册中心,而是服务消费方直接调用服务提供方,类似Dubbo,也可以没有注册中心,直接进行调用。

将环境搭建好之后,接下来将注册中心搭建起来。通过向注册中心注册了服务,服务消费方再来进行调用服务提供方。

  1. 打开IDEA,建立服务的一个模块为Maven模块,该Maven模块为一个父项目(到时候其他子项目将会继承该父项目,这里是用到了maven的继承和聚合结构)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ncpmZYn-1621472105043)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512001042089.png)]

  1. 在弹出的界面【New Module】当中找到【Maven】并点击。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lueZ1NtV-1621472105044)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512001835616.png)]

  1. 选择好Module SDK:1.8(java version "1.8.0_201")之后进行点击 Next 按钮。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6I5gvQd2-1621472105045)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512002218042.png)]

  2. 点击 Next 按钮之后,将会出现另外一个弹窗。并在弹窗中输入GroupId、ArtifactId以及Version(这是一个父工程),填写完成之后再点击 Next 按钮下一步。

    GroupId:com.bjpowernode.springcloud
    
    ArtifactId:34-springcloud-service-parent
    
    Version:1.0.0
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D1DSinhE-1621472105046)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512002836707.png)]

  3. 在弹出的新弹窗中,检查Content root:标签该行中的内容取值是否正确。如若不正确则进行修改。这里看到显然是不正确的,需要将取值_34springcloudserviceparent修改为34-springcloud-service-parent。在进行修改Content root:标签该行中的取值时,Module name:Module file location:也会跟着进行更改。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tEUFdLvl-1621472105047)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512003131413.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W0SjruCr-1621472105048)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512003309291.png)]

  4. 最后点击 Finish 按钮,完成。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9dbxMqGJ-1621472105050)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512003522279.png)]

  5. 点击导入import Changes

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ip8dJeuU-1621472105051)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512004200305.png)]

  6. 在该父项目34-springcloud-service-parent 当中主要是配置些基础的内容。

    首先在该父项目中配置一个Spring Boot的相关内容。(Spring Boot 的父级依赖)该父项目工程需要集成springboot父项目。

<!-- 继承springboot父项目 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/><!-- looup parent from repository -->
</parent>

​ 即在34-springcloud-service-parent父项目的pom.xm文件当中添加内容如上,以下是添加好的,接着点击import Changes导入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 继承springboot父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/><!-- lookup parent from repository -->
    </parent>

    <groupId>com.bjpowernode.springcloud</groupId>
    <artifactId>34-springcloud-service-parent</artifactId>
    <version>1.0.0</version>


</project>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-991k4v4K-1621472105053)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512005248279.png)]

  1. 当前的SpringCloud的G版本需要使用Spring Boot的2.1.x系列,所以spring-boot-starter-parent的版本version需要进行修改为2.1.9.RELEASE或者其他(2.1.9是目前最新的版本),不能够使用Spring Boot的2.2.x系列。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FtWP2y26-1621472105054)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512005733587.png)]

修改的pom.xml如下,当中仅仅修改了版本号为2.1.9.RELEASE

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 继承springboot父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/><!-- lookup parent from repository -->
    </parent>

    <groupId>com.bjpowernode.springcloud</groupId>
    <artifactId>34-springcloud-service-parent</artifactId>
    <version>1.0.0</version>


</project>
  1. 再将如下内容粘贴到34-springcloud-service-parent工程的pom.xml中

    <!--依赖管理 -->
    <dependencyManagement>
        <dependencies>
            <!--现在spring cloud使用的是G版本即Greenwich SR3,所以需要将此处的Finchley.RELEASE H版本换成G版本Greenwich SR3版本的依赖,此处可以去maven仓库粘贴过来-->
          <!--<dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
               <version>Finchley.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>-->
            
            <!--
    	步骤:
    	1. 浏览器打开网址:https://mvnrepository.com/
    	2. 在最上方的文本框中输入spring-cloud-dependencies
    	3. 点击Search按钮进行检索
    	4. 在查询出来的列表中,点击最上方一条Spring Cloud Dependencies超链接
    	5. 在跳转到的页面中进行查找Greenwich.SR3该版本链接并点击
    	6. 进行复制spring-cloud-dependencies依赖
    	<!- - https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies - ->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.SR3</version>
        <type>pom</type>
        <scope>runtime</scope>
    </dependency>
    
    	7. 将内容复制进来之后再将<scope>runtime</scope>标签中的内容修改为import,即<scope>runtime</scope>
    	即
    <!- - https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies - ->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.SR3</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    	8. 最后将F版(Finchley.RELEASE)的spring-cloud-dependencies依赖进行删除(此处做出注释处理)
    
    Greenwich.SR3为Spring Cloud的一个整体的英文版本,
    那么spring-cloud-dependencies该依赖下依赖了一系列的组件,
    且该依赖的一系列组件的版本都各不相同,比如说:
    spring-cloud-dependencies依赖下的组件版本如下所示,将这些不同版本的组件依赖都进行了归纳,归纳成为spring-cloud-dependencies的一个英文版本Greenwich.SR3
    所以此处只需要依赖一个spring-cloud-dependencies的一个英文版本即可,该spring-cloud-dependencies下依赖的各个组件不同版本都已经被归纳好了,不需要去关注底下那些组件的小版本,因为spring-cloud-dependencies依赖了一系列的组件了已经。
    
    <properties>
            <spring-cloud-aws.version>2.1.3.RELEASE</spring-cloud-aws.version>
            <spring-cloud-bus.version>2.1.3.RELEASE</spring-cloud-bus.version>
            <spring-cloud-cloudfoundry.version>2.1.3.RELEASE</spring-cloud-cloudfoundry.version>
            <spring-cloud-commons.version>2.1.3.RELEASE</spring-cloud-commons.version>
            <spring-cloud-config.version>2.1.4.RELEASE</spring-cloud-config.version>
            <spring-cloud-consul.version>2.1.3.RELEASE</spring-cloud-consul.version>
            <spring-cloud-consul.version>2.1.3.RELEASE</spring-cloud-consul.version>
            <spring-cloud-contract.version>2.1.3.RELEASE</spring-cloud-contract.version>
            <spring-cloud-function.version>2.0.2.RELEASE</spring-cloud-function.version>
            <spring-cloud-gateway.version>2.1.3.RELEASE</spring-cloud-gateway.version>
            <spring-cloud-gcp.version>1.1.3.RELEASE</spring-cloud-gcp.version>
            <spring-cloud-kubernetes.version>1.0.3.RELEASE</spring-cloud-kubernetes.version>
            <spring-cloud-netflix.version>2.1.3.RELEASE</spring-cloud-netflix.version>
            <spring-cloud-openfeign.version>2.1.3.RELEASE</spring-cloud-openfeign.version>
            <spring-cloud-security.version>2.1.4.RELEASE</spring-cloud-security.version>
            <spring-cloud-sleuth.version>2.1.4.RELEASE</spring-cloud-sleuth.version>
            <spring-cloud-stream.version>FIshtown.SR4</spring-cloud-stream.version>
            <spring-cloud-task.version>2.1.3.RELEASE</spring-cloud-task.version>
            <spring-cloud-vault.version>2.1.3.RELEASE</spring-cloud-vault.version>
            <spring-cloud-zookeeper.version>2.1.3.RELEASE</spring-cloud-zookeeper.version>
            </properties>
    -->
            
            
            
            <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies 
    spring-cloud-dependencies
    -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Greenwich.SR3</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    
        </dependencies>
    </dependencyManagement>
    
  2. 以下为34-springcloud-service-parent父项目的pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 继承springboot父项目-->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.9.RELEASE</version>
            <relativePath/><!-- lookup parent from repository -->
        </parent>
    
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
    
        <!--依赖管理 -->
        <dependencyManagement>
            <dependencies>
                <!--现在spring cloud使用的是G版本即Greenwich SR3,所以需要将此处的Finchley.RELEASE H版本换成G版本Greenwich SR3版本的依赖,此处可以去maven仓库粘贴过来-->
                <!--<dependency>
                      <groupId>org.springframework.cloud</groupId>
                      <artifactId>spring-cloud-dependencies</artifactId>
                     <version>Finchley.RELEASE</version>
                      <type>pom</type>
                      <scope>import</scope>
                  </dependency>-->
    
                <!--
            步骤:
            1. 浏览器打开网址:https://mvnrepository.com/
            2. 在最上方的文本框中输入spring-cloud-dependencies
            3. 点击Search按钮进行检索
            4. 在查询出来的列表中,点击最上方一条Spring Cloud Dependencies超链接
            5. 在跳转到的页面中进行查找Greenwich.SR3该版本链接并点击
            6. 进行复制spring-cloud-dependencies依赖
            <!- - https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies - ->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR3</version>
            <type>pom</type>
            <scope>runtime</scope>
        </dependency>
    
            7. 将内容复制进来之后再将<scope>runtime</scope>标签中的内容修改为import,即<scope>runtime</scope>
            即
        <!- - https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies - ->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
            8. 最后将F版的spring-cloud-dependencies依赖进行删除
        -->
                <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Greenwich.SR3</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
    
            </dependencies>
        </dependencyManagement>
    </project>
    
  3. 接下来进行创建服务提供者以及服务消费者,以及服务提供者以及服务消费者需要继承父项目34-spring-cloud-service-parent

    现在建立一个服务提供者的子服务(产品服务goods)。

    打开IDEA,找到顶部的File选项卡并点击,找到New后,再找到Module...

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uOjmnvHX-1621472105056)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512094716694.png)]

    由于知道Spring Cloud开发底下采用的依然是Spring Boot,所以这里选择Spring Boot来进行开发Spring Cloud。

    在弹出的弹窗当中找到Spring Initializr该选项卡并点击,将Module SDK:该标签行的内容修改为1.8(java version "1.8.0_201"),然后点击Next按钮,下一步

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQ9OMhAQ-1621472105058)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095048200.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYRftlZm-1621472105059)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095147802.png)]

    点击Next按钮之后将出现弹窗如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bHy9LqcW-1621472105060)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095327158.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X5JTgwpH-1621472105061)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095404768.png)]

    此处改为通过maven创建Spring Boot项目。

    同样打开IDEA–>File–>New–>Module...–>Maven–>将Module SDK: 该标签行的内容修改为1.8(java version "1.8.0_201")–>点击Next按钮

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YluF7197-1621472105062)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095710345.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wTxnFLEv-1621472105063)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512095742926.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L5PEphsR-1621472105064)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512100003284.png)]

    点击Next按钮之后将弹出新窗口,在对应的标签行中填入相应的值之后(34-spring-cloud-service-goods即产品服务),再次点击Next按钮

    GroupId:com.bjpowernode.springcloud
    
    ArtifactId:34-springcloud-service-goods
    
    Version:1.0.0
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O6gg1NMn-1621472105066)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512100358726.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsIYtoEk-1621472105067)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512100557032.png)]

    点击完Next按钮之后,在弹出的新窗口页面当中进行修改Content root: 标签行内的取值_34springcloudserivcegoods修改为34-springcloud-service-goodsModule name:标签行中的内容以及Module file location: 标签行内的内容也会跟着修改,

    以及还需要将Content root: 该标签行中的内容\34-springcloud-service-parent去掉,否则的话工程将建立在34-springcloud-service-parent该项目/文件夹中,同时Module file location: 该标签行中的内容也会跟着改变。

    修改完成之后点击Finish按钮,最后点击import Changes

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Px3ykgbc-1621472105068)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512100925653.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ar06iBp2-1621472105069)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512101008084.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wnDhJaaQ-1621472105070)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512101531582.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KiqPTlvp-1621472105071)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512101728318.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MRtRDMTl-1621472105082)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512102015090.png)]

    可以看到左侧工程列中出现了有34-springcloud-service-goods,那么此时就将该产品服务建立起来了。产品服务建立起来之后,就通过maven的方式进行继承父项目,也就是34-springcloud-service-parent

    子项目产品服务34-springcloud-service-goods继承父项目则需要将父项目34-springcloud-service-parentpom.xml中的gav坐标,也就是groupIdartifactIdversion这三个坐标在子项目中,也就是产品服务34-springcloud-service-goodspom.xml中进行定义一下,即子项目产品服务继承父项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChyMREXB-1621472105083)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512103113491.png)]

    即将如下内容放到子项目产品服务34-springcloud-service-goods中的pom.xml中(需要加上<parent></parent>标签)

    <parent>
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
    </parent>
    

    即此时子项目产品服务34-springcloud-service-goods中的pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 统一继承的父项目 -->
        <parent>
            <groupId>com.bjpowernode.springcloud</groupId>
            <artifactId>34-springcloud-service-parent</artifactId>
            <version>1.0.0</version>
        </parent>
    
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-goods</artifactId>
        <version>1.0.0</version>
    </project>
    

    点击import Changes

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0c77QxFl-1621472105085)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512103330752.png)]

    当子项目继承好父项目之后,由于父项目当中已经定义好了Spring Boot(spring-boot-starter-parent)的版本为2.1.9.RELEASE,所以后续在使用Spring Boot进行开发的时候都不再需要填写Spring Boot的版本号了,因为在父项目当中已经继承了spring-boot-starter-parent依赖了。

    由于子项目继承了父项目,父项目继承了spring-boot-starter-parent,所以相当于子项目也继承了spring-boot-starter-parent Spring Boot项目。

    在子项目产品服务34-springcloud-service-goods当中看到pom.xml中其

    <groupId>com.bjpowernode.springcloud</groupId>
    

    groupId标签背景为淡淡的橙黄色背景,说明该标签groupId是可以省略的,为什么可以进行省略呢,由于子项目中继承了父项目,且子项目与父项目中pom.xml中的groupId如果一致,则子项目中的groupId可以进行省略。此处由于父项目pom.xml中的groupId的取值和子项目pom.xml中的groupId的取值一样,都为com.bjpowernode.springcloud,所以此处子项目中的groupId可以进行省略,也可以不进行省略,放在这里也可以。除非子项目pom.xml中的groupId和父项目pom.xml中的groupId不一样,就不能进行省略。

    这是maven的继承关系。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IZgSTkLl-1621472105085)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512103910064.png)]

​ 开始进行写服务提供者即产品服务。

​ 该服务提供者项目的开发和原来SpringBoot项目的开发其实是有什么大的区别,即按照SpringBoot开发即可。

该Maven工程需要变成SpringBoot项目的步骤如下

  1. 子项目产品服务34-springcloud-service-goods需要继承父级依赖父项目即34-springcloud-service-parent,即需要在子项目产品服务34-springcloud-service-goods的pom.xml中配置如下

    <!-- 继承统一的父项目 -->
    <parent>
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
    </parent>
    
  2. 然后将一些配置文件(application.properties)、main方法(Application)等类文件拷贝过来即可(创建文件夹com.bjpowernode.springcloud将Application该main方法放入该文件夹中即可)。

    这样就可以变成SpringBoot项目了,因为刚刚是使用Maven进行创建的子项目产品服务34-springcloud-service-goods。

    由于后续到时候将可能有多个Application main方法,所以此处做一下区分,将该Application修改名称为GoodsApplication。

    package com.bjpowernode.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class GoodsApplication{
        public static void main(String[] args){
            SpringApplication.run(GoodsApplication.class,args);
        }
    }
    

    此处可以发现GoodsApplication该类中的@SpringBootApplication等注解还有一些类报错,找不到。

    这个时候就需要在子项目产品服务34-springcloud-service-goods的pom.xml中添加SpringBoot的相关依赖。因为这里是使用Spring Boot进行开发,这时候将Spring Boot的相关依赖添加进来。

    将如下内容放入到子项目产品服务34-springcloud-service-goods 的pom.xml中,并点击import Changes

    <name>34-springcloud-service-goods</name>
    <description>34-springcloud-service-goods project for Spring Boot</description>
    
    <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <dependencies>
        <!-- spring web 起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--此处使用内嵌的Tomcat-->
            <!--
    <!--排除内嵌的Tomcat- ->
            <exclusions>
                <exclusion>
                    <groupId>
                    	org.springframework.boot
                    </groupId>
                    <artifactId>
                    spring-boot-starter-tomcat
                    </artifactId>
                </exclusion>
            </exclusions>
    		-->
        </dependency>
    </dependencies>
    
    

    在这当中web的起步依赖已经有了,

    后续将开发的是一个web程序,为什么子项目产品服务将会是一个web程序呢?

    由于该子项目产品服务相当于是一个服务提供者,即当客户端请求后端查询产品服务的相关信息时,由于SpringCloud当中服务与服务之间的服务调用是通过RESTful API风格,也就是Controller调用Controller。所以该项目并不是一个Java项目,而是一个Web项目,需要提供Controller以供别人去进行调用。

    所以在子项目产品服务的pom.xml中添加有spring-boot-starter-web web的起步依赖。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B1JDsixK-1621472105087)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512110517600.png)]

  3. 在依赖完spring-boot-starter-web web起步依赖之后,再来看GoodsApplication该类文件时,就已经没有那么多报错内容了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U4qx3Dsy-1621472105089)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210512111141283.png)]

    然后在完成上述操作之后,该服务该怎么进行开发就怎么进行开发。

    比如说需要进行查询产品信息,那么就进行开发查询数据库那一块的内容,因为该项目依然是Spring Boot,Spring Cloud当中项目依然是Spring Boot。

    创建mapper、model、service、service impl去进行查询数据的相关文件夹在com.bjpowernode.springcloud文件夹下。

    需要进行添加mybatis的启动器,起步依赖,即自动配置起步依赖。

    mybatis以及jdbc驱动

    maven:https://mvnrepository.com/search?q=mybatis-spring-boot-starater

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xRHSl3s1-1621472105092)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210513145917448.png)]

    <!--mybatis-spring-boot-starter-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.1</version>
    </dependency>
    
    <!-- MySQL的jdbc驱动包 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    

    GoodsMapper.java

    package com.bjpowernode.springcloud.mapper;
    
    import com.bjpowernode.springcloud.model.Goods;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    @Mapper
    public interface GoodsMapper{
        
        int deleteByPrimaryKey(Integer id);
        
        int insert(Goods record);
        
        int insertSelective(Goods record);
        
        Goods selectByPrimaryKey(Integer id);
        
        int updateByPrimaryKeySelective(Goods record);
        
        int updateByPrimaryKey(Goods record);
        
        List<Goods> selectAllGoods();
        
        int updateByStore(@Param("goodsId") Integer goodsId, @Param("buyNum") Integer buyNum);
    }
    

    GoodsMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.bjpowernode.springcloud.mapper.GoodsMapper">
        <resultMap id="BaseResultMap" type="com.bjpowernode.springcloud.model.Goods">
            <id column="id" jdbcType="INTEGER" property="id" />
            <result column="name" jdbcType="VARCHAR" property="name" />
            <result column="price" jdbcType="DECIMAL" property="price" />
            <result column="store" jdbcType="INTEGER" property="store" />
        </resultMap>
        
        <sql id="Base_Column_List">
            id,name,price,store
        </sql>
        
        <select id="selectAllGoods" resultMap="BaseResultMap">
            select 
            <include refid="Base_Column_list" />
            from goods 
        </select>
        
        <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
            select 
            <include refid="Base_Column_List" />
            from goods
            where id = #{id, jdbcType=INTEGER}
        </select>
        
        <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
            delete 
            from goods
            where id = #{id, jdbcType=INTEGER}
        </delete>
        
        <insert id="insert" parameterType="com.bjpowernode.springlcoud.model.Goods">
            insert into goods(id, name, price, store)
            values(#{id, jdbcType=INTEGER}, #{name, jdbcType=VARCHAR}, #{price, jdbcType=DECIMAL}, #{store, jdbcType=INTEGER})
        </insert>
        
        
        <insert id="insertSelective" parameterType="com.bjpowernode.springcloud.model.Goods">
            insert into goods
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="id != null">
                    id,
                </if>
                <if test="name != null">
                    name,
                </if>
                <if test="price != null">
                    price,
                </if>
                <if test="store != null">
                    store,
                </if>
            </trim>
            
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="id != null">
                    #{id, jdbcType=INTEGER},
                </if>
                <if test="name != null">
                    #{name, jdbcType=VARCHAR},
                </if>
                <if test="price != null">
                    #{price, jdbcType=DECIMAL},
                </if>
                <if test="store != null">
                    #{store, jdbcType=INTEGER},
                </if>
            </trim>
        </insert>
        
        
        <update id="updateByPrimaryKeySelective" parameterType="com.bjpowernode.springcloud.model.Goods">
        update goods 
            <set>
                <if test="name != null">
                    name = #{name, jdbcType=VARCHAR},
                </if>
                <if test="price != null">
                    price = #{price, jdbcType=DECIMAL},
                </if>
                <if test="store != null">
                    store = #{store, jdbcType=INTEGER},
                </if>
            </set>
            where id = #{id, jdbcType=INTEGER}
        </update>
        
        <update id="updateByPrimaryKey" parameterType="com.bjpowernode.springcloud.model.Goods">
            update goods 
            set name = #{name, jdbcType=VARCHAR},
            price = #{price, jdbcType=DECIMAL},
            store = #{store, jdbcType=INTEGER} 
            where id = #{id, jdbcType=INTEGER}
        </update>
        
        <update id="updateByStore">
            update goods
            set store = store - #{buyNum, jdbcType=INTEGER} 
            where id = #{id, jdbcType=INTEGER}
        </update>
    </mapper>
    
    package com.bjpowernode.springcloud.service;
    
    import com.bjpowernode.springcloud.model.Goods; 
    
    import java.util.List;
    
    public interface GoodsService{
        
        public List<Goods> getAllGoods();
        
        public Goods getGoodsById(Integer goodsId);
    }
    
    package com.bjpowernode.springcloud.service.impl;
    
    import com.bjpowernode.springcloud.mapper.GoodsMapper;
    import com.bjpowernode.springcloud.model.Goods;
    import com.bjpowernode.springcloud.service.GoodsService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class GoodsServiceImpl implements GoodsService {
    
        @Autowired
        private GoodsMapper goodsMapper;
    
        public List<Goods> getAllGoods(){
            return goodsMapper.selectAllGoods();
        }
    
        public Goods getGoodsById(Integer goodsId){
            return goodsMapper.selectByPrimaryKey(goodsId);
        }
    }
    

    目录结构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joNCyqxn-1621472105093)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210513152125857.png)]

    以上接口以及实现都有了。

    像model类当中,例如Users、ResultObject等等有可能在消费者服务当中也会被使用到,所以会将model类在项目当中单独提出来使用,和dubbo开发很相似,一些model类、公共的方法、公共的工具类等等提出来,提出来即这时候新建一个项目,这个项目是一个maven项目,该项目主要提供一些model类、常用工具类、常量类等等,是一个maven项目,不是SpringBoot,就是一个maven项目。

    新建maven项目步骤:

    1. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HG3e7ZwL-1621472105094)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519120848970.png)]

    2. image-20210519121018640
    3. GroupId:com.bjpowernode.springcloud
      ArtifactId:34-springcloud-service-commons
      Version:1.0.0
      # 该项目当中放一些通用的内容
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0nKrydMG-1621472105096)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519122259600.png)]

    4. Module name:34-springcloud-service-commons
      Content root:F:\Project\UserProject\fsn\34-springcloud-service-commons
      Module file location:F:\Project\UserProject\fsn\34-springcloud-service-commons
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U8s8mlu2-1621472105098)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519122420421.png)]

    5. import Changes

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3lGOwm5-1621472105099)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519122542767.png)]

    6. 那么此时通用项目 commons就准备好了。准备好了之后,在该项目当中建立包package,包名为:com.bjpowernode.springcloud,包名新建好之后,将34-springcloud-service-goods服务当中的com.bjpowernode.springcloud包下的model包复制到34-springcloud-service-commons服务中来。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c9R72WCG-1621472105101)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519122749131.png)]

    7. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ssAs3owZ-1621472105102)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519123131177.png)]

不记录这么详细了,就自己实操一边先

3、服务消费方 直接调用 服务提供方

我们知道,SpringCloud 构建微服务是基于 SpringBoot开发的。

也就是 刚刚的案例当中,服务消费方直接调用服务提供方,通过服务提供方提供的一个地址去进行调用即可。

  1. 创建一个SpringBoot工程,并且添加SpringBoot的相关依赖;

  2. 创建服务提供者的访问方法,也就是后续 消费者如何访问提供者;

    Spring Cloud 是基于 rest 的访问,所以我们添加一个 Controller,在该 Controller 中提供一个 访问入口:

    @RestController
    public class GoodsController{
        
        @Autowired
        private GoodsService goodsService;
        
        /*
        * 查询所有商品
        * @param model
        * @return 
        */
        @GetMapping("/service/goods")
        public ResultObject goods(Model model){
            List<Goods> goodsList = goodsService.getAllGoods();
            return new ResultObject(Constant.ZERO, "查询成功", goodsList);
        }
    }
    
  3. 启动运行该 SpringBoot 程序,访问该 controller。

服务消费者 也是一个 SpringBoot项目,服务消费者 主要用来 消费服务提供者 提供的服务;

  1. 创建一个 SpringBoot 工程,并且添加 SpringBoot的相关依赖;

  2. 开发一个消费者方法,去消费服务提供者提供的服务,这个消费者方法也是一个Controller

    @RequestMapping("/cloud/goods")
    public @ResponseBody Object goods(Model model){
        ResponseEntity<ResultObject> responseEntity = restTemplate.getForEntity(GOODS_URL_01, ResultObject.class);
        int statusCodeValue = responseEntity.getStatusCodeValue();
        HttpStatus httpStatus = responseEntity.getStatusCode();
       HttpHeaders httpHeaders = responseEntity.getHeaders();
        ResultObject body = responseEntity.getBody();//最终的数据
        
        System.out.println(statusCodeValue);
        System.out.println(httpStatus);
        System.out.println(httpHeaders);
        System.out.println(body);
        
        model.addAttribute("goodsList", body.getData());
       return body;
    }
    
  3. 启动该 SpringBoot程序,测试服务消费者调用服务提供者;

上述中消费方直接调用服务提供方就完成了。

在上述步骤中还并没有使用到 spring cloud。

我们仅仅使用了 RestTemplate 类来进行调用。那么该 RestTemplate是 spring自带的。它本身存在于spring中,所属包 package org.springframework.web.client;

所以controller与controller之间的调用即使不使用springcloud也可以使用restTemplate去进行调用。

那么接下来就开始引入spring cloud 的组件。

4、 服务注册与发现

那么第一个组件就是 注册中心 组件。上述是直接通过Spring中的RestTemplate调用,没有使用SpringCloud 的注册中心。

前面的例子,我们看到了,是通过 手动指定 每个服务 来实现调用的,这是相当低效的,当服务接口增多,这种手动指定接口地址的方式 变得 非常难以维护

//产品服务的接口地址
private static final String GOODS_SERVICE_URL = "http://localhost:9100/service/goods";
//...
//那么这个时候就需要有注册中心将这些服务的接口地址放到注册中心上

Spring Cloud 提供了 多种服务注册与发现的实现方式,例如:Eureka、Consul、Zookeeper。

Spring Cloud 支持得最好的是 Eureka,其次是 Consul,再次是 Zookeeper。(最早一出来就是Eureka,Eureka目前停止更新维护了,Eureka是Netflix公司的一个产品,除了Eureka之外还有其他的方案,如Consul、Zookeeper等,包括还有国内还有一些产品 阿波罗,百度的…等,大部分公司开发的时候注服务的注册发现还是使用Eureka,虽然它停止更新了,目前的现状这是,可能也有公司会慢慢转向其他的一些产品)

什么是服务注册,原来学过dubbo的话就比较清楚了,将服务在注册中心登记一下,原来dubbo就是这样处理的,将API端口、服务名称放上去。

什么是服务注册?

服务注册:将服务所在 主机、端口号、版本号、通信协议等信息登记到注册中心上。

什么是服务发现?

服务发现:服务消费者向 注册中心 请求已经登记的服务列表,然后得到某个服务的 主机、端口、版本号、通信协议等信息,从而实现对具体服务的调用;

服务发现可以说是 服务订阅,订阅这个服务。

可以认为服务发现是到注册中心上将服务提供者注册到注册中心的接口地址拿到,拿到之后就可以进行调用服务提供方提供的服务了。

和dubbo比较类似,在原理上是差不多的。

Eureka是什么?

Eureka注册中心。

Netflix即国外专门做版权视频的一个公司,同时它也是做云服务的一个公司。该公司下有着很多的开源产品,比如说阿里、百度等旗下都有一些开源产品。那么Eureka就是Netflix公司在GitHub上开源的一个产品,作为注册中心来使用的。

Eureka 是 Netflix 的子模块之一,也是一个核心的模块,Eureka 采用了 C-S(客户端/服务端)的设计架构,也就是 Eureka 由两个组件组成:Eureka服务端和Eureka客户端。

Eureka Server(一个独立的项目)用于注册服务 以及 实现服务的 负载均衡 和 故障转移,它是 服务的 注册中心,

Eureka Client(我们的微服务)它是用于与 Eureka Server交互(我们的服务即Eureka Client客户端与Eureka Server服务端进行交互),获取其上注册的服务(不需要去记住接口地址),使得交互变得非常简单,只需要通过 服务标识 即可拿到服务(其实就是从Eureka Server上获取拿到接口地址,也不需要自己去记住接口地址,即代码层当中的GOODS_SERVICE_URL就不再需要了)。

(我们的服务要注册到Eureka Server上面去,那么我们的服务即Eureka Client,即称为客户端,那么其服务端就是一个单独的项目,需要去单独部署运行;)

与 spring-cloud 的关系:

Eureka 是 Netflix 公司开发的(一家做版权视频和云服务的公司),Spring Cloud封装了 Netflix 公司开发的 Eureka 模块来 实现服务的注册和发现,也就是说 Spring Cloud对 Netflix Eureka做了二次封装。

Spring Cloud将Netflix Eureka 拿进来整合了一下,方便Spring Cloud采用Netflix Eureka来做服务注册中心,方便使用。

所以也就是Spring家族很多的东西不是其自身发明的轮子,而是使用别人的轮子,自己再做一个整合,即整合这个组件,整合那个组件,即整合mybatis、整合hibernate、整合rabbitmq、整合mongodb等等,什么东西都可以进行整合,在它基础上再做了一层包装,让开发者可以结合使用。

Eureka是Netflix公司开发并开源的。

角色关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V1l766CC-1621472105104)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210519162912996.png)]

Eureka Server :注册中心

Service Consumer:消费者

Service Provider: 提供者

消费者、提供者都可以向注册中心注册并订阅服务,拿到接口信息。

搭建与配置 Eureka 服务注册中心

Spring Cloud 要使用 Eureka 注册中心非常简单和方便,

Spring Cloud中的Eureka 服务注册中心 实际上也是一个 Spring Boot 工程,

我们只需要通过 引入 相关 依赖注解配置 就能让 Spring Boot 构建的微服务应用轻松地与 Eureka进行整合。

接下来进行搭建Eureka注册中心,将其搭起来,然后服务就可以在注册中心Eureka上面使用了。就不再是通过restTemplate去调用远程接口了。

再建立一个项目

Eureka Server依然是一个 Spring Boot项目,

Spring Cloud 由于将Eureka做了一个包装,所以开发的时候每个项目都是Spring Boot。

具体步骤如下:

  1. 创建一个 SpringBoot项目,并且添加 SpringBoot的相关依赖。

    03-springcloud-eureka-server

  2. 添加 Eureka的依赖

    <!--Spring Cloud 的 eureka-server 起步依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    
  3. 在 SpringBoot 的入口类上 添加一个 @EnableEurekaServer注解,用于开启 Eureka 注册中心服务端

  4. 在 application.properties 文件配置 Eureka 服务注册中心信息:

    #在application.properties 该核心文件当中指定一下内嵌tomcat端口是多少
    
    #内嵌定死tomcat 的端口
    server.port=8761
    
    # 服务的hostname,本地的 localhost
    #设置该服务注册中心的 hostname
    eureka.instance.hostname=localhost
    
    # register-with-eureka 注册使用Eureka
    # 因为 eureka-server 该项目本身也是一个微服务,spingboot开发的项目web应用,微服务;那么这个微服务的话会默认自己向自己进行注册
    # 修改为false的原因在于,自己只是作为注册中心,自己并不代表其他服务,不代表服务提供者或者服务消费者,所以不要将自己本身 注册中心 往注册中心也就是自己 进行注册
    # 应该是可以理解为 自己该服务并不提供业务服务出去也不会进行消费业务服务,
    # 由于我们目前创建的应用是一个 服务注册中心,而不是普通的应用,默认情况下,这个应用会向注册中心(也是它自己)注册它自己
    # 设置为false,表示禁止这种 自己向自己注册的默认行为
    eureka.client.register-with-eureka=false
    
    # 修改为false 即 不要去检查其他服务,由于自己本身就是注册中心,不用去检索其他服务
    # fetch 获取
    # 表示不去从服务端 检索 其他服务信息,因为自己就是服务端,服务注册中心本身的职责就是维护服务实例,它不需要去检索其他服务
    # 即不需要去订阅其他的服务,去发现其他的服务
    eureka.client.fetch-registry=false
    
    # 也就是注册中心的路径,可以理解为对外提供的注册接口的地址
    # 即http://eureka.instance.hostname + : + eureka-server.server.port + /eureka
    # 表示注册中心到时候提供的服务是这个接口地址,其他子服务 通过这个接口地址向注册中心注册服务即可,它就可以接应到
    # eureka-server本身也提供了对外的一个接口,然后其他子服务 往这个接口去进行注册即可,对外暴露该接口,然后其余子服务向该接口注册服务即可
    # 指定服务注册中心的位置
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    
    
    # 一般情况下配置如上
    # eureka.  后面会有很多的配置信息,有一些配置存在有默认值,
    # springboot当中不管集成什么,都会有一大堆这样类似的配置;不需要每一个配置都去看一遍,使用一些常用的即可
    # 上述配置完成之后,进行启动与测试 Eureka 服务注册中心
    # 1. 完成上面的项目搭建后,我们就可以启动springboot程序, main方法运行
    # 2. 启动成功之后,通过在浏览器地址栏访问我们的注册中心;
    
    
    
    
    启动与测试 Eureka 服务注册中心
  5. 完成上面的项目搭建后,我们就可以启动 springboot 程序,main 方法运行;

  6. 启动成功之后,通过在浏览器地址栏访问我们的注册中心;

3-7. 向 Eureka 服务注册中心注册服务

我们前面搭建了 服务提供者项目(goods),接下来我们就可以将该 服务提供者注册到 Eureka注册中心,步骤如下:

  1. 在该服务提供者中添加 Eureka的依赖,因为服务提供者向注册中心注册服务,需要连接 eureka,所以需要 eureka客户端的支持;

    <!--spring-cloud-starter-netflix-eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  2. 激活 Eureka中的 EnableEurekaClient 功能:在 SpringBoot 的入口函数处,通过添加 @EnableEurekaClient 注解来表明自己是一个 eureka客户端,让我的服务提供者 可以连接 eureka 注册中心;

  3. 配置服务名称和注册中心地址

    # 在添加完 eureka client 依赖之后,接着进行配置 eureka client相关内容
    # 配置服务名称和注册中心地址
    # 每间隔 2s,向服务端发送一次心跳,证明自己依然 “存活”
    #lease 最近的 renewal 续约的 interval 间隔 seconds 秒
    # goods服务提供者同时也是 eureka client客户端,eureka client客户端是注册到服务端 eureka server,注册到注册中心
    # 下面该表示 eureka client 每隔2s 会给 eureka server服务端发送一次心跳,告诉eureka server服务端该服务提供者 该eureka client 客户端没有宕机
    # 让服务端 eureka server知道
    eureka.instance.lease-renewal-interval-in-seconds=2
    
    # 告诉服务端,如果我 10s 之内没有给你发心跳,就代表我故障了,将我踢出掉
    # 即在10s内,如果eureka client客户端没有给 eureka server服务端发送心跳,就让服务端 eureka server认为该 eureka client客户端已经宕机了,让其将该eureka client进行剔除掉
    # 如果有别的服务需要调用该goods服务的话,那么由于10s内该eureka client没有给eureka server发送心跳被剔除之后就没有办法再次调用该,本服务了
    # 就调用不到了,要不就调用别的另外一个服务,即可能本服务goods该服务进行部署了多份,比如说该服务进行部署了三份,当前该份服务宕机了之后,其余的两份服务并没有宕机
    # 将该份宕机的服务剔除掉了之后,那么有别的服务需要调用的时候,就让它去调用另外那两份没有宕机的服务
    eureka.instance.lease-expiration-duration-in-seconds=10
    
    # 这个心跳原理是什么?一直不太理解,类似于ping 吗?
    # 心跳原理即 eureka client 每隔一段时间就发送一个信息给eureka server服务端,不同的注册中心服务端与注册中心客户端发的内容有所不同
    # 比如说redis的redis-client会向redis-server发送一个ping,这个时候redis-server就会返回redis-client一个pong
    # 比如说mysql的话,心跳则是做一次select查询,select 1、select user等作为查询,那么它这个里面,它进行发心跳就可能是发送一个字符串之类的信息
    # 这个需要具体看一下它的源码实现,看eureka的源码,具体是发送什么信息需要看源码才能知道
    # 即eureka client发送个信息过去然后 eureka server 接收到了,代表着eureka client客户端是活着的,存活着的心跳
    # 不同的应用都存在有这样的机制,很多都有,redis、mysql 一些的服务都有它们的心跳机制,即发送个信息过去
    
    
    #告诉服务端,服务实例以 IP 为链接,而不是取 机器名
    # 等运行之后再看效果,在后台可以看到,链接地址默认是取的机器名称;这里修改为true表示默认取ip;这个配不配置都没有太大关系
    eureka.instance.prefer-ip-address=true
    
    # 告诉服务端,服务实例的名字
    # 即当前goods 服务提供者 eureka client向 服务注册中心注册服务了,给出服务提供者的名称,
    # 即给出 eureka server服务端,该eureka client客户端的名称;相当于对自己的服务做了一个标记,标记一下自己
    eureka.instance.instance-id=34-springcloud-service-goods
    
    # eureka 注册中心的连接地址
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    
    # 就像dubbo当中连接zookeeper一样,在dubbo程序当中连接zookeeper,肯定要在dubbo程序当中配置zookeeper的ip、端口;那么此处也是一样
    # 要进行配置 eureka-server服务端的ip 端口 eureka client要向 eureka server注册中心进行注册,那么首先需要知道 eureka server注册中心的接口地址是什么,才能往这个接口地址当中进行注册
    # http://localhost:8761/eureka 这个就是eureka server 服务端所提供的接口地址,当时指定了服务注册中心的路径 eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    # eureka server 对外提供服务的接口地址路径即 http://localhost:8761/eureka
    # 所以在eureka client当中填写 注册中心的连接地址时就需要填写上面这个地址,就相当于要将这个goods服务注册到这个地址上去
    
    # 以上配置完成之后,停止GoodsApplication之后重新启动该GoodsApplication
    # 重新启动成功之后就将注册到 eureka server服务注册中心上去了
    # 看到http://127.0.0.1:8761 首页进行刷新
    # 首页HOME中的 DS Replicas 下的 Instances currently registered with Eureka 下的表格栏 Application     AMIs        Availability Zones      Status下有一行记录
    # 记录值为: UNKNOWN      n/a(1)      (1)       UP(-1)-34-springcloud-service-goods
    
    #以及此时再去看http://127.0.0.1:8761 的菜单 LAST 1000 SINCE STARTUP中的 DS Replicas 下的 LAST 1000 newly  registered leases 下的表格栏 Timestamp       Lease下的记录值
    #记录值为   2021-5-19 23:14:06          UNKNOWN(34-springcloud-service-goods)
    # 表明该服务注册了
    
    # 这两处当中都有一个问题,即UNKNOWN
    # 该记录值Application 所对应的取值为UNKNOWN,有点不正常,需要进行调整,服务注册是ok的
    # spring应用名称 添加完成之后将服务提供者goods重启;需要到main方法当中去进行添加@EnableEurekaClient注解
    # 然后再去看http://127.0.0.1:8761 进行刷新,发现UNKNOWN就变为了下面的spring应用名称
    # 此时在首页HOME的表格Application...中有两条记录,但是UNKNOWN 这一条由于经过重启变为了34-springcloud-service-goods,则该条记录将在一段时间后消失掉;
    # 点击Status 字段下的服务提供者名称超链接,超链接的地址为http://192.168.0.104:9100/actuator/info  actuator 监控功能 所以此处点击它即打开了项目的服务监控功能,即项目需要配置一下项目监控功能,这样的话到时候点击超链接进去就可以看到,没有配置的话否则就会点进去报错;没有配置该actuator的功能
    # Application代表spring 服务提供者应用名称  Status当中取值为UP 代表是开着的是正常的
    spring.application.name=34-springcloud-service-goods
    
    # 提示有 EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT .
    # RENEWALS ARE LESSER THAN  THRESHOLD  HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFF.
    #即:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
    # 这个是一个安全模式,后续解释
    
    # 在消费者项目当中也是如此步骤 1.添加依赖 2. application.properties 配置eureka client以及eureka server url 3.写代码
    
  4. 启动服务提供者SpringBoot程序的main方法运行;

  5. 启动运行之后,通过在浏览器地址访问我们之前搭建好的eureka注册中心,就可以看到有一个服务已经注册成功了。

3-8. 从 Eureka 服务注册中心 发现与消费 服务

在服务注册已经ok的情况下,继续下面的步骤。然后就是需要从Eureka服务注册中心进行 发现与消费服务, 消费服务,即调用该服务。之前是通过spring中的restTemplate进行直接调用的,那么现在是需要通过注册中心的方式获取得到这个服务以后,然后再去调用。

我们已经搭建一个服务注册中心,同时也向这个服务注册中心注册了服务,接下来我们就可以 发现和消费服务了,这其中 服务的发现 由eureka客户端实现,而服务的消费 由 Ribbon 实现(这个组件后续还会进行介绍,底层使用到了Ribbon),也就是说服务的调用需要 eureka客户端和 Ribbon,两者配合起来才能实现;(发现和调用,首先要找到这个服务才能够进行调用这个服务,两者结合起来)

Eureka客户端 是一个 Java客户端,用来连接 Eureka服务端,与服务端进行交互、负载均衡,服务的故障切换等;

Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡器,当使用 Ribbon对服务进行访问的时候,它会扩展 Eureka客户端的服务发现功能,实现从 Eureka注册中心中 获取服务端列表,并通过 Eureka客户端来确定服务端是否已经启动。(在这当中使用到了Ribbon,可以看jar包依赖,它其中本身就有依赖到Ribbon,看消费者portal项目或者goods项目都可以,只要有spring-cloud-starter-netflix-eureka-client依赖都可以看到)

  • org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:2.1.3.RELEASE
    • org.springframework.cloud:spring-cloud-starter:2.1.3.RELEASE
    • org.springframework.cloud:spring-cloud-netflix-hystrix:2.1.3.RELEASE
    • org.springframework.cloud:spring-cloud-netflix-eureka-client:2.1.3.RELEASE
    • com.netflix.eureka:eureka-client:1.9.13
    • com.netflix.eureka:eureka-core:1.9.13
    • org.springframework.cloud:spring-cloud-starter-netflix-archaius:2.1.3.RELEASE
    • org.springframework.cloud:spring-cloud-starter-netflix-ribbon:2.1.3.RELEASE
    • com.netflix.ribbon:ribbon-eureka:2.3.0
    • com.thoughtworks.xstream:xstream:1.4.11.1

在该spring-cloud-starter-netflix-eureka-client依赖当中,该依赖又依赖了有关于ribbon的依赖,即com.netflix.ribbon:ribbon-eureka:2.3.0

Ribbon 在 Eureka 客户端 服务发现的基础上,实现了 对服务实例的选择策略,从而实现对服务的负载均衡。(Ribbon在后续会进一步讲解,当前暂时只是用一下这个组件;因为Eureka客户端client本身底层有依赖这个组件,然后用它Ribbon来进行消费)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lb0ISQ93-1621472119059)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520003241478.png)]

接下来我们来让 消费者去消费服务(通过注册中心的方式发现服务并通过Ribbon消费服务):

我们前面搭建了 服务消费者项目,接下来我们就可以使用该 服务消费者 通过 注册中心 去调用 服务提供者,步骤如下:

  1. 在该 消费者项目 中添加 eureka 的依赖,因为 服务消费者 从注册中心 获取服务,需要连接 eureka,所以需要 eureka 客户端的支持;

    <!--spring-cloud-starter-netflix-eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  2. 激活 Eureka 中的 EnableEurekaClient 功能,在Spring Boot 的入口函数处,通过添加 @EnbaleEurekaClient 注解来表明自己是一个 eureka 客户端,让我的消费者 可以使用 eureka 注册中心(进行发现服务)。

  3. 配置服务的名称和注册的地址

    spring.application.name=03-springcloud-web-consumer
    eureka.client.service-url.defaultZone=http://localhost:8761/eureka
    
  4. 前面我介绍了 服务的发现由eureka 客户端实现,而服务的真正调用由Ribbon 实现,所以我们需要在 调用服务提供者时 使用ribbon来调用:

    @LoadBalanced //使用Ribbon实现负载均衡的调用,Ribbon的一个注解叫做负载均衡 LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    

    加入了 ribbon的支持,那么在调用时,即可改为使用 服务名称来访问:(后续通过服务的名称去进行调用即可,该名称即相当于服务的标识,通过其标识去调用我们消费者需要的服务,相当于该标识=ip+端口,这个标识等价于ip+端口,这样去进行调用)

    restTemplate.getForEntity("http://34-SPRINGCOUD-SERVICE-GOODS/service/goods", String.class).getBody();
    
  5. 完成上面的步骤后,我们就可以启动 消费者的 SpringBoot程序,main方法

  6. 启动成功之后,通过在浏览器地址栏访问我们的消费者,看是否可以正常调用远程服务提供者提供的服务;

先将前端项目进行关闭portal项目关闭。

Eureka 与 Zookeeper的比较

著名的 CAP 理论指出,一个 分布式系统 不可能同时满足 C(一致性)、A(可用性)和P(分区容错性)。

由于 P(分区容错性)是在 分布式系统 中必须要保证的,因此我们只能在 A(可用性)和C(一致性)之间进行权衡,在此 Zookeeper 保证的是CP(即一致性和分区容错性),而Eureka则是AP(即可用性和分区容错性)。

两种方案:

Zookeeper 保证 CP(一致性、分区容错性)

在 Zookeeper中,当 master 结点因为 网络故障 与其他结点失去联系,剩余结点会重新进行 leader选举,但是问题在于,选举leader需要一定时间,且选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务瘫痪。

在云部署的环境下,因网络问题使得Zookeeper集群失去master结点是大概率事件,虽然服务最终能够恢复,但是在选举时间内导致服务注册长期不可用是难以容忍的。

(在选举期间整个服务是不能够进行注册的,即注册不了,由于选举确实是需要一点时间的,多少毫秒、或者是多少秒的时间。在这个毫秒或者秒的时间之内没有办法进行服务的注册,就相当于是服务的不可用)

即Zookeeper的这种注册方式,在其选举期间是不能够进行注册服务的,那么这个时候就相当于服务进行注册但是报错了,日志当中抛出了异常,服务不可用。

所以Zookeeper保证的是数据的一致性C和分区容错性P。所以Zookeeper是牺牲掉了可用性A(选举的时候没有办法注册,没有可用性,可用性不强,但是其保证了数据的一致性)。

Eureka 保证 AP(可用性、分区容错性)

Eureka 优先保证 可用性,Eureka 各个结点是平等的,某几个结点挂掉不会影响 正常结点的工作,剩余的节点 依然可以提供 注册和查询 服务。

而Eureka 的 客户端在向 某个 Eureka 注册或是 如果发现 连接失败(Eureka集群有多个,其中一个Eureka连接不上时会切换到另外一个节点Eureka上),则会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。(比如说Eureka部署了三台,其中一台Eureka宕机了,但是依然可以注册服务,通过其余剩下的没有出现宕机的两台Eureka,这一台Eureka服务宕机不行了会自动切换到另外一台Eureka上去,还可以进行服务注册,优先保证了服务的可用性,除非三台Eureka都宕机了,那就没有办法注册服务了。不保证强一致性的原因: 比如说Eureka有三台进行部署了服务,a订单服务注册到了第一台Eureka注册中心当中,[后续会说到Eureka的集群],有三台Eureka,以及存在一些微服务到这三台Eureka当中进行注册,刚刚说到的a订单服务到第一台Eureka进行注册服务,但是这个时候出现了状况,即a订单服务向第一台Eureka注册了服务之后,第一台Eureka马上就宕机了,而此时另外一个服务正好在第一台Eureka宕机的时候要进行访问a订单服务,而在第一台Eureka服务宕机之后,就会切换到第二台剩余的没有宕机的Eureka服务,另外一个服务需要访问Eureka发现a订单服务肯定不会去访问第一台的Eureka,因为第一台宕机会自动切换到第二台,而第二台Eureka服务注册中心中并没有a 订单服务的服务注册,所以此时另外一个服务在第二台Eureka上是拿不到a 订单服务的,因为Eureka不保证强一致性,即注册到第一台Eureka上去之后,第一台Eureka有可能出现马上宕机的情况,而第二台第三台Eureka是没有服务的注册信息的;而但是如果不是马上宕机的话,第一台Eureka上的服务注册信息是会往第二台第三台Eureka上进行复制服务注册信息的,即稍微等待片刻之后,第二台Eureka和第三台Eureka也会有服务的相关注册信息,第一台Eureka当中的注册信息会复制到第二台和第三台Eureka中来,那么此时第一台Eureka没有马上宕机的话,稍等片刻后,等待第一台的Eureka中的服务注册信息复制到第二台第三条Eureka上之后,第一台Eureka再宕机,这个时候,另外一个服务在第二台或者第三台Eureka上是可以查询得到注册的a 订单服务的相关信息的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TJywCUyX-1621472119063)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520020115665.png)]

所以 Eureka在 网络故障导致部分节点失去联系的情况下,只要有一个节点可用,那么注册和查询服务就可以正常使用,而不会像 zookeeper那样使整个注册服务瘫痪,Eureka优先保证了可用性。

Eureka不保证一致性。如果是Zookeeper的master节点宕机的情况下,之后会有一个选举的过程,master节点宕机之后,即后面两个节点之间都在选举过程中,都是连接不上的,没有办法去连接,因此就没有办法保证可用性了,而是保证的一致性。

不能连接,即不能用。虽然不能使用但是它保证了数据的一致性。即数据的复制是已经复制过来到从结点上,但是由于leader的选举问题从而导致服务不可注册不可用。而且zookeeper就是说在master节点写了数据之后,master将会发一个确认给两个从结点机器,收到超过半数机器的确认以后,master节点机器才会进行持久化操作,不然的话master节点机器写该数据是没有写成功的。比如说master节点在写了数据之后马上宕机了,而该数据并没有持久化,因为写数据的这一个操作并没有得到半数从结点机器的确认,这个时候就相当于master主节点机器写操作失败了。master节点机器需要等两个从结点机器确认之后,才进行写操作,才成功。所以zookeeper从而保证了数据的一致性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cn5PLgVp-1621472119065)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520020318256.png)]

C(一致性)即数据的一致性,数据不会出现不一致的情况。比如说这个服务的数据是1,那个服务的数据是2,而应该两个服务的数据都是1,这样才表示数据是一致的。

A(可用性)比较好理解,即服务的可用,该服务能不能用,能不能访问,有没有宕机,这个是可用性。

P(分区容错性)不太好理解,分区容错性的意思就是我的服务并没有问题,但是由于网络的原因,网络这个时候中断了,然后另外一个服务来进行访问该服务的时候发现访问不了,但是其实该服务并没有任何问题,只是网络的原因,比如说网络突然的一个抖动、中断等问题,瞬间中断一小会儿,毫秒级别的一个闪断,那么这个情况下就可以叫做分区容错性。一般情况下是由于外部网络等原因造成的问题,不可避免,叫做分区容错性。

以上就是 Eureka和Zookeeper之间的比较。Zookeeper保证数据的一致性,Eureka保证服务的可用性。

而分区容错性P为什么需要保证呢?

即因为需要保证网络没有问题,不能说因为网络的断开,人为的断开。网络原因导致的话是偶尔的情况。人为的断开肯定不行。分区容错性是Eureka和Zookeeper都要进行保证的,网络不能断了,网路断了就没有办法工作了。所以网络不能断。P分区容错性主要是指网络的中断、闪断的这种情况。

协调服务-一致性-zookeeper

可用性-eureka(对生产环境的影响最小化,只要有一个eureka在,服务注册中心即可用,但是数据并不保证强一致性,对于保证数据一致性会有点影响,即服务注册成功之后,第一台Eureka马上宕机后,到第另外一个eureka上面去进行查询的时候发现该服务没有注册,没有该服务的相关信息,即第一台eureka没有同步到第二台第三台eureka上,没有同步过来,也是eureka的一个问题)

Eureka 注册中心 高可用集群

这节课先搭建一下eureka集群,下节课再在这个基础之上再进行操作。也就是环境搭建好之后,就直接在项目工程当中进行使用了,后续就直接在项目工程当中写代码了。当前需要做eureka集群,目前的话是只有一台eureka注册中心的。注册中心一般会有集群。后续的注册中心就直接使用集群的模式。

在微服务架构的这种 分布式系统中,我们要充分考虑各个 微服务组件的高可用性问题,不能有单点故障,由于注册中心 eureka 本身也是一个服务,如果它只有一个节点,那么它有可能发生故障,这样我们就不能注册与查询服务了,所以我们需要一个高可用的服务注册中心,这就需要通过注册中心集群来解决。(搭建三台或者几台)

eureka服务注册中心 它本身也是一个服务,它也可以看做是一个提供者,又可以看做是一个消费者,我们之前通过配置:

eureka.client.register-with-eureka=false 让注册中心不注册自己,但是我们可以向其他注册中心注册自己。

Eureka Server的 高可用 实际上就是将自己 作为服务 向其他服务注册中心注册自己(自身也是一个服务,eureka有三台的话,那么就是相互进行注册,将每一个都看做是一个服务,eureka除去自身将其他的服务/eureka注册中心都当成服务,向自己注册,其余也是一样;三台eureka服务两两注册),这样就会形成一组互相注册的服务注册中心,进而实现 服务清单的互相同步(数据也会进行复制),往注册中心 A 上注册的服务,可以被复制同步到注册中心B上,所以从任何一台注册中心上都能查询到已经被注册的服务,从而达到高可用的效果。(注册完成之后,数据会同步会复制)

集群思路如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-moegtIf5-1621586775387)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520143836041.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4N1J4Ha7-1621586775390)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520144101550.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPrcRuE1-1621586775392)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520144118727.png)]

eureka server之间进行相互数据复制。

现在搭建一下这个eureka集群环境。

Eureka 注册中心 高可用集群搭建

搭建eureka server 注册中心步骤:

  1. 添加依赖 spring-cloud-starter-netflix-eureka-server

  2. 配文件,配置application.properties有关eureka server的相关内容配置

    #设置该服务注册中心的hostname
    eureka.instance.hostname=localhost
    #由于我们目前创建的应用是一个服务注册中心,而不是普通的应用,默认情况下,这个应用会向自己注册服务
    eureka.client.register-with-eureka=false
    #表示不去从服务端检索其他服务信息,因为自己就是服务端,服务注册中心本身的职责就是维护
    eureka.client.fetch-registry=false
    #指定服务注册中心的位置
    eureka.client.service-url.defualtZone=http://localhost:8761/eureka
    
  3. 写内容,在main方法中添加@EnableEurekaServer注解

当前 34-springcloud-service-eureka已经是一个完整正常的服务注册中心,那么当下需要三份eureka注册中心,即将34-springcloud-service-eureka项目进行复制三份即可。而复制三份这个操作,可以使用多文件来进行实现,之前有在springboot当中讲过多文件的方式,即多环境配置。还有一个办法就是将该项目程序进行拷贝三份(太麻烦了,程序、配置都一样,没有必要,所以使用多配置文件的形式去做eureka集群就可以了)。这是两种做法。

第一种办法多文件环境配置,即复制三份application.properties文件出来,分别命名为application-eureka8761.properties、application-eureka8762.properties、application-eureka8763.properties这三个文件(三个注册中心)

我们知道,Eureka注册中心高可用集群 就是各个 注册中心相互注册,所以:

  1. 在8761的配置文件中,让它的 service-url 指向8762,在8762的配置文件中让它的service-url指向 8761。

  2. 由于 8761 和 8762 互相指向双方,实际上我们构建了一个 双节点的服务注册中心集群。(在当前的项目当中已经搭建了 34-springcloud-service-eureka)

    eureka.client.service-url.defaultZone=http://eureka8762:8762/eureka,http://eureka8762:8763/eureka/
    
    eureka.client.service-url.defaultZone=http://eureka8761:8761/eureka/
    

    (需要进行修改一下 host ip的名字,为什么要改这个host ip名字呢?在host 上面去配置像 eureka8761、eureka8762、eureka8763这种形式的名字,搭建集群的时候才能够进行识别,否则无法进行识别;

    即在eureka-server项目当中的application-eureka8763.properties中的配置 eureka.client.service-url.defaultZone=http://localhost:8761/eureka,http://localhost:8762/eureka 中的localhost即本地的127.0.0.1,但是需要将其替换成 eureka8761、eureka8762这种形式的名字,进行修改hosts文件。搭建eureka集群的时候需要进行修改这个hosts文件,通过eureka8761、eureka8762、eureka8763这种名称去替换掉127.0.0.1以及localhost

    然后在本地 hosts 文件配置:C:\Windows\System32\drivers\etc\hosts

    127.0.0.1 eureka8761
    127.0.0.1 eureka8762
    127.0.0.1 eureka8763
    

    通过上述方式进行指定名称,指定名称完成之后如何进行区别,搭建eureka集群需要使用hosts修改名称的这种方式,如果不使用这种方式就将出现问题。(之前做rabbitmq镜像队列的时候,也是进行修改hosts文件,通过修改名称…)

    运行时,在运行配置项目 Program Arguments 中配置:

    --spring.profiles.active=eureka8761
    --spring.profiles.active=eureka8762
    --spring.profiles.active=eureka8763  
    

    分别启动两个注册中心,访问两个注册中心页面,观察注册中心页面是否正常。

    --spring.profiles.active 这是表示激活哪个文件,当前激活的是applicaition-eureka8761.properties

    在激活文件的时候讲过,如果要激活application-eureka8761.properties文件,则在--spring.profiles.active=后面的取值即为application-后面的那个单词/内容(除去.properties)。即该eureka server运行的时候是通过该文件进行运行服务的。

    通过idea的edit configuration的Spring Boot中复制程序,将EurekaApplication修改为EurekaApplication8761之后,点击它并进行复制两个出来,名为EurekaApplication8762和EurekaApplication8763。

    此处就有三个EurekaApplication了,到时候运行这三个EurekaApplicatin程序即可。

    将之前的EurekaApplication关闭,在重新启动EurekaApplication8761。

Eureka 注册中心高可用集群测试

在要进行注册的服务配置:

#eureka 注册中心的连接地址
eureka.client.service-url.defaultZone=http://eureka8761:8761/eureka,http://eureka8762:8762/eureka,http://eureka8763:8763/eureka

启动服务提供者服务/服务消费者服务,然后观察注册中心页面,可以看到服务会在两个注册中心上都注册成功;

集群的注册中心打包发布

在 真实项目 中,需要将 Eureka 发布到具体服务器上进行执行,打包部署其实和 springboot 里面讲的大同小异,对于 properties文件,不同的环境会有不同的配置文件,比如application-dev.properties,application-test.properties,application-pro.properties等;

运行在8761端口上:java -jar springcloud-eureka-server.java

运行其他两个 profile 配置:

java -jar spring-eureka-server.jar --spring.profiles.active=eureka8762

java -jar spring-eureka-server.jar --spring.profiles.active=eureka8763

后续在环境当中就不再搭建eureka集群了。就将其他的一些组件之类的编码使用了。

SpringCloud注册中心Eureka注册中心打包(有点小问题后续解决)

将集群的注册中心进行打包一下

打包发布的意思即,注册中心集群已经在本地电脑上已经启动起来了,已经弄好了,但是下次每次要使用eureka服务的时候,都需要启动这三个服务eureka8761、eureka8762、eureka8763,这样很麻烦,而且占用机器的内存,干脆就将这个注册中心集群部署到linux环境当中,下次直接在项目当中访问linux当中的eureka注册中心即可。在linux环境上进行发布部署,该eureka 注册中心 集群都不在需要在本地保留了,这就叫做发布。

注册中心的发布和springboot项目一样,且eureka本身就是一个springboot项目程序。

springboot当中可以进行war包部署,jar包部署。

springboot程序默认打jar包。后面跟着参数激活一下对应的配置文件即可。(--spring.profiles.active=eureka876X

使用Maven工具Lifecycle中的package即可。

打包时报错:

Non-resolvable parent POM for com.bjpowernode.springcloud:34-springcloud-service-eureka:1.0.0: Failure to find com.bjpowernode.springcloud:34-springcloud-service-parent:pom:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at wrong local POM @ line 12, column 13 -> [Help 2]

报错原因在于:当前使用了父项目即34-springcloud-service-parent,父项目并没有打包。

eureka-server项目上有统一的父依赖即34-springcloud-service-parent

<!--
    该当前项目依然是SpringBoot项目,和之前一样
    1. 首先继承父依赖 parent,有一个统一的父依赖 继承统一的父依赖,从goods服务中的pom.xml中粘贴过来或者 portal中的pom.xml粘贴过来即可
    -->
    <!-- 统一继承的父项目 -->
    <parent>
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
    </parent>

在父项目当中进行聚合操作,聚合各个子项目。通过module进行聚合一下。

<modules>
    <module>../34-springcloud-service-commons</module>
    <module>../34-springcloud-service-eureka</module>
    <module>../34-springcloud-service-goods</module>
    <module>../34-springcloud-service-portal</module>
</modules>

经此之后,该父项目就变成聚合项目了,将四个子服务聚合起来。

在Idea当中的左侧maven中可以看到 34-springcloud-service-parent后面是跟着(root)字符的,表示这是一个父项目。

以及在父项目当中添加pom打包方式

<!--打包方式:在父项目当中需要指定pom,接着import Changes-->
    <packaging>pom</packaging>

接着再次进行eureka的package打包。

此时打包仍然报错;

报错内容如下:

Non-resolvable parent POM for com.bjpowernode.springcloud:34-springcloud-service-eureka:1.0.0: Failure to find com.bjpowernode.springcloud:34-springcloud-service-parent:pom:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at wrong local POM @ line 12, column 13
Spring Cloud Eureka 注册中心打包发布与集群部署

微服务专题-一站式微服务架构 SpringCloud(开发框架开发架构)

1、快速回顾
  1. 分布式与微服务架构的理论梳理;

  2. 什么是Spring Cloud?

    Spring Cloud,一站式进行微服务开发的一套架构、组件,工具。

  3. Spring Cloud的整体架构

    存在有服务提供者、服务消费者,但是角色并不固定,即服务提供者也可以是服务消费者,服务消费者也可以是服务提供者。然后还有一个注册中心。整体上来说还是三个部分。(提供者、消费者、注册中心)与dubbo相类似,因为dubbo也是类似远程调用的一种方式。

  4. 服务消费者Controller直连调用服务提供者Controller(controller调用controller,可以使用restTemplate,spring提供的这样一个工具类。也可以使用HTTPClient,或者是java.util,java.net下的一些包进行使用 HTTP URL等一些类进行调用,存在有很多方式,这是直接调用)

  5. Spring Cloud注册中心Eureka(可以将服务放到Eureka上面去,后续在服务注册中心上获取得到服务列表,然后再去进行调用,那么这样就不在需要写服务提供者提供过来的连接地址、接口地址了)

  6. Spring Cloud Eureka与 Zookeeper比较(eureka保证可用性和分区容错性即AP,zookeeper保证一致性和分区容错性即CP,分区容错性在分布式当中都会要求进行保证即网络的通道,即网络不要出现网络不同,这种说的分区容错性;eureka保证的可用性,zookeeper保证数据的一致性。它们的取舍不一样;eureka实现AP,zookeeper实现CP)

  7. Spring Cloud Eureka高可用集群(使用eureka搭建了集群,高可用的注册中心,即三个节点(搭建了三个注册中心),每个节点两两相互的复制数据,两两相互的进行注册,相互复制,那么这样的话就实现了eureka高可用注册中心,通过多配置文件的方式进行搭建。)

2、Spring Cloud Eureka集群注册中心打包发布

在实际项目中,需要将Eureka发布到具体服务器上进行部署,打包部署其实和SpringBoot里面的一样,我们可以将其打成jar包,启动时对于properties文件,不同的环境激活不同的配置文件。

运行:

java -jar springcloud-service-eureka.jar --spring.profiles.active=eureka8761

java -jar springcloud-service-eureka.jar --spring.profiles.active=eureka8762

java -jar springcloud-service-eureka.jar --spring.profiles.active=eureka8763

通过父项目 34-springcloud-service-parent 进行打包,其他的子服务项目commons、eureka、goods、portal都是继承了父项目,在commons项目当中也要继承父项目,所以在父项目当中复制 gav坐标到commons项目当中的pom.xml中

即在commons项目当中粘贴如下内容即可:

<!--
    该当前项目依然是SpringBoot项目,和之前一样
    1. 首先继承父依赖 parent,有一个统一的父依赖 继承统一的父依赖,从goods服务中的pom.xml中粘贴过来或者 portal中的pom.xml粘贴过来即可
    统一继承的父项目 
    -->
    <parent>
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
    </parent>

所有的子服务项目都继承了父项目,

之前的报错内容当中告诉我们

[ERROR]   The project com.bjpowernode.springcloud:34-springcloud-service-eureka:1.0.0 (F:\Project\UserProject\fsn\34-springcloud-service-eureka\pom.xml) has 1 error
[ERROR]     Non-resolvable parent POM for com.bjpowernode.springcloud:34-springcloud-service-eureka:1.0.0: Failure to find com.bjpowernode.springcloud:34-springcloud-service-parent:pom:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at wrong local POM @ line 12, column 13 -> [Help 2]

在继承父项目的时候需要指明parent父项目的相对位置,即

resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at wrong local POM @ line 12, column 13

中的:parent.relativePath

在每个子服务项目当中的<parent>结点当中再添加一个<relativePath>结点,结点内容为 ../34-springcloud-service-parent/pom.xml即可

即如下内容:

<!--
    该当前项目依然是SpringBoot项目,和之前一样
    1. 首先继承父依赖 parent,有一个统一的父依赖 继承统一的父依赖,从goods服务中的pom.xml中粘贴过来或者 portal中的pom.xml粘贴过来即可
    统一继承的父项目
    -->
    <parent>
        <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-parent</artifactId>
        <version>1.0.0</version>
        <relativePath>../34-springcloud-service-parent/pom.xml</relativePath>
    </parent>

中间的

        <relativePath>../34-springcloud-service-parent/pom.xml</relativePath>

此处的relativePath即为相对路径

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XspJWRxF-1621586775396)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520210041944.png)]

../回到上一层目录。

这四个子项目微服务都需要在parent结点当中添加relativePath相对路径,然后再进行eureka的打包maven-lifecycle-package部署。

下面就使BUILD SUCCESS的相关信息

F:\jdk\jdk1.8202\jdk\bin\java.exe -Dmaven.multiModuleProjectDirectory=F:\Project\UserProject\fsn\34-springcloud-service-eureka "-Dmaven.home=F:\ideaUI\IntelliJ IDEA 2018.3.1\plugins\maven\lib\maven3" "-Dclassworlds.conf=F:\ideaUI\IntelliJ IDEA 2018.3.1\plugins\maven\lib\maven3\bin\m2.conf" "-javaagent:F:\ideaUI\IntelliJ IDEA 2018.3.1\lib\idea_rt.jar=61246:F:\ideaUI\IntelliJ IDEA 2018.3.1\bin" -Dfile.encoding=UTF-8 -classpath "F:\ideaUI\IntelliJ IDEA 2018.3.1\plugins\maven\lib\maven3\boot\plexus-classworlds-2.5.2.jar" org.codehaus.classworlds.Launcher -Didea.version=2018.3.1 package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building 34-springcloud-service-eureka 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ 34-springcloud-service-eureka ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 4 resources
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ 34-springcloud-service-eureka ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to F:\Project\UserProject\fsn\34-springcloud-service-eureka\target\classes
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ 34-springcloud-service-eureka ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory F:\Project\UserProject\fsn\34-springcloud-service-eureka\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ 34-springcloud-service-eureka ---
[INFO] Changes detected - recompiling the module!
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ 34-springcloud-service-eureka ---
[INFO] 
[INFO] --- maven-jar-plugin:3.1.2:jar (default-jar) @ 34-springcloud-service-eureka ---
[INFO] Building jar: F:\Project\UserProject\fsn\34-springcloud-service-eureka\target\34-springcloud-service-eureka-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.148 s
[INFO] Finished at: 2021-05-20T21:01:55+08:00
[INFO] Final Memory: 47M/294M
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

总结之前打包eureka出错的原因在于,

  1. parent父项目当中缺少modules标签,parent没有将其下的子服务进行聚合起来(parent需要聚合另外的四个模块)。

    <modules>
        <module>../34-springcloud-service-commons</module>
        <!-- ... -->
    </modules>
    
  2. parent父项目下的每一个子服务(commons、eureka、goods、portal)的pom.xml,在依赖父项目的时候,需要进行添加relativePath,写出父项目pom.xml的相对路径(../34-springcloud-service-parent)。

在上述完成之后是可以进行eureka的打包操作的。 (先进行clean再进行package操作)

在打包成功之后,就将其进行部署了。

部署的包的路径在:34-springcloud-service-eureka工程下的target目录:34-springcloud-service-eureka-1.0.0.jar

linux输入命令如下:

cd /usr/local

mkdir java

tar -zxvf jdk-8u221-linux-x64.tar.gz

yum -y install vim*

vim /etc/profile

#-------------------
  # Java Environment Path
export JAVA_HOME=/usr/jdk1.8.0_221
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
#-------------

source /etc/profile

java -version
java
javac

# 创建springcloud-eureka文件夹,相当于是注册中心服务端
mkdir spring-cloud-eureka

cd spring-cloud-eureka

#安装rz命令
yum install lrzsz -y 

#传jar包到当前目录
rz

#编辑shell脚本进行启动该34-springcloud-service-eureka.jar
vim eureka_server.sh

#34-springcloud-service-eureka-1.0.0.jar
#--------------------------
#/!bin.sh
#后面指定配置参数,使用哪一个配置文件,--spring.profiles.active参数指定
#当前是第一台eureka server服务
#将其日志放到一个文件当中去,nohup来产生一个文件./logs/eureka8761.log
# 后台启动加&,&表示后台启动
nohup java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka8761 > ./logs/eureka8761.log &

#第二台eureka server服务
nohup java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka87
62 > ./logs/eureka8762.log &

#第三条eureka server服务
nohup java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka87
63 > ./logs/eureka8763/log &

#上述都是通过jar包进行启动
# 英文的冒号 :wq 退出vim编辑模式
#--------------------------

#此时还需要进行修改hosts文件,因为代码当中是使用 eureka server不同端口的服务名称去代替了本机host name
#代码中是eureka-server项目中的application.properties配置文件中eureka.client.service-url.defaultZone=http://eureka8762:8762/eureka,http://eureka8763:8763/eureka这种方式,将IP替换成了不同端口的eureka server服务名称
#所以在linux环境当中也需要在hosts文件当中进行配置 内网ip为不同端口的eureka server服务名称,类似在windows系统上的操作,即将ip和不同端口的eureka server服务名称做一个映射处理
vim /etc/hosts
#-----------------
# 配置eureka server不同端口的服务名称 映射本机ip
# 此处的127.0.0.1也可以写成内网ip,linux通过命令 ifconfig 查看内网ip
# 本机的内网ip为 192.168.182.130
127.0.0.1 eureka8761
127.0.0.1 eureka8762
127.0.0.1 eureka8763
#-----------------
#最后 :wq 退出保存

#创建日志脚本文件夹
cd spring-cloud-eureka
mkdir logs

#eureka_server.sh目前没有执行权限,需要对其赋予权限,仅修改root用户执行权限,其他用户不变动
chmod 744 eureka_server.sh

# 查看机器有没有其他的java进程
ps -ef|grep java
#启动脚本
./eureka_server.sh

#返回如下:nohup: redirecting stderr to stdout
#nohup: redirecting stderr to stdout
#nohup: redirecting stderr to stdout

cd logs

#查看日志
cat eureka8761.log
#返回如下:no main manifest attribute, in 34-springcloud-service-eureka.jar,表示没有main属性,打的jar有问题,在打包的时候需要指定编译的方式,因为我们是通过java -jar的方式启动的jar包,现在的日志提示jar包不是那种可执行的jar包,即可能是一个普通的jar包,不是可执行的。在windows环境中可用压缩软件打开这个jar包,发现该jar包不是springboot打出来的那种可执行的jar包的结构,结构不是这样子,这只是一个普通的jar包;普通jar包结构:com、META-INF、application.properties、application-eureka8761.properties、application-eureka8762.properties、application-eureka8763.properties
#所以需要重新打包,需要添加springboot打包的插件,这样子打出来的包才是正常的


在eureka-server的pom.xml中添加如下内容后,再次进行打包(通过父项目打包即可,因为父项目当中聚合了所有的子项目clean-package),打包成功之后,将新打的包替换到linux上去

<!--
    在创建springboot项目的时候,会自动添加上这个插件,通过这个插件打出来的包是可执行的
    在parent中写完modules结点之后,将4个子服务项目进行聚合
    然后在4个子服务项目的pom.xml中在parent结点中添加relativePath parent父依赖的pom.xml的相对路径之后
    通过maven的lifecycle的package打包不正常
    此时需要添加springboot的打包插件进行打包
    使用springboot专门用于打包的插件,打包编译插件
    -->
    <build>
        <plugins>
            <!--SpringBoot提供的编译、打包的Maven插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!-- TODO  如果是打一个jar运行的话,jar包里面有JSP页面,那么要采用1.4.2.RELEASE 版本来打包,否则JSP无法访问-->
                <!--此时该项目当中没有JSP页面自然也就不需要填写这个版本号了,import Changes
                然后再通过idea左侧的maven-lifecycle-package再次对eureka-server进行打包操作
                -->
                <!--<version>1.4.2.RELEASE</version>-->
            </plugin>
        </plugins>
    </build>

通过该插件打出来的可执行jar包,其目录结构为:BOOT-INF、META-INF、org,这个jar包是可以通过 java -jar进行运行的。

linux命令

cd spring-cloud-eureka
#删除原来的不能执行的jar包
rm -rf 34-springcloud-service-eureka.jar

#进行重命名
mv 34-springcloud-service-eureka-1.0.0.jar 34-springcloud-service-eureka.jar 

#通过shell脚本进行启动三台eureka server注册中心
./eureka_server.sh

#查看日志,无返回内容
cat logs/eureka8761.log

#查看java进程
ps -ef|grep java
#返回如下
[root@localhost logs]# ps -ef|grep java
root      18000      1 29 22:48 pts/0    00:00:05 java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka8761
root      18001      1 29 22:48 pts/0    00:00:05 java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka8762
root      18002      1 31 22:48 pts/0    00:00:06 java -jar 34-springcloud-service-eureka.jar --spring.profiles.active=eureka8763
root      18035  17886  2 22:49 pts/1    00:00:00 grep --color=auto java

此时就可以看到存在有三个java进程,此时就可以在浏览器当中进行访问三个注册中心eureka server了。

访问地址如下(访问不了的检查防火墙是否开启了这三个端口)

#查看防火墙状态
systemctl status firewalld 

#如果为开启状态则进行查看防火墙已经开放的端口有哪些;查看所有打开的端口: firewall-cmd --zone=public --list-ports
firewall-cmd --zone=public --list-ports

#添加eureka 8761、8762、8763这三个端口   (--permanent永久生效,没有此参数重启后失效)
firewall-cmd --zone=public --add-port=8761/tcp --permanent

firewall-cmd --zone=public --add-port=8762/tcp --permanent 

firewall-cmd --zone=public --add-port=8763/tcp --permanent   

#重新载入
firewall-cmd --reload

#再次查看防火墙开启的所有端口
firewall-cmd --zone=public --list-ports

#然后进行页面访问eureka server

访问地址为:

eureka server 8761:
http://192.168.182.130:8761/

eureka server 8762:
http://192.168.182.130:8762/

eureka server 8763:
http://192.168.182.130:8763/

#此时可以看到 8761当中的DS Replicas有8762和8763、8762当中的DS Replicas有8761和8763、8763当中的DS Replicas有8762和8761 是正常的

此时相当于本地的eureka项目可以进行删除不再使用了。本地项目如果需要使用eureka server注册中心,可以使用linux环境上已经部署好的eureka服务。即直接将本地的服务注册到服务器上。本机上就不再需要启动eureka服务了。

防火墙相关命令:https://www.cnblogs.com/moxiaoan/p/5683743.html

一般公司当中在测试环境当中有一套eureka服务,然后在开发过程当中不需要管测试环境服务器上的eureka,只需要知道它的连接地址即可,配置到项目的application.properties中的eureka.client.service-url.defaultZone即可,主要是开发服务提供者和服务消费者,开发一个个的服务,而注册中心搭建一个即可,在linux环境上部署好就行了。

以上为自己在本机的虚拟机上进行运行部署的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K9YpfUo7-1621586775399)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520230602339.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3lvo96f-1621586775400)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520230617567.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mzp1BDDD-1621586775401)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520230634381.png)]

Spring Cloud Eureka注册中心的自我保护机制

自我保护机制 是 Eureka注册中心的重要特性,当Eureka注册中心进入自我保护模式时,在Eureka Server首页会输出如下警告信息:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

小写是(字母大小写转换工具地址:https://www.iamwawa.cn/daxiaoxie.html):

emergency! eureka may be incorrectly claiming instances are up when they're not. renewals are lesser than threshold and hence the instances are not being expired just to be safe.


翻译:紧急情况!eureka可能错误地声称实例在没有启动的情况下启动了。续订小于阈值,因此实例不会为了安全而过期。

在没有 Eureka 自我保护的情况下,如果 Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例,但是当发生网络分区故障时,那么微服务与 Eureka Server之间将无法正常通信,以上行为可能变得非常危险了,因为微服务本身其实是正常的,此时不应该注销这个微服务,如果没有自我保护机制,那么Eureka Server就会将此服务注销掉。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n2lLVMP1-1621586775402)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520231940881.png)]

每个微服务都会与eureka server进行心跳的连接,表示这个微服务还存活着,通过这个机制来保证服务是否存活着。如果有一个服务很久没有给注册中心eureka server发送心跳了,那么eureka server将会注销该服务的实例。网络分区故障的意思是:网络的原因造成访问不同的情况。因为网络原因导致微服务和注册中心eureka连接不上,但是服务本身是没有任何问题是正常的。所以没有这个自我保护机制的话,那么eureka server就将会把这个因为网络原因而导致无法访问的微服务给注销掉。

Eureka通过自我保护模式可以不进行注销该因为网络分区故障原因导致不可用的微服务。

Eureka 通过 “自我保护模式” 来解决这个问题(网络分区故障)----Eureka Server节点在短时间内丢失过多客户端时(在短时间内发现有很多客户端没有向它发送心跳了)(它就判断认为可能发生了网络分区故障),那么就会把这个微服务节点进行保护(也就是该微服务依然在Eureka Server这里被认为是存活着,不将它进行踢出)。

一旦进入自我保护模式,Eureka Server就会保护 服务注册表中的信息,不删除 服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该 Eureka Server节点会再自动退出 自我保护模式。(当Eureka Server退出自我保护模式,即红色的字符就会消失掉)

即如果一段时间内没有向Eureka Server发送心跳,它会认为是发生了网络分区故障,然后Eureka Server就进入自我保护模式,将微服务保护起来,该微服务没有被踢出,还在注册中心上。

所以,自我保护模式 是一种应对 网络异常 的安全保护措施,它的 架构哲学 是 宁可同时保留所有的微服务(健康的微服务和不健康的微服务都会被保留),也不盲目注销任何健康的微服务,使用自我保护模式,可以让 Eureka 集群更加的健壮、

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

即为Eureka server进入自我保护模式所提示的信息,即当前没有服务给该Eureka Server注册中心发送心跳,此时Eureka Server认为这是由于网络故障原因从而导致的微服务不可用,即一段时间没有服务实例给Eureka Server发送心跳,它就会进入自我保护模式,目前该Eureka Server当中有哪些服务,就将一直保存起来不将它们进行注销掉,不进行踢出,这个就叫做自我保护。

当然Eureka也有可能出现误判断的情况,即微服务确确实实是因为宕机了所以才无法发送心跳,如果这个时候进入自我保护模式,而这个微服务也确实是调不通了,但是Eureka由于进入自我保护模式,从而也还是会有这个不健康的微服务,即宕机的微服务。

存在误判的可能性。

当然也可以使用配置项:eureka.server.enable-self-preservation=false #禁止自我保护模式(即该微服务没有发送心跳给Eureka了,那么就让Eureka Server将该微服务进行踢出,禁止自我保护,如需要配置则配置到eureka server 服务端的application.properties 当中)

关闭自我保护模式后会出现红色:

THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

该警告表示将自我保护模式关闭了之后也可能会带来一些危险,如果发生网络分区故障了,可能该微服务是健康的是正常的,但是Eureka仍然会将该服务进行踢出,在Eureka当中没有该微服务,由于网络分区故障缘故导致微服务没有发送心跳给Eureka Server注册中心。

即关闭了Eureka的自我保护模式,也会存在有不足。也有其弊端。如果关闭了也会有提示信息

翻译:
自我保护模式已关闭。如果出现网络/其他问题,这可能无法保护实例过期。

即网络出现问题了,Eureka无法保护该微服务。

EurekaApplication没有配置Program arguments的话则读取默认的配置文件即application.properties

启动该EurekaApplication服务,也会出现如上警告;

访问地址:http://localhost:8761

THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GUNKNpt-1621586775403)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210520235459168.png)]

即平时开发的时候出现该上述红色警告不要过于担心。

但是 Eureka Server 自我保护模式也会给我们带来一些困扰,如果在保护期内某个服务提供者刚好 非正常 下线了(刚好故障宕机了),此时 服务消费者 就会拿到一个 无效的服务实例,此时会调用失败,对于这个问题需要 服务消费者端 具有一些容错机制,如 重试、断路器等。(即针对的是弊端,微服务确确实实宕机了但是Eureka认为它是因为网络分区故障原因导致,所以进入了自我保护模式,没有进行注销这个不健康的服务实例)

Eureka 的自我保护模式 是有意义的,该模式被激活后,健康的、不健康的微服务不会从 注册列表中 被踢出因长时间没收到心跳导致 注册过期的服务,而是等待修复,直到心跳回复正常之后,它自动退出自我保护模式。

这种模式旨在 避免因 网络分区故障 导致服务不可用的 问题。

例如,两个微服务客户端实例 A 和B 之间有调用关系,A是消费者,B是服务提供者,但是由于网络故障,B未能及时向Eureka发送心跳续约,这时候Eureka不能简单地将B从注册表中踢出,因为如果剔除了,A就无法从Eureka服务器中获取B注册的服务,但是这时候B服务是可用的;

所以,Eureka的自我保护模式最好还是开启它。

假设微服务部署在一个机房,而注册中心部署在另外一个机房,那么这两者就有可能会发生网络分区问题,即使在同一个机房当中,两个服务之间也有可能会出现闪断、故障,也有可能。基于考虑到了这种问题(网络分区故障原因),所以出现有了自我保护机制。

关于 自我保护 常用的几个配置如下:

服务器端配置(关闭自我保护模式),在注册中心服务端进行配置,表示关闭自我保护:

#测试时关闭自我保护机制,保证不可用服务及时踢出
eureka.server.enable-self-preservation=false

客户端配置(微服务给Eureka注册中心发送心跳时间间隔以及多久没有发送心跳就让Eureka将其踢出),在客户端微服务当中进行配置,表示多久发送心跳以及多久没有发送心跳将其进行踢出:

#每间隔2s,向服务端发送一次心跳,证明自己依然“存活”
eureka.instance.lease-renewal-interval-in-seconds=2

#告诉服务端,如果我10s之内没有给你发心跳,就代表我故障了,将我踢出掉
eureka.instance.lease-expiration-duration-in-seconds=10
4、Spring Cloud Ribbon

在RestTemplate构造Bean上添加了@LoadBalanced(负载均衡,eureka client底层有依赖这个组件ribbon,通过ribbon知道向Eureka注册过服务的服务名称等信息)

Spring Cloud Ribbon 客户端负载均衡

Ribbon是什么?

Spring Cloud Ribbon是基于 Netflix Ribbon实现的一套 客户端负载均衡器;

我们通常说的 负载均衡是指将 一个请求均匀地分摊到不同的节点单元上执行,负载均衡分为 硬件负载均衡和软件负载均衡:

硬件负载均衡:比如F5、深信服、Array等;(最著名的就是F5,它是一个设备,买一台就像一个服务器一样,一般大公司会使用到硬件负载均衡)

软件负载均衡:比如Nginx、LVS、HAProxy等;(HAProxy,在做rabbitmq镜像队列的时候就是用到过HAProxy这个产品)(这些是由服务器来进行实现的软件负载均衡)

Ribbon也是一个软件负载均衡器。

Ribbon也是Spring Cloud中服务调用的一个组件。

Spring Cloud当中封装了大量Netflix公司的开源项目。

所以当前会分为两块,一块是Spring Cloud Netflix,另外一块是Spring Cloud Alibaba。

因为现在Spring Cloud Alibaba现在也有一套。

在Spring Cloud Netflix当中大量使用了Netflix公司的开源项目、组件。

在Spring Cloud Alibaba当中则大量使用了Alibaba公司的开源项目、组件。

所以目前分有两套。

当前Ribbon 客户端负载均衡器是Netflix公司提供的开源组件。

Ribbon 是 Netflix公司发布的 开源项目(组件、框架、简单理解就是一个jar包,ribbon可以理解为是jar来实现负载均衡),主要功能是 提供客户端的软件负载均衡算法,它会从 eureka 中获取一个可用的 服务端列表,通过心跳检测 来剔除 故障的服务端节点 以保证 清单中都是可以正常访问的服务端节点。

第一步首先从注册中心eureka,将可用的服务列表的服务接口都拿取过来,拿到之后再进行负载均衡,比如说服务端有三个接口,部署了了三份,那就将这三个接口拿到之后,一个个轮询一个个校验服务端接口服务是否可用。这种模式,其实ribbon就是一个jar包。

当客户端发送请求,则 ribbon 负载均衡器按照某种算法(比如轮询、权重、最小连接数等),从维护的可用服务端清单中取出一台服务端的地址,然后进行请求;(因为服务可能有多个请求接口,部署了多份,服务是通过集群的方式进行部署的,协助)

Ribbon非常简单,可以说就是一个jar包,这个 jar包实现了 负载均衡算法,Spring Cloud对 Ribbon做了二次封装,可以让我们使用 RestTemplate的服务请求,自动转换成 客户端负载均衡的服务调用。(RestTemplate对象+添加@LoadBalanced注解即可使用,spring帮助开发人员进行封装了ribbon所以只需添加一个注解即可实现对ribbon负载均衡调用)

Ribbon 支持多种 负载均衡算法,还支持 自定义的负载均衡算法。(还可以自己去扩展它的接口,自己去实现)

客户端负载均衡 vs 服务端负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-knAfCoD8-1621586775404)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521003700265.png)]

上图就是服务端负载均衡,客户端有一个APP应用,通过80端口访问Nginx,Nginx作为一个负载均衡设备,然后它将请求分发到8100、8200、8300的Web Server服务器,那么上述称之为服务端的负载均衡,应用请求到Nginx服务器,然后再通过Nginx转发请求到分发到不同的web服务器,然后实现负载均衡。

这个是服务器端的负载均衡。Nginx,即请求会经过一个中转站,部署有Nginx的服务器即为一个中转站,通过该中转站来进行转发,那么Nginx即成为了服务端的负载均衡。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7cxV2UL-1621586775405)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521004133679.png)]

上图为客户端的负载均衡。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SIO0jDbO-1621586775406)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521004202594.png)]

客户端负载均衡。

客户端有一个APP应用,服务端有提供应用goods service、goods service、goods service,通过集群部署了三份相同的服务。

现在app端需要调用服务提供者,即goodsservice,那么就通过负载均衡算法去进行调用服务端应用。而ribbon该jar包其实就放在APP当中。

因为首先APP的后端服务首先会连接高可用集群注册中心Eureka8761、8762、8763,首先进行注册服务,再就是发现服务,发现服务就是从eureka注册中心将服务列表即goods service、goods service、goods service 通过集群部署了三份的应用服务的接口地址都拿取到,即发现服务,拿到这些服务列表接口地址之后,在通过ribbon这个jar包当中的负载均衡算法进行调用应用服务goods service。

通过集群进行部署的goods service,应用服务也会到eureka注册中心进行注册服务。三份goods service启动之后都会到注册中心eureka上进行注册服务。

APP端的后端服务启动之后首先也会进行往注册中心eureka进行注册服务,然后就会发现服务,发现服务之后将eureka中 三份goods service的服务列表拿到,拿到之后,当下次需要进行调用的时候,这个时候通过ribbon这个jar包来进行实现负载均衡调用。比如说第一次调用goods service1,第二次调用goods service 2,第三次调用goods service3这样子。

所以这个ribbon,负载均衡是在客户端APP当中实现的,那么就叫做客户端的负载均衡。在APP端进行实现的通过ribbon进行负载均衡算法调用应用服务接口,而不是通过服务器去进行实现的。这就是客户端负载均衡。

Spring Cloud Ribbon客户端负载均衡应用测试
采用 Ribbon实现服务调用
  1. 首先加入 ribbon的依赖,但是 eureka已经依赖了 ribbon,所以这里不需要再引用 ribbon 的依赖;

  2. 要使用 ribbon,只需要一个注解:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }
    

    在 RestTemplate 上面加入 @LoadBalanced 注解,这样就可以实现RestTemplate在调用时自动负载均衡。

    看到portal前端项目当中的pom.xml当中进行依赖了 spring-cloud-stater-netflix-eureka-client eureka-clietn依赖,而可以看到idea左侧的maven依赖中,该eureka-client依赖底层是有对ribbon进行依赖的。

    spring-cloud-starter-netflix-ribbon下包括ribbon-core、ribbon-httpclient、loadbalancer等等。loadbalancer即负载均衡。

    ribbon-loadbalancerjar包当中包括有ribbon-core、netflix-statistics、rxjava、slf4j-api、servo-core、guava、archaius-core、netflix-commons-util等;(netflix公司提供的相关的一些jar包)loadbalancer主要实现负载均衡。eureka client客户端已经自动依赖了loadbalancer这个jar包。

    在netflix-ribbon的起步依赖当中底层已经添加了loadbalancer依赖。spring-cloud-starter-netflix-ribbon中添加有起步器即starter,这个启动器自动配置到时候就会把所有相关的bean准备好,开发人员直接使用即可。

    所以第一步就不再需要进行添加该ribbon的相关依赖了。

    第二步即在restTemplate上添加@LoadBalanced的注解即可。这样就可以自动实现负载均衡了。

    我们这里现在启动了 eureka集群(3个eureka)和服务提供者集群(2个 service-goods)和一个服务调用这(service-portal)

    #告诉服务端,服务实例的唯一id
    eureka.instance.instance-id=34-springcloud-service-portal
    

    3个注册中心已经在linux环境上进行部署好了。然后服务提供者提供两份,然后服务调用者提供一份,看自动的负载均衡有没有实现。

    复制goods工程为9200时,需要在新的工程9200工程下删除文件34-springcloud-service-goods.iml以及文件夹target,然后编辑goods9200工程当中的pom.xml文件。

    <!--gav坐标中进行修改 a,artifactId的取值在后面加一个-9200-->
    <groupId>com.bjpowernode.springcloud</groupId>
        <artifactId>34-springcloud-service-goods-9200</artifactId>
        <version>1.0.0</version>	
    <!--name结点标签内容也需要添加-9200 以及description结点内容-->
    <name>34-springcloud-service-goods-9200</name>
        <description>34-springcloud-service-goods-9200 project for Spring Boot</description>
    

    修改完成之后再通过idea的New-Module from Existing Sources…

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pywqyAU0-1621586775406)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521102100082.png)]

    接着选中复制的goods9200工程当中的pom.xml文件即可

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mz1eFx4n-1621586775407)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521102145409.png)]

    OK之后在弹出的页面当中点击Next按钮,然后再次点击Finish按钮即可。

    注册中心目前在linux当中。所以就不需要再关注eureka。

    当前已经提供了两份服务提供者。

    微服务启动比较麻烦,服务比较多。

    两个GoodsApplication9100和9200服务提供者启动之后,接着启动portal消费端。portal项目当中再RestConfig当中的RestTemplate上面已经添加了@LoadBalanced注解,负载均衡。(使用Ribbon实现负载均衡的调用)

    @LoadBalanced即spring cloud在底层对ribbon进行了封装,即spring cloud在底层进行封装了ribbon、eureka、restTemplate都进行了封装。

Ribbon负载均衡策略

Ribbon 是用来做负载均衡使用的。帮助开发者实现负载均衡调用。Ribbon是存在有很多的负载均衡策略的,主要是由IRule接口定义。rule 规则。

Ribbon 的负载均衡策略是由 IRule 接口定义,该接口由如下实现:

在jar 包:com.netflix.ribbon#ribbon-load-balancer中:ribbon-loadbalancer该jar包即位于spring-cloud-starter-netflix-eureka-client依赖下的spring-cloud-starter-netflix-ribbon依赖下的ribbon相关的jar包即ribbon-loadbalancer

ribbon的负载均衡就是在ribbon-loadbalancer该jar包当中实现的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jHhBT0c2-1621586775408)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521141504395.png)]

该ribbon-loadbalancer jar包,它的一个继承体系结构如上图。最上层是IRule接口,然后就是实现接口的抽象类,再就是具体的负载均衡算法。中横线的类即表示已经过时的类。

在idea中的portal项目当中,找到其下的External Libraries,找到下面的有关于netflix.ribbon相关的内容;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bW5zk5ti-1621586775409)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521142102417.png)]

找到该jar包,在loadbalancer文件夹下有一个接口IRule

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJIeQSHs-1621586775416)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521142200081.png)]

这是负载均衡的统一的一个接口,负载均衡算法规则接口。该IRule下有多个实现类相当于是多个负载均衡规则算法。

RandomRule 随机算法;

Random随机的,随机的负载均衡。

RoundRobinRule 轮询的负载均衡;

另外还有一些其他的负载均衡算法。WeightedResponseTimeRule即权重负载均衡算法。

ClientConfigEnabledRoundRobinRule
    BestAvailableRule
    PredicateBaseRule
        ZoneAvoidanceRule
        AvailabilityFilteringRule
RoundRobinRule
WeightedResponseTimeRule
ResponseTimeWeightedRule(该类已过期)
RandomRule
RetryRule

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7yNW3Wg-1621586775417)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521143043918.png)]

继承结构。在idea中右击IRule类当中的名称,选择Diagrams源码,然后找到Show Diagram...之后点击,就生成上面的该图了。

需要观察一下没有使用某一种负载均衡策略,那么它默认的负载均衡策略是什么呢?

如果没有加负载均衡策略,则有一天负载均衡的入口,ILoadBalancer即该负载均衡的入口。

ILoadBalancer
	AbstractLoadBalancer
		NoOpLoadBalancer
			DynamicServerListLoadBalancer
				ZoneAwareLoadBalancer

DynamicServerListLoadBalancer 动态选择,就是默认情况下,负载均衡算法从ILoadBalancer该入口进来之后,

首先从注册中心拿到服务即addServers(List<Server>):void,将eureka添加服务列表添加进来;

chooseServer(Object):Server,选择服务器,使用使用哪一个服务器;

markServerDown(Server):void,标记哪一台服务器宕机了;

getReachableServer():List<Server>,获取可以到达的服务器;可到达的服务器表明该服务是通的,可以进行连接上,没有宕机没有报错。

getAllServers():List<Server>拿到所有服务器列表。

public interface ILoadBalancer {
    void addServers(List<Server> var1);
    
Server chooseServer(Object var1);

void markServerDown(Server var1);

/** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1);

List<Server> getReachableServers();

List<Server> getAllServers();
    }

在负载均衡的时候,首先第一步则进行选择负载均衡服务器,即chooseServer(Object):server,该方法的基本实现有

BaseLoadBalancer(com.netflix.loadbalancer) 基本负载均衡实现
NoOpLoadBalancer(com.netflix.loadbalancer)
ZoneAwareLoadBalancer(com.netflix.loadbalancer)
public Server chooseServer(Object key) {
        if (this.counter == null) {
            this.counter = this.createCounter();
        }

        this.counter.increment();
        if (this.rule == null) {
            return null;
        } else {
            try {
                return this.rule.choose(key);
            } catch (Exception var3) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                return null;
            }
        }
    }

if(counter == null){ 该处放一个断点,看到时候进来到这个断点,就将会去实现这个负载均衡。将消费者服务进行断点调试。就会发现它会进来到chooseServer当中进行调用负载均衡。通过debug方式启动portalApplication服务,这样可以通过调试进入断点。

在这个三个chooseServer方法的实现当中都打一个断点,看看到时候会进入哪一个实现方法,经过运行发现断点进入到的是ZoneAwareLoadBalancer该类当中

public Server chooseServer(Object key) {
        if (ENABLED.get() && this.getLoadBalancerStats().getAvailableZones().size() > 1) {

第一步得到状态,下一步Step Over(F6),第二步打印了日志

logger.debug("Zone aware logic disabled or there is only one zone");
return super.chooseServer(key);

然后此处进行选择服务器 chooseServer(key),以及该key,是"default",即为一个 default key,接着进入选择即 chooseServer(Object key);

就到了BaseLoadBalancer当中的chooseServer(Object key)中来了。

public Server chooseServer(Object key) {
        if (this.counter == null) {
            this.counter = this.createCounter();

接着往下走执行到代码行

        this.counter.increment();
//计数器增加

再接着往下走,则进入到规则的判断,该rule为规则鼠标上移出现的是ZoneAvoidanceRule@8523,这个就是规则使用的规则是ZoneAvoidanceRule。即默认的情况下使用的负载均衡是通过ZoneAvoidanceRule类来进行实现的算法。(或许其他版本的Spring使用的负载均衡算法是轮询也就是RoundRobinRule,但是当前G版本的spring使用的负载均衡是通过ZoneAvoidanceRule来进行实现的)

        if (this.rule == null) {

接着继续向下执行,由于rule不为空,那么就会走到相应的规则当中去即进入到else判断

if (this.rule == null) {
            return null;
        } else {
            try {
                return this.rule.choose(key);
            } catch (Exception var3) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                return null;
            }
        }

中的代码行

                return this.rule.choose(key);

继续接着往下执行就走到了ZoneAwareLoadBalancer当中的代码行

            return super.chooseServer(key);

再接着往下走就到了选择服务器了。即ZoneAwareLoadBalancer中的代码行 返回服务器

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
        return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
    } 

由此可以知道ribbon的默认负载均衡实现是使用ZoneAvoidanceRule去进行实现的算法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JRNCaDek-1621586775418)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521151339418.png)]

去掉断点,即上图当中的View Breakpointers(Ctrl+Shift+F8)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hs1al7Wq-1621586775419)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521151446604.png)]

在弹出的界面当中点击 【-】图标,然后进行删除断点记录。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XcVNsCDT-1621586775419)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521151536531.png)]

以上就是清除完之后的样子。

接着点击Done按钮即可。

以上就是负载均衡接口,以及它的体系结构。如果在代码当中想要进行切换负载均衡的实现方式的话(如果要切换负载均衡策略),那么即在配置类当中添加一个@Bean,实现IRule。

在消费者项目当中的RestConfig配置类当中,@LoadBalanced底层默认实现负载均衡的算法是ZoneAvoidanceRule实现类。

而目前是要切换负载均衡策略,显然是要换一种负载均衡实现方式即IRule的不同实现类。就需要进行覆盖一下之前的ZoneAvoidanceRule该类的实现负载均衡方式

要使用 ribbon 实现负载均衡,在 Spring 的配置类里面把 对应的负载均衡接口实现类 作为一个 Bean配置一下 就行了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOP3iHou-1621586775420)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521160228212.png)]

负载均衡的入口:ILoadBalancer该接口,该接口下有一些实现。

@Bean
public IRule iRule(){
    return new RoundRobinRule();
}
负载均衡实现策略
RandomRule随机
RoundRobinRule轮询

问题:消费者在调用的时候是指定application的名字还是status那一栏的值

消费者在调用提供者服务的时候是指定的application下的名字。

即34-SPRINGCLOUD-SERVICE-GOODS这样子的取值,即spring.application.name的取值。而不是服务实例id,即34-springcloud-service-goods-9100、34-springcloud-service-goods-9200这个,如果使用服务实例id则无法调用通。

只有通过spring.application.name的取值可以调通,该取值可以大写也可以小写。这个表示服务名称,通过服务名称来进行调用的。而Status栏下的为服务实例id,不是服务名称。

ribbon的@LoadBalanced负载均衡策略默认是ZoneAvoidanceRule来进行实现的负载均衡算法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7ES1JSa-1621586775421)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20210521161410769.png)]

该操作即将断点全部置为不可用

Mute Breakpoints让所有断点静音(

这个地方好像不太对,mute breakpoints,我是进行的重启服务运行的)

Spring Cloud Ribbon客户端负载均衡策略分析02

负载均衡算法规则

负载均衡实现策略
RandomRule随机
RoundRobinRule轮询(每个服务执行一遍)
AvailabilityFilteringRule先过滤掉由于多次访问故障的服务, 以及并发连接数超过阈值的服务,然后对剩下的服务按照轮询策略进行访问;
WeightedResponseTimeRule根据平均响应时间计算所有服务的权重,响应时间越快服务权重就越大被选中的概率即越高,如果服务刚启动时统计信息不足,则使用RoundRobinRule策略,待统计信息足够会切换到该WeightedResponseTimeRule策略;
RetryRule先按照 RoundRobinRule 策略分发,如果分发的服务不能访问,则在指定时间内进行重试,然后分发其他可用的服务。
BestAvailableRule先过滤掉由于多次访问故障的服务,然后选择一个并发量最小的服务。
ZoneAvoidanceRule(spring cloud G版本使用的默认负载均衡策略)综合判断服务节点所在区域的性能和服务节点的可用性,来决定选择哪个服务;(根据宕机的比例高不高,性能好不好来决定)

如果开发人员没有指定负载均衡策略,ribbon默认的负载均衡是ZoneAvoidanceRule;

ResponseTimeWeightedRule过时了的策略以及AbstractLoadBalancerRule抽象的就不再关注。ClientConfigEnabledRoundRobinRule也不需要关注,ClientConfigEnabledRoundRobinRule就是PredicateBasedRule和BestAvailableRule。PredicateBasedRule也是抽象的。

总共就七个负载均衡策略

  • WeightedResponseTimeRule
  • RoundRobinRule
  • AvailabilityFilteringRule
  • ZoneAvoidanceRule
  • BestAvailableRule
  • RandomRule
  • RetryRule

AbstractLoadBalancerRule、ClientConfigEnabledRoundRobinRule、PredicateBasedRule这三个是抽象的类。

如果要切换ribbon的默认负载均衡策略则在RestConfig配置类当中,让spring容器当中去配置定义一个Bean,即IRule 构造方法中返回任意一个上述七个当中任意一个负载均衡实现方法类的实例对象即可。

(spring cloud新版本即G版本使用的默认的负载均衡策略为ZoneAvoidanceRule)

ribbon即一个jar包。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值