Kratos微服务框架下实现Thrift服务

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式;用户通过Thrift的IDL(接口定义语言)来描述接口函数及数据类型,然后通过Thrift的编译环境生成各种语言类型的接口文件,用户可以根据自己的需要采用不同的语言开发客户端代码和服务器端代码。2007年由facebook贡献到apache基金,是apache下的顶级项目

Kratos微服务框架下实现Thrift服务

什么是Thrift

Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式;用户通过Thrift的IDL(接口定义语言)来描述接口函数及数据类型,然后通过Thrift的编译环境生成各种语言类型的接口文件,用户可以根据自己的需要采用不同的语言开发客户端代码和服务器端代码。2007年由facebook贡献到apache基金,是apache下的顶级项目,具备如下特点:

  • 支持多语言:C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
  • 消息定义文件支持注释,数据结构与传输表现的分离,支持多种消息格式
  • 包含完整的客户端/服务端堆栈,可快速实现RPC,支持同步和异步通信

Thrift的优缺点

Thrift的优点

  • One-stop shop,相对于protobuf,序列化和RPC支持一站式解决,如果是pb的话,还需要考虑选择RPC框架,现在Google是开源了gRpc,但是几年以前是没有第一方的标准解决方案的
  • 特性丰富,idl层面支持map,protobuf应该是最近才支持的,map的key支持任意类型,avro只支持string,序列化支持自定义protocol, rpc支持thread pool, hsha, no blocking 多种形式,必有一款适合你,对于多语言的支持也非常丰富
  • RPC和序列化性能都不错,这个到处都有benchmark,并不是性能最好的,但是基本上不会成为瓶颈或者短板
  • 有很多开源项目的周边支持都是thrift的,hbase提供thrift服务,hive,spark sql,cassandra等一系列对外的标准服务接口都是thrift的以支持多语言。
  • Column Storage的话,parquet支持直接通过thrift idl转换,如果在Hadoop集群上存储数据,elephant-bird 支持得很好,你可以很方便地针对thrift的数据通过pig写dsl,如果你希望在rpc服务外做一系列工作,可以用finagle包装一层。不过,这部分对于protobuf和avro支持一般也不错

Thrift的缺点

  • 基本没有官方文档
  • RPC在 0.6.1 升级到 0.7.0 是不兼容的!这个对于早于 0.6.1 开始使用的用户来说是个大坑
  • bug fix和更新不积极,好在序列化和RPC服务都不是太复杂的问题,需要考量的设计问题不多,自己维护patch的成本不高,如果我没有记错的话,0.6.1的java的ThreadPool Server是会有Thread死亡之后的Thread泄露问题的
  • 不支持双向通道,如果要支持双向通道比较麻烦
  • rpc方法非线程安全,这就是为何很多时候服务器会被挂死,是因为客户端的并发rpc调用导致的,只需要客户端对rpc的调用进行串行化即可。统一服务器应答的时候,也需要串行化,否则有可能会把对方给挂死。特别是在多线程情况下。

什么时候应该选择Thrift

  • 需要在非常多的语言间进行数据交换
  • 对CPU敏感
  • 协议层、传输层有多种控制要求
  • 需要稳定的版本
  • 不需要良好的文档和示例

Thrift 网络栈架构

TTransport 层

  • TSocket :阻塞 Socket
  • TFrameTransport :以 frame 为单位进行传输, 非阻塞式服务中使用
  • TFileTransport : 以文件形式进行传输

TProtocol 层

代表 thrift 客户端和服务端之间的传输数据的协议,指的是客户端和服务端传输数据的格式,比如 Json, thrift 中有如下格式:

  • TBinaryProtocol:二进制格式
  • TCompactProtocol:压缩格式
  • TJSONProtocol : Json格式
  • TSimpleJsonProtocol:提供只写的 JSON 协议

Thrift 支持的 Server 模型

  • TSimpleServer :用于简单的单线程模型,常用于测试
  • TThreadPoolServer :多线程模型,使用标准的阻塞 IO
  • TNoBlockingServer: 多线程服务模型,使用非阻塞 IO,需要使用TFramedTransport 数据传输方式。
  • THsHaServer : THsHa
    引入了线程池去处理,其模型读写任务放到线程池去处理,Half-sync/Half-async处理模式,Half-async是在处理IO事件上(
    accept/read/write io),Half-sync用于handler对rpc的同步处理;

Thrift支持的数据类型以及关键字

基本数据类型

类型 说明
byte 有符号字节
i16 16 位有符号整数
i32 32 位有符号整数
i64 64 位有符号整数
double 64 位浮点数
string 字符串

容器类型

类型 说明
list 一系列由 T 类型的数据组成的有序列表, 元素可以重复
set 一系列由 T 类型组成的无序集合,元素不可以重复
map 一个字典结构,Key 为 K 类型, Value 为 V 类型,和 Java 中的 HashMap 类似thrift 支持 struct 类型,可以将一些数据类型聚合到一块。

Struct类型

Struct:类似于C的struct,是一系列相关数据的封装,在OOP语言中会转换为类(class),struct的每个元素包括一个唯一的数字标识、一个数据类型、一个名称和一个可选的默认值。语法:

struct People {
    1:string name;
    2:i32 age;
    3:string gender;
}

Union类型

union SomeUnion {
  2: string string_thing,
  3: i32 i32_thing
}

Enum类型

Enum:Thrift枚举类型只支持单个32位int类型数据,第一个元素如果没有给值那么默认是0,之后的元素如果没有给值,则是在前一个元素基础上加1,语法:

enum Gender {
    MALE,
    FEMALE
}

别名

Typedef:Thrift 支持C/C++风格的类型自定义,语法:

// typedef 原类型 自定义类型

typedef i32 int
typedef i64 long

常量

Const:定义常量,Thrift允许使用JSON来定义复杂类型和struct类型,语法:

// const 字段类型 名称标识 = 值 | 列表

const i32 MAX_RETRIES_TIME = 10;
const string MY_WEBSITE = "http://facebook.com";

Exception类型

Exception:异常跟struct类似,会跟目标语言本地异常集成,语法:

exception RequestException {
    1:i32 code;
    2:string reason;
}

Service类型

Service:service是Thrift 服务器提供的一系列功能列表接口,在客户端就是调用这些接口来完成操作,语法:

service HelloWorldService {
    // service中可以定义若干个服务,相当于Java Interface中定义的方法
    string doAction(1:string name, 2:i32 age);
}

命名空间

定义名称空间/包名/模块等等,可以使用编程语言名称规定某一特定语言的namespace,用*表示所有未匹配到的语言的namespace,语法

// namespace [语言名称] 标识符

namespace cpp api
namespace go api
namespace d api
namespace dart api
namespace java api
namespace php api
namespace perl api
namespace haxe api
namespace netstd api

// 用*表示所有未匹配到的语言的namespace
namespace * api

注释

# shell风格注释

/*
 * 多行注释
 */

// 单行注释

包含引用

Thrift Include:将所有声明包含的Thrift文档都包含到当前Thrift中来,语法:

// 包含其他的thrift文件
// inlucde "文件名"
include "other.thrift"

C++ Include:将用户自己的C++头文件包含到当前Thrift中来,语法:

// 将用户自己的C++头文件包含到当前Thrift中来
// cpp_include "头文件"
cpp_include "string"

安装编译器

Linux安装编译器

sudo apt install thrift-compiler

Windows安装编译器

先去官网下载编译器:https://thrift.apache.org/download

然后把编译器放在一个全局可以运行的目录下面,比如:c:/Windows。

Mac安装编译器

brew install thrift

编译Thrift文件

# 
thrift --gen <language> <Thrift filename>

# 如果有thrift文件中有包含其他thrift,可以使用递归生成命令
thrift -r --gen <language> <Thrift filename>

# 示例
thrift -r -gen go tutorial.thrift

开始在Kratos微服务框架下使用Thrift

我封装了一个Thrift服务,可以在Kratos微服务框架下直接使用:https://github.com/tx7do/kratos-transport/tree/main/transport/thrift

实例程序的目标是从服务器获取温湿度信息,然后将温湿度信息发送给客户端。示例代码可以在单元测试里面找到。

创建Thrift文件

namespace go api

struct Hygrothermograph {
  1: optional double Humidity,
  2: optional double Temperature,
}

service HygrothermographService {
  Hygrothermograph getHygrothermograph()
}

然后生成代码。生成的代码在thrift文件所在目录下的:gen-go/{namespace}之下。

开发服务器

首先,实现Handler

type HygrothermographHandler struct {
}

func NewHygrothermographHandler() *HygrothermographHandler {
return &HygrothermographHandler{}
}

func (p *HygrothermographHandler) GetHygrothermograph(ctx context.Context) (_r *api.Hygrothermograph, _err error) {
var Humidity = float64(rand.Intn(100))
var Temperature = float64(rand.Intn(100))
_r = &api.Hygrothermograph{
Humidity:    &Humidity,
Temperature: &Temperature,
}
fmt.Println("Humidity:", Humidity, "Temperature:", Temperature)
return
}

Handler在Kratos里面的使用的语义是Service,实际应用的时候,将之实现为Service。

实现服务端

    ctx := context.Background()

srv := NewServer(
WithAddress(":7700"),
WithProcessor(api.NewHygrothermographServiceProcessor(NewHygrothermographHandler())),
)

if err := srv.Start(ctx); err != nil {
panic(err)
}

defer func () {
if err := srv.Stop(ctx); err != nil {
t.Errorf("expected nil got %v", err)
}
}()

使用WithProcessor方法我们把之前的Handler注册成Processor到服务器。

开发客户端

conn, err := Dial(
WithEndpoint("localhost:7700"),
)
if err != nil {
t.Fatal(err)
}
defer conn.Close()

client := api.NewHygrothermographServiceClient(conn.Client)

reply, err := client.GetHygrothermograph(context.Background())
//t.Log(err)
if err != nil {
t.Errorf("failed to call: %v", err)
}
t.Log(*reply.Humidity, *reply.Temperature)

Thrift客户端跟gRpc的客户端是一样的,使用Dial方法创建一个连接,然后直接调用RPC方法。

参考文档

目录
相关文章
|
1月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
107 3
|
1月前
|
Cloud Native Java API
聊聊从单体到微服务架构服务演化过程
本文介绍了从单体应用到微服务再到云原生架构的演进过程。单体应用虽易于搭建和部署,但难以局部更新;面向服务架构(SOA)通过模块化和服务总线提升了组件复用性和分布式部署能力;微服务则进一步实现了服务的独立开发与部署,提高了灵活性;云原生架构则利用容器化、微服务和自动化工具,实现了应用在动态环境中的弹性扩展与高效管理。这一演进体现了软件架构向着更灵活、更高效的方向发展。
|
25天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
24天前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
46 9
|
26天前
|
监控 安全 Java
构建高效后端服务:微服务架构深度解析与最佳实践###
【10月更文挑战第19天】 在数字化转型加速的今天,企业对后端服务的响应速度、可扩展性和灵活性提出了更高要求。本文探讨了微服务架构作为解决方案,通过分析传统单体架构面临的挑战,深入剖析微服务的核心优势、关键组件及设计原则。我们将从实际案例入手,揭示成功实施微服务的策略与常见陷阱,为开发者和企业提供可操作的指导建议。本文目的是帮助读者理解如何利用微服务架构提升后端服务的整体效能,实现业务快速迭代与创新。 ###
60 2
|
1月前
|
消息中间件 Kafka 数据库
微服务架构中,如何确保服务之间的数据一致性?
微服务架构中,如何确保服务之间的数据一致性?
|
1月前
|
Dubbo Java 应用服务中间件
Dubbo学习圣经:从入门到精通 Dubbo3.0 + SpringCloud Alibaba 微服务基础框架
尼恩团队的15大技术圣经,旨在帮助开发者系统化、体系化地掌握核心技术,提升技术实力,从而在面试和工作中脱颖而出。本文介绍了如何使用Dubbo3.0与Spring Cloud Gateway进行整合,解决传统Dubbo架构缺乏HTTP入口的问题,实现高性能的微服务网关。
|
28天前
|
运维 Kubernetes 开发者
构建高效后端服务:微服务架构与容器化技术的结合
【10月更文挑战第18天】 在数字化转型的浪潮中,企业对后端服务的要求日益提高,追求更高的效率、更强的可伸缩性和更易于维护的系统。本文将探讨微服务架构与容器化技术如何结合,以构建一个既灵活又高效的后端服务体系。通过分析当前后端服务面临的挑战,介绍微服务和容器化的基本概念,以及它们如何相互配合来优化后端服务的性能和管理。本文旨在为开发者提供一种实现后端服务现代化的方法,从而帮助企业在竞争激烈的市场中脱颖而出。
25 0
|
2月前
|
消息中间件 Kafka 数据库
微服务架构中,如何确保服务之间的数据一致性
微服务架构中,如何确保服务之间的数据一致性
|
2月前
|
Java API 对象存储
微服务魔法启动!Spring Cloud与Netflix OSS联手,零基础也能创造服务奇迹!
这段内容介绍了如何使用Spring Cloud和Netflix OSS构建微服务架构。首先,基于Spring Boot创建项目并添加Spring Cloud依赖项。接着配置Eureka服务器实现服务发现,然后创建REST控制器作为API入口。为提高服务稳定性,利用Hystrix实现断路器模式。最后,在启动类中启用Eureka客户端功能。此外,还可集成其他Netflix OSS组件以增强系统功能。通过这些步骤,开发者可以更高效地构建稳定且可扩展的微服务系统。
56 1