1、引言
以往单实例情况下:服务间通常采用点对点通信,即采用 IP+端口+接口的形式直接调用,但可能出现单点负载压力过大以及不能高可用
增加多实例可以保障系统性能,但也出现问题:
- 调用方如何选择哪个服务提供者进行处理
- 当服务提供者出现故障后,如何将后续请求转移到其他可用实例上
服务治理
:对所有服务实例统一注册管理、有组织地进行健康检查来保障服务的可用性。
注册中心
是一种服务器组件,服务的提供者和消费者都是注册中心的客户端。其支持服务注册和服务发现
1.1 服务治理的设计模型
访问注册中心的客户端程序一般会嵌入在服务提供者和服务消费者内部。在服务启动时,服务提供者通过内部的注册中心客户端程序自动将自身注册到注册中心,而服务消费者的注册中心客户端程序则可以从注册中心中获取那些已经注册的服务实例信息。
注册中心的基本模型参考下图:
同时,为了提高服务路由的效率和容错性,服务消费者可以配备缓存机制以加速服务路由。更重要的是,当服务注册中心不可用时,服务消费者可以利用本地缓存路由实现对现有服务的可靠调用。
1.2 服务治理的实现策略
对于服务治理工具而言,在实现上的主要难度在于在服务提供者实例状态发生变更时如何同步到服务的消费者。不同的服务治理工具有不同的实现,大体上分为2种:
- 推送push模式:即当注册中心服务信息发生变化时,主动推送变更到该服务的消费者。通常采用服务监听机制实现。
- 拉取pull模式:即消费者定时轮询注册中心提供的服务获取接口获取最新的服务列表并更新本地缓存。
2、注册中心Nacos
2.1 部署Nacos
1.确定Nacos版本
Spring Cloud Alibaba Version | Sentinel Version | Nacos Version | RocketMQ Version | Dubbo Version | Seata Version |
---|---|---|---|---|---|
2.2.10-RC1 | 1.8.6 | 2.2.0 | 4.9.4 | ~ | 1.6.1 |
2022.0.0.0-RC1 | 1.8.6 | 2.2.1-RC | 4.9.4 | ~ | 1.6.1 |
2.2.9.RELEASE | 1.8.5 | 2.1.0 | 4.9.4 | ~ | 1.5.2 |
2021.0.4.0 | 1.8.5 | 2.0.4 | 4.9.4 | ~ | 1.5.2 |
2.2.8.RELEASE | 1.8.4 | 2.1.0 | 4.9.3 | ~ | 1.5.1 |
2021.0.1.0 | 1.8.3 | 1.4.2 | 4.9.2 | ~ | 1.4.2 |
2.2.7.RELEASE | 1.8.1 | 2.0.3 | 4.6.1 | 2.7.13 | 1.3.0 |
2.docker部署nacos:
- 下载镜像
docker pull nacos/nacos-server:v2.1.2-slim
- 启动容器,并配置端口映射
docker run --name nacos-server -e MODE=standalone -p 8848:8848 -p 9848:9848 -d --restart=always nacos/nacos-server:v2.1.2-slim 解释:MODE=standalone(单机模式)
- 开放7848和8848端口
#8848 端口是 Nacos 对客户端提供服务的端口,7848 是 Nacos 集群通信端口 firewall-cmd --zone=public --add-port=8848/tcp --permanent firewall-cmd --zone=public --add-port=7848/tcp --permanent #Nacos2.0 后需要额外放行2个端口 9848 Nacos对客户端提供gRpc服务的端口 9849是Nacos集群间gRpc通讯端口 firewall-cmd --zone=public --add-port=9848/tcp --permanent firewall-cmd --zone=public --add-port=9849/tcp --permanent firewall-cmd --reload
- 访问nacos的web服务管理界面,用户名密码都是nacos
http://192.168.136.137:8848/nacos/index.html
2.2 微服务接入Nacos步骤
- 服务中添加
nacos-discovery
起步依赖<!-- 引入 nacos discovery 起步依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
- 服务中配置nacos注册中心的地址
spring: application: # 应用名称,默认也是在微服务中注册的微服务 ID name: order-service cloud: nacos: discovery: # 配置 Nacos 服务器的IP地址和Port server-addr: 192.168.136.137:8848 #连接 Nacos 服务器使用的用户名、密码,默认为 nacos username: nacos password: nacos #是否注册本服务到nacos,默认值true。如果你只想订阅发现服务而不需要被别的服务发现,则可设置为false #register-enabled: false
重启3个服务,打开nacos注册中心,点击服务管理打开服务列表可以看到服务被注册
发现服务(原始)
public class xxxServiceImpl implements xxxservice{ //注入DiscoveryClient对象,获取所有的服务名即可使用 @Autowired private DiscoveryClient client; public void findAllService(){ List<String> services = client.getServices(); for (String service : services) { System.out.println(service); } } }
- 发现服务(在RestTemplate的Bean上添加@LoadBalanced注解)
//proxyBeanMethods = false:轻量级模式,用来优化配置性能 @Configuration(proxyBeanMethods = false) public class RestTemplateConfig { //发现服务,并赋予策略(Ribbon默认轮询) @LoadBalanced //使用时注入该bean对象即可使用其方法访问远程服务 @Bean public RestTemplate restTemplate(RestTemplateBuilder builder){ //切换底层通信组件为okhttp3 注意restTemplateBuilder为不可变对象,每次修改会返回新的builder,需要重新赋值 builder = builder.requestFactory(()->{ OkHttp3ClientHttpRequestFactory httpRequestFactory = new OkHttp3ClientHttpRequestFactory(); httpRequestFactory.setConnectTimeout(3000);//设置建立连接的超时时间 httpRequestFactory.setReadTimeout(5000);//设置读取数据的超时时间 httpRequestFactory.setWriteTimeout(5000);//设置写出数据的超时时间 return httpRequestFactory; }); //配置拦截器 //builder=builder.additionalInterceptors(new MyClientHttpRequestInterceptor()); return builder.build(); } }
- 根据服务名调用服务的接口
restTemplate.getForObject("http://服务名/rest接口", 返回值类型, url参数);
2.3 Nacos的环境隔离
a.什么是环境隔离
环境:
即逻辑上或物理上独立的一整套系统,包含处理用户请求的全部组件,如网关、服务框架、微服务注册中心、配置中心、消息系统、缓存、数据库等。
环境隔离的应用举例:不同部分在同一Nacos的服务,同一应用开发、测试、线上不同的环境配置。
注:
不同的环境中的系统或服务是相互隔离的,不能互通的。
b.Nacos的环境模型
Nacos的环境模型由三元组唯一确定,包含:namespace、group、service | dataId。
c.自定义环境
spring: cloud: nacos: ... #命名空间,默认public namespace: 5c121938-4be5-41fb-821a-e702cb1872b1 #组,默认default_group group: test
2.4、Nacos的心跳机制
无论是部署 Nacos 服务器还是构建 order-service 微服务,只用了几行代码便实现在 Nacos 注册登记。这一切背后,到底是如何实现的?
下图阐述了微服务与 Nacos 服务器之间的通信过程。在微服务启动后每过5秒,会由微服务内置的 Nacos 客户端主动向 Nacos 服务器发起心跳包(HeartBeat)。心跳包会包含当前服务实例的名称、IP、端口、集群名、权重等信息。
naming 模块在接收到心跳包后,会按下图逻辑处理心跳包并返回响应: