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-productcloud:nacos:# 配置config:namespace: 3d0a77b8-817f-499b-bfda-f90d5a6e4dabserver-addr: 192.168.19.128:13306group: DEFAULT_GROUPfile-extension: yamlusername: nacospassword: nacos# 注册discovery:namespace: 3d0a77b8-817f-499b-bfda-f90d5a6e4dabserver-addr: 192.168.19.128:13306group: DEFAULT_GROUPusername: nacospassword: nacos
provider-product.yaml
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.19.128/cloudalibaba?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=trueusername: rootpassword: 123456mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#配置无数据时 返回nullcall-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端口访问 同样不能负载均衡
@Autowiredprivate 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")@LoadBalancedpublic 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 所以修改权重是没有效果的!下线依然有效

