微服务
- 开发模式(springBoot):
- 服务粒度:正确划分微服务的大小和职责;
- 通信协议:开发人员如何与服务进行通讯,数据传输类型(json、xml、二进制)是什么等等;(Apache 的 Http Cliend、Netty 的 Http Cliend、socket、spring RestTemplate、Feign、OpenFeign)
- 接口设计:便于使用调用,遵循一定的规范和风格;(restful、webservices)
- 服务的配置管理:便于环境迁移;(SpringCloudConfig、Nacos)
- 事件处理:降低服务间的耦合;(SpringCloudStream 异步消息处理,可以集成RabbitMQ和Kafka)
- 路由模式
- 服务发现(Nacos、Eureka、Consul、Zookeeper);
- 服务路由:微服务提供单点入口,以便将安全策略和路由规则统一应用于微服务应用程序中的多个服务实例;(zuul、Gateway)
- 客户端弹性模式:
- 客户端负载均衡(Ribbon、LoadBalancer);
- 断路器模式:阻止客户端继续调用出现故障或者有性能问题的服务;(Hystrix、sentienl)
- 后备模式:服务调用失败后提供插件机制,允许服务的客户端尝试通过调用微服务之外的其他方法来执行工作;
- 舱壁模式:一个服务的调用不影响另一个服务;
- 安全模式:
- 验证,授权;(SpringSecurity是基于令牌的,允许服务通过严恒服务器发出的令牌彼此进行通信)
- 凭证的传播与管理:使用基于令牌的安全方案,可以实现服务验证和授权,而无需传递客户端凭证;
- 日志记录和跟踪模式:
- 日志关联:当一个用户事务调用了多个1服务时要将这些服务的日志关联在一起;(Spring Cloud Sleuth与日志聚合技术工具(如 Papertrail)和跟踪工具(如 Zipkin)结合时能够展现出真正的威力)
- 日志聚合(Papertail是一个基于云的日志记录平台。用于将日志从不同的微服务实时聚合到一个可查询的数据库中。);
- 微服务跟踪:在涉及的所有服务中可视化客户端事务的流程,并了解事务所涉及的服务的性能特征(Zipkin可以获取Spring Cloud Sleuth生成的数据,并允许开发人员可视化单个事务涉及的服务调用流程);
- 构建和布署模式:
- 构建和部署管道:创建一个可重复的构建和部署过程,只需一键即可构建和部署到组织中的任何环境;
- 基础设施即代码:将服务的基础设施作为可在源代码管理下执行和管理的代码去对待;
- 不可变服务器:一旦创建了微服务镜像,如何确保它在部署之后永远不会改变;
- 凤凰服务器(Phoenix Server):服务运行的时间越长,就越容易发生配置漂移。如何确保运行微服务的服务器定期被拆卸,并重新创建一个不可变的镜像;
CAP
- C一致性:每个用户读到的数据必须是一样的;
- A可用性:意思是只要收到用户的请求,服务器就必须给出回应;
- P分区容错:区间通信可能失败,必须解决;
因为存在了分区容错性,所以一致性和可用性不能同时满足;原因:保证一致性则在写的时候需要锁定其他服务的读操作和写操作,这时其他服务不可用;
服务注册中心
Eureka(AP)
-
两个组件:EurekaServer(@EnableEurekaServer)、EurekaClient(@EnableEurekaClient)
-
服务注册:EurekaServer中会维护一张注册表,记录了可用节点的信息;
-
服务发现:添加**@EnableDiscoveryClient** 并通过DiscoveryClient类我们可以获取到客户端的详细信息;
-
心跳机制:客户端会给EurekaServer发送心跳(Http)维持链接(默认30s),多个周期内没有收到的化,EurekaServer会从注册表中移除这个节点;
-
自我保护:但是在短时间( 90秒中)内丢失了大量的服务实例心跳,这时候Eurekaserver会开启自我保护机制,不再注销任何服务实例。防止因为网络抖动的情况下出现严重失误;
-
安全机制:当我们使用SpringSecurity后,无法在eureka上进行注册,所以我们需要关闭csrf;
-
创建一个配置类添加**@EnableWebSecurity** 注解,继承WebSecurityConfigurerAdapter 重写里面的方法
@EnableWebSecurity class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); //取消 csrf() super.configure(http); } }
-
-
负载均衡:内置了ribbon
Nacos
注册中心
-
Nacos本身就是一个SprintBoot 项目,启动命令
startup.cmd -m standalone
-
服务注册:将服务注入进Nacos中(引入依赖,改配置文件)
-
分级存储模型(discovery):微服务实例可能处于不同的机房中,可以以机房划分集群;
spring: cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: HZ # 集群名称 HZ杭州
-
负载均衡NacosRule:优先同集群(机房)的服务访问;
-
权重配置:web页面可视化配置;0-1,越大频率越高,0不会被访问,可用于系统平滑升级等;
-
环境隔离(namespace):
-
创建命名空间namespace
-
spring: cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: HZ namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间ID
-
不同的命名空间的服务不能相互访问,可以用来区别测试、生产、开发环境;
-
-
临时实例(ephemeral):
-
临时实例:实例宕机一定时间则剔除(默认AP)
-
非临时实例:不会剔除实例;(存在则CP)
-
spring: cloud: nacos: discovery: ephemeral: false # 设置为非临时实例
-
配置中心
-
可视化添加配置,可热更新,不变配置保存在微服务中较好;
- Data ID:配置文件名称-profile.后缀名;
- Group:分组,默认即可;
- 文件格式;
- 配置内容;
-
微服务拉取配置:
-
存在问题:服务启动时先去读取Nacos配置文件,此时Nacos的地址就不能配置在application.yaml文件中;
-
解决:配置在更先读取的bootstrap.yaml文件中;
-
spring: application: name: userservice # 服务名称 profiles: active: dev #开发环境,这里是dev cloud: nacos: server-addr: localhost:8848 # Nacos地址 config: file-extension: yaml # 文件后缀名
服务名称-开发环境.文件后缀 = Data ID
-
-
配置热更新:
- 在 @Value注入的变量所在类上添加注解 @RefreshScop
- @ConfigurationProperties
-
配置共享:
-
不同环境共享:Data ID不添加profile,则这个配置可以被多个环境共享;
-
不同微服务共享 (shared-configs,extends-configs):
spring: cloud: nacos: config: file-extension: yaml # 文件后缀名 shared-configs(extends-configs): # 多微服务间共享的配置列表 - dataId: common.yaml # 要共享的配置文件id
-
配置优先级:环境配置(服务名-profile.yaml)>本服务配置(服务名称.yaml)>共享配置(extends-configs>shared-configs)>本地配置
-
负载均衡
ribbon 和 LoadBalancer
-
springcloud 2020.0.1 版本之后 删除了eureka中的ribbon,替代ribbon的是spring cloud自带的LoadBalancer
-
原理图
-
轮询方式:
- RoundRobinRule 轮询(默认)
- RandomRule 随机
- RetryRule 按照轮询,超时重试
- WeightedResponseTimeRule 响应速度越大,权重越大
- AvailabilityFilteringRule 过滤故障,选择并发量小的
- ZoneAvoidanceRule 根据区域(默认)
-
饥饿加载:提高第一次访问速度;
ribbon: eager-load: enabled: true clients: userservice # 项目启动时直接去拉取userservice的集群,多个用","隔开
服务调用
Feign和OpenFeign
-
Feign是轻量级RESTful风格的Http服务,客户端内置了Ribbon;
-
OpenFeign是Feign的扩展,支持SpringMVC的注解;
-
使用:
-
引入依赖
-
在启动类上添加**@EnableFeignClients(“com.”)**指定扫描路径
-
业务逻辑接口+@FeignClient
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE" (调用的哪个微服务集群) , configuration = {} (指定配置类 安全配置等) , fallback = (当超时等情况 进行服务降级 的回退方法) ) public interface PaymentFeignService { @RequestMapping(method = {RequestMethod.GET}, value = {"/getPayment/{id}"}) public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); }
服务集群value、安全配置configuration、服务降级fallback
-
安全配置:
-
在服务端,引入SpringSecurity依赖
-
请求头中添加认证信息;
/** * 因为 produce 加入security,所以需要每个请求头加入authentication 认证信息 */ @Configuration public class FeignClienAuthConfig { @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("product", "a"); } }
-
在@FeignClient中的configuration中指定配置
-
-
-
超时控制:
#设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒) ribbon: #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ReadTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000
-
日志增强:
-
日志级别:
- NONE:默认的,不显示任何日志;
- BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
- FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
-
配置:
-
配置类:
@Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; }
-
配置文件:
logging: level: # feign日志以什么级别监控哪个接口 com.xrl.orderService.PaymentFeignService: debug
-
-
-
服务降级
Hystrix
-
服务雪崩:某个模块的网络或者程序处理出现拥挤或者宕机(引起级联故障),导致其他服务的运行速度降低或者停止的情况;解决方式:
-
后备模式:
-
开启断路器:
feign: circuitbreaker: enabled: true
-
配置Fallback方法:
-
全局:
- 控制器上添加**@DefaultProperties(defaultFallback = " 定义的回退方法 ")**:
- 方法上添加**@HystrixCommand**
-
定制:方法上添加 @HystrixCommand(fallbackMethod = (定义的回退方法), commandProperties = {
@HystrixProperty( 属性 )
})
-
-
-
舱壁模式(线程池):
@HystrixCommand(fallbackMethod = "getCallBack", threadPoolKey = "GetThreadPool", //线程池名字 threadPoolProperties = { @HystrixProperty(name = "coreSize",value = "10"), //核心线程数 @HystrixProperty(name = "maxQueueSize",value = "10") //最大线程数 } )
-
断路器:在方法上添加**@HystrixCommand**:
-
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器 @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数 @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期 @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸 })
-
-
-
服务降级:当服务出现超时或者错误时,给客户端一个返回提示,而不是持续等待(fallback);
-
服务熔断:服务达到饱和后,拒绝后续访问,然后利用服务降级返回提示;
- 基本流程:服务降级->服务重试->恢复调用链路;
- 服务降级:当服务出现拥堵或者错误达到断路器的阈值时 (主要为:快照时间窗(统计时间范围), 请求总数阈值(请求最小数量), 错误百分比阈值)断路器打开,打开后在有请求进行访问此服务时,直接调用降级fallback返回(降级逻辑是临时的成为主逻辑), 从而减小程序卡顿;
- 服务重试和恢复调用链路:当经过一段时间后(休眠时间窗)(默认5秒) ,断路器进入半开状态,此时再有请求过来时,断路器尝试放行一个请求,如何请求返回正确情况,则关闭断路器,让程序正常运行;
- 重要参数:
- 快照时间窗:统计多长时间的数据;
- 请求总数阈值:快照时间窗内,请求需满足多少次数才可能会引发熔断;
- 错误百分比阈值:快照时间窗内,错误的百分比;
- 基本流程:服务降级->服务重试->恢复调用链路;
-
服务限流;
-
图形化:Dashboard(仪表盘),依赖,主启动注解,yaml配置
-
信息采集:turbine(服务信息汇聚),依赖,主启动注解,yaml配置
网关
zuul1
Gateway
核心逻辑:路由转发 + 执行过滤器链。
-
Route路由:外部访问网关由网关来指定访问哪个服务
spring: application: name: gateway # 服务名称 cloud: nacos: server-addr: localhost:8848 # nacos地址 gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,只要唯一即可 uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
-
Predicate断言:开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由;
- 断言工厂:时间(前\后\之间)、请求方式、请求数据(Cookie\Header\指定host\指定参数\ip指定范围),路径符合指定规则、权重;
-
Filter过滤:可以在请求被路由前或者之后对请求进行修改。
-
过滤器工厂:添加请求头:
spring: cloud: gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,只要唯一即可 uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求 filters: - AddRequestHeader=sign, xn2001.com is eternal # 添加请求头
-
全局过滤器:
spring: cloud: gateway: default-filters: - AddRequestHeader=sign, xn2001.com is eternal # 添加请求头
-
自定义全局过滤器:
- 实现GlobalFilter, Ordered 接口
-
执行顺序:先按照order值,再按照 默认过滤器>路由过滤器>全局过滤器
-
-
解决跨域问题:
spring: cloud: gateway: globalcors: # 全局的跨域处理 add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题 corsConfigurations: '[/**]': allowedOrigins: # 允许哪些网站的跨域请求 allowedOrigins: “*” 允许所有网站 - "http://localhost:8090" allowedMethods: # 允许的跨域ajax的请求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowedHeaders: "*" # 允许在请求中携带的头信息 allowCredentials: true # 是否允许携带cookie maxAge: 360000 # 这次跨域检测的有效期