微服务2——服务的注册,调用(Nacos服务注册中心+服务调用+调用负载均衡)sca-comsumer&&sca-provider

一、Nacos的安装和构建  以及启动

其官网地址如下:

Nacos官网

1.安装前提:

第一:确保你电脑已配置JAVA_HOME环境变量(Nacos启动时需要),例如:

在这里插入图片描述

第二:确保你的MySQL版本为5.7以上(MariaDB10.5以上、10.3也可以),例如

在这里插入图片描述

第三:存放nacos的磁盘的写权限问题(nacos服务启动时会在当前磁盘目录写日志),例如:

在这里插入图片描述

2.下载与安装

第一步:Nacos下载与解压

1.可在浏览器直接输入如下地址:

 https://github.com/alibaba/nacos/releases

(本电脑上下载的安装包位置 D:\Nacos)

选择对应版本,直接下载,如图所示:

2. 解压Nacos(最好不要解压到中文目录下--我的解压位置D:\Nacos),其解压后目录结构如下:

在这里插入图片描述

 第二步:导入数据库文件/初始化配置(将sql文件在数据库小黑窗口导入)

1.登陆mysql,执行老师发给同学们的sql脚本(数据库表)。

1)例如,我们可以使用mysql自带客户端,在命令行首先登录mysql(mysql -uroot -proot)

2)然后执行如下指令:(nacos-mysql.sql 是老师给的sql文件,我存在了D盘里----不要用nacos D:\Nacos\nacos\conf 中自带的这个nacos-mysql.sql,有问题)

source d:/nacos-mysql.sql 


 执行成功以后,会创建一个nacos_config数据库,打开数据库会看到一些表,例如;

在这里插入图片描述

常见bug

1

注意:在执行此文件时,要求mysql的版本大于5.7版本(MariaDB最好10.5.11),否则会出现如下错误:

在这里插入图片描述

2

sql文件不存在,例如

在这里插入图片描述

 3

SQL文件应用错误,例如:

在这里插入图片描述

 2.在解压后的Nacos文件夹中  打开/conf/application.properties里打开默认配置,并基于你当前环境配置要连接的数据库,连接数据库时使用的用户名和密码(假如前面有"#"要将其去掉):

### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root      #数据库名
db.password.0=root  #数据库密码

常见bug

1

Nacos的application.properties配置文件中,连接数据库的配置错误.

在这里插入图片描述

 2

数据库的名字配置错误,例如:

在这里插入图片描述

 3

nacos配置文件application.properties配置错误,例如:

在这里插入图片描述

第三步:nacos服务的启动与访问

一、DOS窗口启动nacos服务(二选一)

启动Nacos服务——在解压后的Nacos文件夹中 bin目录打开DOS窗口,根据系统执行如下命令

Linux/Unix/Mac 系统 启动命令(standalone代表着单机模式运行,非集群模式)用:

./startup.sh -m standalone

Windows 系统 启动命令(standalone代表着单机模式运行,非集群模式)用:

startup.cmd -m standalone

 假如所有的配置都正确,还连不上,检查一下你有几个数据库(mysql,…)

常见bug

JAVA_HOME环境变量定义错误,例如:

在这里插入图片描述

说明,这里一定要注意JAVA_HOME单词的拼写,JAVA_HOME中定义的JDK是存在的,还有后面的路径不能有分号“;”.————如下

二、基于idea启动nacos服务(二选一)——推荐

1、

 2、

 

3、

 4、启动nacos服务

三、查看nacos是否启动

访问Nacos服务

打开浏览器,输入http://localhost:8848/nacos地址,出现如下登陆页面 即成功:

在这里插入图片描述

默认账号密码为nacos/nacos.,登陆后显示下图即成功

二、服务注册与调用

1、服务的注册——服务提供方模块(sca-provider)

1)pom.xml文件:所需依赖的添加(实现Nacos服务注册需要添加什么依赖)

web服务依赖    nacos服务注册、发现的discovery依赖


    
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
    

2)resources下创建并修改配置文件application.yml(或者application.properties),实现服务注册

#web 服务启动时所需要的端口————8081
#web 服务向nacos进行服务注册的名字————sca-provider
#web 服务向nacos进行服务注册的地址(此处是本机)————8848

#web 服务启动时所需要的端口
server:
  port: 8081

#web 服务向nacos进行服务注册的名字
spring:
  application:
    name: sca-provider

#web 服务向nacos进行服务注册的地址(此处是本机)
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

3)创建  服务提供方主启动类(假如已有则无需创建),并运行主启动类

 

4)主启动类启动成功后,可以打开浏览器中我们的nacos服务进行查看

如果我们关闭idea中的服务器,服务停了,nacos收不到消息;

那么下图中的健康实例数 15s后就会从原本的1变成0

                                        30s后就会把下图中的服务从列表中移除

停掉sca-provider idea里的服务,然后不断刷新浏览器的nacos服务列表,检查服务的健康状态。

测试 服务提供方模块(sca-provider) 是否能对外提供服务/是否生效

测试时  相当于用户直接通过浏览器访问sca-provider;——此处仅为测试

(实际中 用户要先访问sca-comsumer,再到sca-provider)

    /**构建controller对象,用于处理用户(客户端)的请求——对外提供一些服务
     * 即在这里写一些方法以供调用*/

动态为属性赋值
    /*从项目配置文件中读取server.port的值,然后赋值给serverPort属性,
    * 冒号 右边的8080是我们设置的一个默认值,假如从配置文件读取不到server.port,
    *       就会将默认值赋值给属性serverPort*/
    @Value("${server.port:8080}")
    private String serverPort;

 /*自己写的一个  调用的服务例子*/
    //http://localhost:8081/product/echo/nacos
    @GetMapping("/product/echo/{msg}")
    public String doRestEcho1(@PathVariable("msg") String msg){
        return serverPort + "say hello" + msg;
    }

2、服务的发现和调用——服务消费方模块(sca-consumer)

1)pom.xml文件:所需依赖的添加(实现Nacos服务注册需要添加什么依赖)

web服务依赖     nacos服务注册、发现的discovery依赖


    
        
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
    

2)resources下创建并修改配置文件application.yml(或者application.properties),实现服务注册

#web 服务启动时所需要的端口————要和sca-provider中的端口不同    8090
#web 服务向nacos进行服务注册的名字—————sca-consumer
#web 服务向nacos进行服务注册的地址(此处是本机)————8848

#web 服务启动时所需要的端口
server:
  port: 8090

#web 服务向nacos进行服务注册的名字
spring:
  application:
    name: sca-consumer

  #web 服务向nacos进行服务注册的地址(此处是本机)
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

 3)创建  服务消费方主启动类(假如已有则无需创建),并运行主启动类

因为consumer要调用provider,所以主启动类中要用restTemplate调用

(在sca-consumer启动类中添加如下方法,用于创建RestTemplate对象.)

    @Bean  //bean的名字默认为方法名
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

4)主启动类启动成功后,可以打开浏览器中我们的nacos服务进行查看

如果我们关闭idea中的服务器,服务停了,nacos收不到消息;

那么下图中的健康实例数 15s后就会从原本的1变成0

                                        30s后就会把下图中的服务从列表中移除

停掉sca-provider idea里的服务,然后不断刷新浏览器的nacos服务列表,检查服务的健康状态。

 测试 服务消费方模块(sca-consumer) 是否能对外提供服务/是否生效

测试时  相当于用户直接通过浏览器访问sca-consumer;——此处仅为测试

(实际中 用户要先访问sca-comsumer,再到sca-provider)

/**@Autowired
    private RestTemplate restTemplate;
    Spring中不推荐这种方式构造注入,@Autowired下会有波浪线,
    而且restTemplate此时也是灰暗色,表明Spring不推荐此种注入方式*/

/**Spring推荐使用构造注入——如下:写一个构造方法,通过构造方法为属性赋个值*/
    private RestTemplate restTemplate;
    @Autowired
    public ConsumerController(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }

    @Value("${server.port:8090}")
    private  String serverPort;

    //http://localhost:8090/consumer/doRestEcho1
    @GetMapping("/consumer/doRestEcho1")
    public String doRestEcho1(){
        //在这里调用sca-provider服务   provider的端口我们设的是8081
        //这里写的地址不正确会出现调用404异常(此处的url地址要和ProviderController里的地址一样)
        String url = "http://localhost:8081/product/echo/8090";
        return restTemplate.getForObject(url, String.class,serverPort);
                               //远端的url地址 响应结果的类型(此处是String)
    }

此时provider和consumer的主启动类(服务)都要开着

3、(服务)调用过程

在这里插入图片描述

三.1、Nacos客户端远程服务调用(RPC) 负载均衡 的实现——见下载-微服务中的负载均衡示例代码

一)基于RestTemplate对象  方式实现负载均衡

二)基于Feign的远程服务调用(重点) 

day3 pm-1:21:00——day4 pm-2:20:00

规则:谁通过Feign调用其他服务,以下步骤加在谁上

          因为comsumer通过Feign调用provider服务,所以以下步骤加在sca-comsumer文件中

        (如果provider要通过Feign调用其他服务的话,以下步骤加在sca-provider文件中)

1)在服务消费方sca-comsumer,添加项目依赖


    org.springframework.cloud
    spring-cloud-starter-openfeign

2)在主启动类上添加@EnableFeignClients注解

3)定义Http请求的service API(远程调用服务)接口——因为有多个,所以创一个service包,在service包下写

(接口的作用就是定义规范,此处的API接口用于声明 我们要调用哪个服务和要访问服务中的什么资源),基于此API借助OpenFeign(Feign之后改的名字)访问其他(比如此处四访问sca-provider)服务——我们把此API定义在service层,因为controller层调用service层

package com.jt.consumer.service;

@FeignClient(name/value="sca-provider")//sca-provider为服务提供者名称
public interface RemoteProviderService{
    //方法上要声明访问的服务中的哪个url(资源)——("/provider/echo/{string}")
    @GetMapping("/provider/echo/{string}")//前提是远端sca-provider 的ProviderController里需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

@FeignClient 作用:

         1、声明要调用/访问的(远端)服务是服务名sca-provider
         2、/*当前接口对应的实现类交给Spring管理时,Bean的名字——当然,如果我们不想让value属性的值作为bean对象的名字,可以通过contextId属性指定一个名字

例:@FeignClient(value="sca-provider"  ,contextId = "remoteProviderService" )*/

实际操作:

注意

                        *********************************************************************************************

**1、多个调用接口情况:**

以上3)的写法是服务消费方基于同一个服务提供方写了一个serviceAPI服务调用接口

实际中特殊的普遍的情况:服务消费方基于同一个服务提供方写了很多serviceAPI服务调用接口

理解:一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务
启动就会失败,例如,假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败;例如:

 @FeignClient(name="sca-provider")
 public interface RemoteOtherService {
     @GetMapping("/doSomeThing")
     public String doSomeThing();
}

其启动异常如下:

The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.

解决方式:

此时我们需要为第二/三....个service远程调用服务接口指定一个contextId属性,作为远程调用服务的唯一标识(这个标识是Bean对象的名字)即可,例如:

@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

                        ******************************************************************************************

**2、解决service API接口调用时出现的服务中断,超时等问题

系统出现问题后(远程服务调用不到:service调不到provider时——因为有的时候我们没有运行远端provider服务的主启动类,只运行了consumer服务的主启动类),不能让用户看到如下图的页面否则用户体验不好;必须要有回滚/回调fallback措施**

解决方式:fallbackFactory

我们需要为 每个service API远端调用添加以下步骤

步骤1:在service包下  我们写的service API远程调用服务接口指定fallbackFactory属性

@FeignClient(name="sca-provider",contextId="remoteProviderService",fallbackFactory="")
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

步骤2:创建要回调的方法(在service包下,自己为service API接口写一个实现类 ,类中写方法,以供远程服务调用不到时来调用/回调

 写法1:

写法2:

package com.jt.service.factory;
/**
 * 基于此对象处理RemoteProviderService接口调用时出现的服务中断,超时等问题
 */
@Component
public class ProviderFallbackFactory implements FallbackFactory {
    /**
     * 此方法会在RemoteProviderService接口服务调用时,出现了异常后执行.
     * @param throwable 用于接收异常
     */
    @Override
    public RemoteProviderService create(Throwable throwable) {
        return (msg)->{
                return "服务维护中,稍等片刻再访问";
        };
    }
}

步骤3:完善步骤一

@FeignClient(name="sca-provider",contextId="remoteProviderService",fallbackFactory=ProviderFallbackFactory.class)
interface RemoteProviderService{
    @GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
    public String echoMessage(@PathVariable("string") String string);
}

步骤4:配置文件中启用熔断机制(在sca-consumer的application.yml配置文件中开启熔断机制)

#熔断机制默认是false 关闭,我们要打开变为true
feign:
  hystrix:
    enabled: true

步骤5:在服务提供方provider对应的调用方法中添加Thread.sleep(5000)模拟耗时操作,然后启动consumer主启动类进行服务调用测试

 

4)创建controller(FeignConsumerController)并添加feign访问

package com.jt.consumer.controller;
@RestController
public class FeignConsumerController {
    @Autowired
    private RemoteProviderService remoteProviderService;
    /**基于feign方式的服务调用*/
    @GetMapping("/comsumer/echo/{msg}")
    public String doFeignEcho(@PathVariable  String msg){
        //基于feign方式进行远端服务调用(前提是服务必须存在)
        return remoteProviderService.echoMessage(msg);
    }
}

实际操作:

5)启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示(反复刷新检测其响应结果)

三)如何修改sca-consumer端默认的负载均衡策略

方案1:修改sca-consumer配置文件(application.yml),添加如下语句,例如:

sca-provider: #这个是要进行远程调用的服务id(服务名)-----被调用的 服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡算法

对于方案1写法,在写的过程没有提示,编写困难,但是将来的可运维性会比较好,我们这部分配置写到配置中心,不需要重启服务即可实现配置的动态发布,动态更新。

方案2:修改sca-consumer的启动类,在启动类中添加如下方法,例如:

@Bean
public IRule ribbonRule() {
    return new RandomRule();
}

对于方案2的写法,编写相对简单,编写过程都有提示,但是将来的可运维性比较差,不推荐使用,项目打包以后,我们无法再修改负载均衡算法。

三.2、Idea中Http Client 工具的应用:模拟发起get/post请求,查看服务调用效果(相当于在浏览器输入网址访问)

1、打开HTTP Client中的Test RESTful Web Service——(基于/适用于restful风格:comsumer进行远程服务调用(调用provider服务)时使用)

在这里插入图片描述

 

 

 2、Http Client 工具的使用

1)写url进行模拟请求

多次运行一个相同的url,相当于我们在用浏览器访问url时不断点刷新按钮

2)如果不知道(get/post/json串)格式 写法,有官方提供的例子 

3)规则:

在这里插入图片描述

 

4)不小心把如下图 写的窗口关了,不要急着重写——有历史记录

历史记录位置(可以查找和删除不用的)

你可能感兴趣的:(微服务,java)