gRPC调用坎坷历程记录

gRPC服务的架构图 RPC调用总的来说就是客户端调用存根的代码,然后存根代码和RPC库实现通信,服务端的存根收到了信息后交给具体的服务进行处理,之后再原路返回就完了。 这里附上一篇关于gRPC讲解的博客园的文章 Proto文件代码生成 项目的前后端都是使用的gRPC进行通信,都需要使用protoc编译器把之前定义好的proto文件进行编译生成对应的代码进行调用。 问题1 timestamp.proto文件找不到 timestamp.proto是google的一个时间戳的包,因为在我们自己的proto文件中使用到了google.protobuf.Timestamp,在proeo文件的最上方也要导入对应的proto文件import "google/protobuf/timestamp.proto"; 我记得在下载protoc编译器的时候,压缩包下面就有一个include文件夹,其中就包含有timestamp.proto文件 问题2 go代码生成对应的包名和位置对不上 项目的后端采用的是go,想要把proto文件编译成golang的代码。这就需要在proto文件中加上go_package的字段,比如: syntax = "proto3"; package rpc.auth; option go_package = "github.com/BigNoseCattyHome/aorb/backend/rpc/auth;auth"; import "google/protobuf/timestamp.proto"; // 定义消息,用于请求和响应结构 message LoginRequest { string username = 1; // 用户名/用户ID string password = 2; // 密码的md5摘要 string device_id = 3; // 设备ID google.protobuf.Timestamp timestamp = 4; // 时间戳 string nonce = 5; // 随机数 } 然后在使用protoc编译的时候,在命令行中也要加上go的一些选项,比如: protoc --go_out=. person.proto // 找到当前目录下的person.proto并生成go的代码,输出到当前目录(.) 但是又有了一个问题就是在该文件夹下面,会生成你的包名go_package的层级目录,最后才是你的最终代码。但是我想让proto文件直接生成在一个固定的文件夹位置,并且没有那么多的层级文件夹。 然后发现了有一个命令选项是--go_opt=paths=source_relative,使得生成的Go代码文件的路径与对应的.proto文件的路径保持一致 问题3 dart代码生成的时候老是存在找不到pb.xx 后来上google和stackoverflow看了半天,发现结果是依赖版本的问题,把protobuf的依赖版本从^2....

July 23, 2024 · 4 min · 662 words · sirius1y

Auth微服务开发记录

Auth服务 这里先写我们的初步规划,最终的实现放在最后写。这实际上也是我们的开发思路。 初步规划的API /api/v1/auth/login ​ 登录接口允许用户输入用户名和密码进行登录,服务器验证成功后,会返回一个JWT。JWT会存储在客户端的本地存储中 /api/v1/auth/register ​ 用户注册,填写用户的基本信息,在服务器的数据库上进行注册 /api/v1/auth/verify ​ 用户在拿着JWT去访问别的微服务的时候,我们要先验证这个JWT的合法性。确保用户合法。具体的实现就是去检查这个JWT是否过期,用户名是否正确。 /api/v1/auth/refresh ​ JWT有一个Expire过期时间,当用户还在使用的时候,JWT需要刷新。就使用刷新令牌进行刷新,经过服务器验证之后,返回一个新的刷新令牌。 /api/v1/auth/logout ​ 退出登录,需要在客户端本地删除token,并且把刷新令牌revoke 查阅资料:刷新Token的策略 刷新令牌(Refresh Token) 定义: 刷新令牌是一种用于获取新的访问令牌(Access Token)的凭证,通常在访问令牌过期后使用,以避免用户频繁重新登录。 工作原理: 用户首次登录时,服务器颁发一个访问令牌和一个刷新令牌。 访问令牌用于访问受保护的资源,具有较短的有效期。 当访问令牌过期时,客户端使用刷新令牌向服务器请求新的访问令牌。 服务器验证刷新令牌的有效性,如果有效,则颁发新的访问令牌,并可能同时颁发新的刷新令牌。 优点: 提高用户体验,减少频繁登录的需求。 访问令牌具有较短的有效期,降低安全风险。 缺点: 需要妥善保护刷新令牌,因为刷新令牌的泄露可能导致长期的安全问题。 实现强制注销或更改密码后立即失效所有令牌比较困难。 缓存令牌(Cached Token) 定义: 缓存令牌是指将令牌存储在缓存系统(如Redis)中,以便快速验证和撤销令牌。 工作原理: 用户登录后,服务器生成一个令牌并将其存储在缓存系统中。 客户端在访问受保护的资源时,携带令牌。 服务器从缓存系统中验证令牌的有效性。 如果需要撤销令牌,服务器可以从缓存系统中删除该令牌。 优点: 快速验证和撤销令牌,提高系统的响应速度。 灵活的令牌管理,可以随时撤销某个令牌。 缺点: 增加了系统的复杂性,需要维护缓存系统。 依赖外部服务,如果缓存系统出现故障,会影响整个系统的正常运行。 双令牌机制(Dual Token Mechanism) 定义: 双令牌机制是指使用两种不同类型的令牌来实现更复杂的授权和身份验证流程。 工作原理: 用户通过身份验证后,服务器颁发一个身份验证令牌(例如JWT)和一个授权令牌(例如OAuth 2.0的访问令牌)。 身份验证令牌用于证明用户的身份,通常具有较长的有效期。 授权令牌用于访问受保护的资源,通常具有较短的有效期。 当授权令牌过期时,客户端可以使用身份验证令牌向服务器请求新的授权令牌。 优点: 身份验证令牌具有较长的有效期,减少用户频繁登录的需求。 授权令牌具有较短的有效期,降低安全风险。 可以实现更复杂的授权策略。 缺点: 实现和管理双令牌机制比单一令牌机制更复杂。 需要妥善保护身份验证令牌,因为身份验证令牌的泄露可能导致长期的安全问题。 总结 刷新令牌主要用于在访问令牌过期后获取新的访问令牌,减少用户频繁登录的需求。 缓存令牌通过将令牌存储在缓存系统中,实现快速验证和撤销令牌。 双令牌机制使用两种不同类型的令牌来实现更复杂的身份验证和授权流程。 每种机制都有其适用的场景和优缺点,选择合适的机制需要根据具体的安全需求和业务场景来决定。...

June 18, 2024 · 1 min · 94 words · sirius1y

Protobuf与gRPC初次使用

在项目aorb中能够使用了微服务架构,然后引入了RPC,现在目前开发中,晚点再来完善这篇文章。现在先记录一些主要的概念。 IDL 接口定义语言 IDL(Interface Definition Language,接口定义语言)是一种用于定义软件组件之间接口的语言。IDL允许开发人员定义程序模块之间的接口,使得不同语言、平台和系统能够通过统一的接口进行通信。IDL的主要作用是定义数据类型和RPC(Remote Procedure Call,远程过程调用)的接口。 Proto接口定义的意义 Proto接口定义是指使用Protocol Buffers(protobuf)来定义数据结构和服务接口。protobuf是由Google开发的一种高效的二进制序列化格式,常用于配置文件、数据存储格式和通信协议。 跨语言支持:proto文件可以生成多种语言的代码,包括C++、Java、Python等,确保不同语言的系统可以互相通信。 高效传输:protobuf序列化后的数据体积小,解析速度快,适合网络传输。 版本兼容:proto文件可以通过增加新字段来实现向后兼容,不影响旧的客户端和服务器。 RPC(Remote Procedure Call,远程过程调用) RPC是一种通过网络从远程计算机程序上执行子程序的协议,仿佛是在本地执行一样。RPC隐藏了底层的网络通信细节,使得开发者可以像调用本地方法一样调用远程方法。 IDL和RPC的关系 IDL用于定义RPC接口,指定远程调用所需的参数和返回值类型。通过IDL定义的接口,可以自动生成客户端和服务器的桩代码(stub),这些代码负责处理序列化和反序列化、网络通信等底层细节,使得开发者可以专注于业务逻辑。 RESTful和gRPC的关系 RESTful和gRPC是两种不同的网络通信风格和框架,它们各自服务于不同的应用场景和需求。下面是它们之间的关系和区别: RESTful (Representational State Transfer): RESTful是一种基于HTTP协议的设计风格,它利用HTTP的方法(如GET、POST、PUT、DELETE等)来操作资源。 RESTful服务通常使用JSON或XML作为数据交换格式。 RESTful API设计简单,易于理解和使用,适合于跨平台和跨语言的场景。 由于基于HTTP,RESTful服务天然支持浏览器和各种HTTP客户端,易于缓存和负载均衡。 gRPC (Google Remote Procedure Call): gRPC是由Google开发的高性能、开源的通用RPC框架。 gRPC使用Protocol Buffers(protobuf)作为接口定义语言(IDL)和数据序列化格式。 gRPC支持多种语言,并提供了跨语言的接口调用能力。 gRPC支持双向流式传输,适合于需要高性能和低延迟的场景,如微服务架构。 gRPC默认使用HTTP/2作为传输协议,支持多路复用和服务端推送等特性。 关系: RESTful和gRPC都是用于构建分布式系统和微服务的通信协议,但它们的设计理念和使用场景有所不同。 RESTful更多地依赖于HTTP协议的特性,而gRPC则是一个独立的RPC框架,虽然它也使用了HTTP/2协议,但其核心在于protobuf的序列化和高效的RPC调用。 在实际应用中,选择RESTful还是gRPC取决于具体的需求,如性能要求、开发语言、团队熟悉度、生态系统支持等。 总结: RESTful和gRPC是两种互补的技术,它们各自在不同的领域和场景中发挥作用。开发者可以根据项目的具体需求和约束来选择最合适的通信方式。 .pb.go和_grpc.pb.go文件 在Go语言中使用Protocol Buffers (protobuf) 时,通常会生成两个主要的Go文件,分别是 auth_grpc.pb.go 和 auth.pb.go。这两个文件的作用如下: auth.pb.go: 这个文件是由protobuf编译器根据.proto文件中的消息定义生成的。它包含了所有在.proto文件中定义的消息(messages)、枚举(enums)和任何其他非RPC相关的数据结构的Go语言实现。 auth.pb.go 文件主要负责序列化和反序列化数据,以及提供对消息结构的访问。例如,如果你在.proto文件中定义了一个名为 Token 的消息,auth.pb.go 将包含一个名为 Token 的Go结构体以及用于操作这个结构体的函数,如 Marshal、Unmarshal、New 等。 auth_grpc.pb.go: 这个文件是由protobuf编译器根据.proto文件中的服务定义(service definitions)生成的,特别是当.proto文件中包含了gRPC服务定义时。 auth_grpc....

June 18, 2024 · 1 min · 205 words · sirius1y

Flutter开发

关键字 late late关键字允许变量将在稍后初始化,但必须在使用之前初始化。 这与 final 关键字不同,final 关键字用于声明必须在声明时或构造函数运行之前初始化的变量。 late 关键字的主要优点是可以提高性能,尤其是在构造函数中包含复杂初始化逻辑的类的情况下。通过使用 late 关键字,您可以推迟初始化,直到实际需要使用该变量时再进行初始化。这可以避免在构造函数中执行不必要的初始化工作,从而提高性能。 以下是一些有关如何使用 late 关键字的示例: class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { late String _data; @override void initState() { super.initState(); // 此处推迟了 _data 变量的初始化 _loadData(); } void _loadData() async { // 模拟异步数据加载 await Future.delayed(Duration(seconds: 2)); setState(() { _data = 'Data loaded'; }); } @override Widget build(BuildContext context) { if (_data == null) { return CircularProgressIndicator(); } return Text(_data); } } 在这个示例中,_data 变量使用 late 关键字声明。这意味着该变量不必在声明时或构造函数运行之前初始化。相反,它可以在稍后初始化,例如在 initState 方法中。这可以提高性能,因为只有在实际需要使用该变量时才会进行初始化。...

May 24, 2024 · 8 min · 1578 words · sirius1y

点击排行榜scoreboard

项目概述 项目地址:https://github.com/sirius2alpha/scoreboard 使用Redis在服务器上对用户的点击数排序,并返回点击次数排行榜。 技术栈 整体设计 用户界面 排行榜展示区: 显示当前排行榜的状态。 点击按钮: 用户点击来增加他们的计分。 昵称输入和提交: 允许新用户输入昵称并参与排行榜。 实时更新监听: 不需要用户交互,自动更新排行榜。 WebSocket客户端逻辑 建立连接: 当用户访问网站时,建立WebSocket连接。 发送点击事件: 当用户点击按钮时,发送消息到服务器。 接收排行榜更新: 监听来自服务器的排行榜更新,并更新界面。 用户注册: 发送新用户的昵称到服务器。 处理断开连接: 如果用户20秒未操作,发送断开消息到服务器。 后端设计(Gin + Redis) WebSocket服务器 处理WebSocket连接: 接受和管理WebSocket连接。 接收消息: 解析从客户端接收到的消息(点击事件,新用户注册)。 Redis交互: 更新用户的分数并重新排序排行榜。 广播排行榜更新: 将更新后的排行榜发送给所有连接的客户端。 处理断开: 移除30秒未操作的用户。 Redis逻辑 用户分数管理: 存储和更新用户分数。 排行榜排序: 实时更新排行榜。 数据持久化: 保证数据在服务重启后仍然可用。 API设计 本项目API设计采用的是websocket实现。 由于考虑到用户在点击比较频繁,如果采用HTTP会造成头部开销较大,而websocket的头部开销会相对小一些。 消息类型 UserClick: { type: “UserClick”, nickname: “用户昵称” } NewUser: { type: “NewUser”, nickname: “用户昵称” } UserInactive: { type: “UserInactive”, nickname: “用户昵称” }...

January 21, 2024 · 2 min · 287 words · sirius1y