1.注册中心原理
在微服务架构中,注册中心是最核心的基础服务之一
1.1注册中心主要涉及到三大角色:
- 服务提供者 ---生产者
- 服务消费者 ---
- 服务发现与注册
它们之间na'的关系大致如下:
- 各个微服务在启动时,将自己的网络地址等信息注册到注册中心,注册中心存储这些数据。
- 服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口。
- 各个微服务与注册中心使用一定机制(例如心跳)通信。如果注册中心与某微服务长时间无法通信,就会注销该实例。
- 微服务网络地址发送变化(例如实例增加或IP变动等)时,会重新注册到注册中心。这样,服务消费者就无需人工修改提供者的网络地址了。
1.2注册中心应具备功能:
- 服务注册表
- 服务注册表是注册中心的核心,它用来记录各个微服务的信息,例如微服务的名称、IP、端口等。服务注册表提供查询API和管理API,查询API用于查询可用的微服务实例,管理API用于服务的注册与注销。
- 服务注册与发现
服务注册是指微服务在启动时,将自己的信息注册到注册中心的过程。服务发现是指查询可用的微服务列表及网络地址的机制。 - 服务检查
注册中心使用一定的机制定时检测已注册的服务,如发现某实例长时间无法访问,就会从服务注册表移除该实例。
客户端启动的时候,会开启一个线程,这个线程每过五秒钟调用自己发起心跳服务端也会有一个定时心跳检查任务,会周期性的隔一段时间检查一下,每一个实例有没有与自己保持心跳,如果没有直接删掉。心跳两边都客户端有,服务端也有
2.常见的注册中心
Zookeeper
zookeeper是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式
应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用
配置项的管理等。
Eureka
Eureka是Springcloud Netflix中的重要组件,主要作用就是做服务注册和发现。但是现在已经闭
源
Consul
Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现
和配置管理的功能。Consul的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value
存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件,所以
安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。
Nacos
Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它是 Spring
Cloud Alibaba 组件之一,负责服务注册发现和服务配置,可以这样认为nacos=eureka+config。
nacos简介
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速
实现动态服务发现、服务配置、服务元数据及流量管理。
从上面的介绍就可以看出,nacos的作用就是一个注册中心,用来管理注册上来的各个微服务
3.nacos实战入门
注意:nacos运行
- jdk8以上版本
- 路径 不能含有特殊字符
接下来,我们就在现有的环境中加入nacos,并将我们的两个微服务注册上去
第1步: 安装nacos
下载地址: https://github.com/alibaba/nacos/releases
下载zip格式的安装包,然后进行解压缩操作
1.4.1的下载地址是:
第2步: 启动nacos
startup.cmd -m standalone
bin
sh startup.sh -m standalone
linux启动的时候使用的命令是:sh startup.sh -m standalone
第3步: 访问nacos
打开浏览器输入http://localhost:8848/nacos,即可访问服务,
用户名 密码 默认都是 nacos
3.1将微服务注册到nacos中
1.在pom.xml中添加nacos的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. 在主启动类上添加nacos的开启注解
3. 在application.properties添加nacos的配置
a.设置微服务的名字
b.设置端口号
c.添加到注册中心,将该服务交给注册中心去管理
application.properties相关内容如下:
spring.application.name=product
server.port=8074
#设置注册中心的地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
观察注册中心的服务列表
4.订单微服务注册到nacos中
过程跟product一样
5.一个服务创建多个实例
创建一个和product微服务一样的微服务并修改端口号,启动之后如下
3.2负载均衡
通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡
而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请 求
我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供 者执行。
加入 负载均衡 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
新填一个product子类工程
和pro 一样 相同
order 注入 LoadBalancerClient
按着 服务的名字去找服务
更新了方式 拼接url
@Resource
private RestTemplate restTemplate;
@Resource
private LoadBalancerClient loadBalancerClient;
//根据 商品id 查询商品的信息
@GetMapping("{pid}")
public Result order(@PathVariable Integer pid){
//选择 product
ServiceInstance choose = loadBalancerClient.choose("product");
//获得 对应的主机
String host = choose.getHost();
//获得对应的端口号
int port = choose.getPort();
//http://localhost:8084/pro/1
String url="http://"+host+":"+port+"/pro/"+pid;
//1.根据商品 的id 查询商品的价格 库存
Result forObject = restTemplate.getForObject(url, Result.class);
Object data = forObject.getData();//==product
//product 对象时候 转换
ObjectMapper objectMapper= new ObjectMapper();
Product product = objectMapper.convertValue(data, Product.class);
System.out.println(forObject);
System.out.println("------");
System.out.println(product);
//2.pid price 存订单
return Result.success(product);
}
另一种方式
注入DiscoveryClient
随机
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("order/{pid}")
public Result order1(@PathVariable Integer pid){
//选择 product
List<ServiceInstance> serviceId = discoveryClient.getInstances("product");
//如果有俩相同的微服务 不能定死是第一个 不然就没有任何的意义
//随机产生数字
int i = new Random().nextInt(serviceId.size());
System.out.println("服务******"+i);
ServiceInstance choose = serviceId.get(i);
//获得 对应的主机
String host = choose.getHost();
//获得对应的端口号
int port = choose.getPort();
//http://localhost:8084/pro/1
String url="http://"+host+":"+port+"/pro/"+pid;
//1.根据商品 的id 查询商品的价格 库存
Result forObject = restTemplate.getForObject(url, Result.class);
Object data = forObject.getData();//==product
//product 对象时候 转换
ObjectMapper objectMapper= new ObjectMapper();
Product product = objectMapper.convertValue(data, Product.class);
System.out.println(forObject);
//2.pid price 存订单
return Result.success(product);
}
4.Feign
4.1使用openFeign
OpenFeign默认的负载均衡规则是轮循
1.修改pom文件
<!--使用openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类上加注释
注意:
在调用者上面 加注释
@EnableFeignClients
3.创建接口
是为了 定义 从哪一个服务 哪一个路径上 获取数据
@FeignClient("product")//代表被调用服务的名字
public interface ProductFeign {
@GetMapping("/pro/{id}")//对应controller类上的路径 加上方法上的路径
public Result getProudctById(@PathVariable Integer id);
}
}
4.调用者开始调用
@RestController
@RequestMapping("order1")
public class MyOrderController {
@Resource
private ProductFeign productFeign;
@GetMapping("{pid}")
public Result order(@PathVariable Integer pid ){
Result proudctById = productFeign.getProudctById(pid);
Object data = proudctById.getData();
ObjectMapper objectMapper = new ObjectMapper();
Product product = objectMapper.convertValue(data, Product.class);
return Result.success(product);
}
}
添加一个负载均衡 的注解
@LoadBalanced //负载均衡 默认的的算法是 轮询算法
4.2.feign和openfeign的区别
Feign是netflix
Ribbon的算法
不支持Rest风格的路径
Get post
openfeign是springcloud里面的组件
支持Rest风格的路径
支持所有的方法
支持sentinel
openfeign是feign的升级版 推荐使用openfeign
5使用负载均衡
5.1配置策略
public class LoadBalancerConfig {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
//消费者调用的服务名字
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); //loadbalancer.client.name
// 对应的需要进行负载均衡的名字是什么
System.out.println("======"+name);
// product
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
在启动类 类上 添加注解
//访问product 的时候使用随机策略
//value 代表的是 调用者的服务名字
//congfiguration 使用策略是 什么策略
@LoadBalancerClient(value = "product",configuration = LoadBalancerConfig.class)
5.2开启对sentinel 的支持
1.添加jar
<!-- 加入 sentinel的jar--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
2.写feign实现类
@Service
public class ProductFfign implements ProductFeign{
/**
* 一个兜底策略
* 出现异常 走这个方法
* @param id
* @return
*/
@Override
public Result getProudctById(Integer id) {
Product product = new Product();
if(id==1){
product = new Product(8888,"test",80d,100);
}else{
product = new Product(8888,"test",90d,200);
}
return Result.success(product);
}
}
3.在接口上写fallback
@FeignClient(value = "product",fallback = ProductFfign.class)
4. 在配置文件开启对sentinel的支持
#开启 openfeign 对sentinel的支持
feign.sentinel.enabled=true