一 注册中心原理
在微服务架构中,注册中心是最核心的基础服务之一
注册中心主要涉及到三大角色:
-
服务提供者 ---生产者 被调用
-
服务消费者 --- 消费者 调用者
-
服务发现与注册
它们之间的关系大致如下:
-
各个微服务在启动时,将自己的网络地址等信息注册到注册中心,注册中心存储这些数据。
-
服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口。
-
各个微服务与注册中心使用一定机制(例如心跳)通信。如果注册中心与某微服务长时间无法通信,就会注销该实例。
-
微服务网络地址发送变化(例如实例增加或IP变动等)时,会重新注册到注册中心。这样,服务消费者就无需人工修改提供者的网络地址了。
注册中心应具备功能:
-
服务注册表
服务注册表是注册中心的核心,它用来记录各个微服务的信息,例如微服务的名称、IP、端口等。服务注册表提供查询API和管理API,查询API用于查询可用的微服务实例,管理API用于服务的注册与注销。 -
服务注册与发现
服务注册是指微服务在启动时,将自己的信息注册到注册中心的过程。服务发现是指查询可用的微服务列表及网络地址的机制。 -
服务检查
注册中心使用一定的机制定时检测已注册的服务,如发现某实例长时间无法访问,就会从服务注册表移除该实例。
客户端启动的时候,会开启一个线程,这个线程每过五秒钟调用自己发起心跳服务端也会有一个定时心跳检查任务,会周期性的隔一段时间检查一下,每一个实例有没有与自己保持心跳,如果没有直接删掉。心跳两边都有,客户端有,服务端也有
二 常见的注册中心
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的作用就是一个注册中心,用来管理注册上来的各个微服务
三 nacos实战入门
1.安装nacos
接下来,我们就在现有的环境中加入nacos,并将我们的两个微服务注册上去
第1步: 安装nacos
第2步: 启动nacos
windows启动:
startup.cmd -m standalone
linux启动的时候使用的命令是:
sh startup.sh -m standalone
如果微服务的IP地址显示的是以1 为最后一位的话 直接将对应的虚拟机的网卡禁用即可
第3步: 访问nacos
打开浏览器输入http://localhost:8848/nacos/index.html,即可访问服务, 默认密码是nacos/nacos
1.product微服务注册到nacos
a.在pom.xml中添加nacos的依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
b. 在主启动类上添加nacos的开启注解
@EnableDiscoveryClient
当前微服务可以被nacos发现
c. 在application.properties添加nacos的配置
a.设置微服务的名字
b.设置端口号
c.添加到注册中心,将该服务交给注册中心去管理
application.properties相关内容如下:
spring.application.name=product
server.port=8082
#设置注册中心的地址
spring.cloud.nacos.discovery.server-addr=localhost:8848
开启注解,能够让注册中心扫描到该服务
@EnableDiscoveryClient
d.观察注册中心的服务列表
出现如上即为配置成功
2.订单微服务注册到nacos中
过程跟product一样
配置文件主要代码:
spring.application.name=order
spring.cloud.nacos.discovery.server-addr=localhost:8848
server.port=8081
3.一个服务创建多个实例
创建一个和product微服务一样的微服务并修改端口号,启动之后如下
2.服务调用的负载均衡
什么是负载均衡
通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡
而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求
我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。
基于Ribbon实现负载均衡 (废弃)
Ribbon是Spring Cloud的一个组件, 它可以让我们使用一个注解就能轻松的搞定负载均衡 第1步:在RestTemplate 的生成方法上添加@LoadBalanced注解
代码:
@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
//实现负载均衡需要是用restTemplate
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
Ribbon支持的负载均衡策略 Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为 com.netflix.loadbalancer.IRule ,
我们可以通过修改配置来调整Ribbon的负载均衡策略
1.注入负载均衡策略的bean
@Bean
public IRule getRule(){
return new RandomRule();
}
2.修改消费端的配置文件
yml文件:消费者是调用者order
product: # 调用的提供者的名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
properties文件:
product.ribbon.NFLoadBalancerRuleClassName= com.netflix.loadbalancer.RandomRule
负载均衡
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
轮询算法 /随机算法
配置策略:
package com.ymm.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
/**
* @auther: 余明明
*/
public class LoadBalancerConfig {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
// 获取需要进行负载均衡的名字 loadbalancer.client.name
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
// 对应的需要进行负载均衡的名字是什么
System.out.println("======"+name);
// product
return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
使用策略:
package com.order;
import com.order.config.LoadBalancerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@LoadBalancerClients(
defaultConfiguration = LoadBalancerConfig.class
// product 会使用这个策略
// @LoadBalancerClient(value = "product",configuration= LoadBalancerConfig.class)
)
public class OrderAppliaction {
public static void main(String[] args) {
SpringApplication.run(OrderAppliaction.class);
}
@Bean
// @LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
四 基于Feign实现服务调用
FeignClient和RestTemplate
SpirngCloud 中,默认是使用HTTP进行微服务间通信,其中最常用的有两种实现形式
-
RestTemplate
-
Feign
RestTempale
-
其实在SpringWeb里面,已经原生支持了 RestTemplate,只不过我们一般使用的是把请求URL直接写死,而不是通过服务名的形式来调用,但是在微服务架构中,因为有了注册中心的存在,我们的负载均衡可以不需要使用第三方软件或者硬件实现了,所有,我们最佳的方式是经过服务名访问,请求到那个实例,由 负载均衡策略来替我们决定。
-
ribbion中的负载均衡策略了解
自定义策略(了解)
第一种写法:
直接使用 RestTemplate , Url写死
第二种写法:
LoadBalancerClient 拼接url的方式
@Autowired
public RestTemplate restTemplate;
@Resource
private LoadBalancerClient loadBalancerClient;
@GetMapping("/add2/{pid}")
public Object add2(@PathVariable Integer pid) {
ServiceInstance choose = loadBalancerClient.choose("product");
String requestMsg = "方式二 GET 请求 RibbonServer";
String url = String.format("http://%s:%s", choose.getHost(), choose.getPort() + "/product/getById/" + pid);
System.out.println(url);
// 1. 根据pid 得到商品的信息
Product forObject = restTemplate.getForObject(url, Product.class);
// 实现远程的调用
// product : 分布式部署
// 思考82 和83 之前进行轮询调用
return forObject;
}
利用 LoadBalancerClient 通过应用名获取 url,然后再使用 RestTemplate 请求
使用DiscoveryClient拼接url
@Autowired
public RestTemplate restTemplate;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("add3/{pid}")
public Object add3(@PathVariable Integer pid){
List<ServiceInstance> pro = discoveryClient.getInstances("product");
//
int size = pro.size();
//
int i = new Random().nextInt(size);// =size-1
ServiceInstance choose = pro.get(i);
String url = String.format("http://%s:%s", choose.getHost(), choose.getPort() + "/product/getById/"+pid);
System.out.println("*****"+url);
// 1. 根据pid 得到商品的信息
Product forObject = restTemplate.getForObject(url, Product.class);
// 实现远程的调用
return forObject;
}
第三种写法:
使用OpenFeign
OpenFeign默认的负载均衡规则是轮循
修改pom文件
<!--使用openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类上开启注解
@EnableFeignClients
调用
@FeignClient
service接口:
如果有异常 回滚到哪一个类里面
// fallback代表微服务有问题 走fallback的类
@FeignClient(value = "product",fallback =ProFeignImpl.class )
public interface ProFeign {
// 根据id 查询 商品的信息 需要访问的微服务是哪一个
// "product/getById/{id}"
// 1. nacos 里面找到product 服务 ip port
// 2. 发出一个get请求 路径是 ip:port/product/getById/{id}
@GetMapping("product/getById/{id}")
Product getProById(@PathVariable Integer id);
}
feign接口的实现类
service的实现类
// fallback代表微服务有问题 走fallback的类
@FeignClient(value = "product",fallback =ProFeignImpl.class )
public interface ProFeign {
// 根据id 查询 商品的信息 需要访问的微服务是哪一个
// "product/getById/{id}"
// 1. nacos 里面找到product 服务 ip port
// 2. 发出一个get请求 路径是 ip:port/product/getById/{id}
@GetMapping("product/getById/{id}")
Product getProById(@PathVariable Integer id);
}
使实现类生效
加jar
<!-- -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
开启openfeign对sentinel的支持
(在application.properties中编写)
feign.sentinel.enabled=true
Controller调用
@Resource
private ProFeign proFeign;
@GetMapping("feignOrder/{id}")
public Product getProById(@PathVariable Integer id) {
Product proById = proFeign.getProById(id);
return proById;
}
product的Controller
@RestController
@RequestMapping("/product")
public class ProductController {
@GetMapping("/getById/{id}")
public Product getProductById(@PathVariable("id") Integer id){
System.out.println("商品的id是"+id);
Product product=new Product();
product.setName("测试商品");
product.setId(id);
return product;//返回商品
}
}
五搭建nacos的集群(选修)
linux版
简易版步骤:
1.上压缩包
2.解压
3.配置 conf/cluster.conf
4.在mysql中创建数据库nacos_config
并导入 /conf/nacos-mysql.sql
5.修改application.properties
在最后加上
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user.0=root
db.password.0=root
修改端口号 8848
6.启动
参考教程:
https://www.cnblogs.com/Arthemis-z/p/14505008.html
nginx配置负载均衡
upstream nacoscluster{
server 192.168.58.33:8849;
server 192.168.58.33:8850;
server 192.168.58.33:8851;
}
server {
listen 8847;
server_name localhost;
location /nacos/ {
proxy_pass http://nacoscluster/nacos/;
}
}