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

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 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方法。

参考文档

目录
相关文章
|
28天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
14天前
|
NoSQL 前端开发 测试技术
👀探秘微服务:从零开启网关 SSO 服务搭建之旅
单点登录(Single Sign-On,简称SSO)是一种认证机制,它允许用户只需一次登录就可以访问多个应用程序或系统。本文结合网关和SaToken快速搭建可用的Session管理服务。
64 8
|
2月前
|
弹性计算 持续交付 API
构建高效后端服务:微服务架构的深度解析与实践
在当今快速发展的软件行业中,构建高效、可扩展且易于维护的后端服务是每个技术团队的追求。本文将深入探讨微服务架构的核心概念、设计原则及其在实际项目中的应用,通过具体案例分析,展示如何利用微服务架构解决传统单体应用面临的挑战,提升系统的灵活性和响应速度。我们将从微服务的拆分策略、通信机制、服务发现、配置管理、以及持续集成/持续部署(CI/CD)等方面进行全面剖析,旨在为读者提供一套实用的微服务实施指南。
|
30天前
|
弹性计算 Kubernetes API
构建高效后端服务:微服务架构的深度剖析与实践####
本文深入探讨了微服务架构的核心理念、设计原则及实现策略,旨在为开发者提供一套系统化的方法论,助力其构建灵活、可扩展且易于维护的后端服务体系。通过案例分析与实战经验分享,揭示了微服务在提升开发效率、优化资源利用及增强系统稳定性方面的关键作用。文章首先概述了微服务架构的基本概念,随后详细阐述了其在后端开发中的应用优势与面临的挑战,最后结合具体实例,展示了如何从零开始规划并实施一个基于微服务的后端项目。 ####
|
2月前
|
监控 持续交付 数据库
构建高效的后端服务:微服务架构的深度解析
在现代软件开发中,微服务架构已成为提升系统可扩展性、灵活性和维护性的关键。本文深入探讨了微服务架构的核心概念、设计原则和最佳实践,通过案例分析展示了如何在实际项目中有效地实施微服务策略,以及面临的挑战和解决方案。文章旨在为开发者提供一套完整的指导框架,帮助他们构建出更加高效、稳定的后端服务。
|
3月前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
2月前
|
Kubernetes API Docker
构建高效后端服务:微服务架构的深度实践与优化####
本文深入探讨了微服务架构在现代后端开发中的应用,通过剖析其核心概念、设计原则及实施策略,结合具体案例分析,展示了如何有效提升系统的可扩展性、可靠性和维护性。文章还详细阐述了微服务拆分的方法论、服务间通信的最佳实践、以及容器化与编排工具(如Docker和Kubernetes)的应用技巧,为读者提供了一份全面的微服务架构落地指南。 ####
|
3月前
|
监控 API 持续交付
构建高效后端服务:微服务架构的深度探索
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于支撑复杂的业务逻辑和海量数据处理至关重要。本文深入探讨了微服务架构的核心理念、实施策略以及面临的挑战,旨在为开发者提供一套构建高效、可扩展后端服务的方法论。通过案例分析,揭示微服务如何帮助企业应对快速变化的业务需求,同时保持系统的稳定性和灵活性。
51 9
|
2月前
|
分布式计算 Java 持续交付
如何选择合适的微服务框架
如何选择合适的微服务框架
35 0
|
3月前
|
监控 安全 Java
构建高效后端服务:微服务架构深度解析与最佳实践###
【10月更文挑战第19天】 在数字化转型加速的今天,企业对后端服务的响应速度、可扩展性和灵活性提出了更高要求。本文探讨了微服务架构作为解决方案,通过分析传统单体架构面临的挑战,深入剖析微服务的核心优势、关键组件及设计原则。我们将从实际案例入手,揭示成功实施微服务的策略与常见陷阱,为开发者和企业提供可操作的指导建议。本文目的是帮助读者理解如何利用微服务架构提升后端服务的整体效能,实现业务快速迭代与创新。 ###
71 2