Spring Cloud Alibaba全家桶——微服务链路追踪SkyWalking

Posted 小新要变强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Cloud Alibaba全家桶——微服务链路追踪SkyWalking相关的知识,希望对你有一定的参考价值。

前言

本文小新为大家带来 微服务链路追踪SkyWalking 相关知识,具体内容包括SkyWalking简介SkyWalking环境搭建部署SkyWalking接入微服务SkyWalking持久化跟踪数据自定义SkyWalking链路追踪SkyWalking集成日志框架SkyWalking告警功能SkyWalking高可用SkyWalking UI介绍等进行详尽介绍~

不积跬步,无以至千里;不积小流,无以成江海。每天进步一点点,在成为强者的路上,小新与大家共同成长!

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)

↩️本文上接:Spring Cloud Alibaba全家桶(十)——微服务网关Gateway组件


目录

微服务链路追踪SkyWalking

一、SkyWalking简介

1️⃣链路追踪介绍

对于一个大型的几十个、几百个微服务构成的微服务架构系统,通常会遇到下面一些问题,比如:

  • (1)如何串联整个调用链路,快速定位问题?
  • (2)如何缕清各个微服务之间的依赖关系?
  • (3)如何进行各个微服务接口的性能分折?
  • (4)如何跟踪整个业务流程的调用处理顺序?

2️⃣SkyWalking是什么

SkyWalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。

官网地址:http://skywalking.apache.org/

下载地址:http://skywalking.apache.org/downloads/

Github地址:https://github.com/apache/skywalking

文档地址: https://skywalking.apache.org/docs/main/v8.4.0/readme/

中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking/

3️⃣链路追踪框架对比

  • (1)Zipkin是Twitter开源的调用链分析工具,目前基于springcloud sleuth得到了广泛的使用,特点是轻量,使用部署简单。
  • (2)Pinpoint是韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能强大,接入端无
    代码侵入。
  • (3)SkyWalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能较强,接入端
    无代码侵入。目前已加入Apache孵化器。
  • (4)CAT是大众点评开源的基于编码和配置的调用链分析,应用监控分析,日志采集,监控报警等一系列的监控平台工具。

模拟了三种并发用户:500,750,1000。使用jmeter测试,每个线程发送30个请求,设置思考时间为10ms。使用的采样率为1,即100%,这边与生产可能有差别。pinpoint默认的采样率为20,即50%,通过设置agent的配置文件改为100%。zipkin默认也是1。组合起来,一共有12种。下面看下汇总表:

从上表可以看出,在三种链路监控组件中,skywalking的探针对吞吐量的影响最小,zipkin的吞吐量居中。pinpoint的探针对吞吐量的影响较为明显,在500并发用户时,测试服务的吞吐量从1385降低到774,影响很大。然后再看下CPU和memory的影响,在内部服务器进行的压测,对CPU和memory的影响都差不多在10%之内。

4️⃣SkyWalking功能特性

  • (1)多种监控手段,可以通过语言探针和service mesh获得监控的数据;
  • (2)支持多种语言自动探针,包括 Java,.NET Core 和 Node.JS;
  • (3)轻量高效,无需大数据平台和大量的服务器资源;
  • (4)模块化,UI、存储、集群管理都有多种机制可选;
  • (5)支持告警;
  • (6)优秀的可视化解决方案。

二、SkyWalking环境搭建部署

  • skywalking agent和业务系统绑定在一起,负责收集各种监控数据;
  • skywalking oapservice是负责处理监控数据的,比如接受skywalking agent的监控数据,并存储在数据库中;
  • 接受skywalking webapp的前端请求,从数据库查询数据,并返回数据给前端。skywalking oapservice通常以集群的形式存在;
  • skywalking webapp,前端界面,用于展示数据;
  • 用于存储监控数据的数据库,比如mysql、elasticsearch等。

1️⃣下载 SkyWalking

下载地址: http://skywalking.apache.org/downloads/

目录结构:

2️⃣搭建SkyWalking OAP 服务

🍀启动脚本bin/startup.sh

🍀日志信息存储在logs目录

🍀启动成功后会启动两个服务,一个是skywalking-oap-server,一个是skywalking-web-ui : 8868
skywalking-oap-server服务启动后会暴露11800 和 12800 两个端口,分别为收集监控数据的端口11800和接受前端请求的端口12800,修改端口可以修改config/applicaiton.yml

🍀skywalking-web-ui服务会占用 8080 端口, 修改端口可以修改webapp/webapp.yml


server.port:SkyWalking UI服务端口,默认是8080;collector.ribbon.listOfServers:SkyWalking OAP服务地址数组,SkyWalking UI界面的数据是通过请求SkyWalking OAP服务来获得;

🍀访问:http://192.168.3.100:8080/

页面的右下角可以中英文切换,可以切换选择要展示的时间区间的跟踪数据。

3️⃣SkyWalking中三个概念

服务(Service) : 表示对请求提供相同行为的一系列或一组工作负载,在使用Agent时,可以定义服务的名字;

服务实例(Service Instance) : 上述的一组工作负载中的每一个工作负载称为一个实例, 一个服务实例实际就是操作系统上的一个真实进程;

端点(Endpoint) : 对于特定服务所接收的请求路径, 如HTTP的URI路径和gRPC服务的类名 + 方法签名。

三、SkyWalking接入微服务

1️⃣linux环境——通过jar包方式接入

准备一个springboot程序,打成可执行jar包,写一个shell脚本,在启动项目的Shell脚本上,通过 -javaagent 参数进行配置SkyWalking Agent来跟踪微服务。

🍀startup.sh脚本启动

#!/bin/sh
# SkyWalking Agent配置
export SW_AGENT_NAME=springboot‐skywalking‐demo #Agent名字,一般使用`spring.application.name`
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置 Collector 地址。
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。
export JAVA_AGENT=‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin‐es7/agent/skywalking‐agent.jar
java $JAVA_AGENT ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar #jar启动

启动日志:


🍀以上启动等同于:

java ‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin‐es7/agent/skywalking‐agent.jar
‐DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800
‐DSW_AGENT_NAME=springboot‐skywalking‐demo ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar

参数名对应agent/config/agent.config配置文件中的属性。

属性对应的源码:org.apache.skywalking.apm.agent.core.conf.Config.java。

# The service name in UI
agent.service_name=$SW_AGENT_NAME:Your_ApplicationName
# Backend service addresses.
collector.backend_service=$SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800

我们也可以使用skywalking.+配置文件中的配置名作为系统配置项来进行覆盖。 javaagent参数配置方式优先级更高。

🍀测试: 访问你的微服务

2️⃣Windows环境——在IDEA中使用SkyWalking

在运行的程序配置jvm参数,如下图所示:

# skywalking‐agent.jar的本地磁盘的路径
‐javaagent:D:\\apache\\apache‐skywalking‐apm‐es7‐8.4.0\\apache‐skywalking‐apm‐bin‐es7\\agent\\skywalking‐agent.jar
# 在skywalking上显示的服务名
‐DSW_AGENT_NAME=springboot‐skywalking‐demo
# skywalking的collector服务的IP及端口
‐DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.100:11800

-DSW_AGENT_COLLECTOR_BACKEND_SERVICES 可以指定远程地址, 但是-javaagent必须绑定你本机物理路径的skywalkingagent.jar。

3️⃣SkyWalking跨多个微服务跟踪

Skywalking跨多个微服务跟踪,只需要每个微服务启动时添加javaagent参数即可。

测试:
启动微服务mall-gateway,mall-order,mall-user ,配置skywalking的jvm参数,
访问http://localhost:8888/user/findOrderByUserId/1


注意: 此处存在bug,跟踪链路不显示gateway

拷贝agent/optional-plugins目录下的gateway插件到agent/plugins目录。

四、SkyWalking持久化跟踪数据

默认使用的H2数据库存储,config/application.yml配置文件如下:

基于mysql持久化:

🍀(1)修改config目录下的application.yml,使用mysql作为持久化存储的仓库

🍀(2) 修改mysql连接配置

storage:
  #选择使用mysql 默认使用h2,不会持久化,重启skyWalking之前的数据会丢失
  selector: $SW_STORAGE:mysql
  #使用mysql作为持久化存储的仓库
  mysql:
    properties:
      #数据库连接地址
      jdbcUrl: $SW_JDBC_URL:"jdbc:mysql://1ocalhost:3306/swtest"
      #用户名
      dataSource.user: $SW_DATA_SOURCE_USER:root
      #密码
      dataSource.password: $SW_DATA_SOURCE_PASSWORD:root

注意: 需要添加mysql数据驱动包,因为在lib目录下是没有mysql数据驱动包的,所以修改完配置启动是会报错,启动失败的。

🍀(3) 添加mysql数据驱动包到oap-libs目录下

🍀(4)启动Skywalking

查看swtest数据库,可以看到生成了很多表:

这说明启动成功了,打开配置对应的地址http://192.168.3.100:8080/,j就可以看到skywalking的web界面。

🍀(5)测试:重启skywalking,验证跟踪数据会不会丢失

五、自定义SkyWalking链路追踪

如果我们希望对项目中的业务方法,实现链路追踪,方便我们排查问题,可以使用如下的代码引入依赖:

<!‐‐ SkyWalking 工具类 ‐‐>
<dependency>
  <groupId>org.apache.skywalking</groupId>
  <artifactId>apm‐toolkit‐trace</artifactId>
  <version>8.4.0</version>
</dependency>

1️⃣@Trace将方法加入追踪链路

如果一个业务方法想在ui界面的跟踪链路上显示出来,只需要在业务方法上加上@Trace注解即可:

测试:

2️⃣加入@Tags或@Tag

我们还可以为追踪链路增加其他额外的信息,比如记录参数和返回信息。实现方式:在方法上增加@Tag或者@Tags。

@Tag 注解中 key = 方法名 ; value = returnedObj 返回值 arg[0] 参数。

@Trace
@Tag(key = "list", value = "returnedObj")
public List<User> list()
  return userMapper.list();


@Trace
@Tags(@Tag(key = "param", value = "arg[0]"),
@Tag(key = "user", value = "returnedObj"))
public User getById(Integer id)
  return userMapper.getById(id);


性能分析:

skywalking的性能分析,在根据服务名称、端点名称,以及相应的规则建立了任务列表后,在调用了此任务列表的端点后。skywalking会自动记录,剖析当前端口,生成剖析结果,具体流程如图:

六、SkyWalking集成日志框架

🍀(1)引入依赖

<!‐‐ apm‐toolkit‐logback‐1.x ‐‐>
<dependency>
  <groupId>org.apache.skywalking</groupId>
  <artifactId>apm‐toolkit‐logback‐1.x</artifactId>
  <version>8.5.0</version>
</dependency>

🍀(2)添加logback-spring.xml文件,并配置 %tid 占位符

<?xml version="1.0" encoding="UTF‐8"?>
<configuration>
  <!‐‐ 引入 Spring Boot 默认的 logback XML 配置文件 ‐‐>
  <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
  
  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    <!‐‐ 日志的格式化 ‐‐>
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
      <layout  class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
        <Pattern>$CONSOLE_LOG_PATTERN</Pattern>
      </layout>
    </encoder>
  </appender>

  <!‐‐ 设置 Appender ‐‐>
  <root level="INFO">
    <appender‐ref ref="console"/>
  </root>

</configuration>

🍀(3)测试

🍀(4)Skywalking通过grpc上报日志 (需要v8.4.0+)

gRPC报告程序可以将收集到的日志转发到SkyWalking OAP服务器上。

logback-spring.xml中添加:

<!‐‐ v8.4.0提供 ‐‐>
<appender name="grpc‐log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
  <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
      <Pattern>%dyyyy‐MM‐dd HH:mm:ss.SSS [%Xtid] [%thread] %‐5level %logger36 ‐%msg%n</Pattern>
    </layout>
  </encoder>
</appender>

<root level="info">
  <appender‐ref ref="grpc‐log" />
</root>

打开agent/config/agent.config配置文件,添加如下配置信息:

plugin.toolkit.log.grpc.reporter.server_host=$SW_GRPC_LOG_SERVER_HOST:192.168.3.100
plugin.toolkit.log.grpc.reporter.server_port=$SW_GRPC_LOG_SERVER_PORT:11800
plugin.toolkit.log.grpc.reporter.max_message_size=$SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760
plugin.toolkit.log.grpc.reporter.upstream_timeout=$SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30

以上配置是默认配置信息,agent与oap在本地的可以不配。

agent配置信息:

配置名解释默认值
plugin.toolkit.log.transmit_formatted是否以格式化或未格式化的格式传输记录的数据true
plugin.toolkit.log.grpc.reporter.server_host指定要向其报告日志数据的grpc服务器的主机127.0.0.1
plugin.toolkit.log.grpc.reporter.server_port指定要向其报告日志数据的grpc服务器的端口11800
plugin.toolkit.log.grpc.reporter.max_message_size指定grpc客户端要报告的日志数据的最大大小10485760
plugin.toolkit.log.grpc.reporter.upstream_timeout客户端向上游发送数据时将超时多长时间。单位是秒30

Skywalking UI效果:

访问:https://github.com/apache/skywalking-rocketbot-ui/pull/428

七、SkyWalking告警功能

SkyWalking 告警功能是在6.x版本新增的,其核心由一组规则驱动,这些规则定义在config/alarm-settings.yml文件中。

告警规则的定义分为两部分:

  • (1)告警规则: 它们定义了应该如何触发度量警报,应该考虑什么条件。
  • (2)Webhook(网络钩子): 定义当警告触发时,哪些服务终端需要被告知。

1️⃣告警规则

SkyWalking 的发行版都会默认提供config/alarm-settings.yml文件,里面预先定义了一些常用的告警规则。如下:

  • (1)过去 3 分钟内服务平均响应时间超过 1 秒。
  • (2)过去 2 分钟服务成功率低于80%。
  • (3)过去 3 分钟内服务响应时间超过 1s 的百分比
  • (4)服务实例在过去 2 分钟内平均响应时间超过 1s,并且实例名称与正则表达式匹配。
  • (5)过去 2 分钟内端点平均响应时间超过 1 秒。
  • (6)过去 2 分钟内数据库访问平均响应时间超过 1 秒。
  • (7)过去 2 分钟内端点关系平均响应时间超过 1 秒。

这些预定义的告警规则,打开config/alarm-settings.yml文件即可看到。

告警规则配置项的说明:

  • Rule name:规则名称,也是在告警信息中显示的唯一名称。必须以_rule结尾,前缀可自定义
  • Metrics name:度量名称,取值为oal脚本中的度量名,目前只支持long、double和int类型。详见Official OAL script
  • Include names:该规则作用于哪些实体名称,比如服务名,终端名(可选,默认为全部)
  • Exclude names:该规则作不用于哪些实体名称,比如服务名,终端名(可选,默认为空)
  • Threshold:阈值
  • OP: 操作符,目前支持 >、<、=
  • Period:多久告警规则需要被核实一下。这是一个时间窗口,与后端部署环境时间相匹配
  • Count:在一个Period窗口中,如果values超过Threshold值(按op),达到Count值,需要发送警报
  • Silence period:在时间N中触发报警后,在TN -> TN + period这个阶段不告警。默认情况下,它和Period一样,这意味着相同的告警(在同一个Metrics name拥有相同的Id)在同一个Period内只会触发一次
  • message:告警消息

2️⃣Webhook(网络钩子)

Webhook可以简单理解为是一种Web层面的回调机制,通常由一些事件触发,与代码中的事件回调类似,只不过是Web层面的。由于是Web层面的,所以当事件发生时,回调的不再是代码中的方法或函数,而是服务接口。例如,在告警这个场景,告警就是一个事件。当该事件发生时,SkyWalking就会主动去调用一个配置好的接口,该接口就是所谓的Webhook。

SkyWalking的告警消息会通过 HTTP 请求进行发送,请求方法为 POST,Content-Type 为 application/json,其JSON 数据实基于List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage进行序列化的。JSON数据示例:

[
  "scopeId": 1,
  "scope": "SERVICE",
  "name": "serviceA",
  "id0": "12",
  "id1": "",
  "ruleName": "service_resp_time_rule",
  "alarmMessage": "alarmMessage xxxx",
  "startTime": 1560524171000
, 
  "scopeId": 1,
  "scope": "SERVICE",
  "name": "serviceB",
  "id0": "23",
  "id1": "",
  "ruleName": "service_resp_time_rule",
  "alarmMessage": "alarmMessage yyy",
  "startTime": 1560524171000
]

字段说明:

  • scopeId、scope:所有可用的 Scope 详见org.apache.skywalking.oap.server.core.source.DefaultScopeDefine
  • name:目标 Scope 的实体名称
  • id0:Scope 实体的 ID
  • id1:保留字段,目前暂未使用
  • ruleName:告警规则名称
  • alarmMessage:告警消息内容
  • startTime:告警时间,格式为时间戳

3️⃣邮件告警功能实践

SkyWalking是不支持直接向邮箱、短信等服务发送告警信息的,SkyWalking只会在发生告警时将告警信息发送至配置好的Webhook接口。

但我们总不能人工盯着该接口的日志信息来得知服务是否发生了告警,因此我们需要在该接口里实现发送邮件或短信等功能,从而达到个性化的告警通知。
接下来开始动手实践,这里基于Spring Boot进行实现。

🍀(1)首先是添加依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring‐boot‐starter‐mail</artifactId>
</dependency>

🍀(2)配置邮箱服务

server:
  port: 9134

  #邮箱配置
  spring:
    mail:
      host: smtp.163.com
      #发送者邮箱账号
      username: 你的邮箱@163.com
      #发送者密钥
      password: 你的邮箱服务密钥
      default‐encoding: utf‐8
      port: 465 #端口号465或587
      protocol: smtp
  properties:
    mail:
      debug:
        false
    smtp:
      socketFactory:
        class: javax.net.ssl.SSLSocketFactory

🍀(3)根据SkyWalking发送的JSON数据定义一个DTO,用于接口接收数据

@Data
public class SwAlarmDTO 
  private Integer scopeId;
  private String scope;
  private String name;
  private Integer id0;
  private Integer id1;
  private String ruleName;
  private String alarmMessage;
  private Long startTime;

🍀(4)接着定义一个接口,实现接收SkyWalking的告警通知,并将数据发送至邮箱

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/alarm")
public class SwAlarmController 

  private final JavaMailSender sender;

  @Value("$spring.mail.username")
  private String from;

  /**
  * 接收skywalking服务的告警通知并发送至邮箱
  **/
  @PostMapping("/receive")
  public void receive(@RequestBody List<SwAlarmDTO> alarmList) 
    SimpleMailMessage message = new SimpleMailMessage();
    // 发送者邮箱
    message.setFrom(from);
    // 接收者邮箱
    message.setTo(from);
    // 主题
    message.setSubject("告警邮件");
    String content = getContent(alarmList);
    // 邮件内容
    message.setText(content);
    sender.send(message);
    log.info("告警邮件已发送...");
  
 
  private String getContent(List<SwAlarmDTO> alarmList) 
    StringBuilder sb = new StringBuilder();
    for (SwAlarmDTO dto : alarmList) 
      sb.append("scopeId: ").append(dto.getScopeId())
        .append("\\nscope: ").append(dto.getScope())
        .append("\\n目标 Scope 的实体名称: ").append(dto.getName())
        .append("\\nScope 实体的 ID: ").append(dto.getId0())
        .append("\\nid1: ").append(dto.getId1())
        .append("\\n告警规则名称: ").append(dto.getRuleName()前言 

本文小新为大家带来 微服务调用组件Feign 的相关知识,具体内容包含什么是FeignSpring Cloud Alibaba快速整合OpenFeignSpring Cloud Feign的自定义配置及使用(包括:日志配置契约配置自定义拦截器实现认证逻辑超时时间配置客户端组件配置GZIP 压缩配置)等~

不仅跬步,无以至千里;不积小流,无以成江海。每天进步一点点,在成为强者的路上,小新与大家共同成长!

📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)

↩️本文上接:Spring Cloud Alibaba全家桶(三)——微服务负载均衡器Ribbon与LoadBalancer


目录

微服务调用组件Feign


JAVA 项目中如何实现接口调用?

  • (1)Httpclient

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。HttpClient相比传统 JDK 自带的 URLConnection,提升了易用性和灵活性,使客户端发送 HTTP 请求变得容易,提高了开发的效率。

  • (2)Okhttp

一个处理网络请求的开源项目,是安卓端最火的轻量级框架,由 Square 公司贡献,用于替代
HttpUrlConnection 和 Apache HttpClient。OkHttp 拥有简洁的 API、高效的性能,并支持多种协议(HTTP/2 和 SPDY)。

  • (3)HttpURLConnection

HttpURLConnection 是 Java 的标准类,它继承自 URLConnection,可用于向指定网站发送GET 请求、POST 请求。HttpURLConnection 使用比较复杂,不像 HttpClient 那样容易使用。

  • (4)RestTemplate WebClient

RestTemplate 是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate 提供了多种便捷访问远程 HTTP 服务的方法,能够大大提高客户端的编写效率。上面介绍的是最常见的几种调用接口的方法,我们下面要介绍的方法比上面的更简单、方便,它就是 Feign。

一、什么是Feign

Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。

Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。

Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便

🍀优势

Feign可以做到使用 HTTP 请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

二、Spring Cloud Alibaba快速整合OpenFeign

🍀(1)引入依赖

<!‐‐ openfeign 远程调用 ‐‐>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring‐cloud‐starter‐openfeign</artifactId>
</dependency>

🍀(2)编写调用接口+@FeignClient注解

@FeignClient(value = "mall‐order",path = "/order")
public interface OrderFeignService 

  @RequestMapping("/findOrderByUserId/userId")
  public R findOrderByUserId(@PathVariable("userId") Integer userId);

🍀(3)调用端在启动类上添加@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class MallUserFeignDemoApplication 
  public static void main(String[] args) 
    SpringApplication.run(MallUserFeignDemoApplication.class, args);
  

🍀(4)发起调用,像调用本地方式一样调用远程服务

@RestController
@RequestMapping("/user")
public class UserController 

  @Autowired
  OrderFeignService orderFeignService;

  @RequestMapping(value = "/findOrderByUserId/id")
  public R findOrderByUserId(@PathVariable("id") Integer id) 
    //feign调用
    R result = orderFeignService.findOrderByUserId(id);
    return result;
  

三、Spring Cloud Feign的自定义配置及使用

Feign 提供了很多的扩展机制,让用户可以更加灵活的使用。

1️⃣日志配置

有时候我们遇到 Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要
配置 Feign 的日志了,以此让 Feign 把请求信息输出来。

🍀(1)定义一个配置类,指定日志级别

// 注意: 此处配置@Configuration注解就会全局生效,如果想指定对应微服务生效,就不能配置
public class FeignConfig 
  /**
 * 日志级别
 *  * @return
  */
  @Bean
  public Logger.Level feignLoggerLevel() 
    return Logger.Level.FULL;
  

通过源码可以看到日志等级有 4 种,分别是:

  • NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。
  • BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
  • HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
  • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。

🍀(2)局部配置,让调用的微服务生效,在@FeignClient 注解中指定使用的配置类

🍀(3)在yml配置文件中执行 Client 的日志级别才能正常输出日志,格式是 “logging.level. feign接口包路径=debug”

logging:
  level:
  com.tuling.mall.feigndemo.feign: debug

测试: BASIC级别日志

补充: 局部配置可以在yml中配置

对应属性配置类:
org.springframework.cloud.openfeign.FeignClientProperties.FeignClientConfiguration

feign:
  client:
  config:
  mall‐order: #对应微服务
  loggerLevel: FULL

2️⃣契约配置

Spring Cloud 在 Feign 的基础上做了扩展,使用 Spring MVC 的注解来完成Feign的功能。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的,通过配置契约来改变这个配置,Spring Cloud 中默认的是 SpringMvcContract。

Spring Cloud 1 早期版本就是用的原生Fegin。随着netflix的停更替换成了Open feign。

🍀(1)修改契约配置,支持Feign原生的注解

/**
* 修改契约配置,支持Feign原生的注解
* @return
*/
@Bean
public Contract feignContract() 
  return new Contract.Default();

注意: 修改契约配置后,OrderFeignService 不再支持springmvc的注解,需要使用Feign原生的注解

🍀(2)OrderFeignService 中配置使用Feign原生的注解

@FeignClient(value = "mall‐order",path = "/order")
public interface OrderFeignService 
  @RequestLine("GET /findOrderByUserId/userId")
  public R findOrderByUserId(@Param("userId") Integer userId);

🍀(3)补充,也可以通过yml配置契约

feign:
  client:
  config:
  mall‐order: #对应微服务
  loggerLevel: FULL
  contract: feign.Contract.Default #指定Feign原生注解契约配置

3️⃣自定义拦截器实现认证逻辑

public class FeignAuthRequestInterceptor implements RequestInterceptor 
  @Override
  public void apply(RequestTemplate template) 
    // 业务逻辑
    String access_token = UUID.randomUUID().toString();
    template.header("Authorization",access_token);
  


@Configuration // 全局配置
public class FeignConfig 
  @Bean
  public Logger.Level feignLoggerLevel() 
    return Logger.Level.FULL;
  
  /**
  * 自定义拦截器
  * @return
  */
  @Bean
  public FeignAuthRequestInterceptor feignAuthRequestInterceptor()
    return new FeignAuthRequestInterceptor();
  

测试:

补充: 可以在yml中配置

feign:
  client:
  config:
  mall‐order: #对应微服务
  requestInterceptors[0]: #配置拦截器
  com.tuling.mall.feigndemo.interceptor.FeignAuthRequestInterceptor

mall-order端可以通过 @RequestHeader获取请求参数,建议在filter,interceptor中处理

4️⃣超时时间配置

通过 Options 可以配置连接超时时间和读取超时时间,Options 的第一个参数是连接的超时时间(ms),默认值是 2s;第二个是请求处理的超时时间(ms),默认值是 5s。

🍀(1)全局配置

@Configuration
public class FeignConfig 
  @Bean
  public Request.Options options() 
    return new Request.Options(5000, 10000);
  

🍀(2)yml中配置

feign:
  client:
  config:
  mall‐order: #对应微服务
  # 连接超时时间,默认2s
  connectTimeout: 5000
  # 请求处理超时时间,默认5s
  readTimeout: 10000

补充说明: Feign的底层用的是Ribbon,但超时时间以Feign配置为准

测试超时情况:

返回结果:

5️⃣客户端组件配置

Feign 中默认使用 JDK 原生的 URLConnection 发送 HTTP 请求,我们可以集成别的组件来替换掉 URLConnection,比如 Apache HttpClient,OkHttp。

Feign发起调用真正执行逻辑:feign.Client#execute (扩展点)

🍀(1)配置Apache HttpClient

引入依赖:

<!‐‐ Apache HttpClient ‐‐>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign‐httpclient</artifactId>
<version>10.1.0</version>
</dependency>

然后修改yml配置,将 Feign 的 Apache HttpClient启用 :

feign:
  #feign 使用 Apache HttpClient 可以忽略,默认开启
  httpclient:
  enabled: true

关于配置可参考源码: org.springframework.cloud.openfeign.FeignAutoConfiguration

测试: 调用会进入feign.httpclient.ApacheHttpClient#execute

🍀(2)配置 OkHttp

引入依赖:

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign‐okhttp</artifactId>
</dependency>

然后修改yml配置,将 Feign 的 HttpClient 禁用,启用 OkHttp,配置如下:

feign:
  #feign 使用 okhttp
  httpclient:
  enabled: false
  okhttp:
  enabled: true

关于配置可参考源码: org.springframework.cloud.openfeign.FeignAutoConfiguration

测试: 调用会进入feign.okhttp.OkHttpClient#execute

6️⃣GZIP 压缩配置

开启压缩可以有效节约网络资源,提升接口性能,我们可以配置 GZIP 来压缩数据:

feign:
  # 配置 GZIP 来压缩数据
  compression:
    request:
      enabled: true
      # 配置压缩的类型
      mime‐types: text/xml,application/xml,application/json
      # 最小压缩值
      min‐request‐size: 2048
    response:
      enabled: true

注意: 只有当 Feign 的 Http Client 不是 okhttp3 的时候,压缩才会生效,配置源码在FeignAcceptGzipEncodingAutoConfiguration

核心代码就是 @ConditionalOnMissingBean(type=“okhttp3.OkHttpClient”),表示Spring BeanFactory 中不包含指定的 bean 时条件匹配,也就是没有启用 okhttp3 时才会进行压缩配置。


后记

👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

以上是关于Spring Cloud Alibaba全家桶——微服务链路追踪SkyWalking的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Alibaba全家桶——微服务调用组件Feign

Spring Cloud Alibaba全家桶——微服务链路追踪SkyWalking

Spring Cloud Alibaba全家桶——微服务组件Nacos注册中心

Spring Cloud Alibaba全家桶——微服务组件Sentinel介绍与使用

Spring Cloud Alibaba全家桶——微服务组件Nacos配置中心

Spring Cloud Alibaba全家桶——Sentinel规则持久化