首页 文章 精选 留言 我的

精选列表

搜索[SpringCloud],共1289篇文章
优秀的个人博客,低调大师

SpringCloud之zuul源码解析

Zuul源码解析 zuul各版本实现存在一些微小的变化,总的实现思想未改变,以spring-cloud-netflix-core-1.3.6.RELEASE为例 一、zuul的重要的初始化类 org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration org.springframework.cloud.netflix.zuul.ZuulFilterInitializer org.springframework.cloud.netflix.zuul.RibbonCommandFactoryConfiguration ZuulServerAutoConfiguration 初始化路由规则 初始化一些重要的filter如PreDecorationFilter,RibbonRoutingFilter 初始化ZuulFilterInitializer 初始化ZuulHandlerMapping 代码如下 //路由规则 @Bean @ConditionalOnMissingBean(DiscoveryClientRouteLocator.class) public DiscoveryClientRouteLocator discoveryRouteLocator() { return new DiscoveryClientRouteLocator(this.server.getServletPrefix(), this.discovery, this.zuulProperties, this.serviceRouteMapper); } // pre filters @Bean public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) { return new PreDecorationFilter(routeLocator, this.server.getServletPrefix(), this.zuulProperties, proxyRequestHelper); } // route filters @Bean public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) { RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers); return filter; } @Configuration protected static class ZuulFilterConfiguration { @Autowired private Map<String, ZuulFilter> filters; @Bean public ZuulFilterInitializer zuulFilterInitializer( CounterFactory counterFactory, TracerFactory tracerFactory) { FilterLoader filterLoader = FilterLoader.getInstance(); FilterRegistry filterRegistry = FilterRegistry.instance(); return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry); } } @Bean public ZuulController zuulController() { return new ZuulController(); } @Bean public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) { ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController()); mapping.setErrorController(this.errorController); return mapping; } ZuulProxyAutoConfiguration zuulProxAutoConfiguration继承ZuulServerAutoConfiguration功能上和zuulServerAutoConfiguration 主要功能是增加了RibbonCommandFactoryConfiguration的配置,初始化所有的实现ribbon的方式如apache,okhttp。 ZuulFilterInitializer 该类的作用主要是把初始化的过滤器注册到zuul的FilterRegistry,FilterRegistry是一个单例用于初始化路由信息,在ZuulRunner中使用 RibbonCommandFactoryConfiguration 主要作用是配置转发的实现,实现主要有apache,okhttp 二、zuul的转发实现 首先第一步转到ZuulHandlerMapping中的lookupHandler方法,把转发转到zuulController中 @Override protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { if (this.errorController != null && urlPath.equals(this.errorController.getErrorPath())) { return null; } String[] ignored = this.routeLocator.getIgnoredPaths().toArray(new String[0]); if (PatternMatchUtils.simpleMatch(ignored, urlPath)) { return null; } RequestContext ctx = RequestContext.getCurrentContext(); if (ctx.containsKey("forward.to")) { return null; } if (this.dirty) { synchronized (this) { if (this.dirty) { registerHandlers(); this.dirty = false; } } } return super.lookupHandler(urlPath, request); } 第一次访问时dirty为true会初始化一次请求规则如下 private void registerHandlers() { Collection<Route> routes = this.routeLocator.getRoutes(); if (routes.isEmpty()) { this.logger.warn("No routes found from RouteLocator"); } else { for (Route route : routes) { registerHandler(route.getFullPath(), this.zuul); } } } 第二步ZuulController继承ServletWrappingController的会把请求转到ZuulServlet中如下 /** * @author Spencer Gibb */ public class ZuulController extends ServletWrappingController { public ZuulController() { setServletClass(ZuulServlet.class); setServletName("zuul"); setSupportedMethods((String[]) null); // Allow all } @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { try { // We don't care about the other features of the base class, just want to // handle the request return super.handleRequestInternal(request, response); } finally { // @see com.netflix.zuul.context.ContextLifecycleFilter.doFilter RequestContext.getCurrentContext().unset(); } } } 第三步ZuulServlet的service方法如下主要执行pre,route,postRoute三种路由器 @Override public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); // Marks this request as having passed through the "Zuul engine", as opposed to servlets // explicitly bound in web.xml, for which requests will not have the same data attached RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { preRoute(); } catch (ZuulException e) { error(e); postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); } } 四、最后由SendResponseFilter执行返回结果,filterOrder为1000所以最好post的filter不要超过1000否则影响返回结果

优秀的个人博客,低调大师

springcloud(六):熔断监控Turbine

在复杂的分布式系统中,相同服务的节点经常需要部署上百甚至上千个,很多时候,运维人员希望能够把相同服务的节点状态以一个整体集群的形式展现出来,这样可以更好的把握整个系统的状态。 为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。愿意了解源码的朋友直接求求交流分享技术:二一四七七七五六三三 1、添加依赖 <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-turbine</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-turbine</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency> </dependencies> 2、配置文件 spring.application.name=hystrix-dashboard-turbine server.port=8001 turbine.appConfig=node01,node02 turbine.aggregator.clusterConfig= default turbine.clusterNameExpression= new String("default") eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/ turbine.appConfig:配置Eureka中的serviceId列表,表明监控哪些服务turbine.aggregator.clusterConfig:指定聚合哪些集群,多个使用”,”分割,默认为default。可使用http://.../turbine.stream?cluster={clusterConfig之一}访问turbine.clusterNameExpression: 1. clusterNameExpression指定集群名称,默认表达式appName;此时:turbine.aggregator.clusterConfig需要配置想要监控的应用名称;2. 当clusterNameExpression: default时,turbine.aggregator.clusterConfig可以不写,因为默认就是default;3. 当clusterNameExpression: metadata[‘cluster’]时,假设想要监控的应用配置了eureka.instance.metadata-map.cluster: ABC,则需要配置,同时turbine.aggregator.clusterConfig: ABC3、启动类启动类添加@EnableTurbine,激活对Turbine的支持 @SpringBootApplication @EnableHystrixDashboard @EnableTurbine public class DashboardApplication { public static void main(String[] args) { SpringApplication.run(DashboardApplication.class, args); } } 到此Turbine(hystrix-dashboard-turbine)配置完成 4、测试在示例项目spring-cloud-consumer-hystrix基础上修改为两个服务的调用者spring-cloud-consumer-node1和spring-cloud-consumer-node2spring-cloud-consumer-node1项目改动如下: application.properties文件内容 spring.application.name=node01 server.port=9001 feign.hystrix.enabled=true eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/ spring-cloud-consumer-node2项目改动如下: application.properties文件内容 spring.application.name=node02 server.port=9002 feign.hystrix.enabled=true eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/ HelloRemote类修改: @FeignClient(name= "spring-cloud-producer2", fallback = HelloRemoteHystrix.class) public interface HelloRemote { @RequestMapping(value = "/hello") public String hello2(@RequestParam(value = "name") String name); } 对应的HelloRemoteHystrix和ConsumerController类跟随修改,具体查看代码 修改完毕后,依次启动spring-cloud-eureka、spring-cloud-consumer-node1、spring-cloud-consumer-node1、hystrix-dashboard-turbine(Turbine) 打开eureka后台可以看到注册了三个服务: 访问 http://localhost:8001/turbine.stream 返回: : ping data: {"reportingHostsLast10Seconds":1,"name":"meta","type":"meta","timestamp":1494921985839} 并且会不断刷新以获取实时的监控数据,说明和单个的监控类似,返回监控项目的信息。进行图形化监控查看,输入:http://localhost:8001/hystrix,返回酷酷的小熊界面,输入: http://localhost:8001/turbine.stream,然后点击 Monitor Stream ,可以看到出现了俩个监控列表整体代码结构如下:资料和源码来源

优秀的个人博客,低调大师

springCloud(1):微服务简介

一、什么是微服务 微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。 二、微服务架构特性 1、每个微服务可独立运行在自己的进程里 2、一系列独立运行的微服务共同构建起整个系统 3、每个服务为独立的业务开发,一个微服务只关注某个特定的功能,如:订单管理 4、微服务之间通过一些轻量级的通信机制进行通信,例如:通过RESTful API进行调用 5、可以使用不同的语言与数据存储技术 6、全自动的部署机制 三、微服务的优点与挑战 3.1、优点 1、易于开发和维护 一个微服务只会关注一个特定的业务功能。 2、单个微服务启动较快 单个微服务代码量较少 3、局部修改容易部署 单体应用只要要修改就得重新部署整个应用,微服务解决了这一问题 4、技术栈不受限 语言不受限制 5、按需伸缩 可根据需要,实现细粒度的扩展 3.2、挑战 1、运维成本较高 更多的服务意味着更多的运维投入 2、分布式固有的复杂性 使用微服务构建的是分布式系统,对于一个分布式系统,系统容错、网络延迟、分布式事务等都会带来巨大的挑战 3、接口调整成本高 微服务之间通过接口进行通信,如果修改某一个微服务的API,可能所有使用了该接口的微服务都需要做调整 4、重复劳动 很多服务可能都会使用到相同的功能,而这个功能并没有达到分解为一个微服务的程度。 四、微服务设计原则 4.1、单一职责原则 指的是一个单元(类、方法或者服务等)只应关注整个系统功能中单独、有界限的一部分。(SOLID原则之一) 4.2、服务自治原则 指每个微服务应具备独立的业务能力 、依赖与运行环境。应该与其它服务高度解耦,每个微服务从开发、测试、构建、部署,都应当可以独立运行,而不应该依赖其它的服务 4.3、轻量级通信原则 轻量级的通信机制应具备两点: 1、体量较轻 2、跨语言 微服务架构中,常用的协议有REST、AMQP、STOMP、MQTT等 4.4、微服务粒度 微服务的粒度是难点,也常常是争论的焦点。应当使用合理的粒度划分微服务,而不是一味的把服务做小。 五、微服务架构的实现 不仅需要开发框架的支持,还需要一些自动化的部署工具,以及IaaS、PaaS或CaaS的支持。 开发框架的选择: 可以使用Spring Cloud作为微服务开发框架。当然也可以使用Dubbo等 本文转自我爱大金子博客51CTO博客,原文链接http://blog.51cto.com/1754966750/1941022如需转载请自行联系原作者 我爱大金子

优秀的个人博客,低调大师

SpringCloud——使用Ribbon做负载均衡

Ribbon负载均衡 一、简介 1:什么是负载均衡 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。 负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。以上内容来自于百度百科 个人理解而言,负载均衡,是弥补了单体架构或者单个服务的负载能力不足而导致的整体性能瓶颈,因此,可以通过将一个服务部署多台服务器,然后将一台机器原来的压力分摊到多个执行单元上,这样就提升了原有架构的性能瓶颈。可以理解为 “将负载均衡到多个服务中”。常见的负载均衡有两种策略: Nginx独立进程做负载均衡,通过负载均衡策略,将请求转发到不同的执行单元上 客户端负载均衡策略,通过在客户端保存服务列表信息,然后自己调用负载均衡策略,分摊调用不同的执行单元。 2:什么是Ribbon Ribbon是Netflix公司开源的一个负载均衡的组件,它属于上述负载均衡方式中的第二种。将负载均衡的逻辑封装在了客户端中,并且运行在客户端。Ribbon经过了非常严格的测试,可以更好的控制Http和Tcp客户端的负载均衡行为。 Ribbon的负载均衡有两种方式 和RestTemplate结合 和Feign结合 Ribbon的核心子模块 ribbon-loadbalancer:可以独立使用或者和其他模块一起使用的负载均衡API ribbon-eureka:结合Eureka作客户端的API ribbon-core:Ribbon的核心API 3:什么是RestTemplate RestTemplate是SpringResource中一个访问第三方RESTful API接口的网络通讯框架。其主要方法都与REST的HTTP协议的方法紧密关联。 RestTemplate支持常见的HTTP请求方式,例如GET、POST、PUT、DELETE等,所以RestTemplate很容易构建RESTful API 调用方式例如 restTemplate.getForObject("http://common-service/hello", String.class) 其核心API如下 https://docs.spring.io/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html 二、开始使用Ribbon Ⅰ.代码编写 ribbon-test父项目 pom.xml <groupId>com.calvin.ribbon</groupId> <artifactId>ribbon-test</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>common-service</module> <module>eureka-server</module> <module>ribbon-service</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> eureka-server pom.xml <parent> <groupId>com.calvin.ribbon</groupId> <artifactId>ribbon-test</artifactId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>eureka-server</artifactId> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> application.yml server: port: 8080 eureka: instance: hostname: localhost client: register-with-eureka: false fetch-registry: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka ServerApplication.java @EnableEurekaServer @SpringBootApplication public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class); } } commons-service pom.xml <parent> <artifactId>ribbon-test</artifactId> <groupId>com.calvin.ribbon</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>common-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> application.yml spring: application: name: common-service eureka: client: service-url: defaultZone: http://localhost:8080/eureka/ 此处没有指定server.port,是因为我们在启动此服务的是时候做点手脚,需要以不同端口在本地启动, 即配置两个Name不同的启动类,给分别指定不同的Environment variables,内容为server.port=8083, server.port=8084 具体教程是在Idea下的EditConfiguration中做如下操作: CommonServiceApplication.java @SpringBootApplication @EnableEurekaClient public class CommonServiceApplication { public static void main(String[] args) { SpringApplication.run(CommonServiceApplication.class); } } HelloController.java @RestController public class HelloController { @Value("${server.port}") private String port; /** * 接口测试 * @return */ @GetMapping("/hello") public String sayHello(){ return "port : " + port ; } } ribbon-service pom.xml <parent> <artifactId>ribbon-test</artifactId> <groupId>com.calvin.ribbon</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ribbon-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> application.yml server: port: 8082 spring: application: name: ribbon-service eureka: client: service-url: defaultZone: http://localhost:8080/eureka/ RibbonClientApplication.java @EnableEurekaClient @SpringBootApplication public class RibbonServerApplication { public static void main(String[] args) { SpringApplication.run(RibbonServerApplication.class); } /** * 配置LoadBalance和RestTemplate * @return RestTemplate */ @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } } 接下来就是调用的关键代码 RemoteCommonService.java /** * <p> * CommonService服务远程调用类 * </p> * @author Calvin * @date 2019/10/09 * @since 1.0 */ @Service public class RemoteCommonService { /** * 注入RestTemplate */ @Autowired private RestTemplate restTemplate; /** * 远程调用common-service/hello * @return */ public String sayHi(){ return restTemplate.getForObject("http://common-service/hello", String.class); } } SayHiController.java @RestController public class SayHiController { @Autowired private RemoteCommonService remoteCommonService; @GetMapping("hi") public String sayHi(){ return remoteCommonService.sayHi() + ", this is ribbon service"; } } Ⅱ.配置启动 最终配置四个启动类,如图所示: 启动顺序: step1. EurekaSeverApplicaton step2. CommonServiceApplication step3. CommonServiceApplication2 step4. RibbonServerApplication Ⅲ.结果验证 Eureka管理界面 http://localhost:8080/ 调用 http://localhost:8082/hi 刷新页面 三、核心剖析——LoadBalancerClient 负载均衡的核心类是LoadBalanceClient,此类可以获取负载均衡的服务提供者的实例信息,当然这些实例信息是通过EurekaClient获取的,并且缓存了一份服务实例信息。 @Autowired private LoadBalancerClient loanBalanceClient; /** * 远程调用common-service/hello * @return */ public String sayHi(){ ServiceInstance serviceInstance = loanBalanceClient.choose("common-service"); logger.info("current service info is {} : {}", serviceInstance.getHost(), serviceInstance.getPort()); return restTemplate.getForObject("http://common-service/hello", String.class); } 此时不断刷接口,同样可以看到LoadBalancerClient在不断的改变请求的实例信息。 四、小结 认识了关于Ribbon以及常用负载均衡的概念 动手实践了一下Ribbon进行负载均衡的调用 认识Ribbon的一个核心类 五、总结 本文首次实践Ribbon做负载均衡,缺乏原理剖析 文章中代码相对简单,但是基本可以表达Ribbon所做的事情 需要在以后,对整个Ribbon的源码进行解析(算是插眼) 关于RestTemplate还有很多用法,后续可以专门出文章进行深入理解

优秀的个人博客,低调大师

SpringCloud微服务架构升级总结

一、背景 1.1 应用系统的架构历史 1.2 什么是微服务? 起源:微服务的概念源于 2014 年 3 月 Martin Fowler 所写的一篇文章“Microservices”。文中内容提到:微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。 通信方式:每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于 HTTP 的 RESTful API)。 微服务的常规定义:微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务。 把原来的一个完整的进程服务,拆分成两个或两个以上的进程服务,且互相之间存在调用关系,与原先单一的进程服务相比,就是“微服务”。(微服务是一个比较级的概念,而不是单一的概念) 1.3 微服务架构的优势 可扩展性:在增加业务功能时,单一应用架构需要在原先架构的代码基础上做比较大的调整,而微服务架构只需要增加新的微服务节点,并调整与之有关联的微服务节点即可。在增加业务响应能力时,单一架构需要进行整体扩容,而微服务架构仅需要扩容响应能力不足的微服务节点。 容错性:在系统发生故障时,单一应用架构需要进行整个系统的修复,涉及到代码的变更和应用的启停,而微服务架构仅仅需要针对有问题的服务进行代码的变更和服务的启停。其他服务可通过重试、熔断等机制实现应用层面的容错。 技术选型灵活:微服务架构下,每个微服务节点可以根据完成需求功能的不同,自由选择最适合的技术栈,即使对单一的微服务节点进行重构,成本也非常低。 开发运维效率更高:每个微服务节点都是一个单一进程,都专注于单一功能,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂度低,每个微服务可由一个小规模团队或者个人完全掌控,易于保持高可维护性和开发效率。 Spring Cloud作为目前最流行的微服务开发框架,不是采用了Spring Cloud框架就实现了微服务架构,具备了微服务架构的优势。正确的理解是使用Spring Cloud框架开发微服务架构的系统,使系统具备微服务架构的优势(Spring Cloud就像工具,还需要“做”的过程)。 1.4 什么是Spring Boot?什么是Spring Cloud? Spring Boot框架是由Pivotal团队提供的全新框架,其设计目的是用来简化基于Spring应用的初始搭建以及开发过程。SpringBoot框架使用了特定的方式来进行应用系统的配置,从而使开发人员不再需要耗费大量精力去定义模板化的配置文件。 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务注册,服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。 1.5 微服务、Spring Boot、Spring Cloud三者之间的关系 思想:微服务是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。 脚手架:Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务。 多个组件的集合:Spring Cloud是一个基于Spring Boot实现的服务治理工具包;Spring Boot专注于快速、方便集成的单个微服务个体;Spring Cloud关注全局的服务治理框架。 二、技术解析 2.1 Everything is jar, Everything is http Spring Boot通过@SpringBootApplication注解标识为Spring Boot应用程序。所有的应用都通过jar包方式编译,部署和运行。 @SpringBootApplication public class Application { private static final Logger LOGGER = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); LOGGER.info(”启动成功!"); } } 每个Spring Boot的应用都可以通过内嵌web容器的方式提供http服务,仅仅需要在pom文件中依赖spring-boot-start-web即可,原则上微服务架构希望每个独立节点都提供http服务。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 2.2 Spring boot Task 任务启动和定时任务 在Spring Boot需要启动任务时,只要继承CommandLineRunner接口实现其run方法即可。 @SpringBootApplication public class ClientDataListener implements CommandLineRunner public void run(String... strings) throws Exception { clientInfoListenerHandler(); } } 在Spring Boot需要执行定时任务时,只需要在定时任务方法上增加@Scheduled(cron = “0 15 0 ?”)注解(支持标准cron表达式),并且在服务启动类上增加@EnableScheduling的注解即可。 @SpringBootApplication @EnableScheduling public class Application { private static final Logger LOGGER = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); LOGGER.info(”启动成功!"); } } // some class @Scheduled(cron = "0 15 0 * * ?") public void someTimeTask() { *** } 2.3 Spring boot Actuator 监控 Actuator是spring boot提供的对应用系统自身进行监控的组件,在引入spring-boot-start-web基础上引入spring-boot-starter-actuator即可。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 2.4 Spring cloud Config 配置中心 在我们实现微服务架构时,每个微服务节点都需要自身的相关配置数据项,当节点众多,维护就变得非常困难,因此需要建立一个中心配置服务。 Spring Cloud Config分为两部分。Spring Cloud Config server作为一个服务进程,Spring Cloud Config File为配置文件存放位置。 2.5 Spring cloud Eureka 服务注册中心 服务注册的概念早在微服务架构之前就出现了,微服务架构更是把原先的单一应用节点拆分成非常多的微服务节点。互相之间的调用关系会非常复杂,Spring Cloud Eureka作为注册中心,所有的微服务都可以将自身注册到Spring Cloud Eureka进行统一的管理和访问(Eureka和Zookeeper不同,在AOP原则中选择了OP,更强调服务的有效性) 2.6 Spring cloud Zuul 服务端智能路由 当我们把所有的服务都注册到Eureka(服务注册中心)以后,就涉及到如何调用的问题。Spring Cloud Zuul是Spring Cloud提供的服务端代理组件,可以看做是网关,Zuul通过Eureka获取到可用的服务,通过映射配置,客户端通过访问Zuul来访问实际需要需要访问的服务。所有的服务通过spring.application.name做标识, 不同IP地址,相同spring.application.name就是一个服务集群。当我们增加一个相同spring.application.name的节点,Zuul通过和Eureka通信获取新增节点的信息实现智能路由,增加该类型服务的响应能力。 2.7 Spring cloud Ribbon 客户端智能路由 与Spring Cloud Zuul的服务端代理相对应,Spring Cloud Ribbon提供了客户端代理。在服务端代理中,客户端并不需要知道最终是哪个微服务节点为之提供服务,而客户端代理获取实质提供服务的节点,并选择一个进行服务调用。Ribbon和Zuul相似,也是通过和Eureka(服务注册中心)进行通信来实现客户端智能路由。 2.8 Spring cloud Sleuth 分布式追踪 2.9 Spring cloud Zipkin 调用链 2.10 Spring cloud Feign http客户端 Spring Cloud Feign是一种声明式、模板化的http客户端。 使用Spring Cloud Feign请求远程服务时能够像调用本地方法一样,让开发者感觉不到这是远程方法(Feign集成了Ribbon做负载均衡)。 把远程服务和本地服务做映射 @FeignClient(name = "rabbitmq-http", url = "${SKYTRAIN_RABBITMQ_HTTP}") public interface TaskService { @RequestMapping(value = "/api/queues", method = RequestMethod.GET) public String query(@RequestHeader("Authorization") String token); } 以调用本地服务的方式调用远程服务 @Autowired private TaskService taskService; private String queryRabbitmqStringInfo() { byte[] credentials = Base64 .encodeBase64((rabbitmqHttpUserName + ":" + rabbitmqHttpPassword).getBytes(StandardCharsets.UTF_8)); String token = "Basic " + new String(credentials, StandardCharsets.UTF_8); return taskService.query(token); } 2.11 Spring cloud Hystrix 断路器 三、微服务实践 3.1 我们开发的几个微服务组件—应用管理中心 应用管理中心可以对每个已经注册的微服务节点进行停止,编译,打包,部署,启动的完整的上线操作。 3.2 我们开发的几个微服务组件—zookeeper数据查询中心 zookeeper数据查询中心根据zookeeper地址,端口,命令获取zookeeper数据信息。 3.3 我们开发的几个微服务组件—微服务健康检测中心 健康检测中心周期性检查每个微服务的状态,当发现有微服务状态处于DOWN或连接超时时,触发报警。 3.4 我们开发的几个微服务组件—定时任务查询中心 // 在BeanPostProcessor子类中拦截 @Component public class SkytrainBeanPostProcessor implements BeanPostProcessor, Ordered { *** /** * Bean 实例化之后进行的处理 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { beanPostProcessor.postProcessAfter(bean, beanName); return bean; } *** } // 拦截后获取定时任务注解 *** public Object postProcessAfter(Object bean, String beanName) { Class targetClass = AopUtils.getTargetClass(bean); Map annotatedMethods = MethodIntrospector.selectMethods(targetClass, new MethodIntrospector.MetadataLookup() { public Set inspect(Method method) { Set scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class); return (!scheduledMethods.isEmpty() ? scheduledMethods : null); } }); if (!annotatedMethods.isEmpty()) { String className = targetClass.getName(); for (Map.Entry entry : annotatedMethods.entrySet()) { Method method = entry.getKey(); for (Scheduled scheduled : entry.getValue()) { String key = className + ":" + method.getName(); String value = scheduled.toString(); taskInfos.put(key, value); } } } return null; } *** // 获取定时任务后注册 *** public void taskRegister() { String nodeInfo = ipAddress + ":" + serverPort + ":"; try { /** * 定时任务 */ Map infos = taskInfos; for (Entry item : infos.entrySet()) { String taskId = nodeInfo + item.getKey(); String taskParameter = item.getValue(); JSONObject info = new JSONObject(); info.put("taskId", taskId); info.put("taskParameter", taskParameter); info.put("applicationName", applicationName); info.put("taskType", "schedule"); LOGGER.info(info.toString()); zooKeeperExecutor.createZKNode(SKYTRAIN_TASK_ZKNODE_PREFIX + taskId, info.toString()); } } catch (Exception ex) { LOGGER.error("", ex); } } *** 3.5 微服务的分类 微服务平台组件 公共服务组件 基础服务组件/业务服务组件 3.6 整体微服务架构图 作者:梁鑫 来源:宜信技术学院

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册