概述:最近学完了尚硅谷阳哥的Springcloud第二季,特此记下笔记。通过此笔记,你可以大致的了解Springcloud全家桶与SpringAlibaba在微服务中的作用。
首先,上一张springcloud迭代图。
Eureka(飞机):作为服务注册中心,可以及时的响应微服务启动并将其注册进入其中。作为ACP原则中的AP(高可用性(当微服务挂掉的时候,Eureka并不会立马抹去微服务),分区性(Eureka集群模式)),可以显示当前启动的微服务、以及它们的所在服务器和显示ip。Eureka自带负载均衡功能,本身与Rribbon相结合,通过restTemplate与@LoadBlance注解实现负载均衡。默认的负载模式是轮询负载。这一点可以从Eureka的依赖中看出,如图:
Nacos(飞机):作为阿里的开源项目,微服务注册中心(当然,也可以作为微服务的配置中心,后面会讲)的后起之秀。在ACP原则中,它既可以作为AP,也可以作CP。Eureka有的作用Nacos同样也有,例如可视化界面、服务监听等。 配置通常较为简单,如图:
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
还有一点,别忘记在启动类上加上@EnableDiscoveryClient注解,标识注册中心。
Zookeeper(飞机):同样的,服务注册中心也可以是ZK,但是比起前面两种,ZK并没有可视化界面。作为ACP中的CP原则,当微服务挂掉的时候,ZK上的service下的微服务名称节点立马挂掉。配置如图:
spring:
application:
name: payment-zk-service
cloud:
zookeeper:
connect-string: 10.201.7.113:2181
ZK的默认端口为2181,有一点需要注意的是,搭建ZK环境的服务器至少要有3台,这是由它内部的选举机制决定的。
Ribbon(飞机):作为微服务调用负载工具,可以有效的减缓服务器端的压力,防止流量定点直冲,造成服务雪崩。自带轮询负载,当然也可以通过自定义设置负载模式。
OpenFeign(飞机):作为Feign的取代者。Feign有的功能OpenFeign同样也有。由于Feign已经停止维护,所以需使用OpenFeign实现微服务的便捷调用。为什么要使用OpenFeign这个工具?举个例子:现有订单微服务和库存微服务。通用逻辑是下订单->减库存。现库存微服务在3台服务器上运行着(真实环境就是如此,高可用),那在订单微服务中如何调?指定Ip和端口?这样不能负载。所以,需要通过OpenFeign中@FeignClient注解再结合Eureka实现多台服务器的轮询调用,达到负载目的。如图:
@ComponentScan
@FeignClient(value = "PAYMENT-SERVICE") //指定微服务名称->对应Spring application name
public interface FeignService {
@RequestMapping("/select/{id}") //对应上面服务名下的接口
CommonResponse<Payment> select(@PathVariable("id") Long id);
}
Hystrix(飞机):简称豪猪哥。是一款当服务挂掉时(运行异常、超时、宕机),给用户反馈一个友好信息。拥有服务降级、熔断等功能。
服务降级:当客户端调用接口的接口出现异常时,为避免长时间等待或者出现不合适的响应信息时,使用使用@HystrixCommand注解,进入指定指定方法,自定义响应信息。
降级代码如图:
@RestController
//@DefaultProperties(defaultFallback = "commonFallBack") //全局服务降级通配标签
public class ConsumerController {
@Autowired
private ConsumerService consumerService;
@RequestMapping("/ok")
//服务降级(客户端超过最大等待时间3s或此方法执行出错,都将进入兜底方法okHanel)
@HystrixCommand(fallbackMethod = "okHandel", commandProperties =
{
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
public String ok() {
return consumerService.ok();
}
public String okHandel() {
return "您好,系统繁忙,请稍等重试~";
}
}
其实,客户端的每个接口方法都有一个降级方法没必要,可以通过上图中的相关配置实现全局降级。
服务熔断:当调用目的接口达到一定的失败率的时候,进行服务熔断,并阻止外部调用,熔断器处于半开状态
通过熔断,可以有效的阻挡外部客户端再次调用微服务,防止出现服务出问题仍在调用的情况。有效代码如图:
@RestController
public class PaymentHystrixController {
@Autowired
private PaymentService paymentService;
@RequestMapping("/testBreak/{id}")
@HystrixCommand(fallbackMethod = "testBreakHandel",
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")}) //失败率
public String testBreak(@PathVariable("id") Long id) {
if (id < 0) {
throw new RuntimeException("id不能为负数");
}
return "恭喜调用成功,此次服务的流水号为:" + UUID.randomUUID().toString();
}
//此处方法的参数不可不传,必须需要降级的方法保持一致,否则报错
public String testBreakHandel(@PathVariable("id") Long id) {
return "本次请求id:" + id + " 正在进行服务熔断,请稍后重试~";
}
}
其中的@HystrixProperty属性可以控制熔断是否开启并设置熔断相关属性配置,已达到限流目的。
Getway(飞机):俗称网关。由于Zuul也已经停止维护,所以取而代之的是Getway。在网关中,有三个重要的概念:断言、路由、过滤。所谓路由就是微服务的唯一访问id(实际上就是域名),通常与断言(接口映射地址)一起使用,最后通过过滤层实现接口参数相关的过滤。yml配置如图(包含断言和路由配置):
spring:
application:
name: gateway-9527-service
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment-routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://payment-service #匹配后提供服务的路由地址 gateway与eureka通过微服务名称实现负载均衡
predicates:
- Path=/select/** #断言,路径相匹配的进行路由
- After=2020-04-16T11:25:18.381+08:00[Asia/Shanghai] #表示在这个时段范围后才能访问上面的接口
过滤层实现如图:
@Service
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
//获取请求的参数
String name = serverWebExchange.getRequest().getQueryParams().getFirst("name");
//如果name为null,拒绝访问
if (name == null) {
System.out.println("用户名name为空,拒绝访问~");
serverWebExchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return serverWebExchange.getResponse().setComplete();
}
return gatewayFilterChain.filter(serverWebExchange);
}
@Override
public int getOrder() {
return 0;
}
}
Config(飞机):简称配置中心,可细分为服务端配置和客户端配置。主要对各个微服务子moudel里面的配置文件如yml进行配置。有一点可以了解下,配置中心可以在github、gitlab、gitee等代码托管中心。可根据自身喜好进行迁移。通过配置,指定托管中心,指定配置文件,服务配置如图:
spring:
application:
name: config-3344-service
cloud:
config:
server:
git:
uri: git@gitee.com:chenghuanqing/springcloud-config.git #项目地址
search-paths: - spring-cloud-config #仓库地址
label: master
management:
endpoints:
web:
exposure:
include: 'bus-refresh' #暴露消息动态刷新点
客户端配置如图:
spring:
application:
name: config-client-3355-service
cloud:
config:
label: master #分支名称
name: conf #配置头
profile: test #配置后缀
uri: http://localhost:3344 #相当于访问http://localhost:3344/master/conf-test.yml
默认情况下,配置中心的配置一旦更改,服务端配置会立马刷新,而客户端的配置需要手动启动微服务刷新。这样就带来一个问题,加入微服务工程底下有几十个微服务,重启40下?接下来,介绍消息总线Bus。
Bus(飞机):作为消息总线,可以全方面覆盖进行了相关配置的微服务,做到配置一次刷新,处处生效的效果。一般来说,需要结合消息中间件例如RabbitMQ、Kafka结合使用。服务端配置如图:
spring:
application:
name: config-3344-service
cloud:
config:
server:
git:
uri: git@gitee.com:chenghuanqing/springcloud-config.git #项目地址
#uri: git@github.com:chq19970719/spring-cloud-config.git
search-paths: - spring-cloud-config #仓库地址
label: master
rabbitmq: #新增消息中间件
host: localhost
port: 5672
username: guest
password: guest
management:
endpoints:
web:
exposure:
include: 'bus-refresh' #暴露动态刷新点
客户端配置如下:
spring:
application:
name: config-client-3355-service
cloud:
config:
label: master #分支名称
name: conf #配置头
profile: test #配置后缀
uri: http://localhost:3344 #相当于访问http://localhost:3344/master/conf-test.yml
rabbitmq: #新增消息中间件
host: localhost
port: 5672
username: guest
password: guest
#动态更新配置客户端
management:
endpoints:
web:
exposure:
include: "*"
通过配置,使用命令curl -X POST "http://localhost:3344/actuator/bus-refresh"
即可实现消息的全局生效。
Nacos(飞机):上面说到Nacos作为服务注册中心的作用,同样的,Nacos也可以作为服务的配置中心。说白了,配置中心的作用就是将配置文件挂载到配置中心点上,以至于实现配置云端管理。目前来说,本人接触到的配置中心有Disconf、Nacos这两种。基于Nacos有这样的功能,所以也就替代了Springcloud中的Config+Bus组合。配置也是简单易懂,如图:
spring:
application:
name: sentinel-provider
cloud:
nacos:
discovery:
server-addr: 10.201.7.175:8848,10.201.7.176:8848,10.201.7.177:8848 #Nacos集群模式
sentinel:
transport:
dashboard: localhost:8080
port:
datasource: #sentinel持久化配置,将配置信息放入nacos中的mysql
d1:
nacos:
server-addr: 10.201.7.175:8848,10.201.7.176:8848,10.201.7.177:8848
dataId: sentinel-provider
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
management: #动态刷新配置
endpoints:
web:
exposure:
include: '*'
有一点需要说明,Nacos上的配置文件yaml等,数据默认是放在Nacos自带的数据库Derby上的。通常来说,实际开发中,需要将配置信息数据迁移到持久层框架Mysql中去,而且Mysql有主从库,可以有效防止数据丢失。
Sentinel(飞机):作为服务降级、熔断、限流的框架。Hystrix有的功能Sentinel同样也有,且配置更为人性化,不需要你在写配置代码,只需在Sentinel的可视化界面中进行相关配置即可。配置如下:
@RestController
public class ProviderController {
@Value("${service.port}")
String port;
@RequestMapping("testSentinel/{id}")
//降级、熔断、限流配置注解
@SentinelResource(value = "testSentinel", blockHandler = "dealTestSentinel", fallback = "globalHandel",
exceptionsToIgnore =RuntimeException.class)
//剔除指定异常造成的降级现象、直接出现ErrorPage
public String testSentinel(@PathVariable String id) {
if ("2".equals(id)) {
throw new RuntimeException("非法id");
}
return "hi i am sentinel ,i am from " + " " + port;
}
//针对sentinel配置页面的限流降级配置所触发
//当两者都配置时,此方法优先执行
public String dealTestSentinel(@PathVariable String id,BlockException execption) {
return "开始限流 " + execption.getMessage();
}
//针对java代码运行时异常触发
public String globalHandel(@PathVariable String id) {
return "兜底了";
}
}
上图中,@SentinelResource注解是核心,其中的value是Sentinel页面配置上出现的资源名,它与访问映射只差了一个/,这点需要注意。后面的blockHandler意思是当超出Sentinel页面的限流配置例如QPS(每秒访问量)大于1,即触发服务降级。而当服务执行的时候发生异常时(比如上面的id为2)服务便会走fallback指定的方法。特别注意,如果同时出现QPS大于1,并且id=2的时候,那么此时,只会走限流方法dealTestSentinel,并没有走globalHandel方法。还有一点需要声明一下,Sentinel配置持久化的问题。例如,当你的微服务手动停止的时候,Sentinel上的所有的有关此微服务的配置全部失效。必须要重新配置。那么问题来了,灵魂拷问:微服务有40个,重新配置40个?且每个微服务下面都有不同环境的例如product、dev、test这样的环境,那不得配死人?所以,Sentinel的配置必须持久化,在上图中的yml文件中,我已经将持久化配置展示出来。配置之后,及时你重启微服务,Sentinel上的配置依然生效。
好了,以上就是最新版微服务架构讲解说明了,声明一下:这里并没有给出具体的各个框架的搭建,只是蜻蜓点水、告诉大家SringCloud全家桶与SpringAlibaba在微服务中的作用。具体的相关配置,如有不懂,请留言,我会逐一解答。