当前位置: 首页 > news >正文

网站域名跳转代码有云服务器怎么做网站

网站域名跳转代码,有云服务器怎么做网站,php做投票网站,做的网站电脑上跟手机上不一样吗文章目录 一、服务调用Feign1.1 Feign的基本使用1.2 Feign的属性配置1.2.1 Ribbon配置1.2.2 Hystrix配置 二、网关服务Zuul2.1 Zuul的基本使用2.1.1 请求路由2.1.2 请求过滤 2.2 路由详解2.2.1 传统路由配置2.2.2 服务路由配置2.2.3 服务路由的默认规则2.2.4 自定义路由映射规则… 文章目录 一、服务调用Feign1.1 Feign的基本使用1.2 Feign的属性配置1.2.1 Ribbon配置1.2.2 Hystrix配置 二、网关服务Zuul2.1 Zuul的基本使用2.1.1 请求路由2.1.2 请求过滤 2.2 路由详解2.2.1 传统路由配置2.2.2 服务路由配置2.2.3 服务路由的默认规则2.2.4 自定义路由映射规则2.2.5 路径匹配2.2.6 路由前缀2.2.7 Cookie与头信息2.2.8 Hystrix和Ribbon支持 2.3 过滤器详解2.3.1 请求的生命周期2.3.2 核心过滤器2.3.3 异常处理2.3.4 禁用过滤器2.3.5 用过滤器限流 三、动态配置Apollo3.1 Apollo的四个维度3.2 Apollo的使用3.2.1 页面操作3.2.2 Web中使用 四、Spring Cloud相关问题4.1 SpringBoot和SpringCloud的区别4.2 Spring Cloud断路器的作用4.3 什么是Spring Cloud Gateway4.4 Spring Cloud如何实现服务的注册4.5 REST和RPC对比4.6 说说RPC的实现原理4.7 接口限流方案 本系列文章 Spring一控制反转、两种IOC容器、自动装配、作用域 Spring二延迟加载、生命周期、面向切面、事务 Spring三父子容器、国际化、异步调用、定时器、缓存 Spring四Spring MVC Spring五Spring Boot Spring六Spring Cloud----Eureka、Ribbon、Hystrix Spring七Spring Cloud----Feign、Zuul和Apollo 一、服务调用Feign Spring Cloud Feign基于Netflix Feign实现 整合了Spring Cloud Ribbon与Spring Cloud Hystrix。并且它还提供了一种声明式的 Web 服务客户端定义方式。 1、Feign采用的是基于接口的注解。   2、Feign整合了Ribbon具有负载均衡的能力。   3、Feign整合了Hystrix具有熔断的能力。 在使用Ribbon时通常都会利用它对RestTemplate的请求拦截来实现对依赖服务的接口调用而RestTemplate已经实现了对HTTP请求的封装处理。Feign在此基础上做了进一步封装在Feign的实现下我们只需要创建一个接口并用注解的方式来配置它即可完成对服务提供方的接口绑定简化了在使用Ribbon时自行封装服务调用客户端的开发量。   简而言之Feign是一种声明式、模板化的HTTP客户端。 Feign的一个关键机制就是使用了动态代理。其具体调用过程 首先如果你对某个接口定义了FeignClient注解Feign就会针对这个接口创建一个动态代理接着你要是调用哪个接口本质就是会调用Feign创建的动态代理Feign的动态代理会根据你在接口上的RequestMapping等注解来动态构造出你要请求的服务的地址最后针对这个地址发起请求、解析响应。 Feign的优点 Feign采用的是基于接口的注解Feign整合了Ribbon具有负载均衡的能力整合了Hystrix具有熔断的能力。 Ribbon和Feign的区别 1、都是调用其他服务的但方式不同。 2、启动类注解不同Ribbon是RibbonClientfeign的是EnableFeignClients。 3、服务指定的位置不同Ribbon是在RibbonClient注解上声明Feign则是在定义抽象方法的接口中使用FeignClient声明。 4、调用方式不同Ribbon需要自己构建http请求模拟http请求然后使用RestTemplate发送给其他服务步骤相当繁琐。Feign需要将调用的方法定义成抽象方法即可。 1.1 Feign的基本使用 1、引入Eureka和Feign的相关依赖   示例 dependencygroupidorg.springfrarnework.cloud/groupidartifactidspring-cloud-starter-eureka/artifactid /dependency dependencygroupidorg.springframework.cloud/groupidartifactidspring-cloud-starter-feign/artifac七Id /dependency2、使用EnableFeignClients 注解   通过EnableFeignClients 注解开启 Spring Cloud Feign 的支待功能。示例 EnableFeignClients EnableDiscoveryClient SpringBootApplication public class ConsumerApplication {public static void main(String(J args) {SpringApplication.run(ConsurnerApplication.class, args);} }3、使用FeignClient注解   通过FeignClient 注解指定服务名来绑定服务 然后再使用 Spring MVC 的注解来绑定具体该服务提供的 REST 接口。示例 //这里服务名不区分大小写 所以使用 hello-service和HELLO-SERVICE 都是可以的 FeignClient(hello-service) public interface HelloService {RequestMapping(/hello)String hello(); }4、调用服务   创建一个 ConsumerController 来实现对 Feign 客户端的调用。 使用Autowired 直接注入上面定义的 HelloService 实例 并在 helloConsumer函数中调用这个绑定了 hello-service 服务接口的客户端来向该 服务发起/hello 接口的调用。 RestController public class ConsumerController {AutowiredHelloService helloService;RequestMapping(value /feign-consumer, method RequestMethod.GET)public String helloConsumer() {return helloService.hello();} }参数绑定   现实系统中的各种业务接口比较复杂 会在HTTP的各个位置传入各种不同类型的参数 并且在返回请求响应的时候也可能是一个复杂的对象结构。   我们把服务提供方的接口修改下 RequestMapping(value /hellol, method RequestMethod.GET)public String hello(RequestParam String name) {return Hello name;}RequestMapping(value /hello2, method RequestMethod.GET)public User hello(RequestHeader String name, RequestHeader Integer age) {return new User(name, age);}RequestMapping(value /hello3, method RequestMethod.POST)public String hello(RequestBody User user) {return Hello user.getNarne() , user. getAge();}服务提供方中的User类中包含name和age2个属性。   在服务消费方一般也要创建一样的实体类此处指User类。然后 在 HelloService 接口中增加对上述三个新增接口的绑定声明。示例 FeignClient(HELLO-SERVICE) public interface HelloService {RequestMapping(/hello)String hello();RequestMapping(value /hellol, method RequestMethod.GET)String hello(RequestParam(name) String name) ;RequestMapping(value /hello2, method Reques七Method.GET)User hello(RequestHeader(name) String name, RequestHeader(age) Integer age);RequestMapping(value /hello3, method Reques七Method.POST)String hello(RequestBody User user); }1.2 Feign的属性配置 1.2.1 Ribbon配置 由于SpringCloudFeign的客户端负载均衡是通过SpringCloudRibbon实现的所以我们可以直接通过配置Ribbon客户端的方式来自定义各个服务客户端调用的参数。 全局配置   全局配置的方法非常简单 我们可以直接使用ribbon.keyvalue的方式来设置ribbon的各项默认参数。 比如 修改默认的客户端调用超时时间 ribbon.ConnectTimeout500 ribbon.ReadTimeout5000指定服务配置   在使用SpringCloudFeign的时候针对各个服务客户端进行个性化配置的方式与使用SpringCloudRibbon时的配置方式是一样的 都采用client. Ribbon.keyvalue的格式进行设置。 此处client对应的客户端名称就是FeignClient注解中的name或value属性值。比如上个小节中对应的FeignClient(“HELLO-SERVICE”)注解对应的客户端我们可以设置如下属性 HELLO-SERVICE.ribbon.ConnectTimeout500 HELLO-SERVICE.ribbon.ReadTimeout2000 HELLO-SERVICE.ribbon.OkToRetryOnAllOperationstrue HELLO-SERVICE.ribbon.MaxAutoRetriesNextServer2 HELLO-SERVICE.ribbon.MaxAutoRetries1在配置Ribbon的超时时间时需要 让Hystrix的超时时间大于Ribbon的超时时间 否则Hystrix命令超时后 该命令直接熔断 重试机制就没有任何意义了。 1.2.2 Hystrix配置 默认情况下Spring CloudFeign会为将所有Feign客户端的方法都封装到Hystrix命令中进行服务保护。 全局配置   直接使用它的 默认配置前缀hystrix.command.default就可以进行设置 比如设置全局的超时时间 hystrix.command.default.execution.isolation.thread.timeoutinMilliseconds5000另外在对Hystrix进行配置之前我们需要确认feign.hystrix.enabled默认值为true参数没有被设置为false, 否则该参数设置会关闭 Feign客户端的Hystrix支持。 禁用Hystrix   在 Spring Cloud Feign 中 可以 通 过 feign.hystrix.enabledfalse来关闭Hystrix功能。 另外 如果不想全局地关闭Hystrix支持 而只想针对某个服务客户端关闭Hystrix 支待时 需要通过使用Scope (“prototype”)注解为指定的客户端配置Feign.Builder实例。   步骤1构建一 个关闭Hystrix的配置类。 Configuraion public class DisableHystrixConfiguration {BeanScope(proto七ype)public Feign.Builder feignBuilder() {return Feign.builder();} }步骤2在 FeignClient注解中通过configuration参数引入上面实现的配置。示例 FeignClient(nameHELLO - SERVICE, configuration DisableHystrixConfiguration.class) public in七erface HelloService { }指定命令配置   对于Hystrix命令的配置在实际应用时往往也会根据实际业务情况制定出不同的配置方案。 配置方法也跟传统的 Hystrix 命令的参数配置相似 采用hystrix.command.commandKey作为前缀。 commandKey默认情况下会采用Feign客户端中的方法名作为标识 所以 针对上一节介绍的尝试机制中对/hello接口的熔断超时时间的配置可以通过其方法名作为commandKey来进行配置。示例 hystrix.command.hello.execution.isolation.thread.timeoutinMilliseconds5000在使用指定命令配置的时候 需要注意 由于方法名很有可能重复 这个时候相同方法名的Hystrix配置会共用所以在进行方法定义与配置的时候需要做好一定的规划。当然也可以重写Feign.Builder的实现并在应用主类中创建它的实例来覆盖自动化配置的HystrixFeign.Builder实现。 服务降级配置   由于Spring Cloud Feign在定义服务客户端的时候与Spring Cloud和bbon有很大差别HystrixCommand定义被封装了起来 我们无法像之前介绍Spring CloudHystrix时 通过HystrixCommand注解的fallback参数那样来指定具体的服务降级处理方法。 但是 Spring Cloud Feign提供了另外一 种简单的定义方式。   步骤1服务降级逻辑的实现只需要为 Feign 客户端的定义接口编写一个具体的接口实现类。比如为 HelloService 接口实现一个服务降级类 HelloServiceFallback, 其中每个重写方法的实现逻辑都可以用来定义相应的服务降级逻辑。示例 Component public class HelloServiceFallback implements HelloService {Overridepublic String hello() {return error;}Overridepublic String hello(RequestParam(name) String name) {return error;}Overridepublic User hello(RequestHeader(name) S七ring name, RequestHeader(age} Integer age) {return new User(未知, 0);}Overridepublic String hello(RequestBody User user) {return error;} }步骤2在服务绑定接口 HelloService 中 通过 FeignClient 注解的 fallback 属性来指定对应的服务降级实现类。示例 FeignClient{narneHELLO-SERVICE, fallback HelloServiceFallback.class) public interface HelloService {RequestMapping(/hello)String hello();RequestMapping(value /hellol, method RequestMethod.GET)String hello(RequestParam(name) String name) ;RequestMapping(value /hello2, method RequestMethod.GET)User hello(Reques七Header(name) String name, RequestHeader(age) Integer age);RequestMapping(value /hello3, method RequestMethod.POST)String hello(RequestBody User user); }压缩配置   Spring Cloud Feign支持对请求与响应进行 GZIP 压缩以减少通信过程中的性能损耗。我们只需通过下面两个参数设置 就能开启请求与响应的压缩功能 feign.compression.request.enabledtrue feign.compression.response.enabledtrue同时 我们还能对请求压缩做一些更细致的设置 比如下面的配置内容指定了压缩的请求数据类型 并设置了请求压缩的大小下限 只有超过这个大小的请求才会对其进行压缩。示例 feign.compression.request.enabledtrue feign.compression.request.mime-typestext/xml,application/xml,application/json feign.compression.request.min-request-size2048二、网关服务Zuul Zuul包含了对请求的路由和过滤两个最主要的功能其中路由功能负责将外部请求转发到具体的微服务实例上是实现外部访问统一入口的基础而过滤器功能则负责对请求的处理过程进行干预是实现请求校验、服务聚合等功能的基础。   如果前端、移动端要调用后端系统统一从Zuul网关进入由Zuul网关转发请求给对应的服务。   Zuul和Eureka进行整合将Zuul自身注册为Eureka服务治理下的应用同时从Eureka中获得其他微服务的消息也即以后的访问微服务都是通过Zuul跳转后获得。   网关有的功能 Zuul基本都有最关键的就是路由和过滤器。Zuul的主要作用可以分为两类首先对于路由规则与服务实例的维护问题。其次对于类似签名校验、登录校验等问题。 1、路由   Spring Cloud Zuul通过与Spring Cloud Eureka进行整合 将自身注册为Eureka服务治理下的应用 同时从Eureka中获得了所有其他微服务的实例信息。 这样的设计非常巧妙地将服务治理体系中维护的实例信息利用起来 使得将维护服务实例的工作交给了服务治理框架自动完成 不再需要人工介入。   对于路由规则的维护 Zuul默认会将通过以服务名作为ContextPath的方式来创建路由映射大部分情况下 这样的默认设置已经可以实现我们大部分的路由需求 除了一些特殊情况比 如兼容一些老的URL)还需要做一些特别的配置 。2、过滤   对于类似签名校验、 登录校验在微服务架构中的冗余问题。 理论上来说 这些校验逻辑在本质上与微服务应用自身的业务并没有多大的关系 所以它们完全可以独立成一个单独的服务存在 只是它们被剥离和独立出来之后 并不是给各个微服务调用 而是在API网关服务上进行统一调用 来对微服务接口做前置过滤 以实现对微服务接口的拦截和校验 。   SpringCloudZuul提供了 一套过滤器机制 它可以很好地支持这样的任务。 开发者可以通过使用Zuul来创建各种校验过滤器然后指定哪些规则的请求需要执行校验逻辑只有通过校验的才会被路由到具体的微服务接口不然就返回错误提示。 通过这样的改造各个业务层的微服务应用就不再需要非业务性质的校验逻辑了 这使得我们的微服务应用可以更专注于业务逻辑的开发 同时微服务的自动化测试也变得更容易实现。 2.1 Zuul的基本使用 1、引入spring-cloud-starter-zuul依赖   示例 dependencygroupidorg.springframework.cloud/groupidartifactldspring-cloud-starter-zuul/artifactid /dependency2、使用EnableZuulProxy注解   一般在主类使用EnableZuulProxy注解开启Zuul的API网关服务功能。示例 EnableZuulProxy SpringCloudApplication public class Application {public static void main(String[] args) {new SpringApplicationBuilder(Application.class).web(true) .run(args);} }3、添加配置信息   在application.properties中配置Zuul应用的基础信息 如应用名、 服务端口号等。示例 spring.application.nameapi-gateway server.port5555完成上面的工作后 通过Zuul实现的API网关服务就构建完毕了。 2.1.1 请求路由 传统路由方式   使用Spring CloudZuul实现路由功能非常简单 只需要对 api-gateway服务增加一些关于路由 规则的配置 就能实现传统的路由转发功能。示例 zuul.routes.api-a-url.path/api-a-url/** zuul.routes.api-a-url.urlhttp://localhost:8080/该配置定义了发往API 网关服务的请求中 所有符合/api-a-url/**规则的访问都将被路 由转发到http://localhost:8080/地址上 也就是说 当我们访问http://localhost:5555/api-a-url/hello的时候 API网关服务会将该请求路由到http://localhost 8080/hello 提供的微服 务接口上。 其中 配置属性zuul.routes.api-a-url.path 中的api-a-url部分为路由的名字可以任意定义但是一组path和url 映射关系的路由 名要相同。 面向服务的路由   很显然传统路由的配置方式对于我们来说并不友好 它同样需要运维人员花费大量的时间来维护各个路由 path与url的关系 。 为了解决这个问题 SpringCloudZuul实现了与SpringCloudEureka的无缝整合 我们可以让路由的path不是映射具体的url, 而是让它映射到某个具体的服务 而具体的url则交给Eureka的服务发现机制去自动维护 我们称这类路由为面向服务的路由。 在Zuul中使用服务路由也同样简单 只需做下面这些配置。   在api-gateway的app巨ca巨on.proper巨es 配置文件中指定Eureka注册中心的位置 并且配置服务 路由。示例 zuul.routes.api-a.path/api-a/** zuul.routes.api-a.serviceIdhello-servicezuul.routes.api-b.path/api-b/** zuul.routes.api-b.serviceidfeign-consumereureka.client.serviceUrl.defaultZonehttp://localhost:llll/eureka/假如有两个微服务应用hello-service和feign-consumer, 在上面的配置中分别定义了 两个名为 api-a 和 api-b的路由来映射它们。 同时通过指定EurekaServer服务注册中心的位置 除了将自己注册成服务 之外 同时也让Zuul能够获取hello-service和feign-consumer 服务的实例清单以实现path映射服务 再从服务中挑选实例来进行请求转发的完整路由机制。   通过上面的搭建工作 我们已经可以通过服务网关来访问 hello-service 和feign-consumer这两个服务 了。 根据配置的映射关系 分别向网关发起下面这些请求。 http://localhost 5555/api-a/hello: 该 url符合/api-a/**规则 由api-a路由负责转发 该路由映射的serviceid为hello-service, 所以最终/hello请求会被发送到hello-service服务的 某个 实例上去。   http://localhost:5555/api-b/feign-consumer: 该url符合/api-b/**规则由 api-b路由负责转发该路由映射的service工d为feign-consumer所以最终/feign-consumer请求会被发送到feign-consumer服务的某个 实例上去。 通过面向服务的路由配置 方式 我们不需要再为各个路由维护微服务应用的具体 实例的位置 而是 通过简单的path与serviceld的映射组合使得维护工作变得非常简单。 这完全归功于Spring CloudEureka的服务发现机制它使得API网关服务可以自动化完成服务实例清单的维护完美地解决了对路由映射 实例的维护问题。 2.1.2 请求过滤 每个客户端用户请求微服务应用提供的接口时 它们的访问权限往往都有 一 定的限制系统并不会将所有的微服务接口都对它们开放。   较好的做法是通过前置的网关服务来完成这些非业务性质的校验。由于网关服务的加入 外部客户端访问我们的系统已经有了统一入口 既然这些校验与具体业务无关 那何不在请求到达的时候就完成校验和过滤 而不是转发后再过滤而导致更长的请求延迟。 同时 通过在网关中完成校验和过滤 微服务应用端就可以去除各种复杂的过滤器和拦截器了 这使得微服务应用接口的开发和测试复杂度也得到了相应降低。   Zuul 允许开发者在API网关上通过定义过滤器来实现对请求的拦截与过滤实现的方法非常简单我们只需要继承 ZuulFi巨er 抽象类并实现它定义的4个抽象函数就可以完成对请求的拦截和过滤。   比如要实现一个简单的 Zuul 过滤器 它实现了在请求被路由之前检查HttpServletReque中是否有 accessToken 参数 若有就进行路由 若没有就拒绝访问 返回 401 Unauthorized 错误。示例 public class AccessFilter extends ZuulFilter {private static Logger log LoggerFactory.getLogger(AccessFilter.class);Overridepublic String filterType() {return pre;}Overridepublic int filterOrder () {return 0;}Overridepublic boolean shouldFilter() {return true;}Overridepublic Object run(){RequestContext ctx RequestContext.getCurrentContext();HttpServletRequest request ctx.getRequest();log.info(send{} request to{}, request.getMethod(),request.getRequestURL().toString());Object accessToken request.getParameter(accessToken);if(accessToken null){log.warn(access token is empty);ctx.setSendZuulResponse(false);Ctx.setResponseStatusCode(401);return null;}log.info(access token ok);return null;} }上面的4个重写方法分别定义了如下内容 fillterType: 过滤器的类型 它决定过滤器在请求的哪个生命周期中执行。 这里定义为pre, 代表会在请求被路由之前执行。   filterOrder: 过滤器的执行顺序。 当请求在 一个阶段中存在多个过滤器时 需要根据该方法返回的值来依次执行。   shouldFilter: 判断该过滤器是否需要被执行。 这里我们直接返回了true, 因此该过滤器对所有请求都会生效。 实际运用中我们可以利用该函数来指定过滤器的有效范围。   run方法: 过滤器的具体逻辑。 这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求 不对其进行路由 然后通过 ctx.setResponseStatus­Code(401)设置了其返回的错误码 当然也可以进 一步优化我们的返回 比如 通过ctx.setResponseBody(body)对返回的body内容进行编辑等。 在实现了自定义过滤器之后 它并不会直接生效 我们还需要为其创建具体的Bean才能启动该过滤器 比如 在启动类中增加。示例 EnableZuulProxy SpringCloudApplication public class Application {public static void main(String[] args) {new SpringApplicationBuilder(Application.class) .web(true) .run(args);}Beanpublic AccessFilter accessFilter() {return new AccessFilter();} }通过上面的例子可以将网关服务的功能可以总结为4条 作为系统的统一入口屏蔽了系统内部各个微服务的细节。 与服务治理框架相结合实现自动化的服务示例维护以及负载均衡的路由转发。实现接口权限检验与微服务业务逻辑的解耦。通过服务网关中的过滤器在各生命周期中去校验请求的内容将原本在对外服务层做的检验前移保证了微服务的无状态行同时降低了微服务的测试难度让服务本身更集中关注业务逻辑的处理。 2.2 路由详解 2.2.1 传统路由配置 传统路由配置方式就是在不依赖千服务发现机制的情况下 通过在配置文件中具体指定每个 路由表达式与服务实例的映射关系来实现API网关对外部请求的路由。   没有Eureka等服务治理框架 的帮助我们需要 根据服务实例的数量采用不同方式 的配置来实现路由规则具体可分为单实例配置、多实例配置。 单实例配置   通过zuul.routes.route.path与zuul.routes.route.url参数对的方式进行配置。示例 zuul.routes.user-service.path/user-service/** zuul.routes.user-service.urlhttp://localhost:8080/该配 置实 现了对符合/user-service/** 规则的请求路径转发到 http://localhost:8080/ 地址的路由规则。 比如当有一个请求http://localhost:5555/user-service/hello被发送到API网关上由千/user-service/hello 能够被上述配置 的 path 规则匹配所 以 API网关 会转发请求到http://localhost:8080/hello士也扛上。 多实例配置   通过zuul.routes.route.path与zuul.routes.route.serviceId参数对的方式进行配置。示例 zuul.routes.user-service.path/user-service/** zuul.routes.user-service.serviceIduser-service ribbon.eureka.enabledfalse user-service.ribbon.listOfServershttp://localhost:8080/,http://localhost:8081/该配 置实 现了对 符合 /user-service/** 规则 的 请 求 路 径 转 发 到http://localhost:8080/和http://localhost:8081/两个实例地址的路由规则。 它的配置 方式与服务 路由的配置 方式 一 样都采用了zuul.routes.route.path与zuul.routes.route.serviceId参数对的映射方式只是这 里的 serviceid 是由用户手工命名 的服 务 名称 配合ribbon.listOfServers 参数实现服务与实例的维护。由于存在多个实例API网关在进行路由转发时需要实现负载均衡策略于是这里还需要Spring Cloud Ribbon的配合。   由于在Spring Cloud Zuul中自带了对Ribbon的依赖 所以我们只需做一些简单的配置即可比如上面示例中关 于Ribbon的2个配置 ribbon.eureka.enabled: 由于zuul.routes.route.serviceId指定的是服务名称默认清况下Ribbon会根据服务发现机制来获取配置服务名对应的实例清单。 但是该示例并没有整合类似Eureka之类的服务治理框架所以需要将该参数设置为false, 否则配置 的serviceId获取不到对应实例的清单。   user-service.ribbon.listOfServers: 该参数内容与zuul.routes.route.serviceId的配置相对应 开头的 user-service 对应 了serviceId的值 这两个参数的配置相当于在该应用内部手工维护了服务与实例的 对应关系。 不论是单实例还是多实例的配置方式 我们都需要为每 一对映射关系指定 一个名称也就是上面配置中的route, 每 一个route对应了 一条路由规则。 每条路由规则都需要通 过path属性来定义 一 个用来匹配客户端请求的路径表达 式 并通过url 或serviceId属性来指定请求表达式映射具体实例地址或服务名。 2.2.2 服务路由配置 Spring Cloud Zuul通过与Spring Cloud Eureka的整合 实现了对服务实例的 自动化维护 所以 在使用服务路由配置的时候 我们不需要向传统路由配置方式那样为serviceId指定具体的服务实例地址只需要通过zuul.routes.route.path与zuul.routes.route.serviceId参数对的方式进行配置即可。示例 zuul.routes.user-service.path/user-service/** zuul.routes.user-service.serviceiduser-service它实现了 对符合 / user-service/**规则的请求路径转发到名为user-service的服务实例上去的路由规则。   对于面向服务的路由配置 除了使用path与serviceId映射的配置方式 之外 还有 一种更简洁的配置方式zuul.routes.serviceIdpath, 其中serviceId用来指定路由的具体服务名path用来配置匹配的请求表达式。比如下面的例子 它的路由规则等价于上面通过path与serviceId组合使用的配置方式。 zuul.routes.user-service/user-service/**我们可以直接将API网关也看作Eureka服务治理下的 一个普通微服务应用。它除了会将自己注册到Eureka服务注册中心上之外也会从注册中心获取所有服务以及它们的实例清单。所以在Eureka的帮助下API网关服务本身就已经维护了系统中所有 serviceId与实例地址的映射关系。当有外部请求到达 API 网关的时候根据 请求的 URL 路径找到最佳匹配的path规则 API 网关就可以知道要将该请求路由到哪个具体的 service Id上去。 由于在 API 网关中已经知道serviceid对应服务实例的地址清单 那么只需要通过Ribbon的负载均衡策略 直接在这些清单中选择一个具体的实例进行转发就能完成路由工作了。 2.2.3 服务路由的默认规则 通过Eureka与Zuul的整合已经为我们省去了维护服务实例清单的大量配置工作剩下只需要再维护请求路径的匹配表达式与服务名的映射关系即可。 在实际的运用过程中会发现 大部分的路由配置规则几乎都会采用服务名作为外部请求的前缀 比如下面的例 子 其中 path路径的前缀使用了user-service, 而对 应的 服 务 名称也是user-service 。 zuul.routes.user-service.path/user-service/** zuul.routes.user-service.serviceIduser-service当我们为Spring Cloud Zuul构建的 API 网关服务引入Spring Cloud Eureka之后 它为Eureka中的每个服务都自动创建一个默认路由规则 这些默认规则的path会使用serviceId配置的服务名作为请求前缀 就如上面的例子那样。   由于默认情况下所有Eureka上的服务都会被 Zuul自动地创建映射关系来进行路由这会使得一 些我们不希望对外开放的服务也可能被外部访问到。 这个时候 我们可以使用zuul.ignored-services参数来设置一个服务名匹配表达式来定义不自动创建路由的规则。 Zuul在自动创建服务路由的时候会根据该表达式来进行判断 如果服务名匹配表达式 那么 Zuul 将跳过 该 服务 不为 其 创建 路 由 规 则 。 比如 设置 为zuul.ignored-services*的时候Zuul将对所有的服务都不自动创建路由规则此时就需要逐条添加路由映射规则。 2.2.4 自定义路由映射规则 在构建微服务系统进行业务逻辑开发的时候 为了兼容外部不同版本的客户端程序尽量不强迫用户升级客户端 一般都会采用开闭原则来进行设计与开发。 这使得系统在迭代过程中 有时候会需要我们为一组互相配合的微服务定义一个版本标识来方便管理它们的版本关系根据这个标识我们可以很容易地知道这些服务需要一起启动并配合使用。比如可以 采 用 类似 这样 的 命 名 userservice-v1 、 userservice-v2 、orderservice-v1、 orderservice-v2。   默认情况下Zuul自动为服务创建的路由表达式会采用服务名作为前缀 比如针对上面的userservice-v1和userservice-v2,它会产生/userservice-vl 和/userservice-v2两个路径表达式来映射但是这样生 成出来的表达式规则较为单一 不利于通过路径规则来进行管理。 通常的做法是为这些不同版本的微 服 务 应 用 生 成以版本代号作 为 路 由 前 缀 定 义 的 路 由 规 则 比如/vl/userservice/ 。这时候 通过这样具有版本号前缀的 URL 路径 我们就可以很容易地通过路径表达式来归类和管理这些具有版本信息的微服务。   针对上面所述的需求如果我们的各个微服务应用都遵循了类似userservice-v1这样的命名规则 通过分隔的规范来定义服务名和服务版本标识 的话那么我们可以使用Zuul中自定义服务与路由映射关系的功能来实现为符合上述规则的微服务自动化地创建类似/vl/userservice/** 的路由匹配规则。 实现步骤非常简单 只需在 API 网关程序中 增加如下Bean即可 Beanpublic PatternServiceRouteMapper serviceRouteMapper() {return new PatternServiceRouteMapper((?name^.)-(?versionv.$),${version}/${name});}PatternServiceRouteMapper对象可以让开发者通过正则表达式来自定义服务与路由映射的生成关系。 其中构造函数的第一个参数是用来匹配服务名称是否符合该自定义规则的正则表达式 而第二个参数则是定义根据服务名中定义的内容转换出的路径表达式规则。当开发者在 API 网关中定义了PatternServiceRouteMapper 实现之后只要符合第一个参数定义规则的服务名 都会优先使用该实现构建出的路径表达式如果没有匹配上的服务则还是会使用默认的路由映射规则即采用完整服务名作为前缀的路径表达式。 2.2.5 路径匹配 在Zuul中 路由匹配的路径表达式采用了Ant风格定义。Ant风格的路径表达式使用起来非常简单 它一共有下面这三种通配符 通配符说明匹配任意单个字符*匹配任意单个字符**匹配任意数址的字符 支待多级目录 示例 URL路径说明/user-service/?可以匹 配/user-service/之后拼接一个任意字符的路径 比如/user-service/a、 /user-service/b、 /user-service/c user-service/*可以匹 配 /user-service/ 之后 拼 接任意字 符的路径 比如/user-service/a 、 /user-service/aaa 、 /user-service/bbb。 但是它无法匹配/user-service/a/b user-service/**可以匹 配/user-service/*包含的内容之外 还可以匹 配形如/user-service/a/b的多级目录路径 URL路径被多个路由规则匹配上怎么办   使用通配符的时候经常会碰到这样的问题 一个 URL 路径可能会被多个不同路由的表达式匹配上。 比如 有这样一 个场景 我们在系统建设的一 开始实现了user-service 服务 并且配置了如下路由规则 zuul.routes.user-service.path/user-service/** zuul.routes.user-service.serviceIduser-service随着版本的迭代 我们对 user-service 服务做了 一 些功能拆分 将原属于user-service 服务的某些功能拆分到了另外一个全新的服务 user-service-ext 中去而这些拆分的外部调用 URL 路径希望能够符合规则/user-service/ext/**, 这个时候我们需要就在配置文件中增加 一个路由规则 完整配置示例 zuul.routes. user-service.path/user-service/** zuul.routes.user-service.serviceIduser-service zuul.routes.user-service-ext.path/user-service/ext/** zuul.routes.user-service-ext.serviceIduser-service-ext调用 user-service-ex七服 务的 URL 路径实 际上会同时被 /user­-service/**和/user-service/ext/**两个表达式所匹配。 在逻辑上 API 网关服务需要优先选择/user-service/ext/**路由然后再匹配/user-service/**路由才能实现上述需求。但是如果使用上面的配置方式实际上是无法保证这样的路由优先顺序的。   由于properties的配置内容无法保证有序所以当出现这种情况的时候 为了保证路由的优先顺序 我们需要使用YAML文件来配置 以实现有序的路由规则。示例 zuul:routes:user-service-ext:path: /user-service/ext/**serviceId: user-service-extuser-service:path: /user-service/**serviceId: user-service忽略表达式   Zuul提供 了 一 个忽 略表达 式参 数zuul.ignored-patterns。该参数可以用来设置不希望被 API 网关进行路由的 URL 表达式。   比如不希望/hello 接口被路由可以这样设置 zuul.ignored-patterns/**/hello/** zuul.routes.api-a.path/api-a/** zuul.routes.api-a.serviceIdhello-service此时通 过网关来访间 hello-service 的 /hello 接口 http://localhost:5555/api-a/hello 。虽然该访问路 径完全符 合 path 参数 定 义 的/api-a/**规则但是由于该路径符合 zuul.ignored-patterns 参数定义的规则所以不会被正确路由。   zuul.ignored-patterns参数在使用时还需要注意它的范围并不是对某个路由 而是对所有路由。 所以在设置的时候需要全面考虑 URL 规则 防止忽略了不该被忽略的 URL 路径。 2.2.6 路由前缀 为了方便全局地为路由规则增加前缀信息Zuul提供了zuul.prefix参数来进行设置。比如希望为网关上的路由规则都增加/api 前缀那么我们可以在配置文件中增加配置zuul.prefix/api。另外 对于代理前缀会默认从路径中移除我们可以通过设置zuul.stripPrefixfalse 来关闭该移除代理前缀的动作也可以通过 zuul.routes.route.strip-prefixtrue来对指定路由关闭移除代理前缀的动作。 zuul.prefix参数BUG   假设我们设置 zuul.prefix/api, 当路由规则的 path表达式以/api开头的时候将会产生错误的映射关系。示例 zuul.routes.api-a.path/api/a/** zuul.routes.api-a.serviceIdhello-servicezuul.routes.api-b.path/api-b/** zuul.routes.api-b.serviceIdhello-servicezuul.routes.api-c.path/ccc/** zuul.routes.api-c.serviceIdhello-service这里配置了三个路由关系 /ap订a/** 、 /api-b/** 、 /eccl**, 这三个路径规则都将被路由到 hello-service 服务上去。当我们没有设置 zuul.prefix/api 的时候一切运作正常。 但是在增加了 zuul.prefix/api 配置之后 会得到下面这样的路由关系   从日志信息中我们可以看到以/api 开头的路由规则解析除了两个看似就有问题的映射URL, 我们可以通过该输出的URL来访问 实际是路由不到正确的服务接口。 只有非/api 开头的路由规则/eccl**能够正常路由所以务必避免让路由表达式的起始字符串与 zuul.prefix 参数相同。 2.2.7 Cookie与头信息 默认情况下 Spring Cloud Zuul在请求路由时 会过滤掉HTTP请求头信息中的 一些敏感信息 防止它们被传递到下游的外部服 务器。 默认的敏感 头信 息 通 过zuul.sensitiveHeaders参数定义包括Cookie、Se七-Cookie、Authorization三个属性。所以 我们在开发Web项目时常用的Cookie在 SpringCloud Zuul网关中默认是不会传递的 这就会引发一个常见的问题 如果我们要将使用了Spring Security、 Shiro 等安全框架构建的Web应用通过SpringCloud Zuul构建的网关来进行路由时由千Cook迳信息无法传递 我们的Web应用将无法实现登录和鉴权。   此时可以通过指定路由的参数来配置2种方法示例 方法一对指定路由开启自定义敏感头 zuul.routes.router.customSensitiveHeaderstrue 方法二将指定路由的敏感头设置为空 zuul.routes.router.sensitiveHeaders这两种方法 仅对指定的Web应用开启对敏感信息的传递影响范围小 不至于引起其他服务的信息泄露问题。 重定向问题   在解决了Cookie问题之后 我们已经能够通过网关来访问并登录到我们的Web 应用了。 但是 这个时候又会发现另外一个问题 虽然可以通过网关访问登录页面并发起登录请求 但是登录成功之后 我们跳转到的页面URL却是 具体Web应用实例的地址 而不是通过网关的路由地址。 这个问题非常严重 因为使用API网关的一个重要原因就是要将网关作为统一入口 从而不暴露所有的内部服务细节。   引起问题的大致原因是由于SpringSecurity或Shiro在登录完成之后通过重定向的方式跳转到登录后的页面 此时登录后的请求结果状态码为302, 请求响应头信息中的 Location指向了具体的服务实例地址 而请求头信息中的Host也指向 了具体的服务实例 IP地址和端口。 所以 该问题的根本原因在于Spring Cloud Zuul在路由请求时并没有将最初的Host信息设置正确。   针对 这个问题目前在 spring-cloud-netflix-core-1.2.x版本的 Zuul中增加了一个参数配置能够使得网关在进行路由转发前为请求设置Host头信息以标识最初的服务端请求地址。 具体配置 zuul.addHostHeadertrue2.2.8 Hystrix和Ribbon支持 spring-cloud-starter-zuul自身就包含了对 spring-cloud-starter-hystrix 和spring-cloud-starter­-ribbon模块的依赖 所以 Zuul天生就拥有线程隔离和断路器的自我保护功能 以及 对服务调用的客户端负载均衡功能。   但是当使用path与url的映射关系来配置路由规则的时候 对于路由转发的请求不会采用HystrixCommand来包装 所以 这类路由请求没有线程隔离和断路器的保护并且也不会有负载均衡的能力。因此我们在使用Zuul的时候尽量使用path和serviceId的组合来进行配置 这样不仅可以保证API网关的健壮和稳定也能用到Ribbon的客户端负载均衡功能。   在使用Zuul搭建API网关的时候可以通过Hystrix和伈bbon的参数来调整路由请求的各种超时时间等配置。   hystrix.command.default.execution.isolation.thread.timeoutinMilliseconds: 该参 数可以用来 设 置API 网关中路由 转 发 请 求的HystrixCommand 执行超时时间 单位为毫秒。 当路由转发请求的命令执行时间超过该配置值之后Hystrix会将该执行命令标记为TIMEOUT并抛出异常Zuul会对该异常进行处理并返回如下JSON信息给外部调用方 {timestamp: 1481350975323,status: 500,error: Internal Server Error,exception: com.netflix.zuul.exception.ZuulException,message: TIMEOUT }ribbon.ConnectTimeout: 该参数用来设置路由转发请求的时候 创建请求连接的超时时间。当ribbon.ConnectTimeout的配置值小于hystrix.command.default.execution.isolation.thread.timeoutlnMilliseconds 配置值的时候 若出现路由请求出现连接超时 会自动进行重试路由请求 如果重试依然失败Zuul会返回如下JSON信息 {timestamp: 1481352582852,status: 500,error: Internal Server Error,exception: com.netflix.zuul.exception.ZuulException,message: NUMBEROF RETRIES NEXTSERVER EXCEEDED }如果 ribbon.ConnectTimeout的配置值大于hystrix.command.defaultexecution.isolation.thread.timeout工nMilliseconds配置值的时候当出现路由请求连接超时时 由于此时对于路由转发的请求命令已经超时 所以不会进行重试路由请求 而是直接按请求命令超时处理 返回TIMEOUT的错误信息。   ribbon.ReadTimeout: 该参数用来设置路由转发请求的超时时间。 它的处理与ribbon.ConnectTimeout类似 只是它的超时是对请求连接建立之后的处理时间。 当ribbon.ReadTimeout的配置值小于 hystrix.command.default.execution.isolation.thread.timeoutinMilliseconds配置值的时候若路由请求的处理时间超过该配置值且依赖服务的请求还未响应的时候 会自动进行重 试 路 由 请 求 。 如果 重 试后依然没有获 得请 求 响 应 Zuul会返 回NUMBEROF_RETRIES_NEXTSERVER_EXCEEDED 错误。如果ribbon.ReadTimeout 的配 置 值大于 hystrix.command.defaul七.execution.isolation.thread.timeoutinMilliseconds配置值若路由请求的处理时间超过该配置值且依赖服务的请求还未响应时不会进行重试路由请求而是直接按请求命令超时处理返回TIMEOUT 的错误信息。 在使用Zuul的服务路由时如果路由转发请求发生超时连接超时或处理超时只要超时时间的设置小于Hystrix的命令超时时间那么它就会自动发起重试。 但是在有些情况下我们可能需要关闭该 重试机制那么可以通过下面的两个参数来进行设置 zuul.retryablefalse zuul.routes.route.retryablefalsezuul.retryable用来全局关闭重试机制而zuul.routes.route.retryable false则是指定路由关闭重试机制。 2.3 过滤器详解 Zuul的路由功能在运行时它的路由映射和请求转发都是由几个不同的过滤器完成的。 其中路由映射主要通过pre类型的过滤器完成它将请求路径与配置的路由规则进行匹配以找到需要转发的目标地址而请求转发的部分则是由route类型的过滤器来完成对pre类型过滤器获得的路由地址进行转发。 所以过滤器可以说是Zuul实现API网关功能最为核心的部件每一个进入Zuul的HTTP请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。   Zuul中实现的过滤器必须包含4个基本特征 过滤类型、 执行顺序、执行条件、 具体操作。 这其实就是ZuulFilter接口中定义的4个方法 String filterType(); int filterOrder(); boolean shouldFilter(); Object run();filterType: 该函数需要返回 一个字符串来代表过滤器的类型 而这个类型就是在HTTP请求过程中定义的各个阶段。在 Zuul 中默认定义了 4 种不同生命周期的过滤器类型 pre可以在请求被路由之前调用 routing在路由请求时被调用 post在routing和error过滤器之后被调用 error处理请求发生错误时被调用。 filterOrder: 通过 int 值来定义过滤器的执行顺序 数值越小优先级越高。   shouldFilter: 返回一个 boolean 值来判断该过滤器是否要执行。 我们可以通过此方法来指定过滤器的有效范围。   run方法: 过滤器的具体逻辑。 在该函数中 我们可以实现自定义的过滤逻辑 来确定是否要拦截当前的请求 不对其进行后续的路由 或是在请求路由返回结果之后对处理结果做一 些加工等。 2.3.1 请求的生命周期 Zuul中4种不同类型的过滤器他们覆盖了一个外部HTTP请求到达API网关直到返回请求结果的全部生命周期。   当外部HTTP请求到达API网关服务的时候首先他会进入第一个阶段pre在这里它会被pre类型的过滤器进行处理该类型过滤器的主要目的是在进行请求路由之前做一些前置贾工比如请求的校验等。   在完成pre类型的过滤器处理之后请求进入第二个阶段routing也就是之前说的路由请求转发阶段请求将会被routing类型过滤器处理。这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程当服务实例将请求结果都返回之后routing阶段完成请求进入第三个阶段post。   此时请求将会被post类型的过滤器处理这些过滤器在处理的时候不仅可以获取到请求信息还能获取到服务实例的返回信息所以在post类型的过滤器中我们可以对处理结果进行一些加工或转换等内容。   还有一个特殊的阶段error该阶段只有上述三个阶段发生异常的时候才会触发但是它最后流向还是post类型的过滤器因为它需要通过post过滤器将最终结果返回给请求客户端。 2.3.2 核心过滤器 在默认启用 的过滤器中包含三种不同生命周期的过滤器 这些过滤器都非常重要。 默认启用的pre过滤器   ServletDetectionFilter执行顺序为-3是最先被执行的过滤器。   Servlet30WrapperFilter执行顺序为-2是第二个执行的过滤器。   FromBodyWrapperFilter执行顺序为-1是第三个执行的过滤器。   DebugFilter执行顺序为1是第四个执行的过滤器。   PreDecorationFilter执行顺序为5是pre阶段最后被执行的过滤器。默认启用的route过滤器   RibbonRoutingFilter执行顺序为10是route阶段第一个执行的过滤器。该过滤器只对请求上下文中存在serviceId参数的请求进行处理即只对通过serviceId配置路由规则的请求生效。   SimpleHostRoutingFilter执行顺序为100是route阶段第二个执行的过滤器。该过滤器只对请求上下文中存在routeHost参数的请求进行处理即只对通过url配置路由规则的请求生效。   SendForwardFilter执行顺序为500是route阶段第三个执行的过滤器。该过滤器只对请求上下文中存在forward.to参数的请求进行处理即用来处理路由规则中forward本地跳转配置。默认启用的post过滤器   SendErrorFilter执行顺序为0是post阶段第一个执行的过滤器。给过滤器仅在请求上下文中包含error.status_code参数由之前执行的过滤器设置的错误编码并且还没有被该过滤器处理过的时候执行。   SendResponseFilter执行吮吸是1000是post阶段最后执行的过滤器。该过滤器会检查请求上下文中是否包含请求响应相关的头信息、响应数据流或是响应体只有在包含他们其中一个时执行处理逻辑。该过滤器的处理逻辑就是利用请求上下文的响应信息来组织需要发送回客户端的响应内容。 2.3.3 异常处理 对自定义过滤器中处理异常的两种基本方法一种是通过在各个阶段的过滤器中增加try-catch块实现过滤器内部的异常处理另一种是利用error类型过滤器的生命周期特性集中处理pre、route、post阶段抛出的异常信息。 第2种方法由于在请求生命周期的 pre、route 、 post 三个阶段中有异常抛出的时候都会进入 error 阶段的处理 所以可以通过创建一个 error 类型的过滤器来捕获这些异常信息并根据这些异常信息在请求上下文中注入需要返回给客户端的错误描述。 error类型过滤器示例 public class ErrorFilter extends ZuulFilter {Logger log LoggerFactory.getLogger(ErrorFilter.class);Overridepublic String filterType() {return error;}Overridepublic int filterOrder() {return 10;}Overridepublic boolean shouldFilter() {return true;}Overridepublic Object run() {RequestContext ctx RequestContext.getCurrentContext();Throwable throwable ctx.getThrowable();log.error(this is a ErrorFilter : {) , throwable.getCause().getMessage());ctx.set(error.status_code, H七tpServletResponse.SC_INTERNAL_SERVER—ERROR);Ctx.set(error.exception, throwable.getCause());return null;} }2.3.4 禁用过滤器 不过是核心过滤器还是自定义过滤器只要在API网关应用中为它们创建了实例默认情况下它们都是默认启用状态的。   通过重写过滤器的shouldFilter逻辑 让它返回false,就可以达到禁用该过滤器的目的。   实际上 在Zuul中特别提供了一个参数来禁用指定的 过滤器 该参数的配置格式 zuul.SimpleClassName.filterType.disabletrueSimpleClassName代表过滤器的类名。filterType即pre/routing/post/error。示例 zuul.AccessFilter.pre.disabletrue2.3.5 用过滤器限流 比如用令牌桶方式来实现限流。   令牌桶限流有个桶如果里面没有满那么就会以一定 固定的速率 会往里面放令牌一个请求过来首先要从桶中获取令牌如果没有获取到那么这个请求就拒绝如果获取到那么就放行。   用Zuul的前置过滤器来实现一下令牌桶限流 Component Slf4j public class RouteFilter extends ZuulFilter {// 定义一个令牌桶每秒产生2个令牌即每秒最多处理2个请求private static final RateLimiter RATE_LIMITER RateLimiter.create(2);Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}Overridepublic int filterOrder() {return -5;}Overridepublic Object run() throws ZuulException {log.info(放行);return null;}Overridepublic boolean shouldFilter() {RequestContext context RequestContext.getCurrentContext();if(!RATE_LIMITER.tryAcquire()) {log.warn(访问量超载);// 指定当前请求未通过过滤context.setSendZuulResponse(false);// 向客户端返回响应码429请求数量过多context.setResponseStatusCode(429);return false;}return true;} }三、动态配置Apollo 在Spring Cloud框架中有Spring Cloud Config可以实现动态配置的功能。不过Apollo也很好用因此此处介绍一下APollo的使用。   Apollo阿波罗是携程框架部门研发的开源配置管理中心能够集中化管理应用不同环境、不同集群的配置配置修改后能够实时推送到应用端并且具备规范的权限、流程治理等特性。   Apollo 的基础模型 用户在配置中心对配置进行修改并发布   配置中心通知Apollo客户端有配置更新   Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用。 Apollo 客户端会把从服务端获取到的配置在本地文件系统缓存一份用于在遇到服务不可用或网络不通的时候依然能从本地恢复配置不影响应用正常运行。 3.1 Apollo的四个维度 Apollo支持4个维度管理Key-Value格式的配置application (应用)、environment (环境)、cluster (集群)、namespace (命名空间)。 application   Apollo 客户端在运行时需要知道当前应用是谁从而可以根据不同的应用来获取对应应用的配置。   每个应用都需要有唯一的身份标识可以在代码中配置 app.id 参数来标识当前应用Apollo 会根据此指来辨别当前应用。environment   在实际开发中我们的应用经常要部署在不同的环境中一般情况下分为开发、测试、生产等等不同环境不同环境中的配置也是不同的在 Apollo 中默认提供了四种环境 FATFeature Acceptance Test功能测试环境 UATUser Acceptance Test集成测试环境 DEVDevelop开发环境 PROProduce生产环境 在程序中如果想指定使用哪个环境可以配置变量 env 的值为对应环境名称即可。 cluster   一个应用下不同实例的分组比如典型的可以按地区划分把上海机房的应用实例分为一个集群把北京机房的应用实例分为另一个集群。对不同的集群同一个配置可以有不一样的值。namespace   一个应用中不同配置的分组可以简单地把 namespace 类比为不同的配置文件不同类型的配置存放在不同的文件中。   Namespace 分为两种权限分别为 public公共的 public权限的 Namespace能被任何应用获取。   private私有的 只能被所属的应用获取到。一个应用尝试获取其它应用 private 的 NamespaceApollo 会报 404 异常。 Namespace 分为三种类型 私有类型 私有类型的 Namespace 具有 private 权限。例如 application Namespace 为私有类型。   公共类型 公共类型的 Namespace 具有 public 权限。公共类型的N amespace 相当于游离于应用之外的配置且通过 Namespace 的名称去标识公共 Namespace所以公共的 Namespace 的名称必须全局唯一。   关联类型继承类型 关联类型又可称为继承类型关联类型具有 private 权限。关联类型的 Namespace 继承于公共类型的 Namespace将里面的配置全部继承并且可以用于覆盖公共 Namespace 的某些配置。 3.2 Apollo的使用 3.2.1 页面操作 比如要新增一个配置参数。示例   创建完成后可以看到配置管理节目新增了一条配置   点击“发布”后就可以在Web应用中使用该参数。 3.2.2 Web中使用 1、引入相关jar   示例 dependencygroupIdcom.ctrip.framework.apollo/groupIdartifactIdapollo-client/artifactIdversion1.4.0/version/dependency2、在配置文件中添加Apollo配置的相关参数   Apollo参数的含义 apollo.metaApollo 配置中心地址。   apollo.cluster 指定使用某个集群下的配置。   apollo.bootstrap.enabled 是否开启 Apollo。   apollo.bootstrap.namespaces 指定使用哪个 Namespace 的配置默认 application。   apollo.cacheDir/opt/data/some-cache-dir 为了防止配置中心无法连接等问题Apollo 会自动将配置本地缓存一份。   apollo.autoUpdateInjectedSpringProperties Spring应用通常会使用 Placeholder 来注入配置如${someKey:someDefaultValue}冒号前面的是 key冒号后面的是默认值。如果想关闭 placeholder 在运行时自动更新功能可以设置为 false。   apollo.bootstrap.eagerLoad.enabled 将 Apollo 加载提到初始化日志系统之前如果设置为 false那么将打印出 Apollo 的日志信息但是由于打印 Apollo 日志信息需要日志先启动启动后无法对日志配置进行修改所以 Apollo 不能管理应用的日志配置如果设置为 true那么 Apollo 可以管理日志的配置但是不能打印出 Apollo 的日志信息。 Apollo参数配置示例 #应用配置 server:port: 8080 spring:application:name: apollo-demo#Apollo 配置 app:id: apollo-test #应用ID apollo:cacheDir: /opt/data/ #配置本地配置缓存目录cluster: default #指定使用哪个集群的配置meta: http://192.168.2.11:30002 #DEV环境配置中心地址autoUpdateInjectedSpringProperties: true #是否开启 Spring 参数自动更新bootstrap: enabled: true #是否开启 Apollonamespaces: application #设置 NamespaceeagerLoad:enabled: false #将 Apollo 加载提到初始化日志系统之前 3、在Java代码中使用Apollo上配置的属性   使用Value主机即可获取。示例 Value(${test:默认值})private String test;四、Spring Cloud相关问题 4.1 SpringBoot和SpringCloud的区别 SpringBoot专注于快速方便的开发单个个体微服务。   SpringCloud是关注全局的微服务协调整理治理框架它将SpringBoot开发的一个个单体微服务整合并管理起来为各个微服务之间提供配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务。   SpringBoot可以离开SpringCloud独立使用开发项目 但是SpringCloud离不开SpringBoot 属于依赖的关系。   SpringBoot专注于快速、方便的开发单个微服务个体SpringCloud关注全局的服务治理框架。 4.2 Spring Cloud断路器的作用 当一个服务调用另一个服务由于网络原因或自身原因出现问题调用者就会等待被调用者的响应 当更多的服务请求到这些资源导致更多的请求等待发生连锁效应雪崩效应。   断路器有不同的状态   完全打开状态一段时间内达到一定的次数无法调用并且多次监测没有恢复的迹象断路器完全打开那么下次请求就不会请求到该服务。   半开短时间内有恢复迹象断路器会将部分请求发给该服务正常调用时断路器关闭。   关闭当服务一直处于正常状态能正常调用。 4.3 什么是Spring Cloud Gateway Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架取代Zuul网关。网关作为流量的在微服务系统中有着非常作用网关常见的功能有路由转发、权限校验、限流控制等作用。   使用了一个RouteLocatorBuilder的bean去创建路由除了创建路由RouteLocatorBuilder可以让你添加各种predicates和filterspredicates断言的意思顾名思义就是根据具体的请求的规则由具体的route去处理filters是各种过滤器用来对请求做各种判断和修改。 4.4 Spring Cloud如何实现服务的注册 服务发布时指定对应的服务名将服务注册到注册中心(eureka zookeeper)。注册中心加EnableEurekaServer服务用EnableDiscoveryClient然后用Ribbon或Feign进行服务直接的调用发现。 4.5 REST和RPC对比 1、RPC主要的缺陷是服务提供方和调用方式之间的依赖太强需要对每一个微服务进行接口的定义并通过持续继承发布严格版本控制才不会出现冲突。   2、REST是轻量级的接口服务的提供和调用不存在代码之间的耦合只需要一个约定进行规范。 4.6 说说RPC的实现原理 首先需要有处理网络连接通讯的模块负责连接建立、管理和消息的传输。其次需要有编解码的模块因为网络通讯都是传输的字节码需要将我们使用的对象序列化和反序列化。剩下的就是客户端和服务器端的部分服务器端暴露要开放的服务接口客户调用服务接口的一个代理实现这个代理实现负责收集数据、编码并传输给服务器然后等待结果返回。 4.7 接口限流方案 限制总并发数比如数据库连接池、线程池。限制瞬时并发数如 nginx 的 limit_conn 模块用来限制 瞬时并发连接数。限制时间窗口内的平均速率如 Guava 的 RateLimiter 、 nginx 的 limit_req 模块限制每秒的平均速率。限制远程接口调用速率。限制MQ的消费速率。可以根据网络连接数、网络流量、 CPU 或 内存负载 等来限流。
http://www.hkea.cn/news/14285149/

相关文章:

  • 龙岗网站建设icxun玉田网站制作
  • 免费建设小说网站四川省建筑人才网
  • 英文外贸网站源码网络营销大师排行榜
  • 如何用ps做网站首页南召seo快速排名价格
  • 网站设计英文报告企业营销策划心得体会
  • 嘉兴网站建设策划方案wordpress menu背景
  • 手机网站 微信怎么做网站搜索
  • 运维网站建设wordpress 文档预览
  • php网站建设入门教程前端网站论文
  • 科技企业网站源码婚庆公司名字大全
  • 酒店网站设计的目的和意义用dw做购票网站模板
  • 怎么进入公司网站seo营销的概念
  • 网站建设与维护 实验报告心得网站开发调研方案
  • 分类信息网站系统cmswordpress在 分栏
  • 个人做外贸的网站武进网站建设好么
  • 新手建立企业网站流程摩洛哥网站后缀
  • 网站能不能用自己的电脑做服务器推广策略用英语怎么说
  • 女和女做网站创办网站要多少钱
  • 做外贸网站 用国外空间 还是 国内空间 区别wordpress手机后台版
  • 十大不收费看盘网站网站开发目的简介
  • 新乡做网站的公司有那些求一个手机能看的网站
  • 沧州网站制作的流程网站建设页面底部叫什么
  • 中国工程建设焊接协会网站渭南做网站哪家公司
  • 网站注册商标属于哪一类网站建设哪里好翰诺科技
  • 如何建立自己的网站教程网站优化的作用
  • 网站建设 知乎网站开发工具 n
  • 介绍几个网站福建网站建建设
  • 响应式做的好的网站有哪些百度一下你就知道百度一下
  • 宝坻网站建设公司成都手机号码销售网站建设
  • 万齐网站建设打开wordpress很慢