2. nacos 服务注册与发现
在大型项目中,巨型单体式应用肯定是不现实的,需要将应用拆分为小的,互相连接的微服务。一个微服务完成某个特定的任务,且每个微服务都是独立的个体。
2.1 什么是服务注册与发现
- 服务注册:在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。
- 服务发现:服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。
简单来说就是把一个一个微服务注册到一个注册中心去,这个注册中心管理着所有的微服务,服务之间靠注册中心这个纽带维持相互的关系。服务之间互动调用也是从注册中心发现另外一个微服务完成调用。
2.2 使用nacos做服务注册与发现中心
使用手册 Nacos-discovery
2.2.1版本选择
微服务组成
- cloud-common 公共内容
- consumer-feign-order8002 服务消费者 基于feign的服务调用
- consumer-order8001 服务消费者 没有feign基于restTemplate调用
- provider-product7001 服务提供者
- provider-product7002 服务提供者
两个微服务提供者代码相同,基于同一个配置文件开启服务
bootstrap.yml
spring:
application:
name: provider-product
cloud:
nacos:
# 配置
config:
namespace: 3d0a77b8-817f-499b-bfda-f90d5a6e4dab
server-addr: 192.168.19.128:13306
group: DEFAULT_GROUP
file-extension: yaml
username: nacos
password: nacos
# 注册
discovery:
namespace: 3d0a77b8-817f-499b-bfda-f90d5a6e4dab
server-addr: 192.168.19.128:13306
group: DEFAULT_GROUP
username: nacos
password: nacos
provider-product.yaml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.19.128/cloudalibaba?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#配置无数据时 返回null
call-setters-on-nulls: true
# 配置全局主键生成策略
global-config:
db-config:
table-prefix: t_
id-type: auto
两个服务提供者的配置文件和 provider-product.yaml 一样 仅提供连接数据库配置
当启动所以服务后 都会注册到nacos,并且 provider-product是多实例
2.2.3 服务调用
provider-product提供一个查询商品的接口
@GetMapping("/product/getProduct/{id}")
public CommonResult<Product> getProduct(@PathVariable("id") Integer id) {
Optional<Product> optional = Optional.ofNullable(productService.findBuyId(id));
return optional.map(CommonResult::ok).orElseGet(CommonResult::error);
}
2.2.3.1 consumer-order8001调用provider-product
使用restTemplate对比4种调用方式 由繁入简
- 基于http直接通过ip调用 只能单独访问某个服务,不能实现负载
注入bean
@Bean("restTemplate")
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@GetMapping("/ip/createOrder/{pid}")
public CommonResult createOrder(@PathVariable("pid") Integer pid) {
CommonResult<Product> result = restTemplate.getForObject("http://127.0.0.1:7001/product/getProduct/" + pid, CommonResult.class);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
if (jsonObject.getInteger("code").equals(0)) {
Product product = jsonObject.getObject("data", Product.class);
orderService.createOrder(product);
return CommonResult.ok();
}
return CommonResult.error();
}
通过discoveryClient获取服务提供者,再通过服务提供者的ip端口访问 同样不能负载均衡
@Autowired
private DiscoveryClient discoveryClient;
/**
* 获取生产者实例再使用restTemplate调用微服务
*
* @param pid
*/
@GetMapping("/service/createOrder/{pid}")
public CommonResult createOrder(@PathVariable("pid") Integer pid) {
String serviceName = "provider-product";
//从nacos中获取服务地址
ServiceInstance serviceInstance = discoveryClient.getInstances(serviceName).get(0);
String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
//通过restTemplate调用商品微服务
CommonResult<Product> result = restTemplate.getForObject("http://" + url + "/product/getProduct/" + pid, CommonResult.class);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
if (jsonObject.getInteger("code").equals(0)) {
Product product = jsonObject.getObject("data", Product.class);
orderService.createOrder(product);
return CommonResult.ok();
}
return CommonResult.error();
}
自定义随机负载
@GetMapping("/myBalance/createOrder/{pid}")
public CommonResult createOrder(@PathVariable("pid") Integer pid) {
String serviceName = "provider-product";
//从nacos中获取服务地址
List<ServiceInstance> instanceList = discoveryClient.getInstances(serviceName);
//根据随机值调用服务
int index = RandomUtil.randomInt(instanceList.size());
ServiceInstance serviceInstance = instanceList.get(index);
String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
//通过restTemplate调用商品微服务
CommonResult<Product> result = restTemplate.getForObject("http://" + url + "/product/getProduct/" + pid, CommonResult.class);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
if (jsonObject.getInteger("code").equals(0)) {
Product product = jsonObject.getObject("data", Product.class);
orderService.createOrder(product);
return CommonResult.ok();
}
return CommonResult.error();
}
使用restTemplate实现负载均衡
早在Spring Cloud Hoxton.M2中就已经放弃了 Netflix Ribbon 的使用,取而代之的是自研的localbalancer进行负载均衡
Spring Cloud Load Balancer使用指南
加入pom<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
添加@LoadBalanced 实现负载均衡
@Bean("restTemplateBalance")
@LoadBalanced
public RestTemplate getRestTemplate2() {
return new RestTemplate();
}
```java @GetMapping(“/rabbinBalance/createOrder/{pid}”) public CommonResult createOrder(@PathVariable(“pid”) Integer pid) {String serviceName = "provider-product";
String url = "http://" + serviceName + "/product/getProduct/" + pid;
//通过restTemplate调用商品微服务
CommonResult<Product> result = restTemplateBalance.getForObject(url, CommonResult.class);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
if (jsonObject.getInteger("code").equals(0)) {
Product product = jsonObject.getObject("data", Product.class);
orderService.createOrder(product);
return CommonResult.ok();
}
return CommonResult.error();
}
<a name="TtwGm"></a>
#### <br />
<a name="3piXv"></a>
#### 2.2.3.2 consumer-order8002使用openFeign负载均衡
pom加入负载均衡和openFeign的集成<br />启动类添加注解 表示启动openFeign @EnableFeignClients
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
添加openFeign 调用Service 直接使用SpringMVC的调用方法
@Service
@FeignClient("provider-product")
public interface ProductService {
/**
* //@FeignClient+@GetMapping 就是一个完整的请求路径 http://provider-product/product/getProduct/{id};
* 指定调用的方法
*
* @param id
* @return
*/
@GetMapping("/product/getProduct/{id}")
CommonResult<Product> getProduct(@PathVariable("id") Integer id);
}
实现负载均衡效果
@GetMapping("/createOrder/{pid}")
public CommonResult createOrder(@PathVariable("pid") Integer pid) {
CommonResult<Product> productCommonResult = productService.getProduct(pid);
log.info("通过feign调用的数据:" + productCommonResult);
if (productCommonResult.getCode().equals(0)) {
orderService.createOrder(productCommonResult.getData());
return CommonResult.ok();
}
return CommonResult.error();
}
修改控制台效果
由于使用loadbalancer而不使用ribbon 所以修改权重是没有效果的!下线依然有效