Nacos

目录

Nacos版本对应  

Nacos Windows版安装路径

Nacos快速入门         

 Nacos服务注册与服务发现

 Nacos服务注册

Nacos服务发现

Nacos配置

 Nacos集群

Nacos配置文件

配置文件刷新

配置空间读取规则

命名空间以及Group

命名空间

多配置文件时

Ribbon

Openfeign

 简介

应用场景 

操作过程

手写Feign

Feign的参数调用(重点掌握)

Hystrix

简介        

使用场景

使用方法

拦截器状态

常见配置


Nacos版本对应  

      首先我们要知道Nacos版本与Spring-Cloud-Alibaba对应的版本以及Spring-Clound对应的版本,如果版本对应的不一致的话,有时候会导致不必要的麻烦

 Nacos Windows版安装路径

        这里我们采用的2.0.3的版本,下载后解压缩后三步走就可以使用。

        1.打开nacos-》conf-》nacos-mysql.sql文件将这个文件导入我们的数据库里面。

        

        2. 打开nacos-》conf-》application.properties进入将33 36 39 40 41 44 45 46 47行解开应用,在39 40 41行

db.url.0=jdbc:mysql://本地数据库的名字:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
 db.user.0=数据库账号
 db.password.0=数据库密码

        3. 打开nacos-》bin-》startup.cmd右键打开查看里面的配置

        这个是打开的方式,我们将他修改为单机模式,就可以双击运行了

                standalone:单机模式

                cluster:集群模式

        运行成功界面 

         在浏览器输入localhost:8848/nacos进入nacos界面,账号密码都是:nacos

Nacos快速入门         

        创建idea的Spring Initializr选择

         

        创建成功后进入pom文件修改版本,将画住的地方修改。    

         修改配置文件,我使用的.yml样式

server:
  port: 8081
spring:
  application:
    name: nacos-client-a
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        在启动类上面加入一个注解@EnableDiscoveryClient 就可以启动了

server:
  port: 8081        端口号
spring:
  application:
    name: nacos-client-a        服务注册的名字
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848        nacos的地址
        username: nacos        nacos账号
        password: nacos        nacos密码

  Nacos服务注册与服务发现

  Nacos服务注册

        完成上面的启动,我们重新创建一个一摸一样,我们添加一个controller

@RestController
public class AController {
//打招呼的接口
    @GetMapping("hello")
    public String hello(String name) {
        return "hello" + name;
    }
}

        运行就完成了服务注册,我们可以在网址上查看一下时候运行成功。

        网址 localhost:端口号/hello?name

Nacos服务发现

        重复上面的步骤到添加一个controller,这里要注意的是配置文件里面的端口号要修改,不然会存在端口号被占用。

@RestController
public class BController {
//    注册服务发现组件
    @Autowired
    private DiscoveryClient discoveryClient;
             //服务发现接口
    @GetMapping("discovery")
    public String dicoveryService(String serviceId){
        //根据实例名称拿到实例集合
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        //根据实例集合拿到一个实例对象
        ServiceInstance serviceInstance = instances.get(0);
        System.out.println(serviceInstance.getHost()+":"+serviceInstance.getPort());
       return serviceInstance.getHost()+":"+serviceInstance.getPort();
    }
}

        运行就可以完成服务发现,我们可以在网址上查看一下时候运行成功。

        网址 localhost:端口号/discovery?serviceId=服务注册的名字

Nacos配置

 Nacos集群

       nacos-》conf-》application.properties ,创建三个nacos修改21行分别是8848,8849,8850

    nacos-》conf-》新建一个文件cluster.conf,记事本打开加入

端口号:8848

端口号:8849

端口号:8850

        nacos-》bin-》startup.cmd修改为集群模式

        连着启动三个,就会打开集群模式

Nacos配置文件       

        创建完成后第一步就是去修改对应的版本,加入一个lombok依赖

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.24</version>
            </dependency>

        我们打开配置会发现多了一个配置

        

        bootstrap是提前加载,可以看出图标有一个云是加载云上的配置,也就是加载nacos的配置

server:
  port: 8888
spring:
  application:
    name: nacos-config
    #项目启动时去哪里找他的配置文件
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        username: root
        password: root
        #这里开始就是开始寻找他的配置文件
        prefix: nacos-config       #读那个配置文件
        file-extension: yml     #文件类型,不写默认properties
#        namespace: #不写默认public
#       group:  #不写默认DEFAULT_GROUP

        在Nacos里面建立一个配置文件 

        建立一个controller

@RestController
public class NacosConfigConfiguration {
    @Value("${hero.name}")
    private String name;
    @Value("${hero.age}")
    private Integer age;
    @Value("${hero.address}")
    private  String address;

    @GetMapping("info")
    public String info(){
        return name+":"+age+":"+address;
    }
}

        运行,只要是不报错就是调用成功,进入网址确认

        网址 localhost:端口号/info

        

配置文件刷新

        当我们修改Nacos里面的配置文件,对应调用配置文件的项目如何进行同步更新。

                如果是项目下线重新运行的话,一个两个还可以,如果是成百上千个工作量就大的离谱。这时候我们就需要一种修改配置文件的时候,项目里面的文件也能同步更新的方法。

        优化上面的代码

        新建一个实体类Hero

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@RefreshScope  //给这个类 添加一个刷新的作用域
public class Hero {
    @Value("${hero.name}")
    private String name;
    @Value("${hero.age}")
    private Integer age;
    @Value("${hero.address}")
    private  String address;

}

        @RefreshScope         加入这个注解就可以实时进行刷新

        对应的controller也要进行优化

@RestController
public class NacosConfigConfiguration {
    @Autowired
    private Hero hero;

    @GetMapping("info")
    public String info() {

        return hero.getName() + ":" + hero.getAge() + ":" + hero.getAddress();
    }
}

配置空间读取规则

         

nacos 配置中心通过 namespace dataId group 来唯一确定一条配置。
Namespace :即命名空间。默认的命名空间为 public ,我们可以在 Nacos 控制台中新建
命名空间;
dataId :即配置文件名称
Group : 即 配 置 分 组 , 默 认 为 DEFAULT_GROUP , 可 以 通 过
spring.cloud.nacos.config.group 配置。
其中: dataId 是最关键的配置字段:格式如下:
${prefix} - ${spring.profiles.active} . ${file-extension}
说明:
prefix 默 认 为 spring.application.name 的 值 , 也 可 以 通 过 配 置 项
spring.cloud.nacos.config.prefix 来配置;
spring.profiles.active 即 为 当 前 环 境 对 应 的 profile 。 注 意 , 当
spring.profiles.active 为空时,对应的连接符 - 也将不存在, dataId 的拼接格式变
${prefix}.${file-extension}
file-extension 为 配 置 内 容 的 数 据 格 式 , 可 以 通 过 配 置 项
spring.cloud.nacos.config.file-extension 来配置。

命名空间以及Group

        Nacos的隔离级别有两种一种是命名空间一种是Group

命名空间

        新建命名空间

命名空间ID如果不写就会自动生成一个uuid

命名空间别名就是起一个名字

描述 就是描述命名空间

 多配置文件时

        Nacos创建新的配置,这里的配置的后缀得加上时什么文件,不然会扫描不上

        在配置类加入

 profiles:
    active:后缀名

server:
  port: 8082
spring:
  application:
    name: nacos-client-b
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        prefix: nacos-config
        file-extension: yml
  profiles:
    active: dev

Ribbon

Openfeign

 简介

        Feign 是 声明性 ( 注解 ) Web 服务 客户端 。它使编写 Web 服务客户端更加容易。 要使用 Feign 请创建一个接口并对其进行注解 。它具有可插入注解支持,包括 Feign 注解和 JAX-RS 注解。 Feign 还支持可插拔编码器和解码器。 Spring Cloud 添加了对 Spring MVC 注解的支持 ,并
支持使用 HttpMessageConverters Spring Web 中默认使用的注解。 Spring Cloud 集成了Ribbon 和 Eureka 以及 Spring Cloud LoadBalancer ,以 在使用 Feign 时提供负载平衡 http 客户端

应用场景 

      比如订单系统,用户要下订单,但是订单的相关代码在user-service里面没有,在order-service里面有,这时候我们就要使用user-service去调用order-service里面接口来完成用户下单的操作。        

操作过程

 建立一个user

        按照上面的操作修改pom文件里面的版本

        建立起yml配置文件

server:
  port: 9001
spring:
  application:
    name: nacos-openfeign-user
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        建立controller

@RestController
public class UserController {

    @GetMapping("user")
    public String user(){
        return "这是user类";
    }

}

        启动类加入Nacos的启动注解

@SpringBootApplication
@EnableDiscoveryClient
public class NacosOpenfeignUserApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosOpenfeignUserApplication.class, args);
    }
}

 建立一个order,选中openfeign

         修改pom的文件的版本

        加入yml配置信息

server:
  port: 9002
spring:
  application:
    name: nacos-openfeign-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos

        根据openfeign的简介我们可以看出,openfeign建立主要分为三步

        1.声明性(注解)web服务客户端

                   加入启动类注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class NacosOpenfeignServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosOpenfeignServiceApplication.class, args);
    }

}

@EnableFeignClients:开启feign的客户端功能 才可以帮助我们发起调用

         2.要使用Feign,创立一个接口并对其进行注解

                建立一个feign包,里面创建feign类   注:起名规范:比如是user调用order类的起名为UserOrderFeign

               建立feign类

@FeignClient(value = "nacos-openfeign-user")
public interface UserOrderOpenfeign {

    @GetMapping("user")
    public String user();
}

@FeignClient(value = "nacos-openfeign-user") :这是feign注解

        nacos-openfeign-user:这是提供者提供的nacos的服务名

                提供者:就是被调用的一方;

@GetMapping("user")

public String user();

        这是一个完整的方法签名

                        方法签名就是一个方法的全部——修饰符 返回值 方法名以及方法的注解

        3.建立controller进行调用

    

@RestController
public class ServiceController {
    @Autowired
   private UserOrderOpenfeign userOrderOpenfeign;

    @GetMapping("service")
    public String service() {
        String user = userOrderOpenfeign.user();
        return user;

    }

}

        两个都得运行,首先得运行user,然后运行service,进入网址确认

        网址:localhost:9002/service 

     如果提供者延时了两秒就会报错,因为feign的默认等待时间是1S;我们可以使用睡眠让user睡眠两秒,在用网址测的时候就会发现报500错误,在控制台上显示连接超时;

        解决方法是加入配置信息,由于feign只是帮你封装了远程调用的功能,底层还是ribbon,所以超时的配置还是ribbon的配置

ribbon:
  ReadTimeout: 3000
  ConnectTimeout: 3000

ReadTimeout: 3000 :3S超时时间

ConnectTimeout: 3000 :链接服务的超时时间

手写Feign


@SpringBootTest
class ApplicationTests {
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 手写feign的核心步骤
     */
    @Test
    void contextLoads() {
        UserOrderFeign o = (UserOrderFeign) Proxy.newProxyInstance(UserController.class.getClassLoader(), new Class[]{UserOrderFeign.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 能去拿到对方的ip和port 并且拿到这个方法上面的注解里面的值 那么就完事了
                GetMapping annotation = method.getAnnotation(GetMapping.class);
                String[] paths = annotation.value();
                String path = paths[0];
                Class<?> aClass = method.getDeclaringClass();
                FeignClient annotation1 = aClass.getAnnotation(FeignClient.class);
                String applicationName = annotation1.value();
                String url = "http://" + applicationName + "/" + path;
                String forObject = restTemplate.getForObject(url, String.class);
                return forObject;
            }
        });
        String s = o.doOrder();
        System.out.println(s);
    }

}

Feign的参数调用(重点掌握)

        提供端建立实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {

    private Integer id;
    private String name;
    private Double price;
    private Date time;

}

        提供端controller


/**
 * url    /doOrder/热干面/add/油条/aaa
 * get传递一个参数
 * get传递多个参数
 * post传递一个对象
 * post传递一个对象+一个基本参数
 */
@RestController
public class ParamController {

    @GetMapping("testUrl/{name}/and/{age}")
    public String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age) {
        System.out.println(name + ":" + age);
        return "ok";
    }

    @GetMapping("oneParam")
    public String oneParam(@RequestParam(required = false) String name) {
        System.out.println(name);
        return "ok";
    }


    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age) {
        System.out.println(name);
        System.out.println(age);
        return "ok";
    }

    @PostMapping("oneObj")
    public String oneObj(@RequestBody Order order) {
        System.out.println(order);
        return "ok";
    }


    @PostMapping("oneObjOneParam")
    public String oneObjOneParam(@RequestBody Order order,@RequestParam("name") String name) {
        System.out.println(name);
        System.out.println(order);
        return "ok";
    }


    // 单独传递时间对象

    @GetMapping("testTime")
    public String testTime(@RequestParam Date date){
        System.out.println(date);
        return "ok";
    }
}

        接收端feign类里面的接口


/**
 * @FeignClient(value = "order-service")
 * value 就是提供者的应用名称
 */
@FeignClient(value = "order-service")
public interface UserOrderFeign {

    /**
     * 你需要调用哪个controller  就写它的方法签名
     * 方法签名(就是包含一个方法的所有的属性)
     *
     * @return
     */
    @GetMapping("doOrder")
    String doOrder();

    @GetMapping("testUrl/{name}/and/{age}")
    public String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age);

    @GetMapping("oneParam")
    public String oneParam(@RequestParam(required = false) String name);

    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age);

    @PostMapping("oneObj")
    public String oneObj(@RequestBody Order order);


    @PostMapping("oneObjOneParam")
    public String oneObjOneParam(@RequestBody Order order, @RequestParam("name") String name);



    @GetMapping("testTime")
    public String testTime(@RequestParam Date date);
}

        接收端的实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {

    private Integer id;
    private String name;
    private Double price;
    private Date time;

}

        接收端controller


@RestController
public class UserController {

    /**
     * 接口是不能做事情的
     * 如果想做事 必须要有对象
     * 那么这个接口肯定是被创建出代理对象的
     * 动态代理 jdk(java interface 接口 $Proxy )  cglib(subClass 子类)
     * jdk动态代理 只要是代理对象调用的方法必须走 java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */
    @Autowired
    public UserOrderFeign userOrderFeign;

    /**
     * 总结
     * 浏览器(前端)-------> user-service(/userDoOrder)-----RPC(feign)--->order-service(/doOrder)
     * feign的默认等待时间时1s
     * 超过1s就在直接报错超时
     *
     * @return
     */
    @GetMapping("userDoOrder")
    public String userDoOrder() {
        System.out.println("有用户进来了");
        // 这里需要发起远程调用
        String s = userOrderFeign.doOrder();
        return s;
    }



    @GetMapping("testParam")
    public String testParam(){
        String cxs = userOrderFeign.testUrl("cxs", 18);
        System.out.println(cxs);

        String t = userOrderFeign.oneParam("老唐");
        System.out.println(t);

        String lg = userOrderFeign.twoParam("雷哥", 31);
        System.out.println(lg);

        Order order = Order.builder()
                .name("牛排")
                .price(188D)
                .time(new Date())
                .id(1)
                .build();

        String s = userOrderFeign.oneObj(order);
        System.out.println(s);

        String param = userOrderFeign.oneObjOneParam(order, "稽哥");
        System.out.println(param);
        return "ok";
    }

    /**
     * Sun Mar 20 10:24:13 CST 2022
     * Mon Mar 21 00:24:13 CST 2022  +- 14个小时
     * 1.不建议单独传递时间参数
     * 2.转成字符串   2022-03-20 10:25:55:213 因为字符串不会改变
     * 3.jdk LocalDate 年月日    LocalDateTime 会丢失s
     * 4.改feign的源码
     *
     * @return
     */
    @GetMapping("time")
    public String time(){
        Date date = new Date();
        System.out.println(date);
        String s = userOrderFeign.testTime(date);

        LocalDate now = LocalDate.now();
        LocalDateTime now1 = LocalDateTime.now();

        return s;
    }



}

Hystrix

简介        

        熔断器,也叫断路器!(正常情况下 断路器是关的 只有出了问题才打开)用来保护微服务不 雪崩的方法
        Hystrix 是 Netflix 公司开源的一个项目,它提供了熔断器功能,能够阻止分布式系统中出现 联动故障 。Hystrix 是通过隔离服务的访问点阻止联动故障的,并提供了故障的解决方案,从而提高了整个分布式系统的弹性。

使用场景

        服务A调用服务B,服务B调用服务C,服务C挂掉了,服务A和服务B一直在等待服务C。占据线程不放掉。就是用熔断器。

使用方法

       调用的一方加入依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        在feign包里面建立hystrix包,新建一个类继承feign接口

@Component
public class ConsumerProviderHystrix implements ConsumerProviderFeign {
    @Override
    public String provider() {
        return "null";
    }
}

        在feign接口的注解里面加入fallback指向熔断后的路径也就是刚才建立的hystrix包里新建的类

@FeignClient(value = "hystrix-provinder", fallback =ConsumerProviderHystrix.class)
public interface ConsumerProviderFeign {

    @GetMapping("provider")
    public String provider();

}

        启动类加入hystrix注解 @EnableHystrix

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
public class HystrixConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixConsumerApplication.class, args);
    }

}

        在配置中打开hystrix,默认是关闭的

server:
  port: 9022
spring:
  application:
    name: hystrix-consumer
  cloud:
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848
feign:
  hystrix:
    enabled: true

拦截器状态

         拦截器状态有三种

                关:默认情况下,断路器是关闭的,正常使用

                开:当在一个时间窗口内(10S)访问失败的次数到达一个阈值,断路器开

                半开:让少许流量去尝试调用,如果正常了,就关掉断路器

常见配置

hystrix:    #hystrix的全局控制
    command:
        default:    #default是全局控制,也可以换成单个方法控制,把default换成方法名即可
            circuitBreaker:
                enabled: true   #开启断路器
                requestVolumeThreshold: 3   #失败次数(阀值)  10次
                sleepWindowInMilliseconds: 20000    #窗口时间
                errorThresholdPercentage: 60    #失败率
            execution:
                isolation:
                    Strategy: thread  #隔离方式 thread线程隔离集合和semaphore信号量隔离级别
                    thread:
                        timeoutInMilliseconds: 3000 #调用超时时长
            fallback:
                isolation:
                    semaphore:
                        maxConcurrentRequests: 1000 #信号量隔离级别最大并发数
ribbon:
    ReadTimeout: 5000   #要结合feign的底层ribbon调用的时长
    ConnectTimeout: 5000
#隔离方式 两种隔离方式  thread线程池 按照group(10个线程)划分服务提供者,用户请求的线程和做远程的线程不一样
# 好处 当B服务调用失败了 或者请求B服务的量太大了 不会对C服务造成影响 用户访问比较大的情况下使用比较好  异步的方式
# 缺点 线程间切换开销大,对机器性能影响
# 应用场景 调用第三方服务 并发量大的情况下
# SEMAPHORE信号量隔离 每次请进来 有一个原子计数器 做请求次数的++  当请求完成以后 --
# 好处 对cpu开销小
# 缺点 并发请求不易太多 当请求过多 就会拒绝请求 做一个保护机制
# 场景 使用内部调用 ,并发小的情况下
# 源码入门  HystrixCommand  AbstractCommand HystrixThreadPool 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值