文章目录
前言
本文是通过观看b站尚硅谷的BV18E411x7eT视频而产生的一些笔记和总结。
父工程
父pom:涉及maven知识点:
- 必须设置packaging为pom。
- 用来做和springboot-dependence里类似的版本规定,只规定不导入,子工程需要声明但是不用设置version。跟springboot里的starter差不多。
- 子模块还会继承maven的groupid和version,创建子模块的时候自动填装。
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
dependencyManagement下的dependence只规定版本,并不会真的导入,
可以看idea中或者maven的外部库,不会有包引入。
支付模块
生产者
创建子模块后,父pom里会生成modules。子工程也有artifactId指向父工程。
接下来就是编码存在一些情况:
- 设置这两个属性useGeneratedKeys=“true” keyProperty="id"可以让插入完毕返回主键自增的id。
- 返回类型为实体类推荐写resultMap。
消费者模块
使用spring自带的restTemplate连接支付模块。
@Configuration
public class ApplicationContextConfig {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
配置这个只是为了实现spring 的ioc思想,能够使用autowire注入,之后也能开启负载均衡。
restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment,CommonResult.class);
restTemplate.getForObject(PAYMENT_URL + "/payment/get/"+id,CommonResult.class);
由于消费者模块也需要payment等相同实体类,所以要进行工程重构。
工程重构
建立一个common模块,复制公共实体类等包,使用maven进行install打成jar包。
然后删除消费者生厂者中的公共实体类包,再pom中引入common模块。
Eureka注册中心
生产者多了,不知道调哪个跟好,所以需要注册中心。
Eureka Server
创建server模块作为注册中心。
Eureka Client
生产者消费者入住Eureka Server。
Eureka集群
相互守望,a指向b,b指向a。
多生产者
构建多生产者,只需要修改tomcat端口即可。
消费者负载均衡
在消费者的RestTemplate上添加@LoadBalanced开启负载均衡,并将url由ip+端口 改为http://生产者服务名字 即可。
Eureka页面优化
配置eureka.instance.instance-id为服务的status展示名称。
再加上eureka.instance.prefer-ip-address: true可以显示ip。
服务发现
生产者提供一个对外的rest接口,返回用DiscoveryClient得到的服务信息。
启动类还需要加@EnableDiscoveryClient。
Eureka自我保护
一个微服务不能用了,Eureka不会立即清理。
禁止自我保护:
注册中心配置
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
服务端配置
eureka:
instance:
#发送心跳间隔
lease-renewal-interval-in-seconds: 1
lease-expiration-duration-in-seconds: 2
CAP:强一致性、高可用性、分区容错。
Ribbon
消费者的进程内的本地负载均衡工具。
负载均衡+RestTemplate。
eureka的starter已经引入了ribbon的starter。
RestTemplate
restTemplate.getForObject/postForObject 返回json。
getForEntity/postForEntity 返回ResponseEntity对象,包含状态码等。
更改负载均衡规则
官方提供了一些规则,IRule的实现类,
需要在启动类包上一级建立一个配置类,配置IRule。
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule();
}
}
并在启动类加上
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
表明对于哪个服务采用什么配置策略,还一个RibbonClients注解应该是配置多个服务对应策略。
负载均衡原理
轮询:请求次数 对于 选取的服务的数量 取余,作为服务器列表的下标。
可以通过查看源码中对于IRule的方法的实现得到。
手写轮询算法
public interface LoadBalancer {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
@Component
public class MyLb implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement(){
int current;
int next;
do{
current = this.atomicInteger.get();
next = current >= 2147483647 ? 0 : current+1;
}while (!this.atomicInteger.compareAndSet(current,next));
System.out.println("***次数 next: " + next);
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
@GetMapping("/consumer/payment/lb")
public String getPaymentLb(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances==null||instances.size()<=0){
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
OpenFeign
简化ribbon的restTemplate操作,实际还是ribbon。feign配好了负载均衡配置类。
Ribbon是在Controller层操作,而feign集成到service层,更符合操作习惯。
@Component
@FeignClient("CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
@GetMapping("/payment/get/{id}")
CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
OpenFeign超时控制
openfeign默认1秒钟没得到返回就报错。
设置时间
ribbon:
ReadTimeout: 5000
ConnectTimeout: 5000
OpenFeign日志增强
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug
Hystrix断路器
在多个微服务连锁调用过程中,中间某个微服务出现问题,会影响到整个系统的高可用性。
当一个接口被高并发,tomcat的线程池不够用,另一个接口也会受影响。
服务降级
返回一个友好提示的响应。
程序异常,超时,服务熔断,线程池满都会导致降级。
生产者,消费者都应该有降级策略,提供备用响应。
生产者:
@HystrixCommand(fallbackMethod = "paymentInfo_TimeoutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_Timeout(Integer id){
int t = 5;
try {
TimeUnit.SECONDS.sleep(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_Timeout , id: "
+ id + "\t" + "耗时:" + t;
}
public String paymentInfo_TimeoutHandler(Integer id){
return "线程池:" + Thread.currentThread().getName() + " 8001系统繁忙,稍后再试 , id: "
+ id + "\t" + "ε(┬┬﹏┬┬)3";
}
消费者
@GetMapping("/consumer/payment/hystrix/Timeout/{id}")
public String paymentInfo_Timeout(@PathVariable("id") Integer id){
String result = paymentHstrixService.paymentInfo_Timeout(id);
return result;
}
public String paymentInfo_TimeoutHandler(Integer id){
return "消费者的服务降级: ε(┬┬﹏┬┬)3";
}
可以配置统一处理结果。
@DefaultProperties写在类上。
避免service和controller混乱。
可以定义一个类实现openfeign的调用service接口,实现方法的返回值即为降级的响应。十分方便。
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
@Component
public class PaymentFallbackService implements PaymentHstrixService {
@Override
public String paymentInfo_Ok(Integer id) {
return "---PaymentFallbackService ok";
}
@Override
public String paymentInfo_Timeout(Integer id) {
return "---PaymentFallbackService timeout";
}
}
服务熔断
先降级,熔断,再恢复调用链路。
熔断了就算是对的,也会触发降级。
服务限流
仪表盘
用来监控经过hystrix的请求。
Gateway服务网关
路由转发,执行过滤链,底层netty,异步非阻塞。
- Predicate断言
- Route路由
- Filter过滤
路由
url条件跟断言匹配则可以走网关。
不能引入web依赖,因为它用的netty,会冲突。
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/**
动态路由
网关侧的负载均衡,不指定地址,而是通过服务名。
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh
#uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/get/**
- id: payment_routh2
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/**
discovery:
locator:
enabled: true
过滤器
前置,后置,全局,单一。
可以通过过滤器修改url地址
predicates:
- Path=/api/thirdparty/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
自定义全局过滤器
@Slf4j
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("======come in MyLogGateWayFilter: "+ LocalTime.now());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null){
log.info("=====用户名为空,非法");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//表示顺序
return 0;
}
}
Config配置中心
统一配置的外部配置中心。
Bus消息总线
对于config的动态刷新的加强,广播,差异化管理。
Stream消息驱动
屏蔽MQ的差异,提供统一操作,类似mvc中返回一个前后端都识别的result类。
binder对象作为中间层。input消费 output生产。
生产者:source推送管道 channel发送管道。
消费者:sink
消息分组,相同组轮询消费,避免重复消费。
Sleuth请求链路跟踪
对服务调用进行监控。
Cloud Alibaba
Nacos
注册中心 + 配置中心
注册中心
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
nacos集成了ribbon支持负载均衡.
nacos支持cp ap切换。
配置中心
新建的配置,data id需要按照官方的规则。
nacos就会按照这个规则自动查找配置。
nacos修改配置后,动态刷新立马更新,无需其他配置。
分组配置
namespace+group+dataId
dataid匹配spring的profiles.active环境。
group和namespace匹配nacos的设置。
Nacos集群和持久化
nacos自带derby数据库,持久化只支持mysql。
nacos自带sql脚本。
Sentinel熔断与限流
跟nacos一样,已经写好打成jar包,直接启动就可以,对Hystrix的取代。
需要被监控的服务先随便调用一个请求。
流控规则
QPS每秒请求数。
达到QPS进行限流。
qps是外部,线程是内部。
关联,a->b,b顶不住了,a就少放点请求。
预热,设定多少秒后才把阈值由初始升至最高,秒杀系统。
排队等待,进了之后排队处理。匀速处理请求。
降级规则
RT:秒级平均响应时间,1秒超过5个请求并且平均处理时间大于阈值才触发。
异常比例:1秒超过5个请求并且异常比例超过阈值。
异常数
热点规则
针对热点参数进行判断,
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false)String p1,
@RequestParam(value = "p2",required = false)String p2){
return "------testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException exception){
return "-----deal_testHotKey";
}
sentinel熔断没有半开状态。
系统规则
对整个系统限流。
@SentinelResuorce
fallback只处理java异常,blockHandler只处理配置异常。
Sentinel持久化
Seata处理分布式事务
Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。
分布式事务处理:
-
全局唯一事务id
-
TC (Transaction Coordinator) - 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。 -
TM (Transaction Manager) - 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务。 -
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
总结
进入cloud开发后,大多都是配置+注解,建议少花点时间了解怎么用。