您的位置:首页 > 运维架构 > Kubernetes

Kubernetes 开发 SpringCloud (三)、使用 SpringCloud Feign 进行 SrpingCloud 服务间的通信

2019-07-25 17:21 603 查看

目录[-]

相关博文:

系统环境:

一、介绍

Feign 简介

       Feign 是一个声明式的 Web Service 客户端,可以帮助我们更快捷、优雅地调用HTTP API。它的出现使开发 Web Service 客户端变得很简单,使用 Feign 只需要创建一个接口加上对应的注解就可以完成服务间的调用。

       Spring Cloud Feign 帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign 的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。

Feign 功能:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解。
  • 支持可插拔的HTTP编码器和解码器(Gson,Jackson,Sax,JAXB,JAX-RS,SOAP)。
  • 支持Hystrix和它的Fallback。
  • 支持Ribbon的负载均衡。
  • 支持HTTP请求和响应的压缩。
  • 灵活的配置:基于 name 粒度进行配置
  • 支持多种客户端:JDK URLConnection、apache httpclient、okhttp,ribbon)
  • 支持日志
  • 支持错误重试
  • url支持占位符
  • 可以不依赖注册中心独立运行

Hystrix 简介

       在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix 是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix 通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。

Hystrix 功能:

  • 服务降级:优先核心服务,非核心服务不可用或弱可用
  • 依赖隔离:依赖隔离其实就是资源隔离,把对依赖使用的资源隔离起来,统一控制和调度。
  • 监控(Dashboard)状态:hystrix 提供了一套监控组件Dashboard,用于查看最近熔断器的情况。
  • 服务熔断:类似现实世界中的”保险丝”,当某个异常条件被触发,直接熔断整个服务,进行服务的降级快速返回”错误”的响应信息而不是一直等到此服务超时。当检测到该节点微服务响应正常后恢复调用链路。

二、Kubernetes 中使用 Feign 进行服务间通信

       在 Kubernetes 环境中使用 SpringCloud 框架开发服务跟本地开发一样,服务间调用也是可用利用

Feign
完成服务间通信工作,保持和本地开发 SpringCloud 模式不变,这样也能减少学习成本。如果使用
SpringCloud Feign
还能配合
SpringCloud Sleuth
生成链路日志,然后配合
Zipkin
配合完成服务间链路追踪工作。

       在 Kubernetes 环境下使用

Feign
还有一个问题是,现在已经将
Eureka
等注册中心去掉了,且在 Kubernetes 中所有的
Service
信息都会通过 Kubernetes 存入
Etcd
中,且每个服务都会通过
CoreDNS
分配一个以
服务名称
命名的不会重复域名,所以我们可以在开发项目过程中,可以通过配置
Feign
使用
域名
+
端口号
方式完成服务间的调用,如下图所示:

三、Kubernetes 中项目使用 Feign 进行服务间通信示例

       这里写三个项目,分别是

提供者
项目 与
消费者
项目 与两个服务都引用的
接口类
项目,开发模式跟在本地使用 SpringCloud 框架开发服务一样,
消费者
调用
提供者
,且两者都引用
接口项目
,其中提供者实现
接口项目
interface
的实现,消费者调通过
Feign
引入
interface
接口。这两个服务创建完成后将其部署到 Kubernetes 环境下,通过
NodePort
方式暴露端口供外部访问,然就外部调用
消费者
服务来测试是否能成功调用
提供者
服务提供的接口。

1、Feign 接口项目示例代码

(1)、Maven 引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>club.mydlq</groupId>
<artifactId>service-feign-interface</artifactId>
<version>0.0.1</version>
<name>service-feign-interface</name>
<description>service feign interface</description>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
</dependencies>

</project>

(2)、Interface 接口类定义

import org.springframework.web.bind.annotation.*;

public interface UserInterface {

/**
* 获取测试信息
* @return
*/
@GetMapping()
public String getInfo();

}

2、服务提供者示例代码

(1)、Maven 引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>

<groupId>club.mydlq</groupId>
<arti
3ff7
factId>service-provider</artifactId>
<version>0.0.1</version>
<name>service-provider</name>
<description>service provider</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<!--SpringBoot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot Actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Service Interface API-->
<dependency>
<groupId>club.mydlq</groupId>
<artifactId>service-feign-interface</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

(2)、实现 UserInterface 接口

import club.mydlq.feign.TestInterface;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController implements TestInterface {

@Override
public String getInfo() {
return "Hello World!";
}

}

(3)、Application 配置文件

spring:
application:
name: service-provider

server:
port: 8080

management:
server:
port: 8081
endpoints:
web:
exposure:
include: "*"

(4)、启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

3、服务消费者示例代码

(1)、Maven 引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>

<groupId>club.mydlq</groupId>
<artifactId>service-customer</artifactId>
<version>0.0.1</version>
<name>service-customer</name>
<description>service customer</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<!--SpringBoot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot Actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Service Interface API-->
<dependency>
<groupId>club.mydlq</groupId>
<artifactId>service-feign-interface</artifactId>
<version>0.0.1</version>
</dependency>
<!--Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

(2)、Feign Service类

import club.mydlq.feign.TestInterface;
import org.springframework.cloud.openfeign.FeignClient;

@FeignClient(name = "http://service-provider:8080", url = "http://service-provider:8080", fallback = TestFallback.class)
public interface TestService extends TestInterface {

}

(3)、Feign Fallback 类

import org.springframework.stereotype.Component;

@Component
public class TestFallback implements TestService {

@Override
public String getInfo() {
return "fallback!";
}

}

(4)、TestController 类

import club.mydlq.k8s.feign.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class TestController {

@Autowired
private TestService testService;

@GetMapping("/")
public String getTestInfo(){
return testService.getInfo();
}

}

(5)、Application 配置文件

spring:
application:
name: service-customer

server:
port: 8080

management:
server:
port: 8081
endpoints:
web:
exposure:
include: "*"

#开启 Hystrix
feign:
hystrix:
enabled: true

(6)、启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

4、构建 Docker 镜像

(1)、执行 Maven 编译

#Manve 编译 service-feign-interface 项目
$ cd service-feign-interface
$ mvn clean install

#Manve 编译 service-provider 项目
$ cd service-provider
$ mvn clean install

#Manve 编译 service-customer 项目
$ cd service-customer
$ mvn clean install

(2)、准备 Dockerfile

Dockerfile

FROM openjdk:8u212-b04-jre-slim
VOLUME /tmp
ADD target/*.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
ENV APP_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

(3)、执行 Docker 构建镜像

#构建 service-provider 镜像
$ docker build -t mydlqclub/service-provider:0.0.1 .

#构建 service-customer 镜像
$ docker build -t mydlqclub/service-customer:0.0.1 .

5、准备 Kubernetes 部署文件

service-provider.yaml

apiVersion: v1
kind: Service
metadata:
name: service-provider
spec:
type: NodePort
ports:
- name: server
nodePort: 31001
port: 8080
targetPort: 8080
- name: management
nodePort: 31002
port: 8081
targetPort: 8081
selector:
app: service-provider
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-provider
labels:
app: service-provider
spec:
replicas: 1
selector:
matchLabels:
app: service-provider
template:
metadata:
name: service-provider
labels:
app: service-provider
spec:
serviceAccountName: springcloud-kubernetes
restartPolicy: Always
containers:
- name: service-provider
image: registry.cn-beijing.aliyuncs.com/mydlq/service-provider:0.0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: server
- containerPort: 8081
name: management
resources:
limits:
memory: 1000Mi
cpu: 1000m
requests:
memory: 500Mi
cpu: 500m

service-customer.yaml

apiVersion: v1
kind: Service
metadata:
name: service-customer
spec:
type: NodePort
ports:
- name: server
nodePort: 31003
port: 8080
targetPort: 8080
- name: management
nodePort: 31004
port: 8081
targetPort: 8081
selector:
app: service-customer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-customer
labels:
app: service-customer
spec:
replicas: 1
selector:
matchLabels:
app: service-customer
template:
metadata:
name: service-customer
labels:
app: service-customer
spec:
serviceAccountName: springcloud-kubernetes
restartPolicy: Always
containers:
- name: service-customer
image: registry.cn-beijing.aliyuncs.com/mydlq/service-customer:0.0.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: server
- containerPort: 8081
name: management
resources:
limits:
memory: 1000Mi
cpu: 1000m
requests:
memory: 500Mi
cpu: 500m

6、将项目推送到 Kubernetes

执行 Kubectl 部署命将项目部署到 Kubernetes。

#创建RBAC
$ kubectl apply -f service-rbac.yaml -n mydlqcloud

#创建service-customer
$ kubectl apply -f service-customer.yaml -n mydlqcloud

#创建service-provider
$ kubectl apply -f service-provider.yaml -n mydlqcloud

7、测试接口

输入地址:http://192.168.2.11:31003 测试

service-customer
服务是否能正常通过
Feign
调用
service-provider
服务。

结果:

Hello World!

将 Kubernetes 中 service-provider 关掉来测试 fallback,再次输入地址:http://192.168.2.11:31003

结果:

fallback!

由上面结果可知,在 Kubernetes 环境下通过 SpringCloud Feign 根据

服务名称
+
端口号
这种方式,完成服务间的通信是可行的。

四、可配置参数

1、Feign 配置

Feign Client 全局默认配置

feign:
client:
config:
default:
connectTimeout: 5000        #默认连接超时时间
readTimeout: 5000           #默认读取超时时间
loggerLevel: basic          #默认日志级别

Feign Client 类单独配置

feign:
client:
config:
<feignClassName>:
connectTimeout: 5000        #连接超时时间
readTimeout: 5000           #读取超时时间
loggerLevel: full           #日志等级

Feign 请求/响应压缩配置

# 请求开启压缩
feign.compression.request.enabled=true
# 响应开启压缩
feign.compression.response.enabled=true
# 什么数据类型才进行压缩操作
feign.compression.request.mine-types=text/xml,application/xml,application/json
# 请求压缩的大小下线
feign.compression.request.min-request-size=2048

Feign 日志配置

在 Feign 中项目中会为每个 Feign 客户端创建一个记录器,默认情况下记录器的名称是接口的完整类名(包名+类名),并且 Feign 仅会记录 Debug 级别的日志。

(1)、Feign 记录器配置

配置 Feign 客户端记录器,且 Feign 仅仅记录 Debug 级别日志。

#配置格式:logging.level.<包路径>.<类名>:DEBUG
#例如本项目设置Feign 客户端日志如下:
logging:
level:
club.mydlq.k8s.feign.HelloService: DEBUG

(2)、Feign 日志级别配置

日志配置器有四种日志级别,分别记录不同的日志信息,需要设置一个配置类配合配置文件来完成日志设置。

@Configuration
public class FeignConfig {

@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}

}
  • NONE:不记录日志(DEFAULT)。
  • BASIC:仅记录请求方法和 URL 以及响应状态代码和执行时间。
  • HEADERS:记录基本信息以及请求和响应 Headers 信息。
  • FULL:记录请求和响应的 Headers、Body 和 Metadata 数据。

2、Hystrix 配置

开启 Hystrix

#在Feign中开启Hystrix
feign:
hystrix:
enabled: true

—END—

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐