SpringCloud相关服务搭建

目录

Eureka

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

eureka是Netflix的子模块之一,包含2个组件:EurekaServer和EurekaClient。

EurekaServer

Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。

EurekaServer需要启动一个单独的服务,Spring Cloud对其进行了整合,来帮助Spring Cloud实现“服务的注册与发现”功能。

为了实现高可用,一般会搭建EurekaServer集群,EurekaServer节点之间互相注册,只要有一个节点活着,就可以正常工作。

EurekaClient可以将自己注册到EurekaServer上,Client和Server之间会进行心跳检测,确保服务还能正常运行,Client宕机后,Server会将其从注册中心剔除,Client恢复后,Server又会将其重新注册进来。

eureka只负责提供“服务的注册与发现”,服务之间的调用由ribbon来完成。

EurekaClient

Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。

EurekaClient是需要集成在我们自己的项目里面的,项目启动时,EurekaClient会与EurekaServer通信,将自己的服务信息封装成InstanceInfo,注册到EurekaServer中。

将一个大型项目拆分成多个微服务之后,单个微服务就是一个EurekaClient,为了方便微服务之间互相发现和通信,EurekaServer提供了“注册与发现”功能,所有的微服务都要注册到EurekaServer中。

基本原则

  • 服务启动时会生成服务的基本信息对象InstanceInfo,然后在启动时会register到服务治理中心。
  • 注册完成后会从服务治理中心拉取所有的服务信息,缓存在本地。
  • 之后服务会30s(可配置)发送一个心跳监测,续约服务。
  • 如果服务治理中心在90s内没有收到一个服务的心跳,就会认为服务已经挂了,会把服务注册信息剔除。
  • 服务停止前,服务会主动发送一个停止请求,服务治理中心会剔除这个服务的信息。
  • 如果Eureka Server收到的心跳包不足正常值的85%(可配置)就会进入自我保护模式(可以关闭),在这种模式下,Eureka Server不会删除任何服务信息,但是仍然可以注册,不会同步到其他节点,保证当前节点可用。

搭建Eureka服务集群

Spring Cloud版本高度依赖于Spring Boot版本,参考官网的版本说明,否则版本不兼容服务启动会报错。

笔者使用的版本:2.1.9.RELEASE、Greenwich.SR4


创建三个SpringBoot项目,并按照如下操作:

pom.xml加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

启动类加注解

@EnableEurekaServer

application.yml

其他节点操作一致,只需稍微修改配置文件即可。

server:
  port: 3001

spring:
  application:
    name: eureka3001 #注册到eureka中的名字

eureka:
  instance:
    hostname: eureka3001.com
  server:
    enable-self-preservation: false #关闭自我保护机制
    eviction-interval-timer-in-ms: 5000 #5s清理一次服务 默认60s
  client:
    register-with-eureka: true #是否把自己当做客户端注册
    fetch-registry: true #是否需要从注册中心同步其他服务注册信息
    service-url:
      #需要修改host,不能使用localhost
      defaultZone: http://eureka3002.com:3002/eureka,http://eureka3003.com:3003/eureka

笔者搭建的环境:3个EurekaServer节点组成的集群,端口分别为:3001、3002、3003。

项目构建完成后,依次启动然后访问,看到如下页面表示搭建成功:

image

Eureka客户端注册

创建一个基于SpringBoot的Web项目,EurekaClient必须要对外提供服务。

这里创建一个User项目。

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

启动类加注解

@EnableEurekaClient

application.yml

server:
  port: 5001

spring:
  application:
    name: user-module #注册到eureka的name

eureka:
  instance:
    hostname: localhost
    instance-id: user-1 #服务注册到eureka的唯一标识
    prefer-ip-address: true #注册服务时使用IP而不是hostname
    lease-renewal-interval-in-seconds: 30 #发送心跳的间隔
    lease-expiration-duration-in-seconds: 60 #超过该时间没有发送心跳就表示宕机

  client:
    service-url:
      defaultZone: http://eureka3001.com:3001/eureka #注册到EurekaServer

EurekaClient已经嵌入到User项目中,只需启动User项目,会自动向EurekaServer注册。

image

Ribbon服务间调用

eureka只负责“服务的注册与发现”,服务之间的调用由ribbon来完成。

spring-cloud-starter-netflix-eureka-client中已经包含ribbon依赖,无需额外引入。

有三个EurekaClient:User、System-1、System-2,两个System命名相同,EurekaServer会将两个服务注册为集群。

现在User要调用System提供的服务,

注入RestTemplate

@Bean
@LoadBalanced//负载均衡注解 默认轮询
public RestTemplate getRestTemplate(){
	return new RestTemplate();
}

通过服务名调用

@RestController
@RequestMapping("user")
public class UserController {
	@Autowired
	private RestTemplate restTemplate;

	private final String SYSTEM_SERVER = "http://system/";

	@RequestMapping("system")
	public Object system() {
		return restTemplate.getForEntity(SYSTEM_SERVER + "system/hello", Map.class);
	}
}

这样就可以在User模块中调用System模块提供的服务。

负载均衡策略

Ribbon自带7种负载均衡策略:

  • RoundRobinRule 轮询

  • RandomRule 随机访问

  • RetryRule
    默认是轮询,如果节点出现问题会重试几次,还是无响应就会移出轮询列表。

  • WeightedResponseTimeRule
    首先是轮询,然后根据轮询的结果来计算节点的权重,之后性能更好的节点会被请求的更多。

  • BestAvailableRule
    优先请求并发量最少的一个节点。

  • AvailabilityFilteringRule

  • ZoneAvoidanceRule

自定义负载均衡策略

如果内置的负载均衡策略无法满足需求,可以自定义一个。

例如:根据请求IP地址的哈希值来决定调用哪一个节点。

实现IRule或者继承AbstractLoadBalancerRule。

/**
 * @Author: 潘
 * @Date: 2019/11/27 21:19
 * @Description: 自定义负载均衡策略
 */
public class MyRule implements IRule {
	private ILoadBalancer lb;
	private Random random = new Random();

	@Override
	public Server choose(Object o) {
		System.out.println("自定义负载均衡策略...");
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		String remoteAddr = request.getRemoteAddr();
		List<Server> allServers = lb.getAllServers();
		int index = remoteAddr.hashCode() % allServers.size();
		System.out.println("命中:" + index);
		return allServers.get(index);
	}

	@Override
	public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
		this.lb = iLoadBalancer;
	}

	@Override
	public ILoadBalancer getLoadBalancer() {
		return lb;
	}
}

将自定义策略类注册到Spring中

@Bean
public IRule iRule(){
	return new MyRule();//随机策略
}

不同服务不同策略

使用@Bean方式注入的负载均衡策略,会被应用于全局。

如果希望不同的服务使用不同的负载均衡策略可以这么做:

创建@Configuration类,但不要被Spring扫描到

@Configuration
public class GoodsRule {

	@Bean
	public IRule iRule(){
		//goods使用随机策略
		return new RandomRule();
	}
}

@Configuration
public class SystemRule {

	@Bean
	public IRule iRule(){
		//system使用轮询策略
		return new RoundRobinRule();
	}
}

在启动类上加注解指明具体策略

@RibbonClients({
		@RibbonClient(name = "system", configuration = SystemRule.class),
		@RibbonClient(name = "goods", configuration = GoodsRule.class)

})

这样就可以了,Goods服务使用随机策略,System服务使用轮询策略。

Feign

Feign是一个声明式WebService客户端,使用Feign能让编写Web Service客户端更加简单。

到目前为止,实现了服务的注册与发现,服务之间的调用也可以完成,但是使用不太友好。

使用Feign可以更加优雅的完成服务的调用,就像调用一个Service一样简单。

引入依赖

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

启动类加注解

//启用Feign
@EnableFeignClients
//默认扫描启动类的所在目录及子包,如果需要扫描指定包:
@EnableFeignClients(basePackages = {"com.ch.douban.feign"})

编写Feign接口

//服务名 goods
@FeignClient("goods")
public interface GoodsServiceClient {

    //调用服务的路径
	@RequestMapping("goods/hello")
	public Object goodsHello();
	//需要接受参数时 @RequestParam String key
}

注入使用即可

@Autowired
private GoodsServiceClient goodsServiceClient;

@RequestMapping("goods")
public Object goods() {
	//使用Feign调用服务
	return goodsServiceClient.goodsHello();
}

负载均衡啥的依然有效。

Hystrix

Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

“熔断器”本身是一个开关装置,可以看成是“保险丝”,当某个微服务节点发生故障时,Hystrix能及时检测到并进行服务降级和熔断,返回一个备选的处理方案,而不是长时间的阻塞或抛出异常,防止服务调用方的线程被长时间的占用,从而避免因为单个服务节点故障导致整个系统瘫痪。

常用配置

# hystrix配置
hystrix:
  threadpool:
    default:
      coreSize: 10 #线程池核心线程数
      maxQueueSize: 5 #任务等待队列长度
      queueSizeRejectionThreshold: 5 #排队线程数阈值
  command:
    default:
      circuitBreaker:
        requestVolumeThreshold: 3 #单位时间内失败的次数达到该值,进行熔断
        sleepWindowInMilliseconds: 5000 #熔断后,5s会进行一次服务重试,服务正常后会关闭熔断
        #errorThresholdPercentage: 50 #失败率达到50%进行熔断
        forceOpen: false #强制打开熔断器,拒绝所有请求 默认false
        forceClosed: false #强制关闭熔断器

      metrics:
        rollingStats:
          timeInMilliseconds: 3000 #滑动窗口的大小 3s内失败了requestVolumeThreshold次进行熔断

      execution:
        timeout:
          enabled: true #是否启用超时监听 默认true
        isolation:
          thread:
            timeoutInMilliseconds: 400 #超时时间
            interruptOnTimeout: true #方法执行超时是否中断 默认true
            interruptOnCancel: true #方法执行取消是否中断 默认true
          semaphore:
            maxConcurrentRequests: 10 #最大请求并发数 默认10 使用SEMAPHORE策略生效

      requestCache:
        enabled: true #请求结果缓存 默认true
      requestLog:
        enabled: true #是否开启请求日志 默认true
      fallback:
        enabled: true #是否开启方法回退 默认true

添加依赖

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

启动类加注解

//启用hystrix
@EnableHystrix

服务降级、超时

当某个微服务出现异常或者响应时间过长时,为了不让线程一直阻塞在那里,或者不把错误信息直接返回给客户端,我们可以提供一个备选的降级方法,当服务出现问题时,Hystrix会自动进行服务降级。

服务降级的好处:

  • 监听请求是否超时
  • 不返回错误信息
  • 系统资源不够用时,可以关闭一些不常用的服务,把资源让出来

在需要进行服务降级的方法上加注解

@RequestMapping("goods")
//fallbackMethod:降级的方法名
@HystrixCommand(fallbackMethod = "goodsFallBack")
public Object goods() {
	return restTemplate.getForEntity(GOODS_SERVER + "goods/hello", Map.class);
}

//goods降级方法
public Object goodsFallBack(){
	//可以进行一些日志的记录...
	return "goods暂时不可用";
}

最基本的“服务降级”就配置好了,当“goods服务”抛出异常,或者响应时间过长时,Hystrix会调用降级方法。

熔断

当某个微服务连续调用多次都失败时,Hystrix就会启用熔断。

开启熔断后,Hystrix不会再请求服务,直接返回降级方法,在一定的时间内会对服务进行重试,直到服务正常后,Hystrix就会关闭熔断,然后请求服务。

默认10秒内20次失败就会开启熔断,5秒进行一次服务重试,可以进行自定义配置。

限流

限制微服务的调用量,当某个微服务支持的并发量达不到预期时,可以进行限流,Hystrix会将多余的请求进行服务降级。

Hystrix通过线程池的方式来管理微服务的调用。

@RequestMapping("goods")
//fallbackMethod:降级的方法名
@HystrixCommand(fallbackMethod = "goodsFallBack",
		threadPoolKey = "goods",
		threadPoolProperties = {
			//核心线程数2 等待队列1 最多能处理3个线程,超过3并发的请求会进行降级
			@HystrixProperty(name="coreSize",value = "2"),
			@HystrixProperty(name="maxQueueSize",value = "1")
		}
)
public Object goods() {
	return restTemplate.getForEntity(GOODS_SERVER + "goods/hello", Map.class);
}

Feign整合Hystrix

Feign是支持Hystrix的,但在新版本的SpringCloud中默认将其关闭了,需要手动开启。

开启Hystrix

#feign启用Hystrix
feign:
  hystrix:
    enabled: true

编写服务降级类

/**
 * @Author: 潘
 * @Date: 2019/11/30 12:27
 * @Description: GoodsServiceClient降级方法
 */
@Component
public class GoodsServiceFallBack implements GoodsServiceClient {

	@Override
	public Object goodsHello() {
		return "Goods服务暂时不可用...";
	}
}

FeignClient通过fallback指明服务降级类

@FeignClient(value = "goods",fallback = GoodsServiceFallBack.class)
public interface GoodsServiceClient {

	//调用服务的路径
	@RequestMapping("goods/hello")
	public Object goodsHello();
}

当服务出现问题时,Feign就会调用服务降级类中的对应方法。

Zuul

Zuul在SpringCloud家族中扮演着API网关的角色。

在微服务架构中,会有很多个服务提供者,对于服务调用者而言,经常需要从多个服务中获取数据,如果让调用者直接请求相应的服务,那么系统需要对外暴露很多地址,不好管理也不安全。

通过Zuul统一对外暴露一个聚合地址,当调用者请求Zuul时,由Zuul来根据URL进行路由的转发,可以屏蔽微服务内部的细节,更加的安全也方便管理。

搭建Zuul服务

引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

启动类加注解

//启用Zuul
@EnableZuulProxy

配置文件

server:
  port: 8001

spring:
  application:
    name: zuul #注册到eureka的name

eureka:
  instance:
    hostname: localhost
    instance-id: zuul-1 #服务注册到eureka的唯一标识

  client:
    service-url:
      defaultZone: http://eureka3001.com:3001/eureka

#zuul配置
zuul:
  ignored-services: "*" #禁止通过服务名调用,只能通过zuul转发
  prefix: /api #统一访问前缀
  routes: #配置路由
    goods: #路由名 自定义
      serverId: goods #路由的服务(注册到eureka的服务名)
      path: /zuul_goods/** #通过该路径访问路由的服务

过滤器

Zuul定义了4中过滤器的类型:

  • PRE
    请求被路由之前调用。可利用这种过滤器实现身份验证、在 集群中选择请求的微服务、记录调试信息等。

  • ROUTING
    将请求路由到微服务。用于构建发送给微服务的请求,并使用Apache HttpCIient或Netfilx Ribbon请求微服务。

  • POST
    路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

  • ERROR
    发生错误时执行。

SpringCloud内置了一些过滤器,在org.springframework.cloud.netflix.zuul.filters包下,可以通过配置文件禁用。

自定义过滤器

继承ZuulFilter重写方法即可

/**
 * @Author: 潘
 * @Date: 2019/11/30 13:05
 * @Description: 自定义Zuul过滤器
 */
@Component
public class MyFilter extends ZuulFilter {

	//过滤器类型
	@Override
	public String filterType() {
		return FilterConstants.PRE_TYPE;
	}

	//过滤器调用顺序,不同类型的过滤器允许返回相同类型的顺序
	@Override
	public int filterOrder() {
		return FilterConstants.PRE_DECORATION_FILTER_ORDER;
	}

	//是否执行过滤器
	@Override
	public boolean shouldFilter() {
		return true;
	}

	//具体过滤逻辑,比如:记录一下访问的IP和uri
	@Override
	public Object run() throws ZuulException {
		RequestContext currentContext = RequestContext.getCurrentContext();
		HttpServletRequest request = currentContext.getRequest();
		String remoteAddr = request.getRemoteAddr();
		String requestURI = request.getRequestURI();
		System.out.println(remoteAddr + requestURI);
		return null;
	}
}

整合Hystrix

Zuul整合了Hystrix和Ribbon,提供降级回退,不同的是Ribbon可以实现API级别的回退,Zuul只能提供服务级别的回退。

实现FallbackProvider编写回退逻辑

/**
 * @Description: Zuul回退降级
 */
@Component
public class MyFallbackProvider implements FallbackProvider {

	@Override
	public String getRoute() {
		//服务id *或者null表示所有服务
		return "*";
	}

	/**
	 * 回退逻辑
	 * @param route 出错的服务
	 * @param cause 错误信息
	 * @return
	 */
	@Override
	public ClientHttpResponse fallbackResponse(String route,final Throwable cause) {
		if (cause instanceof HystrixTimeoutException) {
			return response(HttpStatus.GATEWAY_TIMEOUT);
		} else {
			return response(HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

	private ClientHttpResponse response(final HttpStatus status) {
		return new ClientHttpResponse() {
			//状态信息
			@Override
			public HttpStatus getStatusCode() throws IOException {
				return status;
			}

			//状态码
			@Override
			public int getRawStatusCode() throws IOException {
				return status.value();
			}

			//http的reasonPhrase信息
			@Override
			public String getStatusText() throws IOException {
				return status.getReasonPhrase();
			}

			//降级服务响应结束后调用的方法
			@Override
			public void close() {
			}

			//响应内容
			@Override
			public InputStream getBody() throws IOException {
				return new ByteArrayInputStream("goods服务暂时不可用".getBytes());
			}

			//设置响应报头header信息
			@Override
			public HttpHeaders getHeaders() {
				HttpHeaders headers = new HttpHeaders();
				headers.setContentType(MediaType.APPLICATION_JSON);
				return headers;
			}
		};
	}
}

Gateway

Gateway也是API网关,性能要好于Zuul1.0,由于Zuul的种种问题,Spring决定自己孵化一个API网关项目,Gateway就此诞生,现在更推荐使用Gateway。

添加依赖

因为要将Gateway注册到Eureka上,所以需要加eureka-client依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

启动类加注解

@EnableEurekaClient

配置文件

server:
  port: 8001

spring:
  application:
    name: gateway #注册到eureka的name
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启 Gateway 服务注册中心服务发现
      #配置路由      
      routes:
      - id: gateway-goods
        uri: lb://goods
        predicates:
        - Path=/api/**
        filters:
        - StripPrefix=1 #去掉一个前缀,否则转发时会带/api

eureka:
  instance:
    hostname: localhost
    instance-id: gateway-1 #服务注册到eureka的唯一标识

  client:
    service-url:
      defaultZone: http://eureka3001.com:3001/eureka

这样一个简单的Gateway服务就搭建完成了,Gateway还有很多强大的功能:断言、过滤…。
这里不记录,笔者会单独开一片博客记录。

HystrixDashboard

HystrixDashboard是Hystrix提供的一个可视化工具,可以用于监控服务的调用状态。

actuator

Hystrix本身提供了对服务调用的监控,但是需要结合actuator来查看监控信息。

在需要监控的项目中引入依赖

<!--actuator-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

SpringCloud2.0之后的版本需要做以下配置

#暴露Actuator的端点
management:
  endpoints:
    web:
      exposure:
        include: '*'

启动服务,访问:项目路径/actuator/hystrix.stream即可查看到监控信息。

在这里插入图片描述

actuator以Json数据返回,不方便查看,HystrixDashbord提供了可视化界面。

HystrixDashboard搭建

秉承“单一职责”原则,就不要将HystrixDashboard放到业务服务里了,单独创建一个监控服务。

创建一个HystrixDashboard项目,引入依赖

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

启动类加注解

//启用HystrixDashboard
@EnableHystrixDashboard

配置文件配置一下端口,启动服务即可。

访问:IP:port/hystrix看到如下界面,表示搭建成功。

在这里插入图片描述

在输入框中输入需要监控的地址,即可看到监控的图形化界面。

在这里插入图片描述

仪表盘解释

实心圆

  • 大小:表示请求数量
  • 颜色:表示服务的健康程度

曲线:2分钟内流量的变化。

百分比:10s内错误请求的百分比。

数字

  • 绿色:成功数
  • 蓝色:熔断数
  • 淡蓝:错误请求
  • 黄色:超时数
  • 紫色:线程拒绝数
  • 红色:失败/异常数

Host:服务请求频率。

Circuit:熔断状态。

Spring Cloud Config

统一配置中心

微服务架构中,随着服务的增多,每个服务都要做独立的配置就变得特别的繁琐,也不方便统一管理,一旦某个服务的信息发生变化,牵扯到的服务也要修改对应的配置,十分麻烦。

为了解决这个问题,就需要有一个“统一配置中心”,对配置进行统一的管理,微服务从上面读取配置即可。

服务端搭建

还是“单一职责”原则,新建一个服务来跑配置中心。

引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

启动类加注解

//启用ConfigServer
@EnableConfigServer

Spring Cloud Config支持许多种读取配置的方式:本地、Git、SVN等。

这里为了方便,用本地配置测试。

创建一个供客户端读取的配置文件:config-dev.yml,这里主要配置eureka。

#eureka统一配置
eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true #是否显示IP
    lease-renewal-interval-in-seconds: 30 #发送心跳的间隔
    lease-expiration-duration-in-seconds: 60 #超过该时间没有发送心跳就表示宕机
  client:
    service-url:
      defaultZone: http://eureka3001.com:3001/eureka

编写Server服务自身的配置文件

server:
  port: 2001

spring:
  profiles:
    active: native #本地环境
  cloud:
    config:
      server:
        native: #本地配置文件模式
          search-locations: classpath:/
        #git: #通过github读取配置文件 如果私有仓库需要配置用户名、密码
        #  uri: https://github.com/15797680617/cloud-config.git

配置中心服务搭建完成,启动服务即可。

访问:http://localhost:2001/config-dev.yml即可查看配置文件。

在这里插入图片描述

客户端读取

这里将“goods”服务的配置改为从配置中心读取。

引入依赖

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

删除原application.yml中对eureka的配置。

创建bootstrap.yml配置文件,在这里设置从配置中心读取。

spring cloud有一个“引导上下文"的概念,这是主应用程序的父上下文。bootstrap.yml中的优先级最高,会覆盖application.yml中的配置。

spring:
  cloud:
    config:
      name: config #配置文件名
      profile: dev #获取的环境
      #label: master 版本
      uri: http://localhost:3001/ #configServer的地址

这样就可以了,goods启动时会从服务端读取配置,本地application.yml配置会被覆盖。

Sleuth

在微服务架构中,对于一个客户端的请求,中间可能需要经过很多微服务进行处理,一旦请求异常,就需要对异常进行排查。

微服务异常排查的成本要远高于单机系统,首先要定位到是哪一台服务出了问题,然后再去分析日志。

Sleuth为SpringCloud提供了“分布式链路跟踪”,通过它可以很清楚的看到,对于某一个请求,中间经过了多少服务、耗时多久、之间的依赖关系、异常信息等。

各组件间的关系

  • Sleuth:负责收集数据。
  • Zipkin客户端:负责将Sleuth收集的数据发送到Zipkin服务端。
  • Zipkin服务端:负责接收数据,并以图形界面的方式展示。

分布式链路跟踪

术语:

Span(跨度)

工作的基本单元,span由一个唯一的64位ID标识。
对于客户端的一个请求,每次在不同的微服务之间调用都会生成一个新的span。span还包含其他数据,比如描述、时间戳事件、键值。

Trance(跟踪)

由一组span构成的树状结构。Trance ID也由一个唯一的64位ID标识。

可以理解为:Trance对应着一个请求的一组调用链。

对于客户端的一个请求,不管它在微服务之间如何流转,整个调用链都共享同一个Trance ID,这可以帮助开发人员定位到一个请求的整个调用情况。

Annotation(标注)

用于及时记录服务之间请求的发起和响应的事件信息。

具体信息可以查看官网。

Sleuth可以追踪10种类型的组件:async、Hystrix,messaging,websocket,rxjava,scheduling,web(Spring MVC Controller,Servlet),webclient(Spring RestTemplate)、Feign、Zuul。

Zipkin Server搭建

Zipkin是 Twitter开源的分布式跟踪系统,基于 Dapper的论文设计而来。它的主要功能是收集系统的时序数据,从而追踪微服务架构的系统延时等问题。 Zipkin还提供了一个非常友好的界面,来帮助分析追踪数据。

Sleuth对于分布式链路跟踪仅仅是收集Json数据,开发人员如果要对Json进行分析就太不方便了,Zipkin可以对Sleuth收集的数据用图形界面的方式友好的展示出来。

同样的“单一职责”,搭建新的服务专门跑Zipkin。

创建一个Maven项目,引入依赖

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
    <version>2.8.4</version>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
    <version>2.8.4</version>
</dependency>

配置文件

server:
  port: 1001

management:
  metrics:
    web:
      server:
        autoTimeRequests: false #Zipkin2.7之后要加

Zipkin2.7之后,不支持自定义服务器搭建,必须使用官方版本或Docker搭建,但是通过配置仍然可以使用,正式用推荐官方版本。

服务搭建完成,启动后访问看到下图界面表示搭建成功。

在这里插入图片描述

此时点击Find Traces是没有数据的,因为还没有客户端上传数据到服务端。

Sleuth整合Zipkin

这里将User和Goods模块整合Sleuth、Zipkin,通过User调用Goods,然后看一下调用的链路数据。

需要被跟踪的服务引入依赖

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

配置文件,也可以配置到‘统一配置中心’。

spring:
  zipkin:
    base-url: http://localhost:1001 #zipkin server地址
  sleuth:
    sampler:
      probability: 1.0 #请求采样率 默认0.1即10%

启动服务,发起一个请求,让User去调用Goods,然后查看Zipkin。

在这里插入图片描述

点进去,可以查看调用链的具体信息,包括服务名,耗时、调用的类名、方法名等。

在这里插入图片描述

可以查看到具体的报错信息,更快的定位到问题。

在这里插入图片描述

数据持久化

Zipkin默认将数据保存在内存中,服务一旦重启收集的数据就没了,可能会丢失重要的信息。

可以整合Elasticsearch、MySQL等做数据的持久化。

以ES为例,引入依赖

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId>
    <version>2.3.1</version>
</dependency>

配置文件

#使用ES做数据持久化
zipkin:
  storage:
    type: elasticsearch
    elasticsearch:
      cluster: elasticsearch
      hosts: http://localhost:9200
      index: zipkin

这样即使服务重启,数据也不会丢失。

发布了100 篇原创文章 · 获赞 23 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/103330231