• [技术干货] 方志朋-SpringCloud系列:Spring Cloud Alibaba教程:使用Nacos作为服务注册中心
    什么是Nacos?Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。是Spring Cloud A 中的服务注册发现组件,类似于Consul、Eureka,同时它又提供了分布式配置中心的功能,这点和Consul的config类似,支持热加载。Nacos 的关键特性包括:§ 服务发现和服务健康监测§ 动态配置服务,带管理界面,支持丰富的配置维度。§ 动态DNS 服务§ 服务及其元数据管理Nacos下载Nacos依赖于Java环境,所以必须安装Java环境。然后从官网下载Nacos的解压包,安装稳定版的,下载地址:https://github.com/alibaba/nacos/releases本次案例下载的版本为1.0.0 ,下载完成后,解压,在解压后的文件的/bin目录下,windows系统点击startup.cmd就可以启动nacos。linux或mac执行以下命令启动nacos。1.  sh startup.sh -m standalone启动时会在控制台,打印相关的日志。nacos的启动端口为8848,在启动时要保证端口不被占用。珠穆拉马峰的高度是8844,nacos的端口是8848,有点巧合。启动成功,在浏览器**问:http://localhost:8848/nacos,会跳转到登陆界面,默认的登陆用户名为nacos,密码也为nacos。登陆成功后,展示的界面如下:从界面可知,此时没有服务注册到Nacos上。使用Nacos服务注册和发现服务注册和发现是微服务治理的根基,服务注册和发现组件是整个微服务系统的灵魂,选择合适的服务注册和发现组件至关重要,目前主流的服务注册和发现组件有Consul、Eureka、Etcd等。随着Eureka的闭源,Spring cloud netflix-oss组件大规模的进入到了维护期,不再提供新功能,spring cloud alibaba受到开源社区的大力拥护。服务注册在本案例中,使用2个服务注册到Nacos上,分别为nacos-provider和nacos-consumer。构建服务提供者nacos-provider新建一个Spring Boot项目,Spring boot版本为2.1.4.RELEASE,Spring Cloud 版本为Greenwich.RELEASE,在pom文件引入nacos的Spring Cloud起步依赖,代码如下:1.  <dependency>2.              <groupId>org.springframework.cloud</groupId>3.              <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>4.              <version>0.9.0.RELEASE</version>5.  </dependency>在工程的配置文件application.yml做相关的配置,配置如下:1.  server:2.    port:87623.  spring:4.    application:5.      name:nacos-provider6.    cloud:7.      nacos:8.        discovery:9.          server-addr:127.0.0.1:8848在上述的配置的中,程序的启动端口为8762,应用名为nacos-provider,向nacos server注册的地址为127.0.0.1:8848。然后在Spring Boot的启动文件NacosProviderApplication加上@EnableDiscoveryClient注解,代码如下:1.  @SpringBootApplication2.  @EnableDiscoveryClient3.  publicclassNacosProviderApplication{4.    5.      publicstaticvoidmain(String[]args){6.          SpringApplication.run(NacosProviderApplication.class,args);7.      }8.    9.  }构建服务消费者nacos-consuer和nacos-provider一样,构建服务消费者nacos-consumer,nacos-cosumer的启动端口8763。构建过程同nacos-provider,这里省略。验证服务注册个发现分别启动2个工程,待工程启动成功之后,在访问localhost:8848,可以发现nacos-provider和nacos-consumer,均已经向nacos-server注册,如下图所示:服务调用nacos作为服务注册和发现组件时,在进行服务消费,可以选择RestTemplate和Feign等方式。这和使用Eureka和Consul作为服务注册和发现的组件是一样的,没有什么区别。这是因为spring-cloud-starter-alibaba-nacos-discovery依赖实现了Spring Cloud服务注册和发现的相关接口,可以和其他服务注册发现组件无缝切换。提供服务在nacos-provider工程,写一个Controller提供API服务,代码如下:1.  @RestController2.  publicclassProviderController{3.    4.  Loggerlogger=LoggerFactory.getLogger(ProviderController.class);5.    6.  @GetMapping("/hi")7.  publicStringhi(@RequestParam(value ="name",defaultValue ="forezp",required =false)Stringname){8.    9.          return"hi "+name;10.      }11.  }消费服务在这里使用2种方式消费服务,一种是RestTemplate,一种是Feign。使用RestTemplate消费服务RestTemplate可以使用Ribbon作为负载均衡组件,在nacos-consumer工程中引入ribbon的依赖:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-ribbon</artifactId>4.  </dependency>在NacosConsumerApplication启动文件注入RestTemplate的Bean,代码如下:1.      @LoadBalanced2.      @Bean3.      publicRestTemplaterestTemplate(){4.          returnnewRestTemplate();5.      }加上@LoadBalanced注解即可在RestTemplate上开启LoadBalanced负载均衡的功能。写一个消费服务的ConsumerController,代码如下:1.  @RestController2.  publicclassConsumerController{3.    4.      @Autowired5.      RestTemplaterestTemplate;6.    7.   @GetMapping("/hi-resttemplate")8.      publicStringhiResttemplate(){9.          returnrestTemplate.getForObject("http://nacos-provider/hi?name=resttemplate",String.class);10.   11.      }重启工程,在浏览器**问http://localhost:8763/hi-resttemplate,可以在浏览器上展示正确的响应,这时nacos-consumer调用nacos-provider服务成功。是FeignClient调用服务在nacos-consumer的pom文件引入以下的依赖:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.     <artifactId>spring-cloud-starter-openfeign</artifactId>4.  </dependency>在NacosConsumerApplication启动文件上加上@EnableFeignClients注解开启FeignClient的功能。1.  @EnableFeignClients2.  publicclassNacosConsumerApplication{3.    4.      publicstaticvoidmain(String[]args){5.          SpringApplication.run(NacosConsumerApplication.class,args);6.      }写一个FeignClient,调用nacos-provider的服务,代码如下:1.  @FeignClient("nacos-provider")2.  publicinterfaceProviderClient{3.    4.      @GetMapping("/hi")5.      Stringhi(@RequestParam(value ="name",defaultValue ="forezp",required =false)Stringname);6.  }写一个消费API,该API使用ProviderClient来调用nacos-provider的API服务,代码如下:1.  @RestController2.  publicclassConsumerController{3.    4.    5.      @Autowired6.      ProviderClientproviderClient;7.    8.      @GetMapping("/hi-feign")9.      publicStringhiFeign(){10.         returnproviderClient.hi("feign");11.      }12.  }重启工程,在浏览器**问http://localhost:8763/hi-feign,可以在浏览器上展示正确的响应,这时nacos-consumer调用nacos-provider服务成功。总结本文比较详细的介绍了如何使用Nacos作为服务注册中心,并使用案例介绍了如何在使用nacos作为服务注册中心时消费服务。下一篇教程将介绍如何使用nacos作为分布式配置中心。源码下载https://github.com/forezp/SpringCloudLearning/tree/master/springcloud-alibaba/nacos-discovery参考资料https://nacos.io/zh-cn/docs/what-is-nacos.html 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架Spring Cloud 
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Consul 之Greenwich版本全攻略
    什么是ConsulConsul是HashiCorp公司推出的开源软件,使用GO语言编写,提供了分布式系统的服务注册和发现、配置等功能,这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格。Consul不仅具有服务治理的功能,而且使用分布式一致协议RAFT算法实现,有多数据中心的高可用方案,并且很容易和Spring Cloud等微服务框架集成,使用起来非常的简单,具有简单、易用、可插排等特点。使用简而言之,Consul提供了一种完整的服务网格解决方案。Consul具有以下的特点和功能§ 服务发现:Consul的客户端可以向Consul注册服务,例如api服务或者mysql服务,其他客户端可以使用Consul来发现服务的提供者。Consul支持使用DNS或HTTP来注册和发现服务。§ 运行时健康检查:Consul客户端可以提供任意数量的运行状况检查机制,这些检查机制可以是给定服务(“是Web服务器返回200 OK”)或本地节点(“内存利用率低于90%”)相关联。这些信息可以用来监控群集的运行状况,服务发现组件可以使用这些监控信息来路由流量,可以使流量远离不健康的服务。§ KV存储:应用程序可以将Consul的键/值存储用于任何需求,包括动态配置,功能标记,协调,领导者选举等。它采用HTTP API使其易于使用。§ 安全服务通信:Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接。§ 多数据中心:Consul支持多个数据中心。这意味着Consul的用户不必担心构建额外的抽象层以扩展到多个区域。Consul原理每个提供服务的节点都运行了Consul的代理,运行代理不需要服务发现和获取配置的KV键值对,代理只负责监控检查。代理节点可以和一个或者多个Consul server通讯。Consul服务器是存储和复制数据的地方。服务器本身选出了领导者。虽然Consul可以在一台服务器上运行,但建议使用3到5,以避免导致数据丢失的故障情况。建议为每个数据中心使用一组Consul服务器。如果你的组件需要发现服务,可以查询任何Consul Server或任何Consul客户端,Consul客户端会自动将查询转发给Consul Server。需要发现其他服务或节点的基础架构组件可以查询任何Consul服务器或任何Consul代理。代理会自动将查询转发给服务器。每个数据中心都运行Consul服务器集群。发生跨数据中心服务发现或配置请求时,本地Consul服务器会将请求转发到远程数据中心并返回结果。术语§ Agent agent是一直运行在Consul集群中每个成员上的守护进程。通过运行consul agent 来启动。agent可以运行在client或者server模式。指定节点作为client或者server是非常简单的,除非有其他agent实例。所有的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。§ Client 一个Client是一个转发所有RPC到server的代理。这个client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。§ Server 一个server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。§ DataCenter 虽然数据中心的定义是显而易见的,但是有一些细微的细节必须考虑。例如,在EC2中,多个可用区域被认为组成一个数据中心?我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,但是对于我们而言,同一个EC2中的多个可用区域可以被认为是一个数据中心的一部分。§ Consensus 在我们的文档中,我们使用Consensus来表明就leader选举和事务的顺序达成一致。由于这些事务都被应用到有限状态机上,Consensus暗示复制状态机的一致性。§ Gossip Consul建立在Serf的基础之上,它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系,故障检测和事件广播。更多的信息在gossip文档中描述。这足以知道gossip使用基于UDP的随机的点到点通信。§ LAN Gossip 它包含所有位于同一个局域网或者数据中心的所有节点。§ WAN Gossip 它只包含Server。这些server主要分布在不同的数据中心并且通常通过因特网或者广域网通信。§ RPC 远程过程调用。这是一个允许client请求server的请求/响应机制。                  让我们分解这张图并描述每个部分。首先,我们能看到有两个数据中心,标记为“1”和“2”。Consul对多数据中心有一流的支持并且希望这是一个常见的情况。在每个数据中心,client和server是混合的。一般建议有3-5台server。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入达成共识越慢。然而,并不限制client的数量,它们可以很容易的扩展到数千或者数万台。同一个数据中心的所有节点都必须加入gossip协议。这意味着gossip协议包含一个给定数据中心的所有节点。这服务于几个目的:第一,不需要在client上配置server地址。发现都是自动完成的。第二,检测节点故障的工作不是放在server上,而是分布式的。这是的故障检测相比心跳机制有更高的可扩展性。第三:它用来作为一个消息层来通知事件,比如leader选举发生时。每个数据中心的server都是Raft节点集合的一部分。这意味着它们一起工作并选出一个leader,一个有额外工作的server。leader负责处理所有的查询和事务。作为一致性协议的一部分,事务也必须被复制到所有其他的节点。因为这一要求,当一个非leader得server收到一个RPC请求时,它将请求转发给集群leader。server节点也作为WAN gossip Pool的一部分。这个Pool不同于LAN Pool,因为它是为了优化互联网更高的延迟,并且它只包含其他Consul server节点。这个Pool的目的是为了允许数据中心能够以low-touch的方式发现彼此。这使得一个新的数据中心可以很容易的加入现存的WAN gossip。因为server都运行在这个pool中,它也支持跨数据中心请求。当一个server收到来自另一个数据中心的请求时,它随即转发给正确数据中想一个server。该server再转发给本地leader。这使得数据中心之间只有一个很低的耦合,但是由于故障检测,连接缓存和复用,跨数据中心的请求都是相对快速和可靠的。Consul 服务注册发现流程Consul在业界最广泛的用途就是作为服务注册中心,同Eureka类型,consul作为服务注册中心,它的注册和发现过程如下图:在上面的流程图上有三个角色,分别为服务注册中心、服务提供者、服务消费者。§ 服务提供者Provider启动的时候,会向Consul发送一个请求,将自己的host、ip、应用名、健康检查等元数据信息发送给Consul§ Consul 接收到Provider 的注册后,定期向Provider 发送健康检查的请求,检验Provider是否健康§ 服务消费者Consumer会从注册中心Consul中获取服务注册列表,当服务消费者消费服务时,根据应用名从服务注册列表获取到具体服务的实例(1个或者多个),从而完成服务的调用。Consul VS EurekaEureka是一种服务发现工具。该体系结构主要是客户端/服务器,每个数据中心有一组Eureka服务器,通常每个可用区域一个。通常,Eureka的客户使用嵌入式SDK来注册和发现服务。对于非本地集成的客户端,使用Ribbon等边车通过Eureka透明地发现服务。Eureka使用尽力而为的复制提供弱一致的服务视图。当客户端向服务器注册时,该服务器将尝试复制到其他服务器但不提供保证。服务注册的生存时间很短(TTL),要求客户端对服务器进行心跳检测。不健康的服务或节点将停止心跳,导致它们超时并从注册表中删除。发现请求可以路由到任何服务,由于尽力复制,这些服务可以提供过时或丢失的数据。这种简化的模型允许轻松的集群管理和高可扩展性。Consul提供了一系列超级功能,包括更丰富的运行状况检查,键/值存储和多数据中心感知。Consul需要每个数据中心中的一组服务器,以及每个客户端上的代理,类似于使用像Ribbon这样的边车。Consul代理允许大多数应用程序不知道Consul,通过配置文件执行服务注册以及通过DNS或负载平衡器sidecars进行发现。Consul提供强大的一致性保证,因为服务器使用Raft协议复制状态。Consul支持丰富的运行状况检查,包括TCP,HTTP,Nagios / Sensu兼容脚本或基于的Eureka的TTL。客户端节点参与基于gossip的健康检查,该检查分发健康检查的工作,而不像集中式心跳,这成为可扩展性挑战。发现请求被路由到当选的Consul领导者,这使他们默认情况下非常一致。允许过时读取的客户端允许任何服务器处理其请求,从而允许像Eureka一样的线性可伸缩性。Consul的强烈一致性意味着它可以用作领导者选举和集群协调的锁定服务。Eureka不提供类似的保证,并且通常需要为需要执行协调或具有更强一致性需求的服务运行ZooKeeper。Consul提供了支持面向服务的体系结构所需的功能工具包。这包括服务发现,还包括丰富的运行状况检查,锁定,键/值,多数据中心联合,事件系统和ACL。Consul和consul-template和envconsul等工具生态系统都试图最大限度地减少集成所需的应用程序更改,以避免需要通过SDK进行本机集成。Eureka是更大的Netflix OSS套件的一部分,该套件期望应用程序相对同质且紧密集成。因此,Eureka只解决了有限的一部分问题,期望其他工具如ZooKeeper可以同时使用。Eureka Server端采用的是P2P的复制模式,但是它不保证复制操作一定能成功,因此它提供的是一个最终一致性的服务实例视图;Client端在Server端的注册信息有一个带期限的租约,一旦Server端在指定期间没有收到Client端发送的心跳,则Server端会认定为Client端注册的服务是不健康的,定时任务将会将其从注册表中删除。Consul与Eureka不同,Consul采用Raft算法,可以提供强一致性的保证,Consul的agent相当于Netflix Ribbon + Netflix Eureka Client,而且对应用来说相对透明,同时相对于Eureka这种集中式的心跳检测机制,Consul的agent可以参与到基于goosip协议的健康检查,分散了server端的心跳检测压力。除此之外,Consul为多数据中心提供了开箱即用的原生支持等。Consul下载和安装Consul采用Go语言编写,支持Linux、Mac、Windows等各大操作系统,本文使用windows操作系统,下载地址:https://www.consul.io/downloads.html,下完成后解压到计算机目录下,解压成功后,只有一个可执行的consul.exe可执行文件。打开cmd终端,切换到目录,执行以下命令:1.  consul --version终端显示如下:1.  Consulv1.4.22.  Protocol2spoken bydefault, understands 2to 3(agent will automatically usep3.  rotocol >2whenspeaking to compatible agents)证明consul下载成功了,并可执行。consul的一些常见的执行命令如下:命令解释示例agent运行一个consul agentconsul agent -devjoin将agent加入到consul集群consul join IPmembers列出consul cluster集群中的membersconsul membersleave将节点移除所在集群consul leave更多命令请查看官方网站:https://www.consul.io/docs/commands/index.html开发模式启动:1.  consul agent -dev 启动成功,在浏览器**问:http://localhost:8500,显示的界面如下:spring cloud consul该项目通过自动配置并绑定到Spring环境和其他Spring编程模型成语,为Spring Boot应用程序提供Consul集成。通过几个简单的注释,您可以快速启用和配置应用程序中的常见模式,并使用基于Consul的组件构建大型分布式系统。提供的模式包括服务发现,控制总线和配置。智能路由(Zuul)和客户端负载平衡(Ribbon),断路器(Hystrix)通过与Spring Cloud Netflix的集成提供。使用spring cloud consul来服务注册与发现本小节以案例的形式来讲解如何使用Spring Cloud Consul来进行服务注册和发现的,并且使用Feign来消费服务。再讲解之前,已经启动consul的agent,并且在浏览器上http://localhost:8500能够显示正确的页面。本案例一共有2个工程,分别如下:工程名端口描述consul-provider8763服务提供者consul-consumer8765服务消费者其中,服务提供者和服务消费者分别向consul注册,注册完成后,服务消费者通过FeignClient来消费服务提供者的服务。服务提供者consul-provider创建一个工程consul-provider,在工程的pom文件引入以下依赖,包括consul-discovery的起步依赖,该依赖是spring cloud consul用来向consul 注册和发现服务的依赖,采用REST API的方式进行通讯。另外加上web的起步依赖,用于对外提供REST API。代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-consul-discovery</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>org.springframework.boot</groupId>7.      <artifactId>spring-boot-starter-web</artifactId>8.  </dependency>在工程的配置文件application.yml做下以下配置:1.  server:2.    port: 87633.  spring:4.    application:5.      name: consul-provider6.    cloud:7.      consul:8.        host: localhost9.        port: 850010.        discovery:11.          serviceName: consul-provider上面的配置,指定了程序的启动端口为8763,应用名为consul-provider,consul注册中心的地址为localhost:8500在程序员的启动类ConsulProviderApplication加上@EnableDiscoveryClient注解,开启服务发现的功能。1.  @SpringBootApplication2.  @EnableDiscoveryClient3.  publicclassConsulProviderApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConsulProviderApplication.class, args);7.      }8.    9.  }写一个RESTAPI,该API为一个GET请求,返回当前程序的启动端口,代码如下。1.  @RestController2.  publicclassHiController{3.    4.      @Value("${server.port}")5.      Stringport;6.      @GetMapping("/hi")7.      publicStringhome(@RequestParamStringname) {8.          return"hi "+name+",i am from port:"+port;9.      }10.   11.  }启动工程,在浏览器**问http://localhost:8500,页面显示如下:从上图可知,consul-provider服务已经成功注册到consul上面去了。服务消费者consul-provider服务消费者的搭建过程同服务提供者,在pom文件中引入的依赖同服务提供者,在配置文件application.yml配置同服务提供者,不同的点在端口为8765,服务名为consul-consumer。写一个FeignClient,该FeignClient调用consul-provider的REST API,代码如下:1.  @FeignClient(value = "consul-provider")2.  publicinterfaceEurekaClientFeign{3.    4.    5.      @GetMapping(value = "/hi")6.      StringsayHiFromClientEureka(@RequestParam(value = "name") Stringname);7.  }Service层代码如下:1.  @Service2.  publicclassHiService{3.    4.      @Autowired5.      EurekaClientFeigneurekaClientFeign;6.    7.    8.      publicStringsayHi(Stringname){9.          return eurekaClientFeign.sayHiFromClientEureka(name);10.      }11.  }对外提供一个REST API,该API调用了consul-provider的服务,代码如下:1.  @RestController2.  publicclassHiController{3.      @Autowired4.      HiServicehiService;5.    6.      @GetMapping("/hi")7.      publicStringsayHi(@RequestParam( defaultValue = "forezp",required = false)Stringname){8.          returnhiService.sayHi(name);9.      }10.  }在浏览器**问http://localhost:8765/hi,浏览器响应如下:hi forezp,i am from port:8763这说明consul-consumer已经成功调用了consul-provider的服务。这说明consul-provider的服务已经注册到了consul的注册中心上面去了。consul-consumer能够获取注册中心的注册列表来获来消费服务。使用Spring Cloud Consul Config来做服务配置中心Consul不仅能用来服务注册和发现,Consul而且支持Key/Value键值对的存储,可以用来做配置中心。Spring Cloud 提供了Spring Cloud Consul Config依赖去和Consul相集成,用来做配置中心。现在以案例的形式来讲解如何使用Consul作为配置中心,本案例在上一个案例的consul-provider基础上进行改造。首先在工程的pom文件加上consul-config的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-consul-config</artifactId>4.  </dependency>然后在配置文件application.yml加上以下的以下的配置,配置如下:1.  spring:2.    profiles:3.      active: dev 上面的配置指定了SpringBoot启动时的读取的profiles为dev。然后再工程的启动配置文件bootstrap.yml文件中配置以下的配置:1.  spring:2.    application:3.      name: consul-provider4.    cloud:5.      consul:6.        host: localhost7.        port: 85008.        discovery:9.          serviceName: consul-provider10.        config:11.          enabled: true12.          format: yaml           13.          prefix: config     14.          profile-separator: ':'    15.          data-key: data           关于spring.cloud.consul.config的配置项描述如下:§ enabled 设置config是否启用,默认为true§ format 设置配置的值的格式,可以yaml和properties§ prefix 设置配的基本目录,比如config§ defaultContext 设置默认的配置,被所有的应用读取,本例子没用的§ profileSeparator profiles配置分隔符,默认为‘,’§ date-key为应用配置的key名字,值为整个应用配置的字符串。网页**问consul的KV存储的管理界面,即http://localhost:8500/ui/dc1/kv,创建一条记录,key值为:config/consul-provider:dev/data value值如下:1.  foo:2.    bar: bar13.  server:4.    port: 8081在consul-provider工程新建一个API,该API返回从consul 配置中心读取foo.bar的值,代码如下:1.  @RestController2.  publicclassFooBarController{3.    4.      @Value("${foo.bar}")5.      StringfooBar;6.    7.      @GetMapping("/foo")8.      publicStringgetFooBar() {9.          returnfooBar;10.      }11.  }启动工程,可以看到程序的启动端口为8081,即是consul的配置中心配置的server.port端口。工程启动完成后,在浏览器**问http://localhost:8081/foo,页面显示bar1。由此可知,应用consul-provider已经成功从consul的配置中心读取了配置foo.bar的配置。动态刷新配置当使用spring cloud config作为配置中心的时候,可以使用spring cloud config bus支持动态刷新配置。Spring Cloud Comsul Config默认就支持动态刷新,只需要在需要动态刷新的类上加上@RefreshScope注解即可,修改代码如下:1.  @RestController2.  @RefreshScope3.  publicclassFooBarController{4.    5.      @Value("${foo.bar}")6.      StringfooBar;7.    8.      @GetMapping("/foo")9.      publicStringgetFooBar() {10.          returnfooBar;11.      }12.  }启动consul-provider工程,在浏览器**问http://localhost:8081/foo,页面显示bar1。然后在网页**问consul的KV存储的管理界面,即http://localhost:8500/ui/dc1/kv,修改config/consul-provider:dev/data的值,修改后的值如下:1.  foo:2.    bar: bar23.  server: 4.    port: 8081此时不重新启动consul-provider,在浏览器**问http://localhost:8081/foo,页面显示bar2。可见foo.bar的最新配置在应用不重启的情况下已经生效。注意事项§ consul支持的KV存储的Value值不能超过512KB§ Consul的dev模式,所有数据都存储在内存中,重启Consul的时候会导致所有数据丢失,在正式的环境中,Consul的数据会持久化,数据不会丢失。参考资料https://www.consul.io/intro/index.htmlhttps://www.consul.io/docs/internals/architecture.htmlhttps://www.consul.io/intro/vs/eureka.htmlhttp://www.ityouknow.com/springcloud/2018/07/20/spring-cloud-consul.htmlhttps://springcloud.cc/spring-cloud-consul.htmlhttps://www.cnblogs.com/lsf90/p/6021465.htmlhttps://blog.csdn.net/longgeqiaojie304/article/details/85227936 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud  
  • [行业前沿] 配置中心是什么,是Spring Cloud Config么?能力有什么差别?
    RT
  • [行业前沿] 请问一下ServiceComb和SpringCloud相比优势有哪些?
    可否比较一下ServiceComb与Spring Cloud,甚至dubbo,方便选型参考?
  • [技术干货] 非侵入ServiceMesh和侵入式chassis模式(如Spring Cloud和ServiceComb),谁会一统微服务架构江湖
    【微服务Lean Coffee系列一】ServiceMesh技术2018年异常火爆,Istio推出了1.0版本,CSE Mesher已在一线企业商用,一部分技术公司也正在自研ServiceMesh技术。侵入式的微服务框架依然占据着大部分企业的技术选型list,虽然侵入式框架和业务有较深入的结合,但它目前在性能以及契合业务方面都表现得优秀很多。如果您要落地微服务方案,您会选择哪种方案?为什么?
  • [介绍/入门] [每天学习微服务-网关] ServiceComb+SpringCloud Zuul
    在微服务架构模式中后端服务的实例数一般是动态的,于客户端而言很难发现动态改变的服务实例的访问地址信息,服务网关能对用户提供统一的入口。 ServiceComb Java-Chassis 内置了网关服务EdgeService,开发者可以非常简单的搭建一个EdgeService服务。具体可参考:https://docs.servicecomb.io/java-chassis/zh_CN/edge/by-servicecomb-sdk.html 本文将介绍ServiceComb与SpringCloud的Zuul网关组件协同工作,以构建微服务应用。ServiceComb在自身的处理链HandlerTrain中已完成Zuul的对接,用户用极简单的方法配置后即可使微服务应用具备网关服务的能力。为使读者更好地理解,本文将编写一个简单的Hello微服务,并启动2个实例来进行演示。Hello微服务提供hello/{name}接口,只需从前端输入参数name就可从后端微服务获取到程序员百看不厌的Hello world结果。微服务模式下的Hello应用模型技术准备ServiceComb 作为后端微服务核心框架ServiceCenter 作为服务发现与注册中心SpringCloud Zuul 组件做服务网关环境准备以下环境为Windows 64位系统●安装git,详情可参考git安装教程https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git●安装JDK 1.8,详情可参考JDK安装教程。https://docs.oracle.com/javase/8/docs/technotes/guides/install/install_overview.html●安装Maven 3.x,详情可参考Maven安装教程https://maven.apache.org/install.htmlServiceCenter安装下载地址:http://mirrors.hust.edu.cn/apache/servicecomb/servicecomb-service-center/1.1.0/下载后解压如下▼在该目录下双击service-center.exe即可启动,命令窗口中出现如下信息基本代表ServiceCenter启动成功,从这个信息也可以得知ServiceCenter监听的是30100端口,等下配置文件要用到。问题点:有可能会有如下信息,这个一般是端口被占用,很可能你打开了两个ServiceCenter,都关闭后再打开就可以了。↓↓↓示例一、后端微服务 HelloService01添加依赖新建maven项目HelloService,pom文件如下02配置新建ServiceComb配置文件src/main/resources/microservice.yaml,内容如下▼03项目入口新建启动类HelloApplication.java,内容如下▼新建Controller类HelloController.java (这里我习惯SpringMvc的叫法,重点看注解)04启动到此,Hello微服务就写完了。这里要启动2个实例。1.先打包,执行mvn clean package2.在项目根目录下target目录下将lib目录和生成的jar包复制到另一个目录中 3.复制jar包,修改其中一个jar包微服务启动端口号为8888(通过WinRar解压缩软件打开jar包并打开microservice.yaml文件修改里面的rest端口号) 4.在当前目录打开两个cmd命令窗口,分别执行命令java -jar HelloService-7777.jar和java -jar HelloService-8888.jar 。此时已经启动了2个微服务实例。二、编写Zuul网关服务01 添加依赖新建maven项目 zuulserver,pom文件如下02配置文件新建springboot配置文件src/main/resources/application.yaml,内容如下新建ServiceComb配置文件src/main/resources/microservice.yaml,内容如下03项目入口新建启动类 ZuulApplication.java新建静态文件 src/main/resources/static/index.html,内容如下 (static目录是按springboot项目规范,属于应用静态文件根目录)04启动到此,网关服务器写完,如下在IDEA里面直接启动应用三. 演示效果浏览器访问http://localhost:8080/ ,如下图。 在输入框中输入姓名,就可以在下面看到打招呼的信息连续点击几次打招呼按钮,可以在启动的2个Hello微服务实例的控制台中看到被调用的信息,如下图(由于这里使用的ServiceComb默认的负载均衡策略 轮询,可见到两个实例都均被调用,关于负载均衡,我们将在后续的文章中解读)。此时用户并不需要关心具体哪个实例被调用了,访问的是哪个后端的实例地址,它只要访问网关就可以了:)总结从以上的示例可以看出,通过 ServiceComb 结合SpringCloud Zuul 实现服务网关功能只需一些简单的配置。后续可以在网关服务上实现统一的鉴权,日志记录,和自定义过滤器等。参考[1] SpringCloud Zuulhttps://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html  [2] ServiceCombhttp://servicecomb.apache.org/cn/docs/quick-start/    
  • [行业前沿] [学习微服务-第2天] ServiceComb + SpringCloud Zuul源码解读
    上一篇文章我们介绍了ServiceComb与SpringCloud的Zuul网关组件协同工作,以构建微服务应用。为了给ServiceComb做贡献的伙伴提供指引,本篇将介绍ServiceComb与SpringCloud Zuul的集成源码。ServiceComb 对接 Spring Cloud Zuul 思路ServiceComb没有修改SpringCloud Zuul的源代码,而是利用了 SpringCloud 提供的可扩展的接口。Spring Cloud Zuul官网有如下两段描述▼▼▼•Zuul starter不包括服务发现客户端, 所以为了实现基于service ID的路由转发,你必须同时在类路径下提供一个服务发现客户端 ( 可以使用 Eureka )•DiscoveryClientRouteLocator 过滤器从一个DiscoveryClient(例如Eureka)和属性文件中加载了路由定义信息。详情参考:https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html从以上的描述看,SpringCloud Zuul允许我们自定义服务发现客户端来实现自己的服务发现逻辑。其中DiscoveryClient接口是Spring Cloud Commons提供的与服务治理相关的抽象接口,Spring Cloud Commons做了一层抽象,很好的解耦了服务治理体系,使得我们可以轻易的替换不同的服务治理设施。在我们的上篇文章[每天5分钟学习微服务-网关]ServiceComb+SpringCloud Zuul中实现的zuulserver项目中,pom文件中有如下依赖↓↓↓以上就是一个自定义discovery client。这个discovery client是专门与ServiceComb的服务与发现注册中心ServiceCenter进行交互的。如下图所示,客户端和各个微服务都与Zuul网关直接通信,而Zuul网关通过ServiceComb Discovery与ServiceCenter获取服务的实例信息(真实IP地址和端口等)ServiceComb Discovery源码分析目录结构源码从github上下载↓↓↓https://github.com/apache/servicecomb-java-chassis/tree/master/java-chassis-spring-boot/spring-boot-starter/spring-boot-starter-discovery   很明显这是一个自定义的SpringBoot的starter项目。关于SpringBoot自定义starter可以参考: Creating your own starter(https://docs.spring.io/spring-boot/docs/1.5.12.RELEASE/reference/htmlsingle/#boot-features-custom-starter)springboot的starter项目一般是做自动配置(auto-configure)。那么以下按照starter项目的思路来分析。1. 自动配置入口org.apache.servicecomb.springboot.starter.discovery包下面的ScbDiscoveryClientConfiguration类中和ScbRibbonConfiguration类中找到了AutoConfigureBefore和AutoConfigureAfter注解AutoConfigureBefore:类级别的注解,在指定类初始化配置之前自动执行当前配置类AutoConfigureAfter:类级别的注解,在指定类初始化配置之后自动执行当前配置类tips:查看spring.factories文件是否有org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置或者包下面的类是否有@AutoConfigureBefore,@AutoConfigureAfter注解2. ScbDiscoveryClientConfiguration类这是一个Spring自动配置类,在这个类里只实例化了DiscoveryClient对象这个配置类只实例化了一个DiscoveryClient对象。重点来了,这个DiscoveryClient对象就是给Zuul使用的!!! 最终会被Zuul的 DiscoveryClientRouteLocator 过滤器 用来加载路由定义信息。3. ScbRibbonConfiguration类这是个Spring自动配置类,这个类是为了导入配置类RibbonAutoConfiguration.class代码如上,没有任何实现,注意看注解@RibbonClients ,指定了ScbRibbonClientConfiguration类来配置RibbonClient。下面看这个类。4. ScbRibbonClientConfiguration类这个类是Spring配置类,实例化了Ribbon相关的BeanServerList是Ribbon框架的东西(Ribbon是客户端负载均衡框架)。ServerList是获取服务列表的接口ServiceCombServerList类继承于抽象类AbstractServerList,而AbstractServerList实现了ServerList接口接着看下ServiceCombServerList做了什么事情。5. ServiceCombServerList 类这个类是给Ribbon使用,负责获取服务实例信息(真实IP地址和端口等)。重点在下面这个方法,这个方法使用DiscoveryTree对象真正获取服务实例。最终返回的是可用微服务实例的真实ip地址和端口。DiscoveryTree是ServiceComb的service-registry包的,这个包是负责服务注册的。DiscoveryTree的逻辑比较复杂,可以通过下面的处理流程了解其处理过程。参考官方文档 ↓↓↓https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.html感兴趣的同学可以研究下ServiceComb的service-registry包的实现,这里不展开分析。DiscoveryTree最终会调用到ServiceRegistryClientImpl.findServiceInstances方法▼▼▼ServiceRegistryClientImpl.findServiceInstances在这个方法内直接调用ServiceCenter的rest接口Const.REGISTRY_API.MICROSERVICE_INSTANCES来获取相应的微服务实例信息(http://127.0.0.1:30100/v4/default/registry/instances)文/末/小/结本文向社区读者从源码角度阐述了ServiceComb是如何支持SpringCloud Zuul的。单纯使用的用户实际上不必关心这些细节:)当然,我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb内置的EdgeService网关能力。如果在阅读ServiceComb对Zuul相关支持代码时有任何疑问想交流,欢迎扫码加入进微信群。
  • [行业前沿] [学习微服务-第6天] 负载均衡之ServiceComb + SpringCloud Ribbon
    在微服务架构中,客户端负载均衡是指负载均衡器作为客户端软件的一部分,客户端得到可用的服务实例列表然后按照特定的负载均衡策略,分发请求到不同的服务。ServiceComb内置了客户端负载均衡组件,开发者可以非常简单的使用。具体可参考:https://docs.servicecomb.io/java-chassis/zh_CN/references-handlers/loadbalance.html 本文将介绍ServiceComb与SpringCloud的Ribbon负载均衡组件协同工作,以构建微服务应用。ServiceComb已适配对应的接口和配置,用户用极简单的方法配置后即可使微服务应用具备负载均衡的能力。示例以下通过一个服务提供者provider-service和消费者consumer-service作为demo演示。provider-service会启动3个微服务实例,消费者端consumer-service使用Ribbon负载均衡调用proveder-service服务的接口。其中consumer-service在调用provider-service提供的接口时会打印出真实调用的URL ↓↓↓完整示例地址:https://github.com/lisenwork/servicecomb-demo/tree/master/servicecomb-ribbon 预置条件:  示例应先安装启动服务与注册中心ServiceCenter,详细步骤请参考官网↓↓↓http://servicecomb.apache.org/cn/users/setup-environment/#%E8%BF%90%E8%A1%8Cservice-center 一开发服务消费者comsumer-service只需三步即可开发拥有负载均衡能力的微服务步骤如下:01添加依赖新建pom文件,引入如下依赖。完整pom文件内容请参考↓↓↓https://github.com/lisenwork/servicecomb-demo/blob/master/servicecomb-ribbon/consumer-service/pom.xml     02配置 在resources目录下新建ServiceComb配置文件microservice.yaml。配置微服务信息↓↓↓03项目入口新建启动类ConsumerApplication.java。如下图,启动类里同时实例化一个RestTemplate对象。该对象用于后面的服务间接口调用。新建ConsumerController.java。在该类的consumer方法里使用Ribbon的API动态获取服务实例,并打印出被选中的实例的真实IP地址和端口。最后调用服务实例的接口,获取结果并返回。04启动项目根目录下执行命令 mvn spring-boot:run二开发服务提供者provider-service01添加依赖新建pom文件,引入如下依赖。完整pom文件内容请参考↓↓↓https://github.com/lisenwork/servicecomb-demo/blob/master/servicecomb-ribbon/provider-service/pom.xml 02配置 在src/main/resources目录下新建microservice.yaml03项目入口新建启动类ProviderApplication.java新建ProviderController.java。只向外提供/provider接口04启动 服务提供者要启动3个微服务实例。打开microservice.yaml文件,分别修改微服务监听端口为8888,8889,8890,在项目根目录下执行3次命令 mvn spring-boot:run演示浏览器访问http://localhost:7777/consumer,重复刷新一定次数,观察控制台,会发现服务消费者会轮询调用服务提供者的三个实例。小结本文向社区读者从读者角度阐述了ServiceComb是如何支持SpringCloud Ribbon的。我们也非常欢迎爱好者们向社区提问和贡献代码。下章我们将介绍ServiceComb+SpringCloud Ribbon源码篇。如果在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读[学习微服务-第5天]ServiceComb+Zipkin源码解读[学习微服务-第4天]ServiceComb+Zipkin[学习微服务-第3天] ServiceComb内置高性能网关服务[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul了解更多信息请访问官方网站http://servicecomb.apache.org/ Github代码仓库https://github.com/apache?q=ServiceComb
  • [行业前沿] [学习微服务-第7天] ServiceComb+SpringCloud Ribbon源码解读
    在上一篇 《ServiceComb + SpringCloud Ribbon使用篇》中介绍了负载均衡的概念和ServiceComb协同SpringCloud Ribbon的使用, 本篇将从源码角度介绍ServiceComb是如何实现与SpringCloud Ribbon协同工作的。一. ServiceComb对接 Spring Cloud Ribbon思路在Ribbon的wiki介绍页(https://github.com/Netflix/ribbon/wiki/Working-with-load-balancers)可以发现这样的描述:ServerList - this can be static or dynamic. If it is dynamic (as used by DynamicServerListLoadBalancer), a background thread will refresh and filter the list at certain interval这段介绍了ServerList接口,该接口既可以是静态获取服务实例列表也可以是动态获取的。如果是动态获取服务列表(被DynamicServerListLoadBalancer使用),会有一个后台线程在特定得时间间隔负责刷新和过滤服务列表。也就是说,我们只要实现了ServerList接口,加上相应的配置让Ribbon获取到,就能向Ribbon提供ServiceComb自己的服务发现逻辑。如下图↓↓↓ServiceComb 在如下的org.apache.servicecomb:spring-boot-starter-discovery项目中实现了ServerList接口和相应的配置。<dependency>   <groupId>org.apache.servicecomb</groupId>   <artifactId>spring-boot-starter-discovery</artifactId>   <version>1.1.0</version></dependency>二. 源码分析项目结构如下图,红色方框内为接入SpringCloud Ribbon组件的相关类。下面我们分别来看看这几个类↓↓↓ScbRibbonConfigurationConfiguration 表示这是一个spring的配置类EnableConfigurationProperties 使@ConfigurationProperties注解生效ConditionalOnBean 只有特定名称或者类型的Bean存在于BeanFactory时才创建某个BeanAutoConfigureAfter 只有在指定类的配置类配置完后才会生效RibbonClients 允许在一个类中声明多个RibbonClient注解注意Ribbon是懒加载的,而该类在RibbonAutoConfiguration初始化配置之后才会执行配置,所以该类也是懒加载ScbRibbonClientConfiguration在ScbRibbonConfiguration类中的RibbonClients注解指定了ScbRibbonClientConfiguration来实例化RibbonClient。 如下,该类实例化了一个ServerList对象,实际类型为ServiceCombServerList,该对象会替换DynamicServerListLoadBalancer类里的ServerList对象。ServiceCombServerList在Ribbon体系中,ServerList接口负责获取服务实例列表。ServiceComb使用ServiceCombServerList实现了该接口。该类使用了ServiceComb内置的服务发现能力。ServiceCombServerList构造器里使用discoveryTree添加了一个过滤器ScbRibbonEndpointDiscoveryFilter。•DiscoveryTree是ServiceComb Registry包的类。ServiceComb Registry包提供了服务注册,服务发现与过滤器等能力。•ScbRibbonEndpointDiscoveryFilter继承了AbstractEndpointDiscoveryFilter,而AbstractEndpointDiscoveryFilter实现了DiscoveryFilter。DiscoveryFilter接口主要管理实例进行分组、缓存getInitialListOfServers方法获取初始的servers;getUpdatedListOfServers方法获取更新的serversScbRibbonEndpointDiscoveryFilterScbRibbonEndpointDiscoveryFilter继承于AbstractEndpointDiscoveryFilter类,观察AbstractEndpointDiscoveryFilter代码可发现有一个discovery方法,这个方法会被DiscoveryTree使用以获取服务列表。此时已进入ServiceComb Registry包内部,具体的细节不展开分析。关于filter类,实际上查看DiscoveryTree的源码可发现一些信息,如下是DiscoveryTree的doDiscovery方法,该方法属于ServiceCombServerList获取服务实例列表的调用链上,而该方法会将这个获取信息的任务交给DiscoveryFilter类去处理。小结本文向社区读者从源码角度阐述了ServiceComb是如何与SpringCloud Ribbon协同工作的。 [单纯使用的用户实际上不必关心这些细节]  非常欢迎爱好者们向社区提问和贡献代码:)下篇将介绍ServiceComb内置的负载均衡的能力,内置的能力可支持定制化重试策略。如在阅读代码时有任何疑问想交流,欢迎扫码加入进微信群。期待志同道合的朋友们加入ServiceComb的大门为你们敞开~用心做开源,不忘初衷前期阅读 [学习微服务-第6天] 负载均衡之ServiceComb + SpringCloud Ribbon[学习微服务-第5天]ServiceComb+Zipkin源码解读[学习微服务-第4天]ServiceComb+Zipkin[学习微服务-第3天] ServiceComb内置高性能网关服务[每天学习微服务-源码解读] ServiceComb+SpringCloud Zuul[每天学习微服务-网关]ServiceComb+SpringCloud Zuul-----------------------------------------------了解更多信息请访问: 官方网站http://servicecomb.apache.org/ Github代码仓库https://github.com/apache?q=ServiceComb
  • 求助 springcloud介入cse注册不上
    2019-03-22 15:25:04.396 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [The timeout period of 9000ms has been exceeded while executing GET /v3/default/configuration/items?dimensionsInfo=gateway-server%40spring-cloud-application%231.0.0&revision=default for host cse.cn-north-1.myhuaweicloud.com].2019-03-22 15:25:15.163 ERROR: [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.RestUtils[93] - GET /v4/default/registry/existence?appId=spring-cloud-application&type=microservice&serviceName=gateway-server&env&version=1.0.0 fail, endpoint is cse.cn-north-1.myhuaweicloud.com:443, message: Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:4432019-03-22 15:25:15.164 WARN : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl[105] - invoke service [/v4/default/registry/existence] failed, retry.2019-03-22 15:25:15.165 INFO : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.IpPortManager[100] - Change service center address from cse.cn-north-1.myhuaweicloud.com:443 to cse.cn-north-1.myhuaweicloud.com:4432019-03-22 15:25:16.440 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:443].2019-03-22 15:25:28.593 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [The timeout period of 9000ms has been exceeded while executing GET /v3/default/configuration/items?dimensionsInfo=gateway-server%40spring-cloud-application%231.0.0&revision=default for host cse.cn-north-1.myhuaweicloud.com].2019-03-22 15:25:36.234 ERROR: [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.RestUtils[93] - GET /v4/default/registry/existence?appId=spring-cloud-application&type=microservice&serviceName=gateway-server&env&version=1.0.0 fail, endpoint is cse.cn-north-1.myhuaweicloud.com:443, message: Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:4432019-03-22 15:25:36.235 WARN : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl[105] - invoke service [/v4/default/registry/existence] failed, retry.2019-03-22 15:25:36.236 INFO : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.IpPortManager[100] - Change service center address from cse.cn-north-1.myhuaweicloud.com:443 to cse.cn-north-1.myhuaweicloud.com:4432019-03-22 15:25:40.648 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:443].2019-03-22 15:25:52.813 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [The timeout period of 9000ms has been exceeded while executing GET /v3/default/configuration/items?dimensionsInfo=gateway-server%40spring-cloud-application%231.0.0&revision=default for host cse.cn-north-1.myhuaweicloud.com].2019-03-22 15:25:57.325 ERROR: [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.RestUtils[93] - GET /v4/default/registry/existence?appId=spring-cloud-application&type=microservice&serviceName=gateway-server&env&version=1.0.0 fail, endpoint is cse.cn-north-1.myhuaweicloud.com:443, message: Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:4432019-03-22 15:26:04.862 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:443].2019-03-22 15:26:17.037 ERROR: [config-center-vert.x-eventloop-thread-0] org.apache.servicecomb.config.client.ConfigCenterClient[426] - Config update from https://cse.cn-north-1.myhuaweicloud.com failed. Error message is [The timeout period of 9000ms has been exceeded while executing GET /v3/default/configuration/items?dimensionsInfo=gateway-server%40spring-cloud-application%231.0.0&revision=default for host cse.cn-north-1.myhuaweicloud.com].2019-03-22 15:26:18.415 ERROR: [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.RestUtils[93] - POST /v4/default/registry/microservices fail, endpoint is cse.cn-north-1.myhuaweicloud.com:443, message: Connection timed out: no further information: cse.cn-north-1.myhuaweicloud.com/43.254.0.77:4432019-03-22 15:26:18.416 WARN : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl[105] - invoke service [/v4/default/registry/microservices] failed, retry.2019-03-22 15:26:18.417 INFO : [registry-vert.x-eventloop-thread-0] org.apache.servicecomb.serviceregistry.client.IpPortManager[100] - Change service center address from cse.cn-north-1.myhuaweicloud.com:443 to cse.cn-north-1.myhuaweicloud.com:443
  • [技术干货] 方志朋SpringCloud系列—Spring Cloud Alibba教程:Sentinel的使用
    1. 什么是SentinelSentinel,中文翻译为哨兵,是为微服务提供流量控制、熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的“雪崩”效应,为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维护期,不再提供新功能,Sentinel是一个不错的替代方案。通常情况,Hystrix采用线程池对服务的调用进行隔离,Sentinel才用了用户线程对接口进行隔离,二者相比,Hystrxi是服务级别的隔离,Sentinel提供了接口级别的隔离,Sentinel隔离级别更加精细,另外Sentinel直接使用用户线程进行限制,相比Hystrix的线程池隔离,减少了线程切换的开销。另外Sentinel的DashBoard提供了在线更改限流规则的配置,也更加的优化。从官方文档的介绍,Sentinel 具有以下特征:§  丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。§  完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。§  广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。§  完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。2  如何在Spring Cloud中使用SentinelSentinel作为Spring Cloud Alibaba的组件之一,在Spring Cloud项目中使用它非常的简单。现在以案例的形式来讲解如何在Spring Cloud项目中使用Sentinel。本项目是在之前nacos教程的案例基础上进行改造。在工程的pom文件加上sentinel的Spring Cloud起步依赖,代码如下:1.    <dependency>2.         <groupId>org.springframework.cloud</groupId>3.         <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>4.         <version>0.9.0.RELEASE</version> 5.    </dependency>在工程的配置文件application.yml文件中配置,需要新增2个配置:§  spring.cloud.sentinel.transport.port: 8719 ,这个端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。§  spring.cloud.sentinel.transport.dashboard: 8080,这个是Sentinel DashBoard的地址。1.    server:2.      port: 87623.    spring:4.      application:5.        name: nacos-provider6.      cloud:7.        nacos:8.          discovery:9.            server-addr: 127.0.0.1:884810.       sentinel:11.         transport:12.           port: 871913.           dashboard: localhost:8080写一个RestController,在接口上加上SentinelResource注解就可以了。1.    @RestController2.    public class ProviderController {3.     4.        @GetMapping("/hi")5.        @SentinelResource(value="hi")6.        public String hi(@RequestParam(value = "name",defaultValue = "forezp",required = false)String name){7.     8.            return "hi "+name;9.        }10.    11.   }关于@SentinelResource 注解,有以下的属性:§  value:资源名称,必需项(不能为空)§  entryType:entry 类型,可选项(默认为 EntryType.OUT)§  blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项§  fallback:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。启动Nacos,并启动nacos-provider项目。文末有源码下载链接。3    Sentinel DashBoardSentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能. Sentinel DashBoard下载地址:https://github.com/alibaba/Sentinel/releases下载完成后,以以下的命令启动1.    java -jar sentinel-dashboard-1.6.1.jar默认启动端口为8080,可以-Dserver.port=8081的形式改变默认端口。启动成功后,在浏览器**问localhost:8080,就可以显示Sentinel的登陆界面,登陆名为sentinel,密码为sentinel。登陆sentinel dashboard成功后,并多次访问nacos-provider的localhost:8080/hi接口,在nacos访问信息如下:sentinel dashboard显示了nacos-provider的接口资源信息。在/hi资源处设置接口的限流功能,在“+流控”按钮点击开设置界面如下,设置阈值类型为 qps,单机阈值为2。设置成功后可以在流控规则这一栏进行查看,如图所示:4    测试多次快速访问nacos-provider的接口资源http://localhost:8762/hi,可以发现偶尔出现以下的信息:Blocked by Sentinel (flow limiting)正常的返回逻辑为hi forezp由以上可只,接口资源/hi的限流规则起到了作用。5    在FeignClient中使用SentinelHystrix默认集成在Spring Cloud 的Feign Client组件中,Sentinel也可以提供这样的功能。现以案例的形式来讲解如何在FeignClient中使用Sentinel,z本案例是在之前的nacos教程案例的nacos-consumer工程上进行改造,除了引入spring-cloud-starter-alibaba-sentinel,还需要引入spring-cloud-starter-openfeign,代码如下:1.        <dependency>2.                <groupId>org.springframework.cloud</groupId>3.                <artifactId>spring-cloud-starter-openfeign</artifactId>4.            </dependency>5.            <dependency>6.                <groupId>org.springframework.cloud</groupId>7.                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>8.                <version>0.9.0.RELEASE</version>9.            </dependency>在配置文件中需要加上sentinel.transport. dashboard配置外,还需要加上feign.sentinel.enabled的配置,代码如下:1.    server:2.      port: 87633.    spring:4.      application:5.        name: nacos-consumer6.      cloud:7.        nacos:8.          discovery:9.            server-addr: 127.0.0.1:884810.       sentinel:11.         transport:12.           port: 871913.           dashboard: localhost:808014.    15.   feign.sentinel.enabled: true写一个FeignClient,调用nacos-provider的/hi接口:1.    @FeignClient("nacos-provider")2.    public interface ProviderClient {3.     4.        @GetMapping("/hi")5.        String hi(@RequestParam(value = "name", defaultValue = "forezp", required = false) String name);6.    }写一个RestController调用ProviderClient,代码如下:1.    @RestController2.    public class ConsumerController {3.     4.        @Autowired5.        ProviderClient providerClient;6.     7.        @GetMapping("/hi-feign")8.        public String hiFeign(){9.           return providerClient.hi("feign");10.       }11.   }在FeignClient中,Sentinel为Feign调用生成了资源名策略定义,定义规则为httpmethod:protocol://requesturl。启动nacos-consumer工程,在Sentinel DashBoard生成了如下的资源信息:添加流控,QPS为2,在浏览器上快速多次点击访问http://localhost:8763/hi-feign,浏览器在正常情况下是能够正常返回如下的信息:hi feign在被限流的时候返回错误信息。需要注意的是,被限流的时候FeignClient并不会调用nacos-provider的接口,而是在nacos-consumer工程里直接报错。6    源码下载https://github.com/forezp/SpringCloudLearning/tree/master/springcloud-alibaba/nacos-discovery-sentinel7    参考资料https://github.com/alibaba/Sentinel/releaseshttps://github.com/alibaba/Sentinel/tree/master/sentinel-dashboardhttps://github.com/spring-cloud-incubator/spring-cloud-alibaba/wiki/Sentinelhttps://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0原创作者:方志朋作者简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架Spring Cloud
  • [技术干货] 方志朋SpringCloud系列—Spring Cloud Alibba教程:如何使用Nacos作为配置中心
    在上一篇文章中讲解了如何使用Nacos作为服务注册中心注册。Nacos除了可以作为服务注册中心,它还有服务配置中心的功能。类似于consul config,Nacos 是支持热加载的。本篇文章将讲述如何使用Nacos作为配置中心。本案例是在上一篇文章(Nacos作为服务注册与发现)的nacos-provider工程上改造的,在工程的pom文件引入nacos-config的Spring cloud依赖,版本为0.9.0. RELEASE,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-alibaba-nacos-config</artifactId>4.      <version>0.9.0.RELEASE</version>5.  </dependency>在bootstrap.yml(一定是bootstrap.yml文件,不是application.yml文件)文件配置以下内容:1.  spring:2.    application:3.      name: nacos-provider4.    cloud:5.      nacos:6.        config:7.          server-addr: 127.0.0.1:88488.          file-extension: yaml9.          prefix: nacos-provider10.   profiles:11.     active: dev在上面的配置中,配置了nacos config server的地址,配置的扩展名是ymal(目前仅支持ymal和properties)。注意是没有配置server.port的,sever.port的属性在nacos中配置。上面的配置是和Nacos中的 dataId 的格式是对应的,nacos的完整格式如下:1.  ${prefix}-${spring.profile.active}.${file-extension}§  prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。§  spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profile.active 为空时,对应的连接符- 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}§  file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。启动nacos,登陆localhost:8848/nacos,创建一个data id ,完整的配置如图所示:写一个RestController,在Controller上添加 @RefreshScope 实现配置的热加载。代码如下:1.  @RestController2.  @RefreshScope3.  public class ConfigController {4.   5.      @Value("${username:lily}")6.      private String username;7.   8.      @RequestMapping("/username")9.      public String get() {10.         return username;11.     }12. }启动工程nacos-provider,在浏览器**问localhost:8761/username,可以返回在nacos控制台上配置的username。在nacos 网页上更改username的配置,在不重启nacos-provider工程的情况下,重新访问localhost:8761/username,返回的事修改后的值,可见nacos作为配置中心实现了热加载功能。原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架Spring Cloud
  • [技术干货] 方志朋-SpringCloud系列:spring cloud config将配置存储在数据库中
    原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud Spring Cloud Config Server最常见是将配置文件放在本地或者远程Git仓库,放在本地是将将所有的配置文件统一写在Config Server工程目录下,如果需要修改配置,需要重启config server;放在Git仓库,是将配置统一放在Git仓库,可以利用Git仓库的版本控制。本文将介绍使用另外一种方式存放配置信息,即将配置存放在Mysql中。整个流程:Config Sever暴露Http API接口,Config Client 通过调用Config Sever的Http API接口来读取配置Config Server的配置信息,Config Server从数据中读取具体的应用的配置。流程图如下:案例实战在本案例中需要由2个工程,分为config-server和config-client,其中config-server工程需要连接Mysql数据库,读取配置;config-client则在启动的时候从config-server工程读取。本案例Spring Cloud版本为Greenwich.RELEASE,Spring Boot版本为2.1.0.RELEASE。工程描述config-server端口8769,从数据库中读取配置config-client端口8083,从config-server读取配置搭建config-server工程创建工程config-server,在工程的pom文件引入config-server的起步依赖,mysql的连接器,jdbc的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-config-server</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>mysql</groupId>7.      <artifactId>mysql-connector-java</artifactId>8.  </dependency>9.  <dependency>10.      <groupId>org.springframework.boot</groupId>11.      <artifactId>spring-boot-starter-jdbc</artifactId>12.  </dependency>在工程的配置文件application.yml下做以下的配置:1.  spring:2.    profiles:3.       active: jdbc4.    application:5.       name: config-jdbc-server6.    datasource:7.       url: jdbc:mysql://127.0.0.1:3306/config-jdbc?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=GMT%2B88.       username: root9.       password: 12345610.       driver-class-name: com.mysql.jdbc.Driver11.    cloud:12.       config:13.         label: master14.         server:15.           jdbc: true16.  server:17.    port: 876918.  spring.cloud.config.server.jdbc.sql: SELECT key1, value1 fromconfig_properties whereAPPLICATION=? andPROFILE=? andLABEL=?其中,spring.profiles.active为spring读取的配置文件名,从数据库中读取,必须为jdbc。spring.datasource配置了数据库相关的信息,spring.cloud.config.label读取的配置的分支,这个需要在数据库中数据对应。spring.cloud.config.server.jdbc.sql为查询数据库的sql语句,该语句的字段必须与数据库的表字段一致。在程序的启动文件ConfigServerApplication加上@EnableConfigServer注解,开启ConfigServer的功能,代码如下:1.  @SpringBootApplication2.  @EnableConfigServer3.  publicclassConfigServerApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConfigServerApplication.class, args);7.      }8.  }初始化数据库由于Config-server需要从数据库中读取,所以读者需要先安装MySQL数据库,安装成功后,创建config-jdbc数据库,数据库编码为utf-8,然后在config-jdbc数据库下,执行以下的数据库脚本:1.  CREATE TABLE `config_properties`(2.    `id`bigint(20) NOT NULL AUTO_INCREMENT,3.    `key1`varchar(50) COLLATE utf8_bin NOT NULL,4.    `value1`varchar(500) COLLATE utf8_bin DEFAULT NULL,5.    `application`varchar(50) COLLATE utf8_bin NOT NULL,6.    `profile`varchar(50) COLLATE utf8_bin NOT NULL,7.    `label`varchar(50) COLLATE utf8_bin DEFAULT NULL,8.    PRIMARY KEY (`id`)9.  ) ENGINE=InnoDBAUTO_INCREMENT=3DEFAULT CHARSET=utf8 COLLATE=utf8_bin其中key1字段为配置的key,value1字段为配置的值,application字段对应于应用名,profile对应于环境,label对应于读取的分支,一般为master。**数据config-client 的2条数据,包括server.port和foo两个配置,具体数据库脚本如下:1.  insert into`config_properties`(`id`, `key1`, `value1`, `application`, `profile`, `label`) values('1','server.port','8083','config-client','dev','master');2.  insert into`config_properties`(`id`, `key1`, `value1`, `application`, `profile`, `label`) values('2','foo','bar-jdbc','config-client','dev','master');搭建config-client在config-client工程的pom文件,引入web和config的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.boot</groupId>3.      <artifactId>spring-boot-starter-web</artifactId>4.  </dependency>5.    6.  <dependency>7.      <groupId>org.springframework.cloud</groupId>8.      <artifactId>spring-cloud-starter-config</artifactId>9.  </dependency>在程序的启动配置文件bootstrap.yml做程序的相关配置,一定要是bootstrap.yml,不可以是application.yml,bootstrap.yml的读取优先级更高,配置如下:1.  spring:2.    application:3.      name: config-client4.    cloud:5.      config:6.        uri: http://localhost:87697.        fail-fast: true8.    profiles:9.      active: dev其中spring.cloud.config.uri配置的config-server的地址,spring.cloud.config.fail-fast配置的是读取配置失败后,执行快速失败。spring.profiles.active配置的是spring读取配置文件的环境。在程序的启动文件ConfigClientApplication,写一个RestAPI,读取配置文件的foo配置,返回给浏览器,代码如下:1.  @SpringBootApplication2.  @RestController3.  publicclassConfigClientApplication{4.    5.      publicstaticvoidmain(String[] args) {6.          SpringApplication.run(ConfigClientApplication.class, args);7.      }8.    9.      @Value("${foo}")10.      Stringfoo;11.      @RequestMapping(value = "/foo")12.      publicStringhi(){13.          returnfoo;14.      }15.  }依次启动2个工程,其中config-client的启动端口为8083,这个是在数据库中的,可见config-client从config-server中读取了配置。在浏览器**问http://localhost:8083/foo,浏览器显示bar-jdbc,这个是在数据库中的,可见config-client从config-server中读取了配置。参考资料https://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html#jdbcbackend源码下载https://github.com/forezp/SpringCloudLearning/tree/master/chapter10-5-jdbc 原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud
  • [技术干货] 方志朋-SpringCloud系列:Spring Cloud Consul 之Greenwich版本全攻略-2
    微服务架构是一个分布式架构,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性较高,如果出现了错误和异常,很难去定位。主要体现在一个请求可能需要调用很多个服务,而内部服务的调用复杂性决定了问题难以定位。所以在微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题能够快速定位的目的。                  在微服务系统中,一个来自用户的请求先到达前端A(如前端界面),然后通过远程调用,到达系统的中间件B、C(如负载均衡、网关等),最后到达后端服务D、E,后端经过一系列的业务逻辑计算,最后将数据返回给用户。对于这样一个请求,经历了这么多个服务,怎么样将它的请求过程用数据记录下来呢?这就需要用到服务链路追踪。Spring Cloud SleuthSpring Cloud Sleuth 为服务之间调用提供链路追踪。通过Sleuth 可以很清楚的了解到一个服务请求经过了哪些服务,每个服务处理花费了多长。从而让我们可以很方便的理清各微服务间的调用关系。此外Sleuth 可以帮助我们:§ 耗时分析: 通过Sleuth 可以很方便的了解到每个采样请求的耗时,从而分析出哪些服务调用比较耗时;§ 可视化错误: 对于程序未捕捉的异常,可以通过集成Zipkin 服务界面上看到;§ 链路优化: 对于调用比较频繁的服务,可以针对这些服务实施一些优化措施。Google开源了Dapper链路追踪组件,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇论文是业内实现链路追踪的标杆和理论基础,具有很高的参考价值。Spring Cloud Sleuth采用了Google的开源项目Dapper的专业术语。§ Span:基本工作单元,发送一个远程调度任务就会产生一个Span,Span是用一个64位ID唯一标识的,Trace是用另一个64位ID唯一标识的。Span还包含了其他的信息,例如摘要、时间戳事件、Span的ID以及进程ID。§ Trace:由一系列Span组成的,呈树状结构。请求一个微服务系统的API接口,这个API接口需要调用多个微服务单元,调用每个微服务单元都会产生一个新的Span,所有由这个请求产生的Span组成了这个Trace。§ Annotation:用于记录一个事件,一些核心注解用于定义一个请求的开始和结束,这些注解如下。o   cs-Client Sent:客户端发送一个请求,这个注解描述了Span的开始。o   sr-Server Received:服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳,便可得到网络传输的时间。o   ss-Server Sent:服务端发送响应,该注解表明请求处理的完成(当请求返回客户端),用ss的时间戳减去sr时间戳,便可以得到服务器请求的时间。o   cr-Client Received:客户端接收响应,此时Span结束,如果cr的时间戳减去cs时间戳,便可以得到整个请求所消耗的时间。Spring Cloud Sleuth 也为我们提供了一套完整的链路解决方案,Spring Cloud Sleuth 可以结合Zipkin,将信息发送到Zipkin,利用Zipkin 的存储来存储链路信息,利用Zipkin UI 来展示数据。ZipkinZipkin是一种分布式链路追踪系统。它有助于收集解决微服务架构中的延迟问题所需的时序数据。它管理这些数据的收集和查找。Zipkin的设计基于Google Dapper论文。跟踪器存在于应用程序中,记录请求调用的时间和元数据。跟踪器使用库,它们的使用对用户是无感知的。例如,Web服务器会在收到请求时和发送响应时会记录相应的时间和一些元数据。一次完整链路请求所收集的数据被称为Span。我们可以使用它来收集各个服务器上请求链路的跟踪数据,并通过它提供的REST API 接口来辅助我们查询跟踪数据以实现对分布式系统的监控程序,从而及时地发现系统中出现的延迟升高问题并找出系统性能瓶颈的根源。除了面向开发的API 接口之外,它也提供了方便的UI 组件来帮助我们直观的搜索跟踪信息和分析请求链路明细,比如:可以查询某段时间内各用户请求的处理时间等。Zipkin 提供了可插拔数据存储方式:In-Memory、MySql、Cassandra 以及Elasticsearch。接下来的测试为方便直接采用In-Memory 方式进行存储,生产推荐Elasticsearch.上图展示了Zipkin 的基础架构,它主要由4 个核心组件构成:§ Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为Zipkin 内部处理的Span 格式,以支持后续的存储、分析、展示等功能。§ Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中,我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中。§ RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接系统访问以实现监控等。§ Web UI:UI 组件,基于API 组件实现的上层应用。通过UI 组件用户可以方便而有直观地查询和分析跟踪信息。案例实战在本案例一共有三个应用,分别为注册中心,eureka-server、eureka-client、eureka-client-feign,三个应用的基本信息如下:应用名端口作用eureka-server8761注册中心eureka-client8763服务提供者eureka-client-feign8765服务消费者其中eureka-server 应用为注册中心,其他两个应用向它注册。eureka-client为服务提供者,提供了一个RESTAPI,eureka-client-feign为服务消费者,通过Feign Client向服务提供者消费服务。在之前的文章已经讲述了如何如何搭建服务注册中心,在这里就省略这一部分内容。服务提供者提供一个REST接口,服务消费者通过FeignClient消费服务。服务提供者eureka-client服务提供者,对外提供一个RESTAPI,并向服务注册中心注册,这部分内容,不再讲述,见源码。需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,代码如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-starter-sleuth</artifactId>4.  </dependency>5.  <dependency>6.      <groupId>org.springframework.cloud</groupId>7.      <artifactId>spring-cloud-starter-zipkin</artifactId>8.  </dependency>在工程的配置文件application.yml需要做以下的配置:1.  spring:2.    sleuth:3.      web:4.        client:5.          enabled:true6.      sampler:7.        probability:1.0 # 将采样比例设置为1.0,也就是全部都需要。默认是0.18.    zipkin:9.      base-url:http://localhost:9411/ # 指定了Zipkin 服务器的地址其中spring.sleuth.web.client.enable为true设置的是web开启sleuth功能;spring.sleuth.sampler.probability可以设置为小数,最大值为1.0,当设置为1.0时就是链路数据100%收集到zipkin-server,当设置为0.1时,即10%概率收集链路数据;spring.zipkin.base-url设置zipkin-server的地址。对外提供一个Api,代码如下:1.  @RestController2.  publicclassHiController{3.    4.      @Value("${server.port}")5.      Stringport;6.      @GetMapping("/hi")7.      publicStringhome(@RequestParamStringname){8.          return"hi "+name+",i am from port:"+port;9.      }10.   11.  }服务消费者服务消费者通过FeignClient消费服务提供者提供的服务。同服务提供者一样,需要在工程的pom文件加上sleuth的起步依赖和zipkin的起步依赖,另外也需要在配置文件application.yml做相关的配置,具体同服务提供者。服务消费者通过feignClient进行服务消费,feignclient代码如下:1.  @FeignClient(value ="eureka-client",configuration =FeignConfig.class)2.  publicinterfaceEurekaClientFeign{3.    4.      @GetMapping(value ="/hi")5.      StringsayHiFromClientEureka(@RequestParam(value ="name")Stringname);6.  }servcie层代码如下:1.  @Service2.  publicclassHiService{3.    4.      @Autowired5.      EurekaClientFeigneurekaClientFeign;6.    7.    8.      publicStringsayHi(Stringname){9.          return eurekaClientFeign.sayHiFromClientEureka(name);10.      }11.  }controller代码如下:1.  @RestController2.  publicclassHiController{3.      @Autowired4.      HiServicehiService;5.    6.      @GetMapping("/hi")7.      publicStringsayHi(@RequestParam(defaultValue ="forezp",required =false)Stringname){8.          returnhiService.sayHi(name);9.      }上面的代码对外暴露一个API,通过FeignClient的方式调用eureka-client的服务。zipkin-server在Spring Cloud D版本,zipkin-server通过引入依赖的方式构建工程,自从E版本之后,这一方式改变了,采用官方的jar形式启动,所以需要通过下载官方的jar来启动,也通过以下命令一键启动:1.  curl -sSL https://zipkin.io/quickstart.sh | bash -s2.  java -jar zipkin.jar上面的第一行命令会从zipkin官网下载官方的jar包。如果是window系统,建议使用gitbash执行上面的命令。如果用Docker 的话,使用以下命令:1.  docker run -d -p 9411:9411openzipkin/zipkin通过java -jar zipkin.jar的方式启动之后,在浏览器**问lcoalhost:9411,显示的界面如下:链路数据验证依次启动eureka-server,eureka-client,eureka-client-feign的三个应用,等所有应用启动完成后,在浏览器**问http://localhost:8765/hi(如果报错,是服务与发现需要一定的时间,耐心等待几十秒),访问成功后,再次在浏览器**问zipkin-server的页面,显示如下:从上图可以看出每次请求所消耗的时间,以及一些span的信息。从上图可以看出具体的服务依赖关系,eureka-feign-client依赖了eureka-client。使用rabbitmq进行链路数据收集在上面的案例中使用的http请求的方式将链路数据发送给zipkin-server,其实还可以使用rabbitmq的方式进行服务的消费。使用rabbitmq需要安装rabbitmq程序,下载地址http://www.rabbitmq.com/。下载完成后,需要eureka-client和eureka-client-feign的起步依赖加上rabbitmq的依赖,依赖如下:1.  <dependency>2.      <groupId>org.springframework.cloud</groupId>3.      <artifactId>spring-cloud-stream-binder-rabbit</artifactId>4.  </dependency>在配置文件上需要配置rabbitmq的配置,配置信息如下:1.  spring:2.    rabbitmq:3.      host:localhost4.      username:guest5.      password:guest6.      port:5672另外需要把spring.zipkin.base-url去掉。在上面2个工程中,rabbitmq通过发送链路数据,那么zipkin-server是怎么样知道rabbitmq的地址呢,怎么监听收到的链路数据呢?这需要在程序启动的时候,通过环境变量的形式到环境中,然后zikin-server从环境变量中读取。可配置的属性如下:属性环境变量描述zipkin.collector.rabbitmq.addressesRABBIT_ADDRESSES用逗号分隔的RabbitMQ 地址列表,例如localhost:5672,localhost:5673zipkin.collector.rabbitmq.passwordRABBIT_PASSWORD连接到RabbitMQ 时使用的密码,默认为guestzipkin.collector.rabbitmq.usernameRABBIT_USER连接到RabbitMQ 时使用的用户名,默认为guestzipkin.collector.rabbitmq.virtual-hostRABBITVIRTUALHOST使用的RabbitMQ virtual host,默认为/zipkin.collector.rabbitmq.use-sslRABBITUSESSL设置为true则用SSL 的方式与RabbitMQ 建立链接zipkin.collector.rabbitmq.concurrencyRABBIT_CONCURRENCY并发消费者数量,默认为1zipkin.collector.rabbitmq.connection-timeoutRABBITCONNECTIONTIMEOUT建立连接时的超时时间,默认为60000毫秒,即1 分钟zipkin.collector.rabbitmq.queueRABBIT_QUEUE从中获取span 信息的队列,默认为zipkin比如,通过以下命令启动:1.  RABBIT_ADDRESSES=localhost java-jar zipkin.jar上面的命令等同于一下的命令:1.  java -jar zipkin.jar --zipkin.collector.rabbitmq.addressed=localhost用上面的2条命令中的任何一种方式重新启动zipkin-server程序,并重新启动eureka-client、eureka-server、eureka-client-feign,动完成后在浏览器**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,就可以看到通过Http方式发送链路数据一样的接口。自定义Tag在页面上可以查看每个请求的traceId,每个trace又包含若干的span,每个span又包含了很多的tag,自定义tag可以通过Tracer这个类来自定义。1.  @Autowired2.  Tracertracer;3.    4.   @GetMapping("/hi")5.      publicStringhome(@RequestParamStringname){6.          tracer.currentSpan().tag("name","forezp");7.          return"hi "+name+",i am from port:"+port;8.      }将链路数据存储在Mysql数据库中上面的例子是将链路数据存在内存中,只要zipkin-server重启之后,之前的链路数据全部查找不到了,zipkin是支持将链路数据存储在mysql、cassandra、elasticsearch中的。现在讲解如何将链路数据存储在Mysql数据库中。首先需要初始化zikin存储在Mysql的数据的scheme,可以在这里查看https://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sql,具体如下:1.  CREATE TABLE IF NOT EXISTS zipkin_spans (2.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',3.    `trace_id`BIGINT NOT NULL,4.    `id`BIGINT NOT NULL,5.    `name`VARCHAR(255)NOT NULL,6.    `parent_id`BIGINT,7.    `debug`BIT(1),8.    `start_ts`BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',9.    `duration`BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query'10.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;11.   12.  ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`id`)COMMENT 'ignore insert on duplicate';13.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`,`id`)COMMENT 'for joining with zipkin_annotations';14.  ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTracesByIds';15.  ALTER TABLE zipkin_spans ADD INDEX(`name`)COMMENT 'for getTraces and getSpanNames';16.  ALTER TABLE zipkin_spans ADD INDEX(`start_ts`)COMMENT 'for getTraces ordering and range';17.   18.  CREATE TABLE IF NOT EXISTS zipkin_annotations (19.    `trace_id_high`BIGINT NOT NULL DEFAULT 0COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',20.    `trace_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',21.    `span_id`BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',22.    `a_key`VARCHAR(255)NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',23.    `a_value`BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',24.    `a_type`INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',25.    `a_timestamp`BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',26.    `endpoint_ipv4`INT COMMENT 'Null when Binary/Annotation.endpoint is null',27.    `endpoint_ipv6`BINARY(16)COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',28.    `endpoint_port`SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',29.    `endpoint_service_name`VARCHAR(255)COMMENT 'Null when Binary/Annotation.endpoint is null'30.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;31.   32.  ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`,`trace_id`,`span_id`,`a_key`,`a_timestamp`)COMMENT 'Ignore insert on duplicate';33.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`,`span_id`)COMMENT 'for joining with zipkin_spans';34.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`,`trace_id`)COMMENT 'for getTraces/ByIds';35.  ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`)COMMENT 'for getTraces and getServiceNames';36.  ALTER TABLE zipkin_annotations ADD INDEX(`a_type`)COMMENT 'for getTraces and autocomplete values';37.  ALTER TABLE zipkin_annotations ADD INDEX(`a_key`)COMMENT 'for getTraces and autocomplete values';38.  ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`,`span_id`,`a_key`)COMMENT 'for dependencies job';39.   40.  CREATE TABLE IF NOT EXISTS zipkin_dependencies (41.    `day`DATE NOT NULL,42.    `parent`VARCHAR(255)NOT NULL,43.    `child`VARCHAR(255)NOT NULL,44.    `call_count`BIGINT,45.    `error_count`BIGINT46.  )ENGINE=InnoDBROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;47.   48.  ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`,`parent`,`child`);在数据库中初始化上面的脚本之后,需要做的就是zipkin-server如何连接数据库。zipkin如何连数据库同连接rabbitmq一样。zipkin连接数据库的属性所对应的环境变量如下:属性环境变量描述zipkin.torage.typeSTORAGE_TYPE默认的为mem,即为内存,其他可支持的为cassandra、cassandra3、elasticsearch、mysqlzipkin.torage.mysql.hostMYSQL_HOST数据库的host,默认localhostzipkin.torage.mysql.portMYSQLTCPPORT数据库的端口,默认3306zipkin.torage.mysql.usernameMYSQL_USER连接数据库的用户名,默认为空zipkin.torage.mysql.passwordMYSQL_PASS连接数据库的密码,默认为空zipkin.torage.mysql.dbMYSQL_DBzipkin使用的数据库名,默认是zipkinzipkin.torage.mysql.max-activeMYSQLMAXCONNECTIONS最大连接数,默认是101.  STORAGE_TYPE=mysql MYSQL_HOST=localhost MYSQL_TCP_PORT=3306MYSQL_USER=root MYSQL_PASS=123456MYSQL_DB=zipkin java -jar zipkin.jar等同于以下的命令1.  java -jar zipkin.jar --zipkin.torage.type=mysql --zipkin.torage.mysql.host=localhost --zipkin.torage.mysql.port=3306--zipkin.torage.mysql.username=root --zipkin.torage.mysql.password=123456使用上面的命令启动zipkin.jar工程,然后再浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时去数据库查看数据,也是可以看到存储在数据库的链路数据,如下:这时重启应用zipkin.jar,再次在浏览器**问http://localhost:9411/zipkin/,仍然可以得到之前的结果,证明链路数据存储在数据库中,而不是内存中。将链路数据存在在Elasticsearch中zipkin-server支持将链路数据存储在ElasticSearch中。读者需要自行安装ElasticSearch和Kibana,下载地址为https://www. elastic.co/products/elasticsearch。安装完成后启动,其中ElasticSearch的默认端口号为9200,Kibana的默认端口号为5601。同理,zipkin连接elasticsearch也是从环境变量中读取的,elasticsearch相关的环境变量和对应的属性如下:属性环境变量描述zipkin.torage.elasticsearch.hostsES_HOSTSES_HOSTS,默认为空zipkin.torage.elasticsearch.pipelineES_PIPELINEES_PIPELINE,默认为空zipkin.torage.elasticsearch.max-requestsESMAXREQUESTSESMAXREQUESTS,默认为64zipkin.torage.elasticsearch.timeoutES_TIMEOUTES_TIMEOUT,默认为10szipkin.torage.elasticsearch.indexES_INDEXES_INDEX,默认是zipkinzipkin.torage.elasticsearch.date-separatorESDATESEPARATORESDATESEPARATOR,默认为“-”zipkin.torage.elasticsearch.index-shardsESINDEXSHARDSESINDEXSHARDS,默认是5zipkin.torage.elasticsearch.index-replicasESINDEXREPLICASESINDEXREPLICAS,默认是1zipkin.torage.elasticsearch.usernameES_USERNAMEES的用户名,默认为空zipkin.torage.elasticsearch.passwordES_PASSWORDES的密码,默认是为空采用以下命令启动zipkin-server:1.  STORAGE_TYPE=elasticsearch ES_HOSTS=http://localhost:9200 ES_INDEX=zipkin java -jar zipkin.jar1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --STORAGE_TYPE=elasticsearch --ES_HOSTS=http://localhost:9200 --ES_INDEX=zipkin 1.  java -jar zipkin.jar --zipkin.torage.type=elasticsearch --zipkin.torage.elasticsearch.hosts=http://localhost:9200 --zipkin.torage.elasticsearch.index=zipkin 启动完成后,然后在浏览数**问http://localhost:8765/hi,再访问http://localhost:9411/zipkin/,可以看到链路数据。这时链路数据存储在ElasticSearch。在zipkin上展示链路数据链路数据存储在ElasticSearch中,ElasticSearch可以和Kibana结合,将链路数据展示在Kibana上。安装完成Kibana后启动,Kibana默认会向本地端口为9200的ElasticSearch读取数据。Kibana默认的端口为5601,访问Kibana的主页http://localhost:5601,其界面如下图所示。在上图的界面中,单击“Management”按钮,然后单击“Add New”,添加一个index。我们将在上节ElasticSearch中写入链路数据的index配置为“zipkin”,那么在界面填写为“zipkin-*”,单击“Create”按钮,界面如下图所示:创建完成index后,单击“Discover”,就可以在界面上展示链路数据了,展示界面如下图所示。参考资料https://zipkin.io/https://github.com/spring-cloud/spring-cloud-sleuthhttps://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.1.0.RELEASE/single/spring-cloud-sleuth.htmlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.ymlhttps://github.com/openzipkin/zipkin/blob/master/zipkin-storage/mysql-v1/src/main/resources/mysql.sqlhttps://windmt.com/2018/04/24/spring-cloud-12-sleuth-zipkin/https://segmentfault.com/a/119000001569767http://www.cnblogs.com/JreeyQi/p/9336692.html原创作者:方志朋方志朋简介:SpringCloud中国社区联合创始人,博客访问量突破一千万,爱好开源,热爱分享,活跃于各大社区,保持着非常强的学习驱动力,终身学习践行者,终身学习受益者。目前就职于国内某家知名互联网保险公司,担任DEVOPS工程师,对微服务领域和持续集成领域研究较深,精通微服务框架SpringCloud 
  • [问题求助] CSE可以和spring cloud stream 兼容吗
    加上EnableBinding注解后,启动报端口占用错误猜测是先启动了vertx rest的端口后面再启动spring的tomcat的时候报错了下面是pom和父pom4.0.0com.huawei.aciotparent1.0-SNAPSHOTdevice-common0.0.1-SNAPSHOTdevice-commonDemo project for Spring Boot1.8org.projectlomboklomboktrueorg.apache.servicecombhandler-tracing-zipkinorg.springframework.cloudspring-cloud-stream-test-supporttestorg.springframework.cloudspring-cloud-streamorg.springframework.cloudspring-cloud-stream-binder-kafkaorg.springframework.kafkaspring-kafkacom.huawei.eciotcore-util0.0.1-SNAPSHOT父pomorg.springframework.bootspring-boot-starter-parent2.1.6.RELEASEpomimportorg.springframeworkspring-core5.1.8.RELEASEpomimportcom.huawei.paas.csecse-dependency-spring-boot26.5.62pomimportcom.huawei.paas.csecse-solution-service-engineorg.slf4jslf4j-log4j12org.apache.servicecombspring-boot2-starter-servletorg.springframework.bootspring-boot-starter-testtestyaml:  :    : device-common:  : 8090  :    : /device-north: ac-iot:  : device  : 0.0.1             :    : true  : development:  :    :      : false  :    : 192.188.240.32:${server.port}  :    : /device  :    :      : http://192.88.16.46:30100      :  :    :      :        : loadbalance,tracing-consumer      :        : tracing-provider  :    :      : http://localhost:9411大佬们帮忙看一下是哪里配错了吗
总条数:23 到第
上滑加载中