SpringCloud简介

 Eureka架构图

对于微服务架构、开发的建议:

  1. 应用程序的核心是业务逻辑、按照业务或客户需求组织资源(重、难)

  2. 做有生命的产品,而不是项目

  3. 全栈化

  4. 后台服务贯彻Single Responsibility Principle(单一职责原则)

  5. VM -> Dockers

  6. DevOps

SpringCloud 简介

  Spring Cloud 提供了分布式系统(非模块化开发)(配置管理、服务发现、熔断、路由、微代理、控制总线、一次性Token、全局锁、Leader选举、分布式Session、集群状态)

-------------------------------分布式开发,一个服务一个项目一个目录,每一个目录都是一个工程---------------------------------------

Spring Cloud 创建统一的依赖管理

   Spring Cloud 项目都是基于Spring Boot进行开发,并且都是使用Maven做项目管理工具,所以创建一个依赖管理项目作为Maven的Parent项目使用,对jar包版本的统一管理

工程目录:vacc-spring-cloud-dependencies

Spring Cloud 服务注册与发现

   Spring Cloud提供的动态的获取服务ip;组件,Spring Cloud Netflix 的 Eureka ,Eureka 是一个服务注册和发现模块

工程目录:vacc-spring-cloud-eureka

// 入口类,springboot应用程序
package com.22bat.vacc.spring.cloud.eureka ; @SpringBootApplication @EnableEurekaServer
// 开启Eureka Server public class EurekaApplication { public static void main (String[] args) { SpringApplication.run(EurekaApplication.class, args); } }

resources--->>>application.yml

Spring:
  application:
    name: vacc-spring-cloud-eureka

server:
  port:8761

eureka:
  instance:
    hostname:localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

运行后访问:localhost:8761

Spring Cloud 创建服务提供者

工程目录:vacc-spring-cloud-service-admin  

package  com.22bat.vacc.spring.cloud.service.admin;
@SpringBootApplication
@EnableEurekaClient // 开启Eureka Client
public class ServiceAdiminApplication {
    public static void main (String[] args) {
        SpringApplication.run(ServiceAdiminApplication.class, args); 
  }
}

resources--->>>application.yml

Spring:
  application:
    name: vacc-spring-cloud-service-admin 

server:
  port:8762

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

启动服务器 Eureka -->后启动客户端访问:localhost:8762  因该服务未提供任何服务所以没东西 ;localhost:8761 可以看到启动的服务->管理// 提供Rest服务

// 创建服务

package
com.22bat.vacc.spring.cloud.service.admin.controller;
@RestController
public class AdminController {   
  @Value("$(server.port)")
  private String port;

  @RequestMapping(value = "hi", method = RequestMethod.GET)
  public String sayHi(String message){
    return String.format("Hi your message is : %s prot : %s", message, port);
  }
}

重启 ServiceAdminApplication -> 访问 localhost:8762/hi?message=HelloSpringCloud

Spring Cloud 创建服务消费者(Ribbon)

   在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯时基于http restful的。Spring Cloud有两种调用方式,一种是ribbon + restTemplate,另一种是feign.

  ribbon+rest:Ribbon 是一个负载均衡客户端,很好的控制 http 和 tcp 的一些行为。

工程目录:vacc-spring-cloud-web-admin-ribbon // 客户端的admin,ribbon方式

package  com.22bat.vacc.spring.cloud.web.admin.ribbon;
@SpringBootApplication
@EnableDiscoveryClient 
public class WebAdiminRibbonApplication {
    public static void main (String[] args) {
        SpringApplication.run(WebAdiminRibbonApplication.class, args); 
  }
}

resources--->>>application.yml

Spring:
  application:
    name: vacc-spring-cloud-web-admin-ribbon 
thymeleaf:
cache: false
mode: LEGACYHTML5
encoding: UTF-8
servlet:
content-type: text/html
server: port:8764 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/

启动服务器 Eureka -->后启动客户端访问:localhost:8762  因该服务未提供任何服务所以没东西 ;localhost:8761 可以看到启动的服务->管理// 提供Rest服务

// 创建服务

package com.22bat.vacc.spring.cloud.service.admin.controller;
@RestController public class AdminController {   
  @Value("$(server.port)")
  private String port;

  @RequestMapping(value = "hi", method = RequestMethod.GET)
  public String sayHi(String message){
    return String.format("Hi your message is : %s prot : %s", message, port);
  }
}

 配置注入 RestTemplate 的 Bean, 并通过@LoadBalanced 注解表明开启负载均衡功能

package com.22bat.vacc.spring.cloud.web.admin.ribbon.config;

@Configuration
public class RestTemplateConfiguration{

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

把serviceAdmin端口号改成8763,启动,开启两台服务器,负载均衡 ->访问localhost:8763

package com.22bat.vacc.spring.cloud.web.admin.ribbon.service;

@Service
public class AdminService{

    @Autowired
    private RestTemplate restTemplate;
    public String sayHi(String message){
      return restTemplate.getForObject("http://vacc-spring-cloud-service-adimin/hi?message="+message,port);  
    }        
}
package com.22bat.vacc.spring.cloud.web.admin.ribbon.controller;

@RestController
public class AdminController{

    @Autowired
    private AdminService adminService;
    
    @RequestMapping(value="hi", method = RequestMethod.GET)  
    public String sayHi(@RequestParam String message){
      return adminService.sayHi(message);  
    }        
}

启动WebAdminRibbonApplication,8764 -> localhost:8764/hi?message=HelloRibbon  刷新localhost:8761,会显示全部注册上边的服务

Spring Cloud 创建服务消费者 (Feign)

   Feign 是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡效果

  Feign 采用的是基于接口的注解

  Feign 整合了Ribbon

创建一个工程:vacc-spring-cloud-web-admin-feign 服务消费者项目

package com.22bat.vacc.spring.cloud.web.admin.feign;
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient // 注册到Eureka public class WebAdiminFeignApplication { public static void main (String[] args) { SpringApplication.run(WebAdiminFeignApplication.class, args);
  }
}

resources-> application.yml

Spring:
  application:
    name: vacc-spring-cloud-web-admin-feign
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html

server:
  port:8765

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

AdminService

package com.22bat.vacc.spring.cloud.web.admin.feign.service;

@FeignClient(value = "vacc-spring-cloud-service-admin")
public interface AdminService{

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam(value = "message")String message);    
}

AdminController

package com.22bat.vacc.spring.cloud.web.admin.feign.controller;

@RestController
public class AdminController{

    @value("${server.port}")
    private String port;
    
    @RequestMapping(value="hi", method = RequestMethod.GET)  
    public String sayHi(String message){
      return String.format("Hi your message is : %s port : %s",message, port);  
    }        
}

启动 8765 

Spring Cloud 使用熔断器防止服务雪崩

   “雪崩”效应(熔断器模型的提出):为了保证高可用,单个服务器通常为集群部署。由于网络原因或自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时如有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩效应”。

  Netflix 开源了 Hystrix 组件,实现了熔断器模式,Spring Cloud对这一组件进行了整合。

Ribbon中使用熔断器

  在pom.xml中增加依赖

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

  在 Application 中添加  @EnableHystrix 注解

  在 Service 中添加 @HystrixCommand 注解

package com.22bat.vacc.spring.cloud.web.admin.ribbon.service;

@Service
public class AdminService{

    @Autowired
    private RestTemplate restTemplate;
    
    @HystrixCommand(fallbackMethod = "hiError")  
    public String sayHi(String message){
      return restTemplate.getForObject("http://vacc-spring-cloud-service-adimin/hi?message="+message,port);  
    }        

    public String hiError(String message) {
       return "Hi, your message is :"" + message + "" but request error.";
    }    
}

测试熔断器 ,此时关闭服务提供者,再次请求 http://localhost:8764/hi?message=HelloRibbon

Feign 中使用熔断器

Feign 是自带熔断器的,但默认是关闭的。需要在配置文件中打开
application.yml
feign:
  hystrix:
    enabled: true

  创建熔断器类并实现对应的Feign 接口

package com.22bat.vacc-spring-cloud.web.admin.feign.service.hystrix;

public class AdminServiceHystrix implements AdminService {
    @Override
    public String sayHi(String message) {
       return "Hi, your message is :"" + message + "" but request error.";

}
}

  在 AdminService 接口注解中添加实现类

@FeignClient(value = "vacc-spring-cloud-service-admin",fallback = AdminServiceHystrix.class)

访问 localhost:8765

Spring Cloud 使用熔断器仪表盘监控

 使用Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同

在pom.xml中增加依赖

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

在 Application 中增加 @EnableHystrixDashboard 注解

创建 hystrix.stream 的Servlet配置

SpringBoot2.x 版本开启 Hystrix Dashboard 与 SpringBoot1.x(增加注解即可)方式略有不同,需要增加一个 HystrixMetricsStreamServlet 的配置,代码如下:

package com.22bat.vacc.spring.cloud.web.admin.ribbon.config;

@Configuration
public class HystrixDashboardConfiguration{

@Bean
public ServletRegistrationBean getServlet() { HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet(); // 没有web.xml ,Java中配置Servlet ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet); registrationBean.setLoadOnStratup(1); registrationBean.setUrlMappings("/hystrix.stream"); // servlet的访问路径 registrationBean.setName("HystrixMetricsStreamServlet"); return registrationBean; } }

测试 Hystrix Dashboard -> http://localhost:8765/hystrix

Hystrix Dashboard 中访问 http:/localhost:8764/hystrix.stream    titile中随便起个名字:WebAdminRibbon

刷新触发熔断器,可以在 Hystrix Dashboard 中监控到

Spring Cloud 使用路由网关统一访问接口

 使用路由网关统一访问接口

  在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、熔断器、智能路由、配置管理等,由这几个基础组件相互写作,共同组建一个简单的微服务系统

  在 Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务文件放在 Git 仓库,方便开发人员随时改配置。

  Zuul:主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/usr 转发到 User 服务, /api/shop 转发到shop 服务。Zuul默认和Ribbon结合实现了负载均衡的功能。

 创建工程:vacc-spring-cloud-zuul ,托管pom.xml

package com.22bat.vacc.spring.cloud.zuul;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
    public static void main (String[] args) {
        SpringApplication.run(ZuulApplication.class, args); 
  }
}

resources->application.yml

Spring:
  application:
    name: vacc-spring-cloud-zuul

server:
  port:8769

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

zuul:
  routes:
    api-a:
      path: /api/a/**
      serviceId: vacc-spring-cloud-web-admin-ribbon
    api-b:
      path: /api/b/**
      serviceId: vacc-spring-cloud-web-admin-feign

访问统一网关:localhost:8769/api/a/hi?message=HelloSpringCloud

配置网关路由失败时的回调

package com.22bat.vacc.spring.cloud.zuul.provider;

// 路由 vacc-spring-cloud-web-admin-feign 失败时的回调
@Component
public class WebAdminFeignFallbackProvider implements FallbackProvider {   
  @Override
  public String getRoute(){// 失败调用;如果需要所有调用都支持回退,则 return "*" 或 return null;
    return "vacc-spring-cloud-web-admin-feign";
  }

  @Override // 如果请求服务失败,返回指定的信息给调用者
  public ClientHttpResponse fallbackResponse(String route, Throwable cause){
    return new ClientHttpResponse() {
      // 网关 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
      // 不应该把 api 的 404,405,500 等问题抛给客户端
// 网关和 api 服务集群对客户端来说是hi黑盒
      @Override
      public HttpStatus getStatusCode() throws IOException {
        return HttpStatus.OK;
      }

      @Override
      public int getRawStatusCode() throws IOException {
        return HttpStatus.OK.value();
      }

      @Override
      public String getStatusText() throws IOExcepiton{
        return HttpStatus.OK.getReasonPhrase();
      }

      @Override
      public void close() {
      }

      @Override
      public InputStream getBody() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> map = new HashMap<>();
        map.put("status", 200);
        map.put("message", "无法连接,请检查您的网络");
        return new ByteArrayInputSteam(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
      }

      @Override
      public HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        // 和 getBody 中的编码一致
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        return headers;
      }
    };
  }

}

Spring Cloud 使用路由网关的的服务过滤功能

zuul不仅仅是路由,还有很强大的功能,一下是服务过滤功能,比如用在安全验证方面

创建服务过滤器

package com.22bat.vacc.spring.cloud.zuul.filter;

@Component
public class LoginFileter extends ZuulFileter {   @Override
  public String filterType() {
    return "pre";// pre:路由之前;routing:路由之时;post:路由之后;error:发送错误调用
  }
  @Override
  public int filterOrder() {
    return 0;// 过滤的顺序,数值越小执行越靠前
  }
  @Override
  public boolean shouldFilter() {
    return true;// 是否需要过滤,true是需要过滤
  }
  @Override// 过滤器的具体业务代码
  public Object run() throws ZuulException() {
    
    RequestContext currentContext = RequestContext.getCurrentContext();
    HttpServletRequest request = currentContext.getRequest();
    logger.info("{}>>>{}", request.getMethod, request.getRequestURL.toString);
    String token = request.getParamter("token");
    if (token == null) {
      logger.warn("Token is empty");
      currnetContext.setSendZuulResponse(false);
      currentContext.setResponseStatusCode(401);
      try{
       // HttpServletResponse response = currentContext.getResponse();
       // response.setContextType("text/html;charset=utf-8");
        currentContext.getResponse().getWriter.wirte("Token is empty");
      } catch(IOException) {
        e.printStackTrace();
      }
    }
    return null;
  }
}

localhost:8769/api/a/hi?message=HelloSpringCloud&token=123

SpringCloud 服务配置中心

 创建工程:vacc-spring-cloud-config

package com.22bat.vacc.spring.cloud.config;
@SpringBootApplication
@EnableEurekaClient // 服务提供者 // DiscoverEureka服务消费者 // EnableEurekaServer是Eureka服务器
@EnableConfigServer
public class ZuulApplication {
    public static void main (String[] args) {
        SpringApplication.run(ZuulApplication.class, args); 
  }
}

resources->application.yml

// 中央集中式管理

Spring: application: name: vacc
-spring-cloud-config
cloud:
config:
label: master // 分支
server:
git:
uri: https://github.com/grant_chen/spring-cloud-config //仓库地址
search-paths: respo // 放配置的目录
username: // 仓库的用户名和密码
password:
server: port:
8888 // 默认端口,不能改,修改需要新建 bootstrap.properties(启动的意思) 添加 server.port=8889 // bootstrap.yml/properties是优先被加载 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/

仓库中respo上传一个配置文件 web-admin-feign-dev.yml

Spring:
  application:
    name: vacc-spring-cloud-web-admin-feign
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html
server: port:
8765

feign:
hystrix:
enabled: true
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/

启动配置服务中心:localhost:8888/web-admin-feign/dev/master 可以读到配置

所有配置中添加配置中心的配置

spring.cloud.config.uri // 配置服务中心的网址
spring.cloud.config.name // 配置文件名称的前缀
spring.cloud.config.label // 配置仓库的分支
spring.cloud.config.profile // 配置文件的环境标识 dev/test/prod

以feign为例,本地的application.yml文件修改为:

spring:
  cloud:
    config:
      uri: http://localhost:8888
      name: web-admin-feign
      label: master
      profile: dev

添加一个appliation-prod.yml

spring:
  cloud:
    config:
      uri: http://localhost:8888
      name: web-admin-feign
      label: master
      profile: prod

到feign项目目录下 打jar包,java -jar feign.jar 默认启动application.yml  dev环境的配置

启动 prod的配置   装载->application-prod.yml   java -jar feign.jar --spring.profiles.active=prod

Spring Cloud 服务的链路追踪 (ZipKin)

zipKin简介:ZipKin是一个开放源代码的分布式跟踪系统,由Twitter公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。它的理论模型来自于Google Dapper论文。

每个服务向ZipKin 报告计时数据,ZipKin会根据调用关系通过ZipKin UI生成依赖关系图,显示了多少跟踪请求通过每个服务,该系统让开发者可通过一个Web前端轻松收集和分析数据,例如用户每次请求i服务的处理时间等,可方便的检测系统中存在的瓶颈。

服务追踪说明:微服务架构是通过业务来划分服务的,使用REST调用。对外暴漏一个接口,可能需要很多服务协同才能完整这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用越来越复杂。

术语:

Span:基本工作单元,例如,在一个新建的Span中发送一个RPC等同于发送一个回应请求给RPC,Span通过一个64位ID唯一标识,Trace以另一个64位ID表示.

Trace:一系列Spans组成的一个树状结构,例如,如果你正在运行一个分布式大数据工程,你可能需要创建一个Trace

Annotation:用来即使记录一个事件的存在,一些核心Annotations用来定义个请求的开始和结束

  cs:Client Sent,客户端发起一个请求,这个Annotation描述了这个Span的开始

  sr:Server Received,服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟

  ss:Server Sent:表明请求处理得完整(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要得处理请求事件

  cr:Client Received 表明Span得结束,客户端成功接收到服务端得回复,如果cr减去cs时间戳可得到客户端从服务端获取回复得所需事件

创建一个工程(服务):vacc-spring-cloud-zipkin  -->>pom.xml

package com.22bat.vacc.spring.cloud.zipkin;
@SpringBootApplication
@EnableZipkinServer
@EnableEurekaClient
public class ZipKinApplication {
    public static void main (String[] args) {
        SpringApplication.run(ZipKinApplication.class, args);   
  }
}

resource--->>>application-dev.yml

spring:
  application:
     name: vacc-spring-cloud-zipkin

server:
  port: 9411 // zipkin的默认端口

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  metrics:
    web:
      server:
        auto-time-requests: false

在所有需要被追踪的项目中增加 spring-cloud-starter-zipkin 依赖

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

在这些项目的application.yml 配置文件中增加 ZipKin Server 的地址即可

spring:
  zipkin:
    base-url: http://localhost:9411

启动后访问 localhost:9411

Spring Boot Admin 服务监控:(监控管理系统)

两个角色,Spring Boot Admin Server,Spring Boot Admin Client ,主要对于各个微服务系统得健康状态、会话数量、并发数、服务资源、延迟等度量信息的收集;

所有的服务都需要依赖Spring Boot Admin ;

新建项目:vacc-spring-cloud-admin

package com.22bat.vacc.spring.cloud.admin;
@SpringBootApplication
@EnableAdminServer
@EnableEurekaClient
public class AdminApplication {
    public static void main (String[] args) {
        SpringApplication.run(AdminApplication .class, args);      
  }
}

resource->application.yml

spring:
  application:
     name: vacc-spring-cloud-admin
zipkin:
base-url: http://localhost:9411 server: port: 8084
management: endpoint: health: show-details: always
endpoints:
web:
exposure:
include:["health","info"]
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

启动服务端-localhost:8084

在所有pom.xml中增加客户端的依赖

<dependency>
  <groupId>org.jolokia</groupId>
  <artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

所有配置文件中增加

Spring.boot.admin.client.url: http://localhost:8084

启动顺序:

1. 注册与发现 EurekaApplication:8761

2. 分布式配置中心 ConfigApplication:8888

3. 服务提供者 ZipKinApplication:9411   AdminApplication:8084  ServiceAdminApplication:8763

4. 服务消费者 WebAdminFeignApplication:8765

5. API网关 ZuulApplication

AdminApplication点开,服务监控

-----------------------------------------------------------------------------------

--极限开发--缺什么补什么--只管今天--但每天必须重构--优化

-----------------------------------------------------------------------------------

-----------------------------------------------------------------------------------

-

原文地址:https://www.cnblogs.com/cgy-home/p/12022463.html