springcloud
基本术语
1.服务器
服务器:是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。服务器的构成:包括处理器、硬盘、内存、系统总线等,和通用的计算机架构类似,但是由于需要提供高可靠的服务,因此在处理能力、稳定性、可靠性、安全性、可扩展性、可管理性等方面要求较高。在网络环境下,根据服务器提供的服务类型不同,分为文件服务器、数据库服务器、应用程序服务器、WEB服务器等。
处理器:处理器一般指中央处理器中央处理器(CPU)是一块超大规模的集成电路,是一台计算机的运算核心和控制核心。它的功能主要是解释计算机指令以及处理计算机软件中的数据。中央处理器主要包括运算器和高速缓冲存储器及实现它们之间联系的数据(Data)、控制及状态的总线(Bus)。它与内部存储器(Memory)和输入/输出(I/O)设备合称为电子计算机三大核心部件。
集成电路:或称微电路(microcircuit)、 微芯片(microchip)、芯片(chip)在电子学中是一种把电路(主要包括半导体装置,也包括被动元件等,把构成具有一定功能的电路所需的半导体、电阻、电容等元件及它们之间的连接导线全部集成在一小块硅片上,然后焊接封装在一个管壳内的电子器件)小型化的方式,并通常制造在半导体晶圆表面上。功能:用来产生、放大和处理各种模拟信号或者各种数字信号。
内存:是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。
Web服务器:1.一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等Web客户端提供文档, [1] 也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。目前最主流的三个Web服务器是Apache Nginx IIS。2.Web服务器是可以向发出请求的浏览器提供文档的程序。3.Internet上的服务器也称为Web服务器、Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件反馈到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。4.Web服务器不仅能够存储信息,还能在用户通过Web浏览器提供的信息的基础上运行脚本和程序。
服务器的特点:Windows,Linux与Unix这3个操作系统是架设Web服务器比较常见的操作系统。Linux的安全性能在这3个操作系统中最高,可以支持多个硬件平台,其网络功能比较强大。总的来说,这两大优点是其他操作系统不可替代的:第一,可以依据用户不同的需求来随意修改、调整与复制各种程序的源码以及发布在互联网上;第二,Linux操作系统的市场价格比较便宜,也能够在互联网上免费下载源码。可以说,Linux为架设既高效又安全的Web服务器的比较理想的操作系统。此外,要让Web服务器更具有优越的性能,可以根据服务器系统之特点与用途作进一步的优化与处理,尽量减少Web服务器的数据传输量以及降低其数据传输的频率,进而促进网络宽带的利用率与使用率,以及提高网络客户端的网页加载的速度,同时也可以减少Web服务器各种资源的消耗。
WEB的工作原理:Web服务器的工作原理并不复杂,一般可分成如下4个步骤:连接过程、请求过程、应答过程以及关闭连接。下面对这4个步骤作一简单的介绍。连接过程就是Web服务器和其浏览器之间所建立起来的一种连接。查看连接过程是否实现,用户可以找到和打开socket这个虚拟文件,这个文件的建立意味着连接过程这一步骤已经成功建立。请求过程就是Web的浏览器运用socket这个文件向其服务器而提出各种请求。应答过程就是运用HTTP协议把在请求过程中所提出来的请求传输到Web的服务器,进而实 ****r 7 6ijyy 施任务处理,然后运用HTTP协议把任务处理的结果传输到Web的浏览器,同时在Web的浏览器上面展示上述所请求之界面。关闭连接就是当上一个步骤--应答过程完成以后,Web服务器和其浏览器之间断开连接之过程。Web服务器上述4个步骤环环相扣、紧密相联,逻辑性比较强,可以支持多个进程、多个线程以及多个进程与多个线程相混合的技术。
Apache
Apache仍然是世界上用的最多的Web服务器,市场占有率达60%左右。它源于NCSAhttpd服务器,当NCSAWWW服务器项目停止后,那些使用NCSA WWW服务器的人们开始交换用于此服务器的补丁,这也是apache名称的由来(pache 补丁)。世界上很多著名的网站都是Apache的产物,它的成功之处主要在于它的源代码开放、有一支开放的开发队伍、支持跨平台的应用(可以运行在几乎所有的Unix、Windows、Linux系统平台上)以及它的可移植性等方面。
Tomcat
Tomcat是一个开放源代码、运行servlet和JSP Web应用软件的基于Java的Web应用软件容器。Tomcat Server是根据servlet和JSP规范进行执行的,因此我们就可以说Tomcat Server也实行了Apache-Jakarta规范且比绝大多数商业应用软件服务器要好。
Tomcat是Java Servlet 2.2和JavaServer Pages 1.1技术的标准实现,是基于Apache许可证下开发的自由软件。Tomcat是完全重写的Servlet API 2.2和JSP 1.1兼容的Servlet/JSP容器。Tomcat使用了JServ的一些代码,特别是Apache服务适配器。随着Catalina Servlet引擎的出现,Tomcat第四版号的性能得到提升,使得它成为一个值得考虑的Servlet/JSP容器,因此许多WEB服务器都是采用Tomcat。
宕机:计算机术语,指电脑不能正常工作。
粗粒度与细粒度:是一个相对的概念,像类的设计,为尽可能重用,所以采用细粒度的设计模式,将一个复杂的类(粗粒度)拆分成高度重用的职责清晰的类(细粒度)。 对于数据库的设计,原则:尽量减少表的数量与表与表之间的连接,能够设计成一个表的情况就不需要细分,所以可考虑使用粗粒度的设计方式。
1. 微服务是什么
业界大牛马丁.福勒(Martin Fowler) 这样描述微服务:
论文网址: https://martinfowler.com/articles/microservices.html
就目前而言,对于微服务业界并没有一个统一的、标准的定义(While there is no precise definition of this architectural style)
但通常而言, 微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成一组小的服务,每个服务运行在其独立的自己的进程中,服务之间互相协调、互相配合,为用户提供最终价值。服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。
1)微服务与微服务架构
微服务
强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,
狭意的看,可以看作Eclipse里面的一个个微服务工程/或者Module
微服务架构
微服务架构是⼀种架构模式,它提倡将单⼀应⽤程序划分成⼀组⼩的服务,服务之间互相协调、互相配合,为⽤户提供最终价值。每个服务运⾏在其独⽴的进程中,服务与服务间采⽤轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进⾏构建,并且能够被独⽴的部署到⽣产环境、类⽣产环境等。另外,应当尽量避免统⼀的、集中式的服务管理机制,对具体的⼀个服务⽽⾔,应根据业务上下⽂,选择合适的语⾔、⼯具对其进⾏构建。
2)微服务的优缺点(更详细的连接http://www.cnblogs.com/crazylqy/p/7953944.html)
优点
每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或业务需求
开发简单、开发效率提高,一个服务可能就是专一的只干一件事。
微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。
微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
微服务能使用不同的语言开发。
易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如Jenkins, Hudson, bamboo 。
微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
微服务允许你利用融合最新技术。
微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。
每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一数据库。
缺点
开发人员要处理分布式系统的复杂性
多服务运维难度,随着服务的增加,运维的压力也在增大
系统部署依赖
服务间通信成本
数据一致性
系统集成测试
性能监控……
3)微服务的技术栈
微服务条目落地技术备注服务开发Springboot、Spring、SpringMVC服务配置与管理Netflix公司的Archaius、阿里的Diamond等服务注册与发现Eureka、Consul、Zookeeper等服务调用Rest、RPC、gRPC服务熔断器Hystrix、Envoy等负载均衡Ribbon、Nginx等服务接口调用(客户端调用服务的简化工具)Feign等消息队列Kafka、RabbitMQ、ActiveMQ等服务配置中心管理SpringCloudConfig、Chef等服务路由(API网关)Zuul等服务监控Zabbix、Nagios、Metrics、Spectator等全链路追踪Zipkin,Brave、Dapper等服务部署Docker、OpenStack、Kubernetes等数据流操作开发包SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息)事件消息总线Spring Cloud Bus......
SOA – 代表面向服务的体系结构 – 指的是专注于服务的体系结构.
REST(FUL)
REST是Web服务的一个子集 – 因此也是SOA – 围绕使用HTTP进行通信.有一些常见的做法,例如与URL有某种特定的相关性.RESTful仍然是REST的一个更严格的子集.
rest:Resource Representational State Transfer,直接翻译:表现层状态转移。
通俗来讲就是:资源在网络中以某种表现形式进行状态转移。分解开来:
Resource:资源,即数据(前面说过网络的核心)。比如 newsfeed,friends等;
Representational:某种表现形式,比如用JSON,XML,JPEG等;
State Transfer:状态变化。通过HTTP动词实现。
用URL定位资源,用HTTP描述操作。
看Url就知道要什么
看http method就知道干什么
看http status code就知道结果如何
在确定要把自己的服务创建成RESTFUL之前,要明白什么样的服务什么是RESTFUL service(https://en.wikipedia.org/wiki/Representational_state_transfer)。wiki上面介绍了一些,总结为以下几点:
无状态。确保服务是无状态的。这是为了解除客户端请求与指定某台服务器的耦合。
资源识别。服务提供资源的方式应该是在URL可识别的,包括资源名称,文件格式等。这是为了解除客户端寻找资源的逻辑与服务器端提供资源的逻辑的耦合。
操作资源的方式。操作资源的方式应该是表示的,例如POST,DELETE,UPDATE。这是为了解除客户端操作资源的逻辑与服务器端的耦合。
自我描述的信息。每个HTTP请求都能够自我解释请求什么资源,格式是什么,操作什么资源,等等。这样一来,资源相关的逻辑就与服务器解耦了。
可以看到,RESTFUL服务的目的还是为了解耦,解除客户端与服务器之间的耦合。在软件中,抽象再怎么强调都不过分,无论是什么编程(过程式,面向对象,函数式等等),抽象都是核心。这个RESTful也一样. 可以把restful看作是客户端与服务器之间交互的抽象,定义了一些规则: URL中表达出请求什么资源(以及格式),还有POST DELETE UPDATE PUT定义对资源的操作方式等等 .它们最大化的解除了客户端请求和服务器资源的耦合,开发上前后端的耦合度也降低了,提高了开发效率。
Eureka是什么 (节划分)
Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得
为什么选择SpringCloud作为微服务架构
选型依据
整体解决方案和框架成熟度,社区热度,可维护性,学习曲线
Springcloud是什么
SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。
SpringCloud利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等,它们都可以用SpringBoot的开发风格做到一键启动和部署。
SpringBoot并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包
SpringCloud=分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶
SpringCloud和SpringBoot是什么关系
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系.
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
Dubbo是怎么到SpringCloud的?哪些优缺点让你去技术选型
目前成熟的互联网架构(分布式+服务治理Dubbo)
我们把SpringCloud VS DUBBO进行一番对比
活跃度
https://github.com/dubbo
https://github.com/spring-cloud
对比结果
最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。
严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。
品牌机与组装机的区别
很明显,Spring Cloud的功能比DUBBO更加强大,涵盖面更广,而且作为Spring的拳头项目,它也能够与Spring Framework、Spring Boot、Spring Data、Spring Batch等其他Spring项目完美融合,这些对于微服务而言是至关重要的。使用Dubbo构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手,那这些都不是问题;而Spring Cloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。
社区支持与更新力度
最为重要的是,DUBBO停止了5年左右的更新,虽然2017.7重启了。对于技术发展的新需求,需要由开发者自行拓展升级(比如当当网弄出了DubboX),这对于很多想要采用微服务架构的中小软件组织,显然是不太合适的,中小公司没有这么强大的技术能力去修改Dubbo源码+周边的一整套解决方案,并不是每一个公司都有阿里的大牛+真实的线上生产环境测试过。
总结Cloud与Dubbo
问题:
曾风靡国内的开源 RPC 服务框架 Dubbo 在重启维护后,令许多用户为之雀跃,但同时,也迎来了一些质疑的声音。互联网技术发展迅速,Dubbo 是否还能跟上时代?Dubbo 与 Spring Cloud 相比又有何优势和差异?是否会有相关举措保证 Dubbo 的后续更新频率?
人物:Dubbo重启维护开发的刘军,主要负责人之一
刘军,阿里巴巴中间件高级研发工程师,主导了 Dubbo 重启维护以后的几个发版计划,专注于高性能 RPC 框架和微服务相关领域。曾负责网易考拉 RPC 框架的研发及指导在内部使用,参与了服务治理平台、分布式跟踪系统、分布式一致性框架等从无到有的设计与开发过程。
springcloud能干嘛
Distributed/versioned configuration(分布式/版本控制配置)
Service registration and discovery(服务注册与发现)
Routing(路由)
Service-to-service calls(服务到服务的调用)
Load balancing(负载均衡配置)
Circuit Breakers(断路器)
Distributed messaging(分布式消息管理)
去哪下
http://projects.spring.io/spring-cloud/
怎么用
服务的注册与发现(Eureka)
服务消费者(rest+Ribbon)
服务消费者(Feign)
断路器(Hystrix)消息总线(Spring Cloud Bus)
服务链路追踪(Spring Cloud Sleuth)
断路器监控(Hystrix Dashboard)
路由网关(Zuul)
分布式配置中心(Spring Cloud Config)
分布式配置中心(Spring Cloud Config)
Rest微服务构建案例工程模块
承接着我们的springmvc+mybatis+mysql初级高级课程,以Dept部门模块做一个微服务通用案例
Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务
一个简单的Maven模块结构是这样的:
---- app-parent 一个父项目(app-parent)聚合很多子项目(app-util,app-dao,app-service,app-web)
|---- pom.xml (pom)
|
|-------- app-util
| |-------- pom.xml (jar)
|
|-------- app-dao
| |-------- pom.xml (jar)
|
|-------- app-service
| |-------- pom.xml (jar)
|
|-------- app-web
|-------- pom.xml (war)
一个Project带着多个Module子模块
MicroServiceCloud父工程(Project)下初次带着3个子模块(Module)
其中80端口:(补充:由于我的80端口被占用了,为了方便我就换成了8081端口)
80端口是为HTTP(HyperText Transport Protocol)即超文本传输协议开放的
此为上网冲浪使用次数最多的协议,主要用于WWW(World Wide Web)即万维网传输信息的协议。
可以通过HTTP地址(即常说的"网址")加":80"来访问网站,
因为浏览网页服务默认的端口号都是80,因此只需输入网址即可,不用输入":80"了。
首先我创建一个maven工程
创建完成后由于是父项目不需要src 可以直接把它删了,当然也可以不删
创建完成后,选中父项目右键创建model 就可以创建自己需要的工程类型。
我创建一个springboot 如果没有在父项目的pom文件中产生<models><model></model></models>
就可以自己手动加上
然后在microsoft-springboot-api这个工程中放入公共的接口,实体类即可
接下来创建我们的服务提供者,服务调用者(客户端使用)
简单的写上一个增删改查
需要的依赖pom文件
<dependency> <groupId>microsoft-springcloud-api</groupId> <artifactId>api</artifactId> <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency> <!--微服务架构不用像以前那样发布到Tomcat下面,springboot内置的Tomcat 插件内嵌的容器可以用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--热部署,修改后立即生效--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> 这个不加会报错 <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency>
yml文件
server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml type-aliases-package: cn.edu.aynu.entities mapper-locations: classpath:mybatis/mapper/*.xml spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver #mysql的驱动包 url: jdbc:mysql://localhost:3306/clouddb01?serverTimezone=UTC username: root password: root dbcp2: min-idle: 5 #数据库连接池的最小维持连接数 initial-size: 5 #初始化连接数 max-total: 5 #最大连接数 max-wait-millis: 200 #等待连接获取的最大超时时间
controller
package soft.provider.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import soft.provider.service.DeptService; import springcloud.api.entities.Dept; import java.util.List; /** * Description: SpringCloud * Created by lenovo on 2019/3/30 12:03 */ @RestController public class DeptController { @Autowired private DeptService deptService; @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(@RequestBody Dept dept) { return deptService.add(dept); } @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) public Dept get(@PathVariable("id") Long id) { return deptService.get(id); } @RequestMapping(value = "/dept/list", method = RequestMethod.GET) public List<Dept> list() { return deptService.list(); } }
dao
package soft.provider.dao; import org.apache.ibatis.annotations.Mapper; import springcloud.api.entities.Dept; import java.util.List; /** * Description: SpringCloud * Created by lenovo on 2019/3/30 11:34 */ @Mapper public interface DeptDao { public boolean addDept(Dept dept); public Dept findById(Long id); public List<Dept> findAll(); }
service
package soft.provider.service; import springcloud.api.entities.Dept; import java.util.List; /** * Description: SpringCloud * Created by lenovo on 2019/3/30 11:55 */ public interface DeptService { public boolean add(Dept dept); public Dept get(Long id); public List<Dept> list(); }
package soft.provider.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import soft.provider.dao.DeptDao; import springcloud.api.entities.Dept; import java.util.List; /** * Description: SpringCloud * Created by lenovo on 2019/3/30 11:56 */ @Service public class DeptServiceImpl implements DeptService { @Autowired private DeptDao deptDao; @Override public boolean add(Dept dept) { return deptDao.addDept(dept); } @Override public Dept get(Long id) { return deptDao.findById(id); } @Override public List<Dept> list() { return deptDao.findAll(); } }
mybatis.cfg.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--驼峰命名法--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>
<?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="soft.provider.dao.DeptDao"> <select id="findAll" resultType="Dept"> select * from dept; </select> <select id="findById" resultType="Dept"> select * from dept where deptno=#{id} </select> </mapper>
创建服务调用者(springboot web项目)
<dependency> <groupId>microsoft-springcloud-api</groupId> <artifactId>api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
server: port: 80
package consumer.dept.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * Description: springcloud * Created by lenovo on 2019/3/30 13:48 */ @Configuration public class ConfigBean { //boot-->spring 中的配置文件是application.xml @Configuation 配置 CongigBean这个类 就相当于这个配置文件 @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
package consumer.dept.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import springcloud.api.entities.Dept; import java.util.List; /** * Description: springcloud * Created by lenovo on 2019/3/30 13:54 */ @RestController public class consumerController { /** * 使用RestTemplate 访问restful接口非常的简单粗暴无脑 * (url,requestMapping,ResponseBean.class )这三个参数分别代表rest请求地址,请求参数,http响应转换成对象的类型 */ private static final String REST_URL_PREFIX = "http://localhost:8001"; @Autowired RestTemplate restTemplate; @RequestMapping("/consumer/dept/get/{id}") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX, dept, Boolean.class); } @RequestMapping(value = "/consumer/dept/list/{id}") public Dept get(@PathVariable("id") Long id) { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get" + id, Dept.class); } @RequestMapping(value = "/consumer/dept/list") public List<Dept> list() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class); } }
当未启动服务提供者时服务调用者访问时的报错
成功显示后,这个浏览器对json的显示格式很不好
数据库带下划线的字段,在程序中拿不到值
有几种解决办法
1.在你的mybatis的配置文件中加上驼峰命名法
<configuration> <!--驼峰命名法--> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>
这样你的实体类中的命名就可以不使用下划线 如: snoName sno_name,如果使用了驼峰命名法就不能在实体类中的相应字段再使用下划线了,否则会取不到值
2.将你的实体类中的字段值与数据库中的字段值取相同。
3,写sql语句的时候使用别名映射后。
Eureka服务注册与发现
Eureka(节划分)
Eureka是什么
Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。
Netflix在设计Eureka时遵守的就是AP原则
CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得
原理讲解
Eureka的基本架构
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(请对比Zookeeper)。
Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
请注意和Dubbo的架构对比
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册服务
各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到
EurekaClient是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
三大角色
Eureka Server 提供服务注册和发现
Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务
盘点下目前我们的工程情况
总父工程
通用模块api
服务提供者Provider
服务消费者Consumer
即我们刚才创建的rest格式的工程
microservicecloud-eureka-7001 eureka服务注册中心Module
新建microservicecloud-eureka-7001
pom文件
<!-- eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.1.RELEASE</version> </dependency>
server: port: 7001 eureka: instance: hostname: localhost #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 # 单机service-url: http://${eureka.instance.hostname}:${server.port}/eureka/ service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
package eureka.dept; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer //Eureka服务器端启动类,接收其他微服务注册进来 public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
此时测试启动
还没有服务注册进来,现在将上面写的服务提供者注册进去
修改microservicecloud-provider-dept-8001
<!--将微服务 provider 注册进入 eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>LATEST</version> </dependency>
eureka: client: service-url: defaultZone: http://localhost:7001/eureka instance: #服务名称修改 instance-id: microservicecloud-provider-dept-8001 prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: microservicecloud-provider-dept-8001 company.name: microservicecloud-provider-dept-8001 build.artifaceId: $project.artifactId$ build.version: $project.version$
package soft.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient //本服务启动后会自动注册到eurka 服务中 public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
其实已经很明显了,服务提供者进行的注册当然是在服务提供者中出现的
spring: application: name: microservicecloud-dept
eureka: client: service-url: defaultZone: http://localhost:7001/eureka instance: #服务名称修改 instance-id: microservicecloud-provider-dept-8001
actuator与注册微服务信息完善
主机名称:服务名称 修改 隐藏主机名称
修改microservicecloud-provider-dept-8001
eureka: client: service-url: defaultZone: http://localhost:7001/eureka instance: #服务名称修改 instance-id: microservicecloud-provider-dept-8001 prefer-ip-address: true #访问路径可以显示IP地址
显示当点击 UP后面的那个值的时候出现的info信息就是在yml文件中注册的内容
需要加上一个依赖
<!--主管监控和信息配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
info: app.name: microservicecloud-provider-dept-8001 company.name: microservicecloud-provider-dept-8001 build.artifaceId: $project.artifactId$ build.version: $project.version$
遗留一个小问题,
build.artifaceId: $project.artifactId$ build.version: $project.version$
不能显示内容,而是把它们当成一个字符串来处理了。
我有在父项目中加入
<build>
<finalName>microsoft-springcloud-parent</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
microservicecloud-provider-dept-8001服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
修改microservicecloud-provider-dept-8001工程的DeptController
controller
加上注解 @Autowired DiscoveryClient discoveryClient; @RequestMapping(value = "/dept/discovery", method = RequestMethod.GET) public Object discovery() { List<String> list = discoveryClient.getServices(); System.out.println("**********" + list); List<ServiceInstance> srvList = discoveryClient.getInstances("MICROSERVICECLOUD-DEPT"); for (ServiceInstance element : srvList) { System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t" + element.getUri()); } return this.discoveryClient; }
启动类加上注解
@EnableDiscoveryClient //对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
执行结果
接下来修改
修改microservicecloud-consumer-dept-80工程的DeptController_Consumer 在客户端中访问
修改controller
@RequestMapping(value = "/consumer/dept/discovery") public Object discovery() { return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class); }
因为客户段位服务没有连接数据库所以有可能回报错 所以在启动类上加上
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
http://localhost:8081/consumer/dept/discovery
也是能够访问成功的
集群配置
科普一下集群
基本原理
上图是来自eureka的官方架构图,这是基于集群配置的eureka;
- 处于不同节点的eureka通过Replicate进行数据同步
- Application Service为服务提供者
- Application Client为服务消费者
- Make Remote Call完成一次服务调用
服务启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。
当服务注册中心Eureka Server检测到服务提供者因为宕机、网络原因不可用时,则在服务注册中心将服务置为DOWN状态,并把当前服务提供者状态向订阅者发布,订阅过的服务消费者更新本地缓存。
服务提供者在启动后,周期性(默认30秒)向Eureka Server发送心跳,以证明当前服务是可用状态。Eureka Server在一定的时间(默认90秒)未收到客户端的心跳,则认为服务宕机,注销该实例。
进行实例演示
新建microservicecloud-eureka-7002/microservicecloud-eureka-7003
按照7001为模板粘贴POM
7001的Yml 也要改
server: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 # 单机service-url: http://${eureka.instance.hostname}:${server.port}/eureka/ service-url: defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
7002 项目
<!-- eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka- server</artifactId> <version>2.1.1.RELEASE</version> </dependency>
主启动类
@EnableEurekaServer //Eureka服务器端启动类,接收其他微服务注册进来
server: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 # 单机service-url: http://${eureka.instance.hostname}:${server.port}/eureka/ service-url: defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
7003项目
同上,就是yml文件发生了变化
server: port: 7003 eureka: instance: hostname: eureka7003.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 # 单机service-url: http://${eureka.instance.hostname}:${server.port}/eureka/ service-url: defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
microservicecloud-provider-dept-8001 微服务发布到上面3台eureka集群配置中
也即是将yml文件中的url地址由一个改为三个,来进行访问,把这段代码拿过来使用
eureka: client: service-url: # defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: #服务名称修改 instance-id: microservicecloud-provider-dept-8001 prefer-ip-address: true #访问路径可以显示IP地址
成功后
作为服务注册中心,Eureka比Zookeeper好在哪里
作为服务注册中心,Eureka比Zookeeper好在哪里 著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性P在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。 因此 Zookeeper保证的是CP, Eureka则是AP。 4.1 Zookeeper保证CP 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。 4.2 Eureka保证AP Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: 1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用) 3. 当网络稳定时,当前实例新的注册信息会被同步到其它节点中 因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。
Ribbon负载均衡
概述
是什么?
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
能干吗
LB(负载均衡):
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。
常见的负载均衡有软件Nginx,LVS,硬件 F5等。
相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
官网资料
https://github.com/Netflix/ribbon/wiki/Getting-Started
Ribbon配置初步 (用户的请求平摊的分配到多个服务上所以肯定要修改客户端了)
修改microservicecloud-consumer-dept-80工程
第一步:当然是添加依赖了
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.1.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.1.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>LATEST</version> </dependency>
既然要使用负载均衡我们也需要知道通往注册中心的地址
server: port: 8081 eureka: client: register-with-eureka: false #false表示不向注册中心注册自己 service-url: defaultZone: http://eureka7001.com:7002/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
package consumer.dept.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * Description: springcloud * Created by lenovo on 2019/3/30 13:48 */ @Configuration public class ConfigBean { //boot-->spring 中的配置文件是application.xml @Configuation 配置 CongigBean这个类 就相当于这个配置文件 @Bean @LoadBalanced //springcloud ribbon 是基于Netfix ribbon实现的一套客户端 负载均衡的工具 完成真正的通过为服务的名字eureka上找到并访问 public RestTemplate restTemplate() { return new RestTemplate(); } }
controller类的url地址发生了改变
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";//完成真正的通过为服务的名字eureka上找到并访问
先启动3个eureka集群后,再启动microservicecloud-provider-dept-8001并注册进eureka
再启动microservicecloud-consumer-dept-80
访问路径http://localhost:8081/consumer/dept/list 如果这个访问路径访问不了,那么就加上端口号
访问成功后
Ribbon负载均衡
Ribbon在工作时分成两步
第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server.
第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。
其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。
参考microservicecloud-provider-dept-8001,新建两份,分别命名为8002,8003
新建8002/8003数据库,各自微服务分别连各自的数据库
修改8002/8003各自YML
server: port: 8002 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml #mybatis所在路径 type-aliases-package: com.atguigu.springcloud.entities #entity别名类 mapper-locations: - classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/cloudDB02 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: microservicecloud-dept8002 #自定义服务名称信息 prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: atguigu-microservicecloud company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$
server: port: 8003 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml #mybatis所在路径 type-aliases-package: com.atguigu.springcloud.entities #entity别名类 mapper-locations: - classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/cloudDB03 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: microservicecloud-dept8003 #自定义服务名称信息 prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: atguigu-microservicecloud company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$
对外暴露的统一的服务实例名
启动3个eureka集群配置区
启动3个Dept微服务并各自测试通过
启动microservicecloud-consumer-dept-80
启动服务端的url
http://localhost:8081/consumer/dept/list
注意观察看到返回的数据库名字,各不相同,负载均衡实现
总结:Ribbon其实就是一个软负载均衡的客户端组件,
他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。
Ribbon核心组件IRule
IRule:根据特定算法中从服务列表中选取一个要访问的服务
Ribbon自定义
修改microservicecloud-consumer-dept-80
因为我们要自定义负载均衡算法,所以我们要在客户端访问的时候加以约束
主启动类添加@RibbonClient
在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效,形如:
@RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration=MySelfRule.class)
官方文档明确给出了警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说
我们达不到特殊化定制的目的了。
也就是说我们要放在dept包同级或者在其上面
新建自定义Robbin规则类
当然不能忘记我们的主启动类了
package consumer.dept; import consumer.myruler.MyselfRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.ribbon.RibbonClient; @SpringBootApplication @EnableEurekaClient //客户端的负载均衡 @RibbonClient(name="MICROSERVICECLOUD-DEPT",configuration = MyselfRule.class) public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
由于本人电脑根本跑不起来6个微服务,所以等下回来演示是否执行成功
测试
http://localhost:8081/consumer/dept/list 还是带上端口号吧,否则根本不能运行。
自定义规则深度解析
问题:依旧轮询策略,但是加上新需求,每个服务器要求被调用5次。也即
以前是每台机器一次,现在是每台机器5次
解析源码:https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java
参考源码修改为我们需求要求的RandomRule_ZY.java
创建一个RandomRule_ZY.java
package consumer.myruler; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import java.util.List; /** * Description: microsoft-springcloud-parent * Created by lenovo on 2019/4/5 19:21 */ public class RandomRule_ZY extends AbstractLoadBalancerRule{ private int total = 0; //总共被调用的次数,目前要求每台被调用5次 private int currentIndex = 0;//当前提供服务的机器号 public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List<Server> upList = lb.getReachableServers(); List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { /* * No servers. End regardless of pass, because subsequent passes * only get more restrictive. */ return null; } // int index = rand.nextInt(serverCount); // server = upList.get(index); if(total < 5) { server = upList.get(currentIndex); total++; }else { total = 0; currentIndex++; if(currentIndex >= upList.size()) { currentIndex = 0; } } if (server == null) { /* * The only time this should happen is if the server list were * somehow trimmed. This is a transient condition. Retry after * yielding. */ Thread.yield(); continue; } if (server.isAlive()) { return (server); } // Shouldn't actually happen.. but must be transient or a bug. server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } }
package consumer.myruler; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Configuration; /** * Description: microsoft-springcloud-parent * Created by lenovo on 2019/4/5 19:12 */ @Configuration public class MyselfRule { public IRule myRule(){ //算法有7个,轮询,随机,响应时间加权,默认是轮询,等 只需要定义这一个bean 就可以改变负载均衡的算法 //return new RandomRule(); //Ribbon默认是轮询,我自定义为随机 return new RandomRule_ZY();//我自定义为每个机器被访问5次 } }
测试:http://localhost:8081/consumer/dept/list
Feign负载均衡
概述
官网解释:
http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
;
Feign是一个声明式的Web服务客户端,使得编写Web服务客户端变得非常容易,
只需要创建一个接口,然后在上面添加注解即可。
参考官网:https://github.com/OpenFeign/feign
Feign能干什么
Feign旨在使编写Java Http客户端变得更容易。
前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon
利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
参考microservicecloud-consumer-dept-80 新建microservicecloud-consumer-dept-feign
microservicecloud-consumer-dept-feign工程pom.xml修改,主要添加对feign的支持
也就是要加上一个feign的依赖
修改microservicecloud-api工程,为什么呢是因为
通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
所以既然是接口并且很有可能被多次使用,那么就把他建立在公共类上。
需要在microservicecloud-api上导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.0.2.RELEASE</version> </dependency>
package springcloud.api.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import springcloud.api.entities.Dept; import java.util.List; /** * Description: springcloud02 * Created by lenovo on 2019/4/1 13:20 */ @FeignClient(value = "MICROSERVICECLOUD-DEPT") //@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClinetServiceFallbackFactory.class) public interface DeptClientService { @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET) public Dept get(@PathVariable("id") long id); @RequestMapping(value = "/dept/list",method = RequestMethod.GET) public List<Dept> list(); @RequestMapping(value = "/dept/add",method = RequestMethod.POST) public boolean add(Dept dept); }
package springcloud.api; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ApiApplication { public static void main(String[] args) { SpringApplication.run(ApiApplication.class, args); } }
microservicecloud-consumer-dept-feign工程修改主启动类
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.0.2.RELEASE</version> </dependency>
package consumer.feign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @EnableFeignClients(basePackages= {"consumer.feign.controller"}) @ComponentScan("consumer.feign.controller") public class MicroservicecloudConsumerDeptFeignApplication { public static void main(String[] args) { SpringApplication.run(MicroservicecloudConsumerDeptFeignApplication.class, args); } }
package consumer.feign.controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springcloud.api.entities.Dept; import springcloud.api.service.DeptClientService; import javax.annotation.Resource; import java.util.List; /** * Description: springcloud * Created by lenovo on 2019/3/30 13:54 */ @RestController public class consumerController { @Resource DeptClientService deptClientService ; @RequestMapping(value = "/consumer/dept/get/{id}") public Dept get(@PathVariable("id") Long id){ return this.deptClientService.get(id); } @RequestMapping(value = "/consumer/dept/list") public List<Dept> list() { return this.deptClientService.list(); } @RequestMapping(value = "/consumer/dept/add") public Object add(Dept dept) { return this.deptClientService.add(dept); } }
小总结:
Feign通过接口的方法调用Rest服务(之前是Ribbon+RestTemplate),
该请求发送给Eureka服务器(http://MICROSERVICECLOUD-DEPT/dept/list),
通过Feign直接找到服务接口,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡作用。
Hystrix断路器
分布式系统面临的问题
分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
备注:一般情况对于服务依赖的保护主要有3中解决方案:
(1)熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
(2)隔离模式:这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火少光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。
(3)限流模式:上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。
Hystrix断路器是什么
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
Hystrix断路器能干嘛
服务降级
备注:Hystrix服务降级,其实就是线程池中单个线程障处理,防止单个线程请求时间太长,导致资源长期被占有而得不到释放,从而导致线程池被快速占用完,导致服务崩溃。
Hystrix能解决如下问题:
1.请求超时降级,线程资源不足降级,降级之后可以返回自定义数据
2.线程池隔离降级,分布式服务可以针对不同的服务使用不同的线程池,从而互不影响
3.自动触发降级与恢复
4.实现请求缓存和请求合并
服务熔断
备注:熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
服务限流
备注:限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。
接近实时的监控
官网资料
https://github.com/Netflix/Hystrix/wiki/How-To-Use
服务熔断
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回"错误"的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
新建microservicecloud-provider-dept-hystrix-8001
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.0.0.RELEASE</version> </dependency> <!--主管监控和信息配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--将微服务 provider 注册进入 eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>LATEST</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency> <!--微服务架构不用像以前那样发布到Tomcat下面,springboot内置的Tomcat 插件内嵌的容器可以用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--热部署,修改后立即生效--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>microsoft-springcloud-api</groupId> <artifactId>api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml #mybatis所在路径 type-aliases-package: com.atguigu.springcloud.entities #entity别名类 mapper-locations: - classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/cloudDB01 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: microservicecloud-dept8001-hystrix #自定义服务名称信息 prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: atguigu-microservicecloud company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$
修改DeptController
package com.atguigu.springcloud.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.atguigu.springcloud.entities.Dept; import com.atguigu.springcloud.service.DeptService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @RestController public class DeptController { @Autowired private DeptService service = null; @RequestMapping(value="/dept/get/{id}",method=RequestMethod.GET) @HystrixCommand(fallbackMethod = "processHystrix_Get") public Dept get(@PathVariable("id") Long id) { Dept dept = this.service.get(id); if(null == dept) { throw new RuntimeException("该ID:"+id+"没有没有对应的信息"); } return dept; } public Dept processHystrix_Get(@PathVariable("id") Long id) { return new Dept().setDeptno(id) .setDname("该ID:"+id+"没有没有对应的信息,null--@HystrixCommand") .setDb_source("no this database in MySQL"); } }
一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法
package provider.hystrix; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; @SpringBootApplication @EnableCircuitBreaker public class HystrixApplication { public static void main(String[] args) { SpringApplication.run(HystrixApplication.class, args); } }
如果对应的ID:如:112,数据库里面没有这个记录,我们报错后统一返回。
服务降级
是什么:整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。
服务降级处理是在客户端实现完成的,与服务端没有关系
修改microservicecloud-api工程,
根据已经有的DeptClientService接口新建一个实现了
FallbackFactory接口的类DeptClientServiceFallbackFactory
千万不要忘记在类上面新增@Component注解,大坑!!!
修改microservicecloud-api工程,DeptClientService接口在注解@FeignClient中添加fallbackFactory属性值
package cn.edu.aynu.service; import cn.edu.aynu.entities.Dept; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.List; /** * Description: springcloud02 * Created by lenovo on 2019/4/1 13:20 */ //@FeignClient(value = "MICROSERVICECLOUD-DEPT") @FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClinetServiceFallbackFactory.class) public interface DeptClientService { @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET) public Dept get(@PathVariable("id") long id); @RequestMapping(value = "/dept/list",method = RequestMethod.GET) public List<Dept> list(); @RequestMapping(value = "/dept/add",method = RequestMethod.POST) public boolean add(Dept dept); }
package cn.edu.aynu.service; import cn.edu.aynu.entities.Dept; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; import java.util.List; /** * Description: springcloud02 * Created by lenovo on 2019/4/1 16:08 */ @Component public class DeptClinetServiceFallbackFactory implements FallbackFactory<DeptClientService> { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept get(long id) { return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand").setDb_source("no this database in MySQL"); } @Override public List<Dept> list() { return null; } @Override public boolean add(Dept dept) { return false; } }; } }
microservicecloud-consumer-dept-feign工程修改YML
server: port: 8081 eureka: client: register-with-eureka: false #false表示不向注册中心注册自己 service-url: defaultZone: http://eureka7001.com:7002/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。 feign: hystrix: enabled: true
服务监控hystrixDashboard
除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。
新建工程microservicecloud-consumer-hystrix-dashboard
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--热部署,部署之后立即生效--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <version>2.1.3.RELEASE</version> </dependency>
package hystrix.dashboard; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class DashboardApplication { public static void main(String[] args) { SpringApplication.run(DashboardApplication.class, args); } }
server: port: 9001
填写监控地址
1:Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。
2:Title:该参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。
监控结果
如何看?
7色
1圈
实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
1线
曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。
整图说明
zuul路由网关
Zuul包含了对请求的路由和过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础.Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。
注意:Zuul服务最终还是会注册进Eureka
提供=代理+路由+过滤三大功能
能干嘛
路由,过滤
官网资料
https://github.com/Netflix/zuul/wiki/Getting-Started
新建Module模块microservicecloud-zuul-gateway-9527
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.0.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> <version>2.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.2.RELEASE</version> </dependency> <!--主管监控和信息配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.1.0.RELEASE</version> </dependency> <!-- eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.1.RELEASE</version> </dependency>
server: port: 9527 spring: application: name: springcloud-zuul-gateway eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: #服务名称修改 instance-id: gateway-9527.com prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: atguigu-microservicecloud company.name: www.atguigu.com build.artifaceId: $project.artifactId$ build.version: $project.version$ zuul: routes: mydept.serviceId: microservicecloud-dept mydept.path: /mydept/** ignored-services: microservicecloud-dept
package cull.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableZuulProxy public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } }
路由访问映射规则(将真正的服务名称等隐藏起来)
代理名称:yml
修改之前,暴露了我们的真是的微服务名称 http://myzuul.com:9527/microservicecloud-dept/dept/get/2 zuul:
routes:
mydept.serviceId: microservicecloud-dept
mydept.path: /mydept/** 修改之后将我们的微服务名称隐藏起来 http://myzuul.com:9527/mydept/dept/get/1
此时问题 :
路由访问OK
http://myzuul.com:9527/mydept/dept/get/1
原路径访问OK
http://myzuul.com:9527/microservicecloud-dept/dept/get/2
原真实服务名忽略(yml有两种写法)
zuul: ignored-services: microservicecloud-dept routes: mydept.serviceId: microservicecloud-dept mydept.path: /mydept/**
单个具体,多个可以用"*"
zuul: ignored-services: "*" routes: mydept.serviceId: microservicecloud-dept mydept.path: /mydept/**
设置统一公共前缀
zuul: prefix: /zull ignored-services: "*" routes: mydept.serviceId: microservicecloud-dept mydept.path: /mydept/**
这时的访问地址:http://myzuul.com:9527/zull/mydept/dept/get/1
完整的yml
server: port: 9527 spring: application: name: microservicecloud-zuul-gateway zuul: prefix: /atguigu ignored-services: "*" routes: mydept.serviceId: microservicecloud-dept mydept.path: /mydept/** eureka: client: service-url: defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka instance: instance-id: gateway-9527.com prefer-ip-address: true info: app.name: atguigu-microcloud company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$
用一个实例演示一下
SpringCloud Config分布式配置中心
SpringCloud Config客户端配置与测试
在本地D:\44\mySpringCloud\microservicecloud-config路径下新建文件microservicecloud-config-client.yml
microservicecloud-config-client.yml内容
spring: profiles: active: - dev --- server: port: 8201 spring: profiles: dev application: name: microservicecloud-config-client eureka: client: service-url: defaultZone: http://eureka-dev.com:7001/eureka/ --- server: port: 8202 spring: profiles: test application: name: microservicecloud-config-client eureka: client: service-url: defaultZone: http://eureka-test.com:7001/eureka/
将上一步提交到GitHub中
新建microservicecloud-config-client-3355
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> <version>2.0.0.RELEASE</version> </dependency> <!--主管监控和信息配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--将微服务 provider 注册进入 eureka-server服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> <version>LATEST</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.8</version> </dependency> <!--微服务架构不用像以前那样发布到Tomcat下面,springboot内置的Tomcat 插件内嵌的容器可以用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <!--热部署,修改后立即生效--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>microsoft-springcloud-api</groupId> <artifactId>api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.18</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.12</version> </dependency>
bootstrap.yml是什么
applicaiton.yml是用户级的资源配置项
bootstrap.yml是系统级的,优先级更加高
Spring Cloud会创建一个`Bootstrap Context`,作为Spring应用的`Application Context`的父上下文。初始化的时候,`Bootstrap Context`负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的`Environment`。`Bootstrap`属性有高优先级,默认情况下,它们不会被本地配置覆盖。 `Bootstrap context`和`Application Context`有着不同的约定,
所以新增了一个`bootstrap.yml`文件,保证`Bootstrap Context`和`Application Context`配置的分离。
bootstrap.yml
spring: cloud: config: name: microservicecloud-config-client #需要从github上读取的资源名称,注意没有yml后缀名 profile: dev #本次访问的配置项 label: master uri: http://config-3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取GitHub的服务地址
application.yml
spring: application: name: microservicecloud-config-client
windows下修改hosts文件,增加映射 127.0.0.1 client-config.com
新建rest类,验证是否能从GitHub上读取配置
package com.atguigu.springcloud.rest; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConfigClientRest { @Value("${spring.application.name}") private String applicationName; @Value("${eureka.client.service-url.defaultZone}") private String eurekaServers; @Value("${server.port}") private String port; @RequestMapping("/config") public String getConfig() { String str = "applicationName: "+applicationName+"\t eurekaServers:"+eurekaServers+"\t port: "+port; System.out.println("******str: "+ str); return "applicationName: "+applicationName+"\t eurekaServers:"+eurekaServers+"\t port: "+port; } }
主启动类ConfigClient_3355_StartSpringCloudApp
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ConfigClient_3355_StartSpringCloudApp { public static void main(String[] args) { SpringApplication.run(ConfigClient_3355_StartSpringCloudApp.class,args); } }
SpringCloud Config配置实战
目前情况
1 Config服务端配置配置OK且测试通过,我们可以和config+GitHub进行配置修改并获得内容
2 此时我们做一个eureka服务+一个Dept访问的微服务,将两个微服务的配置统一由于github获得实现统一配置分布式管理,完成多环境的变更
步骤
Git配置文件本地配置
在本地D:\44\mySpringCloud\microservicecloud-config路径下新建文件
microservicecloud-config-eureka-client.yml
microservicecloud-config-eureka-client.yml内容
spring: profiles: active: - dev --- server: port: 7001 #注册中心占用7001端口,冒号后面必须要有空格 spring: profiles: dev application: name: microservicecloud-config-eureka-client eureka: instance: hostname: eureka7001.com #冒号后面必须要有空格 client: register-with-eureka: false #当前的eureka-server自己不注册进服务列表中 fetch-registry: false #不通过eureka获取注册信息 service-url: defaultZone: http://eureka7001.com:7001/eureka/ --- server: port: 7001 #注册中心占用7001端口,冒号后面必须要有空格 spring: profiles: test application: name: microservicecloud-config-eureka-client eureka: instance: hostname: eureka7001.com #冒号后面必须要有空格 client: register-with-eureka: false #当前的eureka-server自己不注册进服务列表中 fetch-registry: false #不通过eureka获取注册信息 service-url: defaultZone: http://eureka7001.com:7001/eureka/
在本地D:\44\mySpringCloud\microservicecloud-config路径下新建文件
microservicecloud-config-dept-client.yml
microservicecloud-config-dept-client.yml内容
spring: profiles: active: - dev --- server: port: 8001 spring: profiles: dev application: name: microservicecloud-config-dept-client datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/cloudDB01 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml type-aliases-package: com.atguigu.springcloud.entities mapper-locations: - classpath:mybatis/mapper/**/*.xml eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka instance: instance-id: dept-8001.com prefer-ip-address: true info: app.name: atguigu-microservicecloud-springcloudconfig01 company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$ --- server: port: 8001 spring: profiles: test application: name: microservicecloud-config-dept-client datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://localhost:3306/cloudDB02 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml type-aliases-package: com.atguigu.springcloud.entities mapper-locations: - classpath:mybatis/mapper/**/*.xml eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka instance: instance-id: dept-8001.com prefer-ip-address: true info: app.name: atguigu-microservicecloud-springcloudconfig02 company.name: www.atguigu.com build.artifactId: $project.artifactId$ build.version: $project.version$
Config版的eureka服务端
新建工程microservicecloud-config-eureka-client-7001
<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.atguigu.springcloud</groupId> <artifactId>microservicecloud</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>microservicecloud-config-eureka-client-7001</artifactId> <dependencies> <!-- SpringCloudConfig配置 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <!-- 热部署插件 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project>
bootstrap.yml
spring: cloud: config: name: microservicecloud-config-eureka-client #需要从github上读取的资源名称,注意没有yml后缀名 profile: dev label: master uri: http://config-3344.com:3344 #SpringCloudConfig获取的服务地址
application.yml
spring:
application:
name: microservicecloud-config-eureka-client
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * EurekaServer服务器端启动类,接受其它微服务注册进来 * @author zhouyang */ @SpringBootApplication @EnableEurekaServer public class Config_Git_EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(Config_Git_EurekaServerApplication.class, args); } }
Config版的dept微服务
参考之前的8001拷贝后新建工程microservicecloud-config-dept-client-8001
<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.atguigu.springcloud</groupId> <artifactId>microservicecloud</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>microservicecloud-config-dept-client-8001</artifactId> <dependencies> <!-- SpringCloudConfig配置 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project>
bootstrap.yml
spring: cloud: config: name: microservicecloud-config-dept-client #需要从github上读取的资源名称,注意没有yml后缀名 #profile配置是什么就取什么配置dev or test #profile: dev profile: test label: master uri: http://config-3344.com:3344 #SpringCloudConfig获取的服务地址
application.yml
spring:
application:
name: microservicecloud-config-dept-client
主启动类及其它一套业务逻辑代码
主启动类
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient //本服务启动后会自动注册进eureka服务中 @EnableDiscoveryClient //服务发现 public class DeptProvider8001_App { public static void main(String[] args) { SpringApplication.run(DeptProvider8001_App.class, args); } }
其它业务逻辑代码.............
配置说明
spring: cloud: config: name: microservicecloud-config-dept-client #需要从github上读取的资源名称,注意没有yml后缀名 #profile配置是什么就取什么配置dev or test #profile: dev profile: test label: master uri: http://config-3344.com:3344 #SpringCloudConfig获取的服务地址 主要看bootstrap.yml文件里面的 profile: 属性具体值是什么,从而确定它能从github上取得什么样的配置 假如配置dev左图,如果配置test那就找右图,具体各自数据库不同,从而依据配置得到分布式配置的目的
第一季内容技术梳理与架构
第二季
微服务架构体系知识展望,包含但不限于 SpringCloud Stream:数据流操作开发包 SpringCloud Turbine是聚合服务器发送事件流数据的一个工具,用来监控集群下hystrix的metrics情况。 SpringCloud Task:提供云端计划任务管理、任务调度。 SpringCloud Sleuth:日志收集工具包实现了一种分布式追踪解决方案,封装了Dapper和log-based追踪以及Zipkin和HTrace操作, SpringCloud Security:基于spring security的安全工具包,为应用程序添加安全控制 服务部署:Kubernetes , OpenStack 全链路追踪:Zipkin,brave 服务监控:zabbix SpringCloud CLI:基于 Spring Boot CLI,可以让你以命令行方式快速建立云组件。 全局控制:选举leader、全局锁、全局唯一id 安全鉴权: auth2、 openId connect 自动化构建与部署: gitlab + jenkins + docker 服务监控和告警(Spring Boot Admin) ……