注册中心
在微服务架构中,注册中心是最核心的基础服务之一
主要涉及到三大角色:
服务提供者 ---生产者
服务消费者
服务发现与注册
它们之间的关系大致如下:1.各个微服务在启动时,将自己的网络地址等信息注册到注册中心,注册中心存储这些数据。
2.服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口。
3.各个微服务与注册中心使用一定机制(例如心跳)通信。如果注册中心与某微服务长时间无法通信,就会注销该实例。
4.微服务网络地址发送变化(例如实例增加或IP变动等)时,会重新注册到注册中心。这样,服务消费者就无需人工修改提供者的网络地址了。
nacos简介
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速
实现动态服务发现、服务配置、服务元数据及流量管理。
从上面的介绍就可以看出,nacos的作用就是一个注册中心,用来管理注册上来的各个微服务
nacos实战入门
安装
下载win或linux版本
启动
win
startup.cmd -m standalone
linux
先进入解压的bin目录下
sh startup.sh -m standalone
访问
默认账号密码都是 nacos
基于 http://t.csdnimg.cn/iFbUc的继续配置
快速回顾:
上篇文章中 父级项目 demo01 子级 comm service 孙级 order product
comm 放置实体类 service 放置生产者和消费者
1.service的pom文件引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.在主启动类上添加nacos的开启注解(Order消费者的启动类上)
java
@EnableDiscoveryClient // 当前的微服务是可以被nacos发现的
3. 在application.properties添加nacos的配置
a.设置微服务的名字
b.设置端口号
c.添加到注册中心,将该服务交给注册中心去管理
javaspring.application.name=order server.port=8081 #设置注册中心的地址 spring.cloud.nacos.discovery.server-addr=localhost:8848
对product进行复制,命名product1
完成如上配置后启动消费者与两个生产者
服务调用的负载均衡
什么是负载均衡
通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上 进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡
而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求。
负载均衡
order 的pom引入依赖
XML
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
配置策略:
java
package com.example.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;
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);
}
}
使用策略:
java
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写死
第二种写法:
拼接url的方式
@Resource
private LoadBalancerClient loadBalancerClient;
@Override
public boolean addOrder(Integer pid) {
ServiceInstance choose = loadBalancerClient.choose("product");
String requestMsg = "方式二 GET 请求 RibbonServer";
String url = String.format("http://%s:%s", choose.getHost(), choose.getPort() + "/pro/t-product/findById/"+pid);
TProduct forObject = restTemplate.getForObject(url, TProduct.class);
System.out.println(forObject);
//添加订单
if(forObject.getKucun()>0){
//添加订单
TOrder oreder=new TOrder();
oreder.setNum(1);
oreder.setPid(pid);
oreder.setUid(1);
boolean save = this.save(oreder);
return save;
//oreder.se
}
return false;
}
利用 LoadBalancerClient 通过应用名获取 url,然后再使用 RestTemplate 请求
使用DiscoveryClient拼接url
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("addOrder/{pid}")
public Result addOrder(@PathVariable("pid") Integer pid){
List<ServiceInstance> serviceId = discoveryClient.getInstances("product");
//如果有俩相同的微服务 不能定死是第一个 不然就没有任何的意义
//随机产生数字
int i = new Random().nextInt(serviceId.size());
System.out.println("服务******"+i);
ServiceInstance instance = serviceId.get(i);
// id username productname
Order order=new Order();
order.setId(1);
order.setUsername("于永利");
System.out.println("http://"+instance.getHost()+":"+instance.getPort()+"/getById/"+pid);
//商品的名字
Result result= restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/getById/"+pid,Result.class);
ObjectMapper objectMapper=new ObjectMapper();
Product pro = objectMapper.convertValue(result.getT(), Product.class);
//jackson
//HashMap<String,String> product=(HashMap) result.getT();
order.setProductname(pro.getName());
return new Result(order);
}
第三种写法:
使用OpenFeign
OpenFeign默认的负载均衡规则是轮循
修改pom文件
<!--使用openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动类上开启注解
@EnableFeignClients
调用
@FeignClient
service接口:
如果有异常 回滚到哪一个类里面
@FeignClient(value="product",fallback = TOrderServiceImpl.class)
public interface ITOrderService{
}
feign接口的实现类
service的实现类
@Service
public class TOrderServiceImpl implements ITOrderService {
@Override
public TProduct addOrder(Integer pid) {
System.out.println("你调用我了吗");
if(pid==0){
System.out.println("出错啦!!!!");
}
return null;
}
}
使实现类生效
加jar
<!-- -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
开启openfeign对sentinel的支持
(在application.properties中编写)
feign.sentinel.enabled=true