SpringColud
文章目录
1.分布式应用*( 微服务)
1.原来的项目会出现的问题?
原来的项目,一个service出现bug就会运行不了,扩展麻烦
分布式架构不一定是微服务,微服务是分布式架构
用户量不大采用分布式架构:想做大做强,防止以后项目大重构。
分布式:
分布式服务顾名思义服务是分散部署在不同的机器上的,一个服务可能负责几个功能,是一种面向SOA架构的,服务之间也是通过rpc来交互或者是webservice来交互的。逻辑架构设计完后就该做物理架构设计,系统应用部署在超过一台服务器或虚拟机上,且各分开部署的部分彼此通过各种通讯协议交互信息,就可算作分布式部署,生产环境下的微服务肯定是分布式部署的,分布式部署的应用不一定是微服务架构的,比如集群部署,它是把相同应用复制到不同服务器上,但是逻辑功能上还是单体应用。
微服务:
简单来说微服务就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事。这个服务可以单独部署运行,服务之间可以通过RPC来相互交互,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期。
SpringCloud概述
分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶
SpringBoot和SpringCloud:
SpringBoot专注于快速方便的开发单个个体微服务。
SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,
为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务
SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系.
SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。
2.Eureka
注册中心
SpringCloud Euraka是SpringCloud集合中一个组件,它是对Euraka的集成,用于服务注册和发现。Eureka是Netflix中的一个开源框架。它和 zookeeper、Consul一样,都是用于服务注册管理的.
原理:
1.在启动每- 个服务的时候会吧自己的信息注册到注册中心中,并且会拉去一份最新的服务列表
2.每个30秒回给注册中心发送心跳包,确保他还活着,并且会拉去一份最新的服务列表
3.如果连续3次,注册中心都没有接受到心跳包,那么他会吧这个节点从服务列表中去掉
2.1 注册中心eureka-server
1.使用Spring Initializr创建SpringBoot项目,选择Cloud Discover->Eureka Server
2.启动类上贴上@EnableEurekaServer注解
3.修改application.properties为application.yml文件,添加相关配置信息. https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#spring-cloud-eureka-server
4.运行测试,打开浏览器输入http://localhost:8761
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2.2 商品服务product-server
1.使用Spring Initializr创建SpringBoot项目,选择Cloud Discover->Eureka Discover 和 Web->Web
2.把application.properties修改成application.yml,并添加配置信息 https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#netflix-eureka-client-starter
3.启动测试,会在Eureka注册中心控制台页面中看到product-server实例
4.启动多个实例,在注册中心管控台页面也可以看到.(在idea启动配置中添加-Dserver.port=8082参数,可以覆盖配置文件中的配置)
5.添加mapper,service,controller类.
server:
port: 8081
spring:
application:
name: product-server
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
2.3 商品服务接口product-api搭建
1.创建骨架类型为quickstart项目,删除多余的依赖和src/test目录的文件
2.复制pom.xml
写一个product类
2.4 SpringCloud Eureka 自我保护机制
Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期,但是在保护期内如果服务刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败,对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。
我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,这个时候就会触发 Eureka 的保护机制,一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐)
3.微服务调用方式Ribbon
3.1订单服务order-server
步骤
1.使用Spring Initializr创建SpringBoot项目,选择Cloud Discover->Eureka Discover , Web->Web , Cloud Routing->Robbin
2.在项目的pom.xml文件添加product-api的依赖
3.添加相关的依赖配置
4.把创建订单的功能实现(获取商品信息暂先放下)
server:
port: 8090
spring:
application:
name: order-server
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
3.2 使用Ribbon来实现远程调用
1.在配置文件中添加RestTemplate的bean
2.使用restTemplate.getObject获取远程接口的信息.
3.3 使用Ribbon实现负载均衡
1.请求地址不写具体ip和端口,而是使用远程服务id
2.在RestTemplate的bean上贴上@LoadBalanced注解
PRODUCT-SERVER:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
注意:服务的名称需要和代码中的服务名称一致,不然是修改不了负载均衡策略.
4.微服务调用方式Feign
4.1使用Feign方式实现远程调用
步骤:
1.在product-api项目中添加openfeign依赖
2.在product-api项目中添加ProductFeignApi接口
3.在product-server项目中添加ProductFeignApi的实现类(本质上就是个Controller),注意要把之前的controller删除掉.
4.在order-server项目中的启动类上贴上@EnableFeignClients注解
5.把之前RestTemplate的远程调用替换成Feign方式调用即可 (注意product-api和order-server中包名的问题.)
1.<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.ProductFeignApi:
@FeignClient(name = "product-server")
public interface ProductFeignApi {
@RequestMapping("/api/v1/product/find")
Product find(@RequestParam("id") Long id);
}
3.ProductFeignClient:
@RestController
public class ProductFeignClient implements ProductFeignApi {
@Autowired
private IProductService productService;
@Value("${server.port}")
private String port;
@Override
public Product find(Long id) {
Product product = productService.get(id);
Product result = new Product();
BeanUtils.copyProperties(product,result);
result.setName(result.getName()+",data from "+port);
return result;
}
}
4.2 Feign超时时间设置
源码中默认options中配置的是6000毫秒,但是Feign默认加入了Hystrix,此时默认是1秒超时.
我们可以通过修改配置,修改默认超时时间.
feign:
client:
config:
default:
connectTimeout: 4000
readTimeout: 4000
4.3 Feign超时重试次数设置
#超时重复次数
#sample-client.ribbon.MaxAutoRetries=0
#sample-client.ribbon.MaxAutoRetriesNextServer=1
5.服务熔断与降级
5.1.熔断降级-hystrix
01.在order-server中添加hystrix依赖
02.在启动类中添加@EnableCircuitBreaker注解
03.在最外层添加熔断降级的处理. 在order-server中的控制器中添加@HystrixCommand(fallbackMethod = "saveFail")注解 (注意fallbackMethod需要和原方法一样的签名
{要注意 贴注解后启动类要能够扫描的到。}
5.2.Feign集成Hystrix
01.在ProductFeignApi的@FeignClient(name = "PRODUCT-SERVER",fallback = ProductFeignHystrix.class)
02.默认是关闭的,需要手动开启一下
feign:
hystrix:
enabled: true
03.创建一个ProductFeignHystrix,里面是feign的降级方法。。。
5.3.熔断降级服务异常报警通知 – redis
01.配置redis相关配置
02.public Order saveFail(Long userId,Long productId){
new Thread(()->{
String redisKey = "order-save";
String value = stringRedisTemplate.opsForValue().get(redisKey);
if(StringUtils.isEmpty(value)){
System.out.println("order下订单服务失败,请查找原因.");
stringRedisTemplate.opsForValue().set(redisKey,"save-order-fail",20, TimeUnit.SECONDS);
}else{
System.out.println("已经发送过短信");
}
}).start();
return new Order();
}
5.4.Hystrix超时时间调整
是否开启超时限制 (一定不要禁用)
hystrix:
command:
default:
execution:
timeout:
enabled:
超时时间调整
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 4000
hystrix配置的时间要比feign的大才有意义,并且hystrix与feign的超时时间都不要超过2s
5.5.断路器Dashboard监控仪表盘
它主要用来实时监控Hystrix的各项指标信息。通过Hystrix Dashboard反馈的实时信息,可以帮助我们快速发现系统中存在的问题。
1.添加dashboard和actuator依赖 actuator:提供接口地址
2.在启动类上贴@EnableHystrixDashboard
3.在配置文件中添加开发监控地址配置 ---application.yml
4.访问入口:http://localhost:启动端口/hystrix,
然后再地址栏上输入:http://localhost:启动端口/actuator/hystrix.stream
management:
endpoints:
web:
exposure:
include: "*"
6.微服务网关Zuul
是什么?
Zuul网关是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
用法:
1.验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
2.审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
3.动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
4.压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
5.负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
6.静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
7.多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
主流的网关:
1.zuul:Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用.
2.kong:由Mashape公司开源的,基于Nginx的API gateway
3.nginx+lua:是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求
6.1网关项目zuul-server
1.使用Spring Initializr创建SpringBoot项目,选择Cloud Discover->Eureka Discover , Cloud Rounting -> Zuul
2.添加application.yml配置文件并添加相关的配置信息.
3.在启动类上贴上@EnableZuulProxy注解
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
#自定义网关
zuul:
ignoredPatterns: /*-server/**
sensitiveHeaders: #------处理cookie请求头问题
routes:
order-server-route:
path: /order/**
serviceId: order-server
product-server-route:
path: /product/**
serviceId: product-server
处理cookie请求头问题:
默认情况,网关会把Cookie", "Set-Cookie", "Authorization"这三个请求头过滤掉,下游的服务是获取不到这几个请求头的。
如果不需要过滤这个请求头,可以修改过滤的集合的值.
下面这个属性直接设置:
sensitiveHeaders
6.2 自定义Zuul过滤器实现登录鉴权
订单服务需要判断是否登陆,
AuthZuulFilter
@Component
public class AuthZuulFilter extends ZuulFilter {
//过滤类型
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
//有多个同类型的过滤器情况下,过滤器执行顺序
@Override
public int filterOrder() {
return 0;
}
//返回值为true,表示需要进行过滤操作。下一步进入run方法,
//返回值为false,表示不需要过滤操作,直接放行了. (不会进入run方法)
@Override
public boolean shouldFilter() {
//获取请求路径
String requestURI = RequestContext.getCurrentContext().getRequest().getRequestURI();
System.out.println("请求路径:"+requestURI);
//判断是否包含order
if(requestURI.indexOf("/order")>=0){
return true;
}
return false;
}
//当shouldFilter返回为true的请求下,在run方法中进行过滤操作。
@Override
public Object run() throws ZuulException {
System.out.println("进入run方法");
RequestContext rc = RequestContext.getCurrentContext();
HttpServletRequest request = rc.getRequest();
String token =request.getHeader("token");
if(StringUtils.isEmpty(token)|| !"123".equals(token)){
//没token
rc.setSendZuulResponse(false);
rc.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}
7.链路追踪组件Sleuth&Zipkin
微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性,如果出现了错误和异常,很难去定位。主要体现在,一个请求可能需要调用很多个服务,而内部服务的调用复杂性,决定了问题难以定位。所以微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题,很快定位。
在微服务系统中,一个来自用户的请求,请求先达到前端A(如前端界面),然后通过远程调用,达到系统的中间件B、C(如负载均衡、网关等),最后达到后端服务D、E,后端经过一系列的业务逻辑计算最后将数据返回给用户。对于这样一个请求,经历了这么多个服务,怎么样将它的请求过程的数据记录下来呢?这就需要用到服务链路追踪。
什么叫埋点
所谓埋点就是在应用中特定的流程收集一些信息,用来跟踪应用使用的状况,后续用来进一步优化产品或是提供运营的数据支撑,包括访问数(Visits),访客数(Visitor),停留时长(Time On Site),页面浏览数(Page Views)和跳出率(Bounce Rate)。这样的信息收集可以大致分为两种:页面统计(track this virtual page view),统计操作行为(track this button by an event)。
7.1集成链路追踪组件Sleuth
01.在product-server和order-server中添加sleuth依赖
02.在需要写日志的类上贴@Slf4j,然后再order-server,product-server中打印日志。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
7.2 什么是Zipkin
zipkin是Twitter基于google的分布式监控系统Dapper(论文)的开发源实现,zipkin用于跟踪分布式服务之间的应用数据链路,分析处理延时,帮助我们改进系统的性能和定位故障。
官网:https://zipkin.io/
CAT:由大众点评开源,基于Java开发的实时应用监控平台,包括实时应用监控,业务监控 。
Pinpoint:由韩国团队naver团队开源,针对大规模分布式系统用链路监控,使用Java写的工具。
SkyWalking:2015年由个人吴晟(华为开发者)开源 , 2017年加入Apache孵化器。
针对分布式系统的应用性能监控系统,特别针对微服务、cloud native和容器化(Docker, Kubernetes, Mesos)架构, 其核心是个分布式追踪系统
7.3 Zipkin+Sleuth整合
01.在微服务项目中添加zipkin依赖(zipkin依赖中已经包含sleuth,所以可以把之前的sleuth依赖删除)
02.启动zipkin服务,我们直接使用的是jar的方式.
03.需要在product-server和order-server中的配置文件中添加zipkin地址.
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
8.分布式配置中心Config
统一管理配置, 快速切换各个环境的配置
在微服务体系中,服务的数量以及配置信息的日益增多,比如各种服务器参数配置、各种数据库访问参数配置、各种环境下配置信息的不同、配置信息修改之后实时生效等等,传统的配置文件方式或者将配置信息存放于数据库中的方式已无法满足开发人员对配置管理的要求,如:
安全性:配置跟随源代码保存在代码库中,容易造成配置泄漏
时效性:修改配置,需要重启服务才能生效
局限性:无法支持动态调整:例如日志开关、功能开关
8.1 搭建config-server项目
在gitee,创建一个仓库
01.使用Spring Initializr创建SpringBoot项目,选择Cloud Discover->Eureka Discover , Cloud Config -> Config Server
02.在启动类中贴上@EnableConfigServer注解
03.添加application.yml并设置相关的配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
server:
port: 9100
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://gitee.com/sinian416/springcloud
ureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
/{name}-{profiles}.properties
/{name}-{profiles}.yml
/{name}-{profiles}.json
/{label}/{name}-{profiles}.yml
name 服务名称
profile 环境名称,开发、测试、生产
lable 仓库分支、默认master分支
8.2 分布式配置中心客户端
01.在order-server中添加config-client的依赖
02.修改对应服务的配置文件,把application.yml 改为 bootstrap.yml
03.把其他配置都放入到git服务器期中管理
spring:
application:
name: ORDER-SERVER
cloud:
config:
discovery:
service-id: config-server
enabled: true
label: master
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
.yml
ureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 9999
spring:
application:
name: ORDER-SERVER
redis:
host: localhost
port: 6379
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1
#负载
PRODUCT-SERVER:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 0
#feign:
# hystrix:
# enabled: true
#超时时间
feign:
client:
config:
default:
connectTimeout: 4000
readTimeout: 4000
#超时重复次数
#sample-client.ribbon.MaxAutoRetries=0
#sample-client.ribbon.MaxAutoRetriesNextServer=1
#超时时间调整
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
#监视仪表盘
management:
endpoints:
web:
exposure:
include: "*"
错误
出现 null问题,可能是注解贴完扫描不到,将启动类提前到cn.wolfcode包下