1 介绍
1.1 Thrift
在介绍spring-cloud-starter-drift之前,我们应该先了解什么是Thrift。
Thrift是一款跨语言的RPC序列化传输框架,由Facebook开源。现已移至Apache。
Thrift如何做到跨语言沟通的呢,我们都知道RPC框架是基于Socket
的长连接。
Thrift通过标准化的接口定义语言IDL来定义接口,再使用Thrift的生成工具将IDL语言翻译为各个语言的接口代码,比如什么JAVA
、CPP
、Python
等。
在对比了几个可以跨语言的RPC框架之后,我们决定使用Thrift来作为我们的跨语言沟通的组件,因为Thrift是所有跨语言的RPC框架中性能最好的。而且出身好,又经过市场上大量的实践,之前饿了么在架构技术整合之前就大规模的使用Thrift进行跨语言沟通。Python端的thriftpy就是饿了么进行开源的。后来升级到了thriftpy2。
1.2 Drift
提到Drift
,我们不得不提他的老爹Nifty.
为什么说是他的老爹呢,因为Drift
和Nifty
都是Facebook
进行开源的JAVA端的Thrift客户端。
Nifty是当年Facebook基于Netty
开发的JAVA语言的Thrift客户端,使JAVA语言的Thrift的性能更上一层楼。
但是为什么又会有Drift呢?因为Facebook在2018-05月停止维护了Nifty,并且开启了新的项目Drift。为JAVA平台的Thrift带来了新的体验。
Drift最大的特点就是,在原有基于Netty的基础上不再需要IDL定义的接口来生成JAVA端的代码了。它使用注解的方式,动态的生成代码,为开发者带来了良好的开发体验。
1.3 SpringCloud-Starter-Drift-Client
由于需求是使用Thrift进行口语言远程调用,在SpringCloud中使用Drift进行编写,还要进行各种配置。简直烦的一比。
于是我动手对drift针对SpringCloud进行了封装,本以为这是件很简单的事,但是经过了仔细思考之后,发现要做的还是蛮多的。比如:
-
我们需要通过
服务发现
来找到对应的服务的IP地址和端口,并进行连接。在目前这个敏感的阶段,Eureka
2闭源,导致大部分公司都迁移至Consul
,部分与Dubbo
生态圈耦合严重的公司依然是用Zookeeper
来进行服务注册,随着阿里的Nacos
开源,大家都在等待Nacos
的成熟完善,就可以把SpringCloud和Dubbo的注册中心进行整合了。在这种情况下,需要对服务发现层进行抽象。这层我使用了SpringCloud Discovery 组件进行服务发现。并且保证服务的健康性。 -
服务发现后要与服务端建立长连接,还要保证连接的可用性,这就涉及到了连接池的概念。这里采用的还是
commons-pool
进行维护连接池
的。 -
建立连接后还要建立
负载均衡层
,这样用户就可以自定义实现负载均衡的算法,比如说轮询、权重等。当服务失败后可以快速切换服务端进行重试。 -
因为使用Drift客户端使用接口+注解的形式,所以我们在对Drift注解进行封装的时候,要考虑到对注解标记过的字段进行注入的时候,要注入一个代理类, 所以要进行
JDK动态代理
来对接口进行代理转发。 -
这些还是功能上的问题,当我开始写代码的时候,我才发现,
Spring
你真的玩透了么?感觉好多的功能自己有思路却不知道怎么实现,然后针对Spring
的各种机制又进行了恶补。比如:BeanPostProcessor
、ClassPathBeanDefinitionScanner
等等。
经过了这次的组件编写,真的是感觉受益良多,对以前有些模模糊糊的概念也逐渐清晰,毕竟书读百遍不如手敲一遍,特别是对Spring的一些接口也有了清晰的认识。
这里就说这么多吧,有兴趣的小伙伴可以去看我的代码,欢迎大家来给我提建议。
2 DEMO
2.1 建立SpringCloud项目
引入maven依赖(目前只支持consul,不过可以自定义实现)。
<dependency>
<groupId>com.naah69</groupId>
<artifactId>spring-cloud-starter-drift-client</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.2 配置组件
编写SpringCloud配置。
spring:
cloud:
consul:
host: 127.0.0.1
port: 8500
retry:
max-attempts: 500
discovery:
health-check-critical-timeout: 5m
health-check-path: /actuator/health
health-check-interval: 5s
tags: dev
instance-id: demo
enabled: true
prefer-ip-address: true
health-check-tls-skip-verify: true
query-passing: true
register: true
drift:
# 开关
enable: true
client:
# 接口扫描路径
package-to-scan: com.example.demo
# 传输模型(com.naah69.rpc.drift.client.properties.DriftTransportModel)
transport-model: framed
# 序列化模型(com.naah69.rpc.drift.client.properties.DriftProtocolModel)
protocol-model: binary
# 服务列表刷新时间
refresh-interval: 30000
pool:
# 连接重试次数
retry-times: 0
# 连接超时时间
connect-timeout: 2000000
# 请求超时时间
request-timeout: 2000
# 最大连接数
pool-max-total-per-key: 1
# 最大空闲数
pool-max-idle-per-key: 1
# 最小空闲数
pool-min-idle-per-key: 1
# 最大等待时间
pool-max-wait: 3000
# 创建时测试可用
test-on-create: true
# 借出时测试可用
test-on-borrow: true
# 返回时测试可用
test-on-return: true
# 空闲连接自动被回收
test-while-idle: true
management:
endpoint:
shutdown:
enabled: true
health:
show-details: always
endpoints:
web:
exposure:
include: "*"
2.3 开启注解
在你的Application上添加以下的注解,开启组件。
@EnableDiscoveryClient
@EnableDriftClient
2.4 编写接口
通过以下几个注解来编写接口,因为怕使用者混淆,所以我们使用ThriftClient,表示这是Thrift服务的客户端。
//服务端在注册中心的名字
@ThriftClient(serviceId = "nlu_service")
public interface NLU {
//对应的方法的名字
@ThriftMethod("parse")
String parse(String scene, String version, String text);
@ThriftMethod("status")
String status();
}
2.5 服务注入
我们使用ThriftRefer注解来注入客户端,使用version字段我们可以进行版本号的设置,防止多版本服务在注册中心注册时调用混乱的BUG.
@ThriftRefer(version = "1.2.1")
private NLU nlu;
2.6 使用服务
经过以上几个步骤,我们就可以进行使用了。
@GetMapping("/demo")
public String demo(){
return nlu.status();
}