精华内容
下载资源
问答
  • 04-Nacos服务注册中心应用实践

    万次阅读 多人点赞 2021-07-22 08:41:40
    如何更好更方便的管理应用中的每一个服务,如何建立各个服务之间联系的纽带,由此注册中心诞生(例如淘宝网卖家提供服务,买家调用服务)。 市面上常用注册中心有Zookeeper(雅虎Apache),Eureka(Netfix),Nacos...

    注册中心简介

    背景分析

    在微服务中,首先需要面对的问题就是如何查找服务(软件即服务),其次,就是如何在不同的服务之间进行通信?如何更好更方便的管理应用中的每一个服务,如何建立各个服务之间联系的纽带,由此注册中心诞生(例如淘宝网卖家提供服务,买家调用服务)。
    市面上常用注册中心有Zookeeper(雅虎Apache),Eureka(Netfix),Nacos(Alibaba),Consul(Google),那他们分别都有什么特点,我们如何进行选型呢?我们主要从社区活跃度,稳定性,功能,性能等方面进行考虑即可.本次微服务的学习,我们选择Nacos,它很好的支持了阿里的双11活动,不仅可以做注册中心,还可以作为配置中心,稳定性和性能都很好。

    Nacos概述

    Nacos(DynamicNaming and Configuration Service)是一个应用于服务注册与发现、配置管理的平台。它孵化于阿里巴巴,成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。其官网地址如下:

    https://nacos.io/zh-cn/docs/quick-start.html
    

    构建Nacos服务

    准备工作

    第一:确保你电脑已配置JAVA_HOME环境变量(Nacos启动时需要),例如:
    在这里插入图片描述
    第二:确保你的MySQL版本为5.7以上(MariaDB10.5以上),例如
    在这里插入图片描述

    下载与安装

    第一步:Nacos下载,可在浏览器直接输入如下地址:

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

    第二步:选择对应版本,直接下载,如图所示:
    在这里插入图片描述

    第三步:解压Nacos(最好不要解压到中文目录下),其目录结构如下:

    在这里插入图片描述

    初始化配置

    第一步:登陆mysql,执行老师发给同学们的sql脚本。例如,我们可以使用mysql自带客户端,在命令行首先登录mysql,然后执行如下指令:

    source d:/nacos-mysql.sql 
    

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

    在这里插入图片描述

    说明:在执行此文件时,要求mysql的版本大于5.7版本(MariaDB最好10.5.11),否则会出现如下错误:
    在这里插入图片描述

    第二步:打开/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
    

    服务启动与访问

    第一步:启动Nacos服务。

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

    ./startup.sh -m standalone
    

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

    startup.cmd -m standalone
    

    说明:
    1)执行执行令时要么配置环境变量,要么直接在nacos/bin目录下去执行.
    2)nacos启动时需要本地环境变量中配置了JAVA_HOME(对应jdk的安装目录),
    3)一定要确保你连接的数据库(nacos_config)是存在的.
    4)假如所有的配置都正确,还连不上,检查一下你有几个数据库(mysql,…)

    第二步:访问Nacos服务。

    打开浏览器,输入http://localhost:8848/nacos地址,出现如下登陆页面:
    在这里插入图片描述

    其中,默认账号密码为nacos/nacos.

    服务注册与调用入门(重点)

    业务描述

    创建两个项目Module分别为服务提供者和服务消费者(假如已有则无需创建),两者都要注册到NacosServer中(这个server本质上就是一个web服务,端口默认为8848),然后服务提供者可以为服务消费者提供远端调用服务(例如支付服务为服务提供方,订单服务为服务消费方),如图所示:
    在这里插入图片描述

    生产者服务创建及注册

    第一步:创建服务提供者工程(module名为sca-provider,假如已有则无需创建),继承parent工程(01-sca),其pom.xml文件内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>01-sca</artifactId>
            <groupId>com.jt</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>sca-provider</artifactId>
        <dependencies>
            <!--Web服务-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--服务的注册和发现(我们要讲服务注册到nacos)-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    第二步:创建并修改配置文件application.yml(或者application.properties),实现服务注册,关键代码如下:

    server:
       port: 8081
    spring:
      application:
        name: sca-provider #进行服务注册必须配置服务名
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
    

    注意:服务名不要使用下划线(“_”),应使用横杠(“-”),这是规则。
    第三步:创建启动类(假如已有则无需定义),关键代码如下:

    package com.jt;
    
    @SpringBootApplication
    public class ProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
      }
    

    第四步:启动启动类,然后刷先nacos服务,检测是否服务注册成功,如图所示:

    在这里插入图片描述

    第五步:停掉sca-provider服务,然后不断刷新nacos服务列表,检查服务的健康状态。

    消费者服务发现及调用

    第一步: 在sca-provider项目中创建服务提供方对象,基于此对象对外提供服务,例如:

        package com.jt.provider.controller;
        /**定义Controller对象(这个对象在spring mvc中给他的定义是handler),
         * 基于此对象处理客户端的请求*/
        @RestController
        public class ProviderController{
            //@Value默认读取项目配置文件中配置的内容
            //8080为没有读到server.port的值时,给定的默认值
            @Value("${server.port:8080}")
            private String server;
            //http://localhost:8081/provider/echo/tedu
            @GetMapping("/provider/echo/{msg}")
            public String doRestEcho1(@PathVariable String msg){
                return server+" say hello "+msg;
            }
        }
    

    第二步:创建服务消费者工程(module名为sca-consumer,假如已有则无需创建),继承parent工程(01-sca),其pom.xml文件内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>01-sca</artifactId>
            <groupId>com.jt</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>sca-consumer</artifactId>
        
       <dependencies>
        <!--Web服务-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--服务的注册和发现(我们要讲服务注册到nacos)-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        </dependencies>
    </project>
    

    第三步:创建sca-consumer服务中的配置文件application.yml,关键代码如下:

    server:
      port: 8090
    spring:
      application:
        name: sca-consumer #服务注册时,服务名必须配置
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 #从哪里去查找服务
    

    第四步:创建消费端启动类并实现服务消费,关键代码如下:

    package com.jt;
    @SpringBootApplication
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class,args);
        }
    }
    

    第五步:在sca-consumer启动类中添加如下方法,用于创建RestTemplate对象.

    @Bean
    public RestTemplate restTemplate(){//基于此对象实现远端服务调用
        return new RestTemplate();
    }
    

    第六步:定义sca-consumer服务的消费端Controller,在此对象方法内部实现远端服务调用

    package com.jt.consumer.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    
    /**
     * 定义服务消费端Controller,在这个Controller对象
     * 的方法中实现对远端服务sca-provider的调用
     */
    @RestController
    public class ConsumerController {
        /**
         * 从spring容器获取一个RestTemplate对象,
         * 基于此对象实现远端服务调用
         */
        @Autowired
        private RestTemplate restTemplate;
        /**
         * 在此方法中通过一个RestTemplate对象调用远端sca-provider中的服务
         * @return
         * 访问此方法的url: http://localhost:8090/consumer/doRestEcho1
         */
        @GetMapping("/consumer/doRestEcho1")
        public String doRestEcho01(){
            //1.定义要调用的远端服务的url
            String url="http://localhost:8081/provider/echo/8090";
            //2.基于restTemplate对象中的相关方法进行服务调用
            return restTemplate.getForObject(url, String.class);
        }
    
    }
    

    第七步:启动消费者服务,并在浏览器输入http://localhost:8090/consumer/doRestEcho1地址进行访问,假如访问成功会出现,如图所示效果:
    在这里插入图片描述

    小节面试分析

    • 为什么要将服务注册到nacos?(为了更好的查找这些服务)
    • 在Nacos中服务提供者是如何向Nacos注册中心(Registry)续约的?(5秒心跳)
    • 对于Nacos服务来讲它是如何判定服务实例的状态?(检测心跳包,15,30)
    • 服务消费方是如何调用服务提供方的服务的?(RestTemplate)

    服务负载均衡设计及实现(重点)

    业务描述

    一个服务实例可以处理请求是有限的,假如服务实例的并发访问比较大,我们会启动多个服务实例,让这些服务实例采用一定策略均衡(轮询,权重,随机,hash等)的处理并发请求,在Nacos中服务的负载均衡(Nacos客户端负载均衡)是如何应用的?

    LoadBalancerClient应用

    LoadBalancerClient对象可以从nacos中基于服务名获取服务实例,然后在工程中基于特点算法实现负载均衡方式的调用,案例实现如下:

    第一步:修改ConsumerController类,注入LoadBalancerClient对象,并添加doRestEcho2方法,然后进行服务访问.

    
      @Autowired
      private LoadBalancerClient loadBalancerClient;
      
      @Value("${spring.application.name:8090}")
      private String appName;
       
      @GetMapping("/consumer/doRestEcho02")
     public String doRestEcho02(){
         ServiceInstance serviceInstance = loadBalancerClient.choose("sca-provider");
         String url = String.format("http://%s:%s/provider/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
         System.out.println("request url:"+url);
         return restTemplate.getForObject(url, String.class);
         }
     }
    

    第二步:打开Idea服务启动配置,如图所示:
    在这里插入图片描述

    第三步:修改并发运行选项(假如没有找到这个选项我们需要通过搜索引擎基于组合查询的方法,去找到对应的解决方案,例如搜索 idea allow parallel run),如图所示:

    在这里插入图片描述

    第四步:修改sca-provider的配置文件端口,分别以8081,8082端口方式进行启动。

    server:
      port: 8082
    spring:
      application:
        name: sca-provider
      cloud:
        nacos:
          server-addr: localhost:8848
    

    第五步:启动成功以后,访问nacos的服务列表,检测服务是否成功注册,如图所示:
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    第六步:启动sca-consumer项目模块,打开浏览器对consumer服务进行访问,访问时不断刷新,检测页面数据变化,例如:

    说明,这里多个实例并发提供服务的方式为负载均衡,这里的负载均衡实现默认是因为Nacos集成了Ribbon来实现的,Ribbon配合RestTemplate,可以非常容易的实现服务之间的访问。Ribbon是Spring Cloud核心组件之一,它提供的最重要的功能就是客户端的负载均衡(客户端可以采用一定算法,例如轮询访问,访问服务端实例信息),这个功能可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡方式的服务调用。

    @LoadBalanced

    当使用RestTemplate进行远程服务调用时,假如需要负载均衡,还可以在RestTemplate对象构建时,使用@LoadBalanced对构建RestTemplate的方法进行修饰,例如在ConsumerApplication中构建名字为loadBalancedRestTemplate的RestTemplate对象:

    @Bean
    @LoadBalanced
    public RestTemplate loadBalancedRestTemplate(){
        return new RestTemplate();
    }
    

    在需要RestTemplate实现负载均衡调用的地方进行依赖注入.例如在ConsumerController类中添加loadBalancedRestTemplate属性

    @Autowired
    private RestTemplate loadBalancedRestTemplate;
    

    接下来,可以在对应的服务端调用方的方法内,基于RestTemplate借助服务名进行服务调用, 例如:

    @GetMapping("/consumer/doRestEcho3")
    public String doRestEcho03(){
        String url=String.format("http://%s/provider/echo/%s","sca-provider",appName);
        //向服务提供方发起http请求,获取响应数据
        return loadBalancedRestTemplate.getForObject(
                url,//要请求的服务的地址
                String.class);//String.class为请求服务的响应结果类型
    }
    

    RestTemplate在发送请求的时候会被LoadBalancerInterceptor拦截,它的作用就是用于RestTemplate的负载均衡,LoadBalancerInterceptor将负载均衡的核心逻辑交给了loadBalancer,核心代码如下所示(了解):

    public ClientHttpResponse intercept(final HttpRequest request, 
        final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
    	final URI originalUri = request.getURI();
    	String serviceName = originalUri.getHost();
    	return this.loadBalancer.execute(serviceName, 
        requestFactory.createRequest(request, body, execution));
    }
    

    @LoadBalanced注解是属于Spring,而不是Ribbon的,Spring在初始化容器的时候,如果检测到Bean被@LoadBalanced注解,Spring会为其设置LoadBalancerInterceptor的拦截器。

    Ribbon负载均衡策略(了解)

    基于Ribbon方式的负载均衡,Netflix默认提供了七种负载均衡策略,对于SpringCloud Alibaba解决方案中又提供了NacosRule策略,默认的负载均衡策略是轮训策略。如图所示:
    在这里插入图片描述
    当系统提供的负载均衡策略不能满足我们需求时,我们还可以基于IRule接口自己定义策略.

    小节面试分析

    • @Bean注解的作用?(一般用于配置类内部,描述相关方法,用于告诉spring此方法的返回值要交给spring管理,bean的名字默认为方法名,假如需要指定名字可以@Bean(“bean的名字”),最多的应用场景是整合第三方的资源-对象)
    • @Autowired注解的作用?(此注解用于描述属性,构造方法,set方法等,用于告诉spring框架,按找一定的规则为属性进行DI操作,默认按属性,方法参数类型查找对应的对象,假如只找到一个,则直接注入,类型多个时还会按照属性名或方法参数名进行值的注入,假如名字也不同,就出报错.)
    • Nacos中的负责均衡底层是如何实现的?(通过Ribbon实现,Ribbon中定义了一些负载均衡算法,然后基于这些算法从服务实例中获取一个实例为消费方法提供服务)
    • Ribbon 是什么?(Netflix公司提供的负载均衡客户端,一般应用于服务的消费方法)
    • Ribbon 可以解决什么问题? (基于负载均衡策略进行服务调用, 所有策略都会实现IRule接口)
    • Ribbon 内置的负载策略都有哪些?(8种,可以通过查看IRule接口的实现类进行分析)
    • @LoadBalanced的作用是什么?(描述RestTemplate对象,用于告诉Spring框架,在使用RestTempalte进行服务调用时,这个调用过程会被一个拦截器进行拦截,然后在拦截器内部,启动负载均衡策略。)
    • 我们可以自己定义负载均衡策略吗?(可以,基于IRule接口进行策略定义,也可以参考NacosRule进行实现)

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

    背景分析

    服务消费方基于rest方式请求服务提供方的服务时,一种直接的方式就是自己拼接url,拼接参数然后实现服务调用,但每次服务调用都需要这样拼接,代码量复杂且不易维护,此时Feign诞生。

    Feign是什么

    Feign 是一种声明式Web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。如图所示:
    在这里插入图片描述

    Feign 最早是由 Netflix 公司进行维护的,后来 Netflix 不再对其进行维护,最终 Feign 由一些社区进行维护,更名为 OpenFeign。

    Feign应用实践(掌握)

    第一步:在服务消费方,添加项目依赖(SpringCloud团队基于OpenFeign研发了starter),代码如下:

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

    第二步:在启动类上添加@EnableFeignClients注解,代码如下:

    @EnableFeignClients
    @SpringBootApplication
    public class ConsumerApplication {}
    

    第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:

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

    其中,@FeignClient描述的接口底层会为其创建实现类。

    第四步:创建FeignConsumerController中并添加feign访问,代码如下:

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

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

    在这里插入图片描述
    说明,feign方式的远程服务调用,底层会自动基于ribbon组件实现负载均衡。

    Feign配置进阶实践

    一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定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.
    

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

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

    还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如,在Feign应用中通过FallbackFactory接口的实现类进行默认的相关处理,例如:

    第一步:定义FallbackFactory接口的实现,代码如下:

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

    第二步:在Feign访问接口中应用FallbackFactory对象,例如:

    @FeignClient(name = "sca-provider", contextId = "remoteProviderService",
                 fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
    public interface RemoteProviderService {
        @GetMapping("/provider/echo/{msg}")
        public String echoMsg(@PathVariable String msg);
    }
    

    第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.

    feign:  
      hystrix:
        enabled: true #默认值为false
    

    第四步:在服务提供方对应的调用方法中添加Thread.sleep(5000)模拟耗时操作,然后启动服务进行访问测试.

    Feign 调用过程分析(了解)

    Feign应用过程分析(底层逻辑先了解):
    1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
    2) Feign Starter 会在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
    3) Feign接口被调用时,底层代理对象会将接口中的请求信息通过编码器创建 Request对象,基于此对象进行远程过程调用。
    4) Feign客户端请求对象会经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
    5) Feign客户端会携带 Request 调用远端服务并返回一个响应。
    6) Feign客户端对象对Response信息进行解析然后返回客户端。

    小节面试分析

    • 为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
    • @FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
    • Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
    • @EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)

    总结(Summary)

    重难点分析

    • 何为注册中心?(用于记录服务信息的一个web服务,例如淘宝平台,滴滴平台,美团外卖平台,……)
    • 注册中心的核心对象?(服务提供方,服务消费方,注册中心-Registry)
    • 市面上常用注册中心?(Google-Consul,Alibaba-Nacos,…)
    • Nacos安装、启动、服务的注册、发现机制以及实现过程
    • 服务调用时RestTemplate对象的应用。
    • 基于Feign方式的服务调用及基本原理?

    FAQ分析

    • Nacos是什么,提供了什么特性(服务的注册、发现、配置)?
    • 你为什么会选择Nacos?(活跃度、稳定、性能、学习成本)
    • Nacos的官网?(nacos.io)
    • Nacos在github的源码?(github.com/alibaba/nacos)
    • Nacos在windows环境下安装?(解压即可使用)
    • Nacos在windows中的的初步配置?(application.properties访问数据库的数据源)
    • Nacos服务注册的基本过程?(服务启动时发送web请求)
    • Nacos服务消费的基本过程?(服务启动时获取服务实例,然后调用服务)
    • Nacos服务负载均衡逻辑及设计实现?(Ribbon)
    • 注册中心的核心数据是什么?(服务的名字和它对应的网络地址)
    • 注册中心中心核心数据的存取为什么会采用读写锁?(底层安全和性能)
    • Nacos健康检查的方式?(基于心跳包机制进行实现)
    • Nacos是如何保证高可用的?(重试,本地缓存、集群)
    • RestTemplate的基本作用是什么?
    • Feign是什么,它的应用是怎样的,feign应用过程中的代理对象是如何创建的(JDK)?
    • Feign方式的调用过程,其负载均衡是如何实现?(Ribbon)

    Bug分析

    • 404
    • 400
    • 405
    • 500
    • ………
    展开全文
  • 在微服务架构或分布式环境下,服务注册与发现技术不可或缺​,这也是程序员进阶之路必须要掌握的核心技术之一,本文通过图解的方式带领大家轻轻松松掌握。 一、引入服务注册与发现组件的原因 先来看一个问题,...

    本文 Github/javamap 已收录,有Java程序员进阶技术知识地图以及我的系列文章,欢迎大家Star。

    在微服务架构或分布式环境下,服务注册与发现技术不可或缺​,这也是程序员进阶之路必须要掌握的核心技术之一,本文通过图解的方式带领大家轻轻松松掌握。

     

    一、引入服务注册与发现组件的原因

    先来看一个问题,假如现在我们要做一个商城项目,作为架构师的你应该怎样设计系统的架构?你心里肯定在想:这还不容易直接照搬淘宝的架构不就行了。但在现实的创业环境中一个项目可能是九死一生,如果一开始投入巨大的人力和财力,一旦项目失败损失就很大。

    作为一位有经验的架构师需要结合公司财力、人力投入预算等现状选择最适合眼下的架构才是王道。大型网站都是从小型网站发展而来,架构也是一样。

    任何一个大型网站的架构都不是从一开始就一层不变的,而是随着用户量和数据量的不断增加不断迭代演进的结果。

    在架构不断迭代演进的过程中我们会遇到很多问题,技术发展的本质就是不断发现问题再解决问题,解决问题又发现问题

     

    单体架构

    在系统建立之初可能不会有特别多的用户,将所有的业务打成一个应用包放在tomcat容器中运行,与数据库共用一台服务器,这种架构一般称之为单体架构。

    在初期这种架构的效率非常高,根据用户的反馈可以快速迭代上线。但是随着用户量增加,一台服务的内存和CPU吃紧,很容易造成瓶颈,新的问题来了怎么解决呢?

     

    应用与数据分离

    随着用户请求量增加,一台服务器的内存和CPU持续飙升,用户请求响应时间变慢。这时候可以考虑将应用与数据库拆开,各自使用一台服务器,你看问题又解决了吧。

    突然有一天扫地阿姨不小心碰了电线,其中一台服务器掉电了,用户所有的请求都报错,随之而来的是一系列投诉电话。

     

    集群部署

    单实例很容易造成单点问题,比如遇到服务器故障或者服务能力瓶颈,那怎么办?聪明的你肯定想到了,用集群呀。

    集群部署是指将应用部署在多个服务器或者虚机上,用户通过服务均衡随机访问其中的一个实例,从而使多个实例的流量均衡,如果一个实例出现故障可以将其下线,其他实例不受影响仍然可以对外提供服务。

    随着用户数量快速增加,老板决定增加投入扩大团队规模。开发团队壮大后效率并没有得到显著的提高,以前小团队可以一周迭代上线一次,现在至少需要两到三周时间。

    业务逻辑越来越复杂,代码间耦合很严重,修改一行代码可能引入几个线上问题。架构师意识到需要进行架构重构。

     

    微服务架构

    当单体架构演进到一定阶段后开发测试的复杂性都会成本增加,团队规模的扩大也会使得各自工作耦合性更严重,牵一发而动全身就是这种场景。

    单体架构遇到瓶颈了,微服务架构就横空出世了。微服务就是将之前的单体服务按照业务维度进行拆分,拆分粒度可大可小,拆分时机可以分节奏进行。最佳实践是先将一些独立的功能从单体中剥离出来抽成一个或多个微服务,这样可以保障业务的连续性和稳定性。

     

    如上图将一个商用应用拆分为六个独立微服务。六个微服务可以使用Docker容器化进行多实例部署。

    架构演化到这里遇到了一个难题,如果要查询用户所有的订单,用户服务可能会依赖订单服务,用户服务如何与订单服务交互呢?订单服务有多个实例该访问哪一个?

    通常有几种解决办法:

    (1)服务地址硬编码

    服务的地址写死在数据库或者配置文件,通过访问DNS域名进行寻址路由。

    服务B的地址硬编码在数据库或者配置文件中,服务A首先需要拿到服务B的地址,然后通过DNS服务器解析获取其中一实例的真实地址,最后可以向服务B发起请求。

    如果遇到大促活动需要对服务实例扩容,大促完需要对服务实例进行下线,运维人员要做大量的手工操作,非常容易误操作。

    (2)服务动态注册与发现

    服务地址硬编码还有一个非常致命的问题,如果一台实例挂了,运维人员可能不能及时感知到,导致一部分用户的请求会异常。

    引入服务注册与发现组件可以很好解决上面遇到的问题,避免过多的人工操作。

     

    架构演进总结

    在单体架构中一个应用程序就是一个服务包,包内的模块通过函数方法相互调用,模型足够简单,根本没有服务注册和发现一说。

    在微服务架构中会将一个应用程序拆分为多个微服务,微服务会部署在不同的服务器、不同的容器、甚至多数据中心,微服务间要相互调用,服务注册和发现成为了一个不可或缺的组件。

     

    二、服务注册与发现基本原理

    服务注册与发现是分为注册和发现两个关键的步骤。

    服务注册:服务进程在注册中心注册自己的元数据信息。通常包括主机和端口号,有时还有身份验证信息,协议,版本号,以及运行环境的信息。

    服务发现:客户端服务进程向注册中心发起查询,来获取服务的信息。服务发现的一个重要作用就是提供给客户端一个可用的服务列表。

     

    服务注册

    服务注册有两种形式:客户端注册和代理注册。

    客户端注册

    客户端注册是服务自己要负责注册与注销的工作。当服务启动后注册线程向注册中心注册,当服务下线时注销自己。

    这种方式的缺点是注册注销逻辑与服务的业务逻辑耦合在一起,如果服务使用不同语言开发,那需要适配多套服务注册逻辑。

    代理注册

    代理注册由一个单独的代理服务负责注册与注销。当服务提供者启动后以某种方式通知代理服务,然后代理服务负责向注册中心发起注册工作。

    这种方式的缺点是多引用了一个代理服务,并且代理服务要保持高可用状态。

     

    服务发现

    服务发现也分为客户端发现和代理发现。

    客户端发现

    客户端发现是指客户端负责向注册中心查询可用服务地址,获取到所有的可用实例地址列表后客户端根据负载均衡算法选择一个实例发起请求调用。

    这种方式非常直接,客户端可以控制负载均衡算法。但是缺点也很明显,获取实例地址、负载均衡等逻辑与服务的业务逻辑耦合在一起,如果服务发现或者负载平衡有变化,那么所有的服务都要修改重新上线。

    代理发现

    代理发现是指新增一个路由服务负责服务发现获取可用的实例列表,服务消费者如果需要调用服务A的一个实例可以直接将请求发往路由服务,路由服务根据配置好的负载均衡算法从可用的实例列表中选择一个实例将请求转发过去即可,如果发现实例不可用,路由服务还可以自行重试,服务消费者完全不用感知。

     

    心跳机制

    如果服务有多个实例,其中一个实例出现宕机,注册中心是可以实时感知到,并且将该实例信息从列表中移出,也称为摘机。

    如何实现摘机?业界比较常用的方式是通过心跳检测的方式实现,心跳检测有主动被动两种方式。

    被动检测是指服务主动向注册中心发送心跳消息,时间间隔可自定义,比如配置5秒发送一次,注册中心如果在三个周期内比如说15秒内没有收到实例的心跳消息,就会将该实例从列表中移除。

    上图中服务A的实例2已经宕机不能主动给注册中心发送心跳消息,15秒之后注册就会将实例2移除掉。

    主动检测是注册中心主动发起,每隔几秒中会给所有列表中的服务实例发送心跳检测消息,如果多个周期内未发送成功或未收到回复就会主动移除该实例。

     

     

    三、业界常用的服务注册与发现组件对比

    了解服务注册与发现的基本原理后,如果你要在项目中使用服务注册与发现组件,当面对众多的开源组件该如何进行技术选型?

    在互联网公司里,有研发实力的大公司一般会选择自研或者基于开源组件进行二次开发,但是对于中小型公司来说直接选用一款开源软件会是一个不错的选择。

    常用的注册与发现组件有eureka,zookeeper,consul,etcd等,由于eureka在2018年已经宣布放弃维护,这里就不再推荐使用了。

    下面结合各个维度对比一下各组件。

    组件

    优点

    缺点

    接口类型

    一致性算法

    zookeeper

    1.功能强大,不仅仅只是服务发现;

    2.提供watcher机制可以实时获取服务提供者的状态;

    3.广泛使用,dubbo等微服务框架已支持;

    1.没有健康检查;

    2.需要在服务中引入sdk,集成复杂度高;

    3.不支持多数据中心;

    sdk

    Paxos

    consul

    1.开箱即用,方便集成;

    2.带健康检查;

    3.支持多数据中心;

    4.提供web管理界面;

    不能实时获取服务变换通知

    restful/dns

    Raft

    etcd

    1.开箱即用,方便集成;

    2.可配置性强

    1.没有健康检查;

    2.需配合三方工具完成服务发现功能;

    3.不支持多数据中心;

    restful

    Raft

    从整体上看consul的功能更加完备和均衡。接下来以consul为例详细介绍一下。

     

    四、Consul——值得推荐的服务注册与发现开源组件

    简单认识一下Consul

    Consul是HashiCorp公司推出的开源工,使用Go语言开发,具有开箱即可部署方便的特点。Consul是分布式的、高可用的、 可横向扩展的用于实现分布式系统的服务发现与配置。

    Consul有哪些优势?

    • 服务注册发现:Consul提供了通过DNS或者restful接口的方式来注册服务和发现服务。服务可根据实际情况自行选择。
    • 健康检查:Consul的Client可以提供任意数量的健康检查,既可以与给定的服务相关联,也可以与本地节点相关联。
    • 多数据中心:Consul支持多数据中心,这意味着用户不需要担心Consul自身的高可用性问题以及多数据中心带来的扩展接入等问题。

    Consul的架构图

    Consul 实现多数据中心依赖于gossip protocol协议。这样做的目的:

    • 不需要使用服务器的地址来配置客户端;服务发现是自动完成的。
    • 健康检查故障的工作不是放在服务器上,而是分布式的。

     

    Consul的使用场景

    Consul的应用场景包括服务注册发现服务隔离服务配置等。

    服务注册发现场景中consul作为注册中心,服务地址被注册到consul中以后,可以使用consul提供的dns、http接口查询,consul支持health check。

    服务隔离场景中consul支持以服务为单位设置访问策略,能同时支持经典的平台和新兴的平台,支持tls证书分发,service-to-service加密

    服务配置场景中consul提供key-value数据存储功能,并且能将变动迅速地通知出去,借助Consul可以实现配置共享,需要读取配置的服务可以从Consul中读取到准确的配置信息。

     

    -- END --

    日常求赞:你好技术人,先赞后看养成习惯,你的赞是我前进道路上的动力,对我非常重要。

    加油技术人!

    简介: 博主从华中科技大学硕士毕业,是一个对技术有追求,对生活有激情的程序员。几年间浪迹于多个一线互联网大厂,具有多年开发实战经验。

    微信搜索公众号【爱笑的架构师】,我有技术和故事,等你来。

    文章持续更新,在 Github/javamap 中可以看到我归档的系列文章,有面试经验和技术干货,欢迎Star。

     

    展开全文
  • Dubbo系列之服务注册与发现

    万次阅读 2019-07-21 20:02:02
    文章目录一、分布式基本理论1.1、分布式基本定义1.2 架构发展演变1.3、RPC简介二、Dubbo理论简介三、Dubbo环境搭建3.1 Zookeeper搭建3.2 Dubbo管理页面搭建四、Dubbo服务注册发现例子4.1、业务场景4.2、api工程创建...

    一、分布式基本理论

    1.1、分布式基本定义

    《分布式系统原理与范型》定义:
    “分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
    分布式系统(distributed system)是建立在网络之上的软件系统。

    1.2 架构发展演变

    架构的发展是由最初的单一应用架构构建的,一般就是ORM框架方便数据库操作。

    不过随着系统越来越复杂,单一应用架构会变得难以维护,所以架构逐渐演变出了垂直应用架构,所谓垂直应用架构其实就是安装业务模板进行拆分,比如可以安装业务将一个电商系统分为订单模块,用户信息管理模块,商品管理模块等等,这时候MVC框架就派上用场,MVC框架可以协助系统更好的按业务拆分,不过业务拆分后虽然是比单一应用架构更好维护了。

    不过随着系统越来约复杂,发现很多共用的模块很难复用起来,这时候分布式服务架构登场了,分布式架构是将一些核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,当应用需要时,就去服务中心调服务就可以,而实现这种服务注册的肯定是RPC框架了。

    当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率,这时候就需要流动计算架构(SOA)[ Service Oriented Architecture],用于提高机器利用率的资源调度,SOA是一个治理中心,综上所述,到目前,软件系统架构演变经历了:单一应用架构->垂直应用架构->分布式应用架构->流动计算架构,下面Dubbo官网的图片可以很好的描述
    在这里插入图片描述

    1.3、RPC简介

    RPC概念
    RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

    RPC核心模块
    RPC有两个核心模块:通信和序列化

    二、Dubbo理论简介

    Apache Dubbo (incubating) |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

    官网:
    http://dubbo.apache.org/

    在这里插入图片描述
    Dubbo的服务治理:
    在这里插入图片描述

    Dubbo原理图片,图片来自Dubbo官网:

    在这里插入图片描述

    Dubbo角色:

    • Provider:暴露服务的服务提供者

    • Container:服务运行的容器

    • Consumer:调用远程服务的消费者

    • Registry:服务注册和发现的注册中心

    • Minitor:统计服务调用次数和时间的监控中心

    调用过程:

    下面根据我的理解说明一下

    • 0:服务器容器负责启动、加载、运行服务提供者

    • 1:服务提供者在启动后就可以向注册中心暴露服务

    • 2:服务消费者在启动后就可以向注册中心订阅想要的服务

    • 3:注册中心向服务消费者返回服务调用列表

    • 4:服务消费者基于软负载均衡算法调用服务提供者的服务,这个服务提供者有可能是一个服务提供者列表,调用那个服务提供者就是根据负载均衡来调用了

    • 5:服务提供者和服务消费者定时将保存在内存中的服务调用次数和服务调用时间推送给监控中心

    三、Dubbo环境搭建

    3.1 Zookeeper搭建

    搭建Zookeeper,首先是搭建分布式架构的注册中心Zookeeper,当然也可以用Redis等等来做服务注册中心,不过本博客只介绍Zookeeper的,因为没有linux服务器,所以只介绍window版的搭建

    • 1、下载Zookeeper:
      网址 https://archive.apache.org/dist/zookeeper/zookeeper-3.4.13/

    • 2、解压Zookeeper
      解压Zookeeper之后,运行bin目录里的zkServer.cmd,发现报错了,提示找不到配置文件,所以需要继续步骤3

    • 3、配置Zookeeper
      因为Zookeeper的conf文件夹下面只提供zoo_sample.cfg文件,需要自己修改命名为zoo.cfg

    对于配置文件需要注意:

    dataDir=./ 临时数据存储的目录(可写相对路径)

    clientPort=2181 zookeeper的端口号

    • 4、使用zkCli.cmd测试
      修改配置文件后,重新启动zkServer.cmd,启动bin目录下面的zkCli.cmd,很显然这是个客户端程序,注意zkServer.cmd是服务端程序,必须启动

    ok,简单在zkCli.cmd敲几个命令测试一下:
    ls /:列出zookeeper根下保存的所有节点
    create –e /testNode 12345678:创建一个testNode节点,值为12345678
    get /testNode:获取/testNode节点的值

    3.2 Dubbo管理页面搭建

    搭建了服务注册中心后,就需要搭建Dubbo-admin了,最近看了一下,dubbo的Github项目已经进行了更新,管理平台已经做了比较大的改动,而我学习的时候,平台是比较简单的,所以本dubbo-admin搭建是以旧版master的为准,不过以学习为目的的,只需要知道具体原理和操作技巧就可以

    • 下载dubbo-admin
      去下载一下dubbo-admin,可以找主干master分支的,找到dubbo-admin,git clone到本地
      https://github.com/apache/incubator-dubbo-ops

    因为我搭建时候(ps:不是博客写作时间),dubbo还没做比较大改动,所以我以比较旧的版本为例子,现在新的具体参考dubbo官方的教程,本博客只是做记录

    • 修改dubbo-admin

    修改 src\main\resources\application.properties 指定zookeeper地址
    在这里插入图片描述

    • Maven package dubbo-admin
    mvn clean package -Dmaven.test.skip=true
    
    • 运行dubbo-admin的jar

    maven打包之后,就去target里找到jar,然后cmd运行

    java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
    

    运行成功之后,访问: http://127.0.0.1:7001,输入默认的账号密码root/root,登录成功

    在这里插入图片描述

    四、Dubbo服务注册发现例子

    经典例子:

    4.1、业务场景

    某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址;
    我们现在 需要创建两个服务模块进行测试

    模块功能
    订单服务模块创建订单等
    用户服务模块查询用户地址等
    • 测试预期结果:
      订单服务web模块在A服务器,用户服务模块在B服务器,A可以远程调用B的功能

    4.2、api工程创建

    创建工程:
    建议将服务接口,服务模型,服务异常等均放在 API 包中,因为服务模型及异常也是 API 的一部分,同时,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。

    创建一个API工程,将实体类和接口都放在api工程

    maven新建一个shop-api-common工程:

    用户地址DTO类:

    package com.test.dubbo.bean;
    import java.io.Serializable;
    public class UserAddress implements Serializable {
    	
    	private Integer id;
        private String userAddress; //用户地址
        private String userId; //用户id
        private String consignee; //收货人
        private String phoneNum; //电话号码
        private String isDefault; //是否为默认地址    Y-是     N-否
        
        public UserAddress() {
    		super();
    	}
        
    	public UserAddress(Integer id, String userAddress, String userId, String consignee, String phoneNum,
    			String isDefault) {
    		super();
    		this.id = id;
    		this.userAddress = userAddress;
    		this.userId = userId;
    		this.consignee = consignee;
    		this.phoneNum = phoneNum;
    		this.isDefault = isDefault;
    	}
    	
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getUserAddress() {
    		return userAddress;
    	}
    	public void setUserAddress(String userAddress) {
    		this.userAddress = userAddress;
    	}
    	public String getUserId() {
    		return userId;
    	}
    	public void setUserId(String userId) {
    		this.userId = userId;
    	}
    	public String getConsignee() {
    		return consignee;
    	}
    	public void setConsignee(String consignee) {
    		this.consignee = consignee;
    	}
    	public String getPhoneNum() {
    		return phoneNum;
    	}
    	public void setPhoneNum(String phoneNum) {
    		this.phoneNum = phoneNum;
    	}
    	public String getIsDefault() {
    		return isDefault;
    	}
    	public void setIsDefault(String isDefault) {
    		this.isDefault = isDefault;
    	}
    }
    
    

    用户信息服务接口:

    package com.test.dubbo.service;
    
    import java.util.List;
    
    import com.test.dubbo.bean.UserAddress;
    
    /**
     * 用户服务
     */
    public interface UserService {
    	
    	/**
    	 * 按照用户id返回所有的收货地址
    	 * @param userId
    	 * @return
    	 */
    	public List<UserAddress> getUserAddressList(String userId);
    
    }
    
    

    订单信息服务接口:

    
        package com.test.dubbo.service;
    
    import java.util.List;
    
    import com.test.dubbo.bean.UserAddress;
    
    public interface OrderService {
    	
    	/**
    	 * 初始化订单
    	 * @param userId
    	 */
    	public List<UserAddress> initOrder(String userId);
    
    }
    
    
    

    ok,创建好api工程

    4.3、服务提供者工程

    要实现服务提供,配置文件主要需要配置如下:
    在这里插入图片描述

    Dubbo提供者加载过程(Dubbo容器的启动):
    在这里插入图片描述
    Spring加载xml配置之后暴露服务的过程:
    在这里插入图片描述
    Exporter方法主要是打开socket的监听,接收客户的请求

    ok,理解了上面的理论知识后,继续创建一个user-service-provider工程:

    • maven配置:
    <!-- 引入dubbo -->
    		<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>dubbo</artifactId>
    			<version>2.6.2</version>
    		</dependency>
    		<!-- 注册中心使用的是zookeeper,引入操作zookeeper的客户端端 -->
    		<dependency>
    			<groupId>org.apache.curator</groupId>
    			<artifactId>curator-framework</artifactId>
    			<version>2.12.0</version>
    		</dependency>
    
    • resources加一个提供者的配置文件provider.xml
    
        <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
    		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
    	<!-- 1、指定当前服务/应用的名字(同样的服务名字相同,不要和别的服务同名) -->
    	<dubbo:application name="user-service-provider"></dubbo:application>
    	
    	<!-- 2、指定注册中心的位置 -->
    	<!-- <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry> -->
    	<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
    	
    	<!-- 3、指定通信规则(通信协议 通信端口) -->
    	<dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>
    	
    	<!-- 4、暴露服务   ref:指向服务的真正的实现对象 -->
    	<dubbo:service interface="com.test.dubbo.service.UserService" 
    		ref="userServiceImpl01" timeout="1000" version="1.0.0">
    		<dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method>
    	</dubbo:service>
    
    	<!--统一设置服务提供方的规则  -->
    	<dubbo:provider timeout="1000"></dubbo:provider>
    
    	<!-- 服务的实现 -->
    	<bean id="userServiceImpl01" class="com.test.dubbo.service.impl.UserServiceImpl"></bean>
    
    	<!-- 连接监控中心 -->
    	<dubbo:monitor protocol="registry"></dubbo:monitor>
    	
    </beans>
    
    
    
    • 加个业务实现类:
    package com.test.dubbo.service.impl;
    
    import java.util.Arrays;
    import java.util.List;
    
    import com.test.dubbo.bean.UserAddress;
    import com.test.dubbo.service.UserService;
    
    public class UserServiceImpl implements UserService {
    
    	//@Override
    	public List<UserAddress> getUserAddressList(String userId) {
    		UserAddress address1 = new UserAddress(1, "北京市昌平区", "1", "李老师", "010-56253825", "Y");
    		UserAddress address2 = new UserAddress(2, "深圳市宝安区", "1", "王老师", "010-56253825", "N");
    		return Arrays.asList(address1,address2);
    	}
    
    }
    
    
    • 启动服务提供者,注册到Zookeeper:
      启动服务提供者有两种方法,一种是IOC启动:
    package com.test.dubbo;
    
    import java.io.IOException;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApplication {
    	
    	public static void main(String[] args) throws IOException {
    		ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
    		ioc.start();
    		
    		System.in.read();
    	}
    
    }
    
    

    另外一种是调dubbo的Main类,启动:

    dubbo的main函数:
    com.alibaba.dubbo.container.Main
    com.alibaba.dubbo.container.spring.SpringContainer

    服务注册成功,可以去dubbo-admin看

    在这里插入图片描述
    查看服务接口的详细信息:

    在这里插入图片描述

    4.4、服务消费者工程

    然后服务已经注册了,现在创建一个消费者工程order-service-comsumer

    • maven加上配置
    <!-- 引入dubbo -->
    		<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>dubbo</artifactId>
    			<version>2.6.2</version>
    		</dependency>
    		<!-- 注册中心使用的是zookeeper,引入操作zookeeper的客户端端 -->
    		<dependency>
    			<groupId>org.apache.curator</groupId>
    			<artifactId>curator-framework</artifactId>
    			<version>2.12.0</version>
    		</dependency>
    
    
    • 消费者配置文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    		http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd
    		http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    	<context:component-scan base-package="com.test.dubbo.service.impl"></context:component-scan>
    
    
    	<dubbo:application name="order-service-consumer"></dubbo:application>
    	
    	<dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry>
    	
    	<!--  配置本地存根-->
    	
    	<!--声明需要调用的远程服务的接口;生成远程服务代理  -->
    	<!-- 
    		1)、精确优先 (方法级优先,接口级次之,全局配置再次之)
    		2)、消费者设置优先(如果级别一样,则消费方优先,提供方次之)
    	-->
    	<!-- timeout="0" 默认是1000ms-->
    	<!-- retries="":重试次数,不包含第一次调用,0代表不重试-->
    	<!-- 幂等(设置重试次数)【查询、删除、修改】、非幂等(不能设置重试次数)【新增】 -->
    	<dubbo:reference interface="com.test.dubbo.service.UserService" 
    		id="userService" timeout="5000" retries="3" version="*">
    		<!-- <dubbo:method name="getUserAddressList" timeout="1000"></dubbo:method> -->
    	</dubbo:reference>
    		
    	<!-- 配置当前消费者的统一规则:所有的服务都不检查 -->
    	<dubbo:consumer check="false" timeout="5000"></dubbo:consumer>
    
    	<dubbo:monitor protocol="registry"></dubbo:monitor>
    	<!-- <dubbo:monitor address="127.0.0.1:7070"></dubbo:monitor> -->
    	
    </beans>
    
    
    • 订单服务类:
    package com.test.dubbo.service.impl;
    
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.test.dubbo.bean.UserAddress;
    import com.test.dubbo.service.OrderService;
    import com.test.dubbo.service.UserService;
    
    /**
     * 让服务消费者去注册中心订阅服务提供者的服务地址
     */
    @Service
    public class OrderServiceImpl implements OrderService {
    
    	@Autowired
    	UserService userService;
    	@Override
    	public List<UserAddress> initOrder(String userId) {
    		System.out.println("用户id:"+userId);
    		//查询用户的收货地址
    		List<UserAddress> addressList = userService.getUserAddressList(userId);
    		for (UserAddress userAddress : addressList) {
    			System.out.println(userAddress.getUserAddress());
    		}
    		return addressList;
    	}
    }
    
    • IOC启动
      同样也是可以ioc启动,或者Dubbo提供的Main类启动:
    package com.test.dubbo;
    
    import java.io.IOException;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.test.dubbo.service.OrderService;
    
    public class MainApplication {
    	
    	@SuppressWarnings("resource")
    	public static void main(String[] args) throws IOException {
    		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
    		OrderService orderService = applicationContext.getBean(OrderService.class);
    		orderService.initOrder("1");
    		System.out.println("调用成功....");
    		System.in.read();
    	}
    
    }
    
    

    调用成功,console打印:

    
    用户id:1
    北京市昌平区
    深圳市宝安区
    调用成功....
    

    在这里插入图片描述

    在这里插入图片描述

    展开全文
  • 服务注册中心---服务发现nacos

    万次阅读 2021-07-15 16:05:09
    英文全称Dynamic Naming and Configuration Service,Na为naming/nameServer即注册中心,co为configuration即注册中心,service是指该注册/配置中心都是以服务为核心。服务在nacos是一等公民 二、有了Eureka为啥还要...

    一、什么是nacos

    英文全称Dynamic Naming and Configuration Service,Na为naming/nameServer即注册中心,co为configuration即注册中心,service是指该注册/配置中心都是以服务为核心。服务在nacos是一等公民
    在这里插入图片描述

    二、有了Eureka为啥还要用nacos?两者区别是什么?

    具体可看这篇文章 很形象

    三、下载安装

    可参考里面的下载安装流程 比较简单

    四、nacos原理

    在这里插入图片描述
    Nacos注册中心分为server与client,server采用Java编写,为client提供注册发现服务与配置服务。而client可以用多语言实现,client与微服务嵌套在一起,nacos提供sdk和openApi,如果没有sdk也可以根据openApi手动写服务注册与发现和配置拉取的逻辑
    注册中心原理
    在这里插入图片描述
    配置中心原理
    在这里插入图片描述

    五、nacos使用

    1. 首先配置NameSpace
      在这里插入图片描述
      如图所示,在控制台的 服务管理-命名空间-新建命名空间按钮可以创建新的命名空间,命名空间创建后,会在列表显示命名空间ID,这个ID后面会用在服务的配置文件中
    2. 在服务上配置注册、配置中心
      以springcloud为例,首先用maven导入nacos clinet的依赖:
    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <version>0.2.1.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba.nacos</groupId>
                        <artifactId>nacos-client</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>0.2.1.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <groupId>com.alibaba.nacos</groupId>
                        <artifactId>nacos-client</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    3.先导入springcloud的alibaba-nacos-config和alibaba-nacos-discovery两个依赖,这两个依赖是用于nacos clinet与cloud结合的工具,0.2.x对应springboot 2.x.x ,0.1.x对应springboot 1.x.x。这两个组件可以和各种版本的nacos-client结合。把其中的nacos-clinet依赖给排除,引入想要引入的nacosclinet版本,如下:

      <!-- https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client -->
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
                <version>1.0.1</version>
            </dependency>
    

    4.在bootstrap.properties上添加配置中心的配置

    spring.cloud.nacos.config.server-addr=nacos.e.189.cn:80
    spring.cloud.nacos.config.namespace=命名空间id
    

    5.在application-xxx.properties新增如下配置

    spring.cloud.nacos.discovery.server-addr=nacos.e.189.cn:80
    spring.cloud.nacos.discovery.namespace=命名空间id
    

    扩展:
    在这里插入图片描述
    在这里插入图片描述

    如果springboot启动类没有@EnableDiscover注解则加上
    完成如上更改,即可使用Nacos注册/配置服务

    六、服务间feign调用

    1. 通过配置更改动态刷新参数
      普通application参数在配置中心直接配置皆可,如果需要可以动态刷新的配置,需要在相应类上加上@RefreshScope注解,示例如下,当在nacos配置中心更改配置后,方法getId的值也会刷新
    @RefreshScope
    public class IdEntity {
        @Value("${id}")
        private int id;
        public int getId(){
            return this.id;
        }
    }
    

    配置中心参数修改/设置
    如下两张图:在nacos控制台的配置管理-配置列表中顶部选择相应的命名空间,点击列表右上角的加号新增配置,Data ID 为 项目名-{spring.profiles.active}.properties,Group如果在bootstrap.properties中不指定则填默认的DEFAULT_GROUP,描述写该配置的描述,配置内容填写Properties格式或者Yaml格式
    在这里插入图片描述

    在这里插入图片描述

    七、nacos其他功能介绍与使用

    控制台手动上下线实例
    在控制台的服务管理-服务列表选择一个服务点击详情,在下方的集群列表可以看到有上线/下线按钮,点击即可以对该实例执行上线/下线操作,下线后的实例不会被请求
    在这里插入图片描述
    配置实例权重
    可以通过手动配置权重来控制流量,当一个集群内两个实例,权重越高,到达该实例的请求比例越多
    在这里插入图片描述
    权重的初始值是1
    配置保护阈值
    保护阈值的范围是0~1
    服务的健康比例=服务的健康实例/总实例个数
    当服务健康比例<=保护阈值时候,无论实例健不健康都会返回给调用方
    当服务健康比例>保护阈值的时候,只会返回健康实例给调用方
    在服务管理-服务列表选择一个服务点击详情可以配置
    在这里插入图片描述

    总结

    如果你使用nacos后和Eureka对比 你会发现nacos好像只用修改配置就可以替换Eureka 无缝支持SpringCloud 会直接注册成功 并且各个服务间是正常使用的 虽然只是单独的服务注册发现功能 但是却足够说明nacos天生就无缝衔接SpringCloud生态 当然所有东西有利必有弊

    展开全文
  • 如何理解服务注册和服务发现

    千次阅读 2019-05-06 11:49:28
    服务注册、服务注册表、服务发现 三者的关系是:通过服务注册机制将启动服务的信息上传至服务注册表,服务发现机制通过服务注册表实时获取可用服务的信息。 服务注册的方式包括:自注册和第三方注册。自注册的意思...
  • nacos服务注册流程

    千次阅读 2020-04-26 10:13:07
    nacos的客户端已经搭建好了,那么客户端是怎么将服务注册到注册中心去的呢。 1、 如果对springboot自动配置原理有一定了解的话,那么第三方框架一般都会通过spi的方式来初始化自己包中的bean。比如mybatis与spring...
  • Consul服务注册与服务发现机制

    千次阅读 2019-06-25 15:43:02
    1、什么是服务注册中心? 顾名思义,假设你有一个分布式系统,里面包含了多个服务,部署在不同的机器上,然后这些不同机器上的服务之间要互相调用。 举个现实点的例子吧,比如电商系统里的订单服务需要调用库存...
  • dubbo服务与zookeeper服务注册中心

    千次阅读 热门讨论 2018-04-23 21:37:51
    1.表现层和服务层是如何实现通信的 2.什么是dubbo 3.dubbo的作用 4.dubbo框架  4.1 节点角色说明:  4.2 调用关系说明: 5.dubbo在工程中的配置,即发布服务  5.1 服务的提供者端配置  5.2 服务的消费者端配置...
  • 基于ZooKeeper的服务注册实现

    千次阅读 2017-08-09 19:01:58
    本文介绍了在Linux本地环境部署ZooKeeper伪集群,并基于ZooKeeper实现了服务注册
  • Spring Cloud(二):服务注册与发现Eureka

    万次阅读 2018-06-25 22:50:50
    在SpringCloud 中提供了多种服务注册与发现组件:Eureka,Consul,Zookeeper。官方推荐使用Eureka。 说明:Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery...
  • Nacos服务注册与服务发现

    万次阅读 2019-04-08 15:50:30
    一、服务注册流程分析 (基于Nacos-0.9.0版本分析) Step1:NacosServiceRegistry.register() NacosNamingService.registerInstance() 1. 创建心跳信息 2. 调用注册方法 NamingProxy.registerService(String ...
  • 1.有了解过dubbo的都知道dubbo分为...查阅相关资料之后可以发现dubbo提供的服务注册方式不仅仅xml配置,还有API配置,注解配置,属性配置,其实,细心的你可以发现,xml配置最终也是转化为java代码实现,只是dubbo帮...
  • 首先确定服务注册中心的结构信息:具体如下图所示 首先定义客户端注册接口,定义了一些基本方法; package lin.remoting.framework.register; import java.util.List; import java.util.Map; /** * 消费端...
  • go 使用consul实现服务注册发现

    万次阅读 2020-02-09 16:36:29
    既然是学习使用consul实现服务注册发现,目标自然是实现一个程序,可以通过consul,发现另一个程序。 为此我准备了3个机器: 1.云服务器A(ubuntu):运行consul agent 2.云服务器B(ubuntu):运行一个服务,并...
  • 什么是服务注册、服务发现 两种服务注册方式 两种服务发现方式 常见的第三方注册工具 后记 前言 好一阵子没有更新了,有些小伙伴在后台问我有没有更新,看来大家还是挺喜欢看我的文章的嘛。主要是这段是间忙着复习...
  • Dubbo服务注册与发现

    万次阅读 2019-07-29 16:16:38
    Dubbo通过ZookeeperRegistry类来注册和订阅服务,通过zookeeper事件监听服务变更,一旦服务变更,消费端收到通知,然后主动去zookeeper拉取该服务的提供者子目录,这些提供者子目录记录了注册服务的URL信息。...
  • springcloud Eureka服务注册和发现

    千次阅读 2018-09-02 22:09:25
    1,Eureka基本介绍: ...Eureka Server 作为服务注册功能的服务器,它是服务注册中心。 而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员...
  • 使用Spring Cloud搭建服务注册中心

    万次阅读 多人点赞 2017-09-03 12:08:25
    ,但是小伙伴们应该也看到了,阿里的dubbo无法单独完成工作,我们还要借助于Apache上的开源框架zookeeper(不是必须,但是最佳实践莫过于zookeeper),使用zookeeper作为服务注册中心,才能实现一个较好的分布式应用...
  • Ubuntu 18.04服务注册方法

    千次阅读 2019-01-25 10:15:10
    背景 systemd is now used for user sessions. System sessions had already been provided by systemd in previous Ubuntu releases. Ubuntu-18.04用 systemctl 命令来...比如以前启动mysql服务,命令为:...
  • 服务发现和服务注册

    千次阅读 2018-06-10 10:17:52
    一 硬编码问题1 适用场景有局限:如果服务提供者的网络地址(IP和端口)发生了变化,将会影响服务消费者。例如,用户微服务的网络地址发生了变化,就需要修改电影微服务的配置,并重新发布,这显然不可取。2 无法...
  • nacos实现服务注册与两种消费方式

    千次阅读 2019-05-21 16:17:28
    nacos实现服务注册与两种消费方式运行nacos服务注册实例两种服务消费方式RestTempletFeign测试参考 运行nacos 预备环境:64位操作系统、64位JDK1.8+、Maven 3.2.x+ 启动服务器: Linux:sh startup.sh -m ...
  • zookeeper实现服务注册与发现

    千次阅读 2019-04-30 22:08:42
    为了使服务之间能够互相通信,需要有一个协调系统来管理这些服务,以便这些服务能够互相找到对方,这就是服务注册以发现机制。这个协调系统有时也被称作“注册中心”; 下面,我们将基于zookeeper来实现服务注册...
  • Zookeeper介绍ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、...
  • 服务注册中心

    千次阅读 2018-07-25 21:34:48
    一、服务注册中心介绍 分布式服务框架部署在多台不同的机器上,例如服务提供者在集群A,服务调用者在集群B,那么B在调用A的服务的过程中,集群A的机器需要和集群B的机器进行通信。 抠张图看看  在上图中,有...
  • Spring Cloud入门-Eureka服务注册与发现(Hoxton版本)

    万次阅读 多人点赞 2019-12-27 09:46:24
    文章目录什么是Spring Cloud摘要Eureka简介搭建Eureka注册中心创建父工程springcloud-learning创建Eureka服务端模块使用IDEA的Run Dashboard来运行SpringCloud应用搭建Eureka客户端搭建Eureka注册中心集群搭建两个...
  • consul服务注册常见bug

    千次阅读 2018-12-17 22:02:11
    java的项目使用consul一般来讲都是通过spring-cloud-consul进行使用,spring-cloud帮助我们封装了consu的服务注册,服务发现等操作,但是在使用过程中还是出现了不少问题在这里记录下. serverId重复导致consul注册中心...
  • 现在大家都在讲服务注册与发现,却没有人来明确解释一下这里的“服务”到底指的是什么。这难道不就是另一种的打豆豆吗。 先拿Dubbo说事,因为大家对它都非常熟悉了。我们经常说把XX功能发布成Dubbo服务,供其它用户...
  • consul+docker实现服务注册

    千次阅读 2019-04-08 17:46:51
    注册中心: 每个服务提供者向注册中心登记自己的服务,将服务名与主机Ip,端口等一些附加信息告诉注册中心,注册中心按服务名分类组织服务清单。如A服务运行在192.168.1.82:3000,192.168.1.83:3000实例上。那么...
  • 微服务网关和服务注册中心

    千次阅读 2019-01-29 11:44:34
    在前面谈微服务架构的时候,已经有多篇文章都谈到过微服务网关,由于微服务网关本身也是提供代理,路由,安全,日志,负载均衡,流量控制等能力,因此我谈的最多的就是可以将微服务网关理解为轻量的ESB服务总线,...
  • SpringCould的简介和SpringCould的服务注册及服务调用

    万次阅读 多人点赞 2019-06-20 11:12:21
    【SpringCould学习一】SpringCould的简介和SpringCould的服务注册及服务调用一、SpringCould的简介二、SpringCould的服务注册及服务调用 一、SpringCould的简介 1、什么是SpringCloud Spring Cloud是一系列框架的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,090,950
精华内容 436,380
关键字:

服务注册