Spring Cloud微服务
概念
微服务的概念源于2014年3月Martin Fowler所写的一篇文章“Microservices”。
微服务架构是一种架构模式,它提倡将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。微服务是一种架构风格,一个大型复杂软件应用有一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间的松耦合的。每个微服务仅关注于完成一件任务并很好的完成该任务。在所有情况下,每个任务代表着一个小的业务能力。
Spring Boot
SpringBoot是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了Spring众多框架中所需的大量且繁琐的配置文件,所以SpringBoot是一个服务于框架的框架,服务范围是简化配置文件
Spring Cloud
SpringCloud基于SpringBoot提供了一整套微服务的解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件。
SpringCloud利用SpringBoot的开发便利性巧妙地简化了分布式系统的基础设施开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、为代理、事件总线,他们都可以用SpringBoot的开发风格做到一键启动和部署
SpringBoot与SpringCloud的区别:
SpringBoot:专注于快速方便的开发单个个体微服务(关注微观);
SpringCloud:关注全局的微服务协调治理框架,将SpringBoot开发的一个个单体微服务组合并管理起来(关注宏观)。
Spring Cloud组件
Fegin(接口调用):微服务之间通过Rest接口通讯,Spring Cloud提供Fegin框架来支持Rest的调用,Fegin使得不同进程的Rest接口调用得以用优雅的方式进行,这种优雅表现得就像同一个进程调用一样
Eureka(注册中心):微服务模式下,一个大的Web应用通常都被拆分为很多比较小的web应用(服务),这个时候就需要有一个地方保存这些服务的相关信息,才能让各个小的应用彼此知道对方,这个时候就需要在注册中心进行注册。每个应用启动时向配置的注册中心注册自己的信息(IP地址,端口号,服务名称等信息),注册中心将他们保存起来,服务间相互调用的时候,通过服务名称就可以到注册中心找到对应的服务信息,从而进行通讯。注册与发现服务为微服务之间的调用带来了方便,解决了硬编码的问题。服务间只通过对方的服务id,而无需知道其ip和端口号即可以获取对方服务。
Ribbon(负载均衡):Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者的地址列表后,Ribbon就可以基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机等。当然,我们也可以为Ribbon实现自定的负载均衡算法。在SpringCloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从EurekaServer获取服务提供者的地址列表,并基于负载均衡算法,请求其中一个服务提供者的实例(为了服务的可靠性,一个微服务可能部署多个实例)。
Hystrix(熔断器):当服务提供者响应非常缓慢,那么消费者对提供者的请求就会被强制等待,知道提供者响应或超时。在高负载场景下,如果不做任何处理,此类问题可能会导致服务提供者的资源耗竭甚至整个系统的崩溃(雪崩效应)。Hystrix正是为了防止此类问题发生。Hystrix是有Netflix开源的一个延迟和容错哭库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。
**Zuul(微服务网关):**不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求。
例如:一个电影购票的手机App,可能嗲用多个微服务的接口才能完成一次购票的业务流程,如果让客户端直接与各个微服务通信,会有以下的问题:
客户端会多次请求不同的微服务,增加了客户端的复杂性。
存在跨域请求,在一定场景下处理相对复杂。
认证复杂,每个服务都需要独立认证。
某些微服务可能使用了对防火墙/浏览器不友好的协议,直接访问时会有一定的困难。
以上问题可借助Zuul微服务网关解决。
微服务网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关。使用微服务网关后,微服务网关将封装应用程序的内部结构,客户端只用根网关交互,而无需直接调用特定微服务的接口。这样,开发就可以得到简化。不仅如此,使用微服务网关还有以下优点:
易于监控:可在微服务网关收集监控数据并将其推送到外部系统进行分析
易于认证:可在微服务网关上进行认证,然后在将请求转发到后端的微服务,而无须在每个微服务中进行认证
减少了客户端与各个微服务之间的交互次数
Spring Cloud Bus(统一配置服务):对于传统的单体应用,常使用配置文件管理所有配置。
例如:一个SpringBoot开发的单体应用,可将配置内容放在application.yml文件中。如果需要切换环境,可设置多个Profile,并在启动应用时指定spring.profiles.active={profile}
。然而,在为服务架构中,微服务的配置管理一般有以下需求:
集中管理配置。一个使用微服务架构的应用系统可能会包含成百上千个微服务,因此集中管理配置是非常有必要的。
不同环境,不同配置。例如,数据源配置在不同的环境(开发、测试、预发布、生成等)是不同的。
运行期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池大小或熔断阈值,并且在调整配置时不停止微服务。
配置修改后自动更新。如配置内容发生变化,微服务能够自动更新配置
综上所述,对于微服务架构而言,一个通用的配置管理机制是必不可少的,常见做法是使用配置服务器管理配置。Spring Cloud Bus利用Git或SVN等管理配置。采用Kafka或者RabbitMQ等消息总线通知所有应用,从而实现配置的自动更并且刷新所有微服务实例的配置
Sleuth+ZipKin(跟踪服务):Sleuth和ZipKin综合使用可以通过图形化的界面查看微服务请求的延迟情况以及各个微服务的依赖情况,可以描绘出微服务系统的拓扑图,也可以根据耗时分析来做对某个微服务的优化。
使用Spring Cloud
Eureka(注册中心)
两台服务器:Java/Maven环境,网络yum
安装Git
yum -y install git
# 下载微服务相关代码样例,会下载到当前路径下
git clone http://github.com/luojunyong/spring-cloud-examples.git
以上下载的代码,就是Spring一些组件的代码
Eureka注册中心配置
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-eureka/
vim src/main/resources/application.properties
# spring应用的名字
spring.application.name=spring-cloud-eureka
# 服务端口
server.port=8000
# 当前应用是否注册到注册中心
eureka.client.register-with-eureka=true # 改为true
# 当前应用是否从注册中心获取信息
eureka.client.fetch-registry=true # 改为true
# 注册中心地址,改为本机ip,另一台是1.4
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/
将eureka项目打包
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-eureka/
mvn clean package
# 运行起来是阻塞的,可以通过页面来访问注册中心
java -jar target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar
访问http://192.168.1.1:8000/
注册中心中需要关注的是,以下部分,Application是应用名,应用名与配置文件中的name是一样的,UP表示该应用的状态
注册中心集群
192.168.1.1
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-eureka/
vim src/main/resources/application.properties
修改
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
192.168.1.4第二台同样的操作
然后两台注册中心进行重新打包
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-eureka/
mvn clean package
完成后使用Java启用Web应用
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-eureka/
java -jar target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar
还是访问192.168.1.1:8000
可以看到,因为两个的应用名一样,所以会在一起显示
Producer(生产者)
模拟多台生产者
以上阻塞的继续运行即可,打开主机的另一台终端
192.168.1.1(生产者)
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-producer/
vim src/main/resources/application.properties
# 修改为注册中心集群地址,在运行时会自动到注册中心进行注册
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
修改生产者回应信息
vim src/main/java/com/neo/controller/HelloController.java
修改
return "hello "+name+",this is first message\n";
进行打包mvn clean package
192.168.1.4(生产者)
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-producer/
vim src/main/resources/application.properties
# 修改为注册中心集群地址
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
修改1.4生产者回应信息
vim src/main/java/com/neo/controller/HelloController.java
修改
return "hello "+name+",this is second message\n";
对两台生产者进行打包
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-producer/
mvn clean package
最后两台都运行producer
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-producer/
java -jar target/spring-cloud-producer-0.0.1-SNAPSHOT.jar
当以上命令运行成功后,再次访问192.168.1.1:8000
或者192.168.1.4:8000
Consumer(消费者)
192.168.1.1模拟消费者
需要再开一个终端,1.1已经三个终端,1.4两个
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-consumer/
vim src/main/resources/application.properties
修改
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
生产者返回信息测试
curl 192.168.1.1:9000/hello?name=abc
hello abc,this is first message
curl 192.168.1.4:9000/hello?name=abc
hello abc,this is second message
vim src/main/java/com/neo/remote/HelloRemote.java
消费者调用方法
对消费者进行打包
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-consumer/
mvn clean package
运行消费者进行验证
cd spring-cloud-examples/eureka-producer-consumer/spring-cloud-consumer/
java -jar target/spring-cloud-consumer-0.0.1-SNAPSHOT.jar
直接访问本机的消费者端口即可http://192.168.1.1:9001/hello/mupei
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is first message
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is second message
不断刷新会变换生产者的返回信息,是因为Spring Cloud的Ribbon负载均衡组件的作用进行集群轮询
一切的拒绝连接,检查防火墙
Hystrix(熔断器)
首先将上面的Consumer消费者的jar包停掉
# spring-cloud-consumer-hystrix含有熔断器代码的消费者
cd spring-cloud-examples/spring-cloud-hystrix/spring-cloud-consumer-hystrix/
vim src/main/resources/application.properties
# 同样修改注册中心的集群地址
eureka.client.serviceUrl.defaultZone=http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
将熔断器进行打包
cd spring-cloud-examples/spring-cloud-hystrix/spring-cloud-consumer-hystrix/
mvn clean package
运行熔断器的jar包,同样也是阻塞模式
cd spring-cloud-examples/spring-cloud-hystrix/spring-cloud-consumer-hystrix/
java -jar target/spring-cloud-consumer-hystrix-0.0.1-SNAPSHOT.jar
因为这个熔断器也是一种消费者,而且他的端口也是9001
直接访问即可
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is second message
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is first message
模拟生产者故障
停掉一台生产者的jar包,发现返回信息只有另一台还在运行的生产者返回信息
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is second message
curl 192.168.1.1:9001/hello/mupei
hello mupei,this is second message
再将另一台生产者也停掉
curl 192.168.1.1:9001/hello/mupei
# 这个返回信息代表,后端没有可用节点,无法处理
hello mupei, this messge send failed
Zuul(微服务网关)
将熔断器消费者停掉,将生产者继续运行
请求路由、请求验证(token验证)
访问格式:http://网关ip:port/微服务名/hello/name=xxx
192.168.1.1
cd spring-cloud-examples/spring-cloud-zuul/spring-cloud-zuul/
vim src/main/resources/application.properties
修改注册中心ip
eureka.client.service-url.defaultZone=http://192.168.1.1:8000/eureka,http://192.168.1.4:8000/eureka
# 释义
#是否开启重试功能,微服务不可用时是否重试
zuul.retryable=true
#对当前服务的重试次数
ribbon.MaxAutoRetries=2
#切换相同Server的次数
ribbon.MaxAutoRetriesNextServer=0
对微服务网关进行打包
cd spring-cloud-examples/spring-cloud-zuul/spring-cloud-zuul/
mvn clean package
运行Zuul的jar包
cd spring-cloud-examples/spring-cloud-zuul/spring-cloud-zuul/
java -jar target/spring-cloud-zuul-1.0.0.BUILD-SNAPSHOT.jar
访问网关端口
http://192.168.1.1:8888/spring-cloud-producer/hello?name=abc&token=abc
使用liunx命令行来访问会报错token is empty
,因为命令行会认为&是后台运行,将url加上单引号即可,将&符号转义也可以
通过网关访问生产者也是成功的,可以轮询
curl http://192.168.1.1:8888/spring-cloud-producer/hello?name=abc\&token=abc
hello abc,this is first message
curl http://192.168.1.1:8888/spring-cloud-producer/hello?name=abc\&token=abc
hello abc,this is second message
Sleuth+ZipKin(微服务链路追踪)
断掉之前的网关和生产者
微服务环境复杂时,使用链路追踪,每经过一个链路(会生成一个调用记录(span),调用记录用来记录请求的去向和请求的处理时长,将各个span连接起来组成trace,可以理解为拓扑图
1、耗时分析:对相应时间较长的节点进行专项优化
2、根据trace描绘出微服务系统的拓扑图,是微服务系统的感知性增强
192.168.1.1
cd spring-cloud-examples/spring-cloud-sleuth-zipkin/zipkin-server/
vim src/main/resources/application.yml
修改注册中心ip:
defaultZone: http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
对Sleuth+ZipKin代码的进行打包
cd spring-cloud-examples/spring-cloud-sleuth-zipkin/zipkin-server/
mvn clean package
运行jar包
java -jar target/zipkin-server-1.0.0.BUILD-SNAPSHOT.jar
192.168.1.1
再准备运行一个含有追踪代码(sleuth)的网关(zuul)
cd spring-cloud-examples/spring-cloud-sleuth-zipkin/spring-cloud-zuul/
vim src/main/resources/application.yml
# 修改zipkin的ip和注册中心集群ip
base-url: http://192.168.1.1:9000
defaultZone: http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
# 释义:
percentage: 1.0 # 数据采集比例,1代表100%,01代表10%
对含有追踪代码的网关进行打包
mvn clean package
运行该代码包
java -jar target/spring-cloud-zuul-1.0.0.BUILD-SNAPSHOT.jar
192.168.1.1
再准备运行一个含有追踪代码(sleuth)的生产者(producer)
cd spring-cloud-examples/spring-cloud-sleuth-zipkin/spring-cloud-producer/
vim src/main/resources/application.yml
# 修改zipkin的ip和注册中心集群ip
base-url: http://192.168.1.1:9000
defaultZone: http://192.168.1.1:8000/eureka/,http://192.168.1.4:8000/eureka/
对生产者进行打包
mvn clean package
运行该生产者jar包
java -jar target/spring-cloud-producer-1.0.0.BUILD-SNAPSHOT.jar
访问192.168.1.1:8000
,当前运行的微服务有以下这些

通过网关访问producer,使得Sleuth+ZipKin可以进行链路追踪
http://192.168.1.1:8888/producer/hello?name=cyj
然后通过访问9000端口的ZipKin192.168.1.1:9000
可以看到图形化的链路追踪
根据时间范围获取,在某个时间段内经过的各个链路的span(调用记录)
2spans
表示经过两个链路,即两个微服务,一共用时2.917s,两个微服务是producer和zuul,producerX1访问producer一次,zuulX2请求访问和返回数据一共经过两次网关,最后的时间和网关的时间是一样的,因为这个时间代表第二次从网关返回数据时的时长
依赖分析中可以看出,两个微服务之间的关系
微服务监控
主要功能:对微服务的存活性进行检测并进行邮件报警
建议内存最少3G,否则在最后启动8000端口内存撑不住,会自动杀死8761的进程
停掉所有微服务
cd spring-cloud-examples/spring-boot-admin-eureka/spring-cloud-eureka/
mvn spring-boot:run # 和之前的打包运行的效果是一样的
然后再准备运行一个生产者(producer)
cd spring-cloud-examples/spring-boot-admin-eureka/spring-cloud-producer
mvn spring-boot:run
再准备运行一个生产者2(producer-2)
cd spring-cloud-examples/spring-boot-admin-eureka/spring-cloud-producer-2
mvn spring-boot:run
最后将监控也运行起来
授权码通过百度方法获取
cd spring-cloud-examples/spring-boot-admin-eureka/spring-boot-admin-server/
vim src/main/resources/application.yml
修改
mail: # 报警邮箱配置
host: smtp.qq.com # 代表使用qq邮箱
username: 841597730@qq.com # 填写自己qq邮箱
password: aqgrmkvhityobbjf # 授权码
boot:
admin:
notify:
mail:
from: 841597730@qq.com # 发件人邮箱
to: mupeifeiyi@gmail.com # 收件人邮箱
mvn spring-boot:run
访问http://192.168.1.1:8761/
可以看到已经运行的四个微服务
然后现在来访问查看监控页面192.168.1.1:8000
模拟其中一台producer微服务down掉,然后就会发送邮件给你指定的邮箱,通知我某个微服务离线
微服务端口号
Eureka:8000
Producer:9000
Consumer:9001
Hystrix Consumer:9001
Zuul:8888
ZipKin-Server:9000
ZipKin-Producer:9001
ZipKin-Zuul:8888
admin-Eureka:8761
admin-server:8000
admin-Producer:9000
admin-Producer-2:9001