一个go http和grpc客户端库

news/2024/11/17 10:02:06/

大家好,我是peachesTao,今天是五一假期的第4天,首先祝大家劳动节快乐。今天给大家推荐一个统一http和grpc客户端调用的库,名为prpc,github地址:prpc,该库是我公司根据最佳实践总结开发出来的,它可以提升开发效率,让开发者聚焦于业务层代码。

下面我从三个方面来介绍

自动生成http客户端代码

1、编写http客户端代码痛点

首选我们来看一段调用http接口获取用户列表的代码

type GetUserListReq struct {Age  int32  `json:"age"`
}type GetUserListReply struct {Code int32       `json:"code"`Msg  string      `json:"msg"`List []*UserInfo `json:"list"`
}type UserInfo struct {Name string `json:"name"`Age  int32  `json:"age"`
}func GetUserList(req *protocol.GetUserListReq) (*GetUserListReply, error) {user := config.GetServerConfig().Userrequest, err := httplib.Post(user.URL+user.GetUserList).Debug(true).JSONBody(req)if err != nil {return nil, err}resp := new(protocol.GetUserListReply)err = request.ToJSON(resp)if err != nil {return nil, err}return resp, nil
}

分别定义了请求和响应数据结构体,从配置文件中获取http服务的url和用户列表接口的path,将请求结构体编码,然后通过http client库发起http请求,将返回的数据解码为响应结构体。

我们发现这样的代码有下面三个痛点

  1. 每次调用都要对req对象编码、res对象进行解码

  2. 需要在代码中硬编码读取配置服务端的url

  3. 如果服务端将Post改成Get方式,要改客户端的代码

这非常影响开发效率且容易出错,这些代码能不能自动生成?答案是可以的,凡是有规律的代码都可以自动生成。我们的实现方案是基于protobuf实现的。

2、基于protobuf的http客户端代码生成

我们使用protobuf定义服务调用方法、请求和响应结构体,再借助http Method Option自定义服务url和http method,最后用prpc内置的插件protoc-gen-go-prpc生成跟grpc相似的函数签名的客户端代码。

GetUserList protobuf文件定义:

syntax = "proto3";option go_package = "/api/";
import "google/api/annotations.proto";service User {//获取用户列表rpc GetUserList(GetUserListReq) returns (GetUserListReply) {option (google.api.http) = {get: "/user/list"body: "*"additional_bindings:[{custom:{kind:"Content-Type", path:"application/json"}}]};}
}message GetUserListReq {int32 age = 1;
}message GetUserListReply {int32 code = 1;string msg = 2 ;repeated UserInfo list = 3;
}message UserInfo {string name = 1;int32 age = 2;
}

自动生成的调用入口函数如下(此处省略了其他部分代码,想看完整的代码可以前往prpc-examples):

func (c *userClient) GetUserList(ctx context.Context, in *GetUserListReq, opts ...http.CallOption) (*GetUserListReply, error) {out := new(GetUserListReply)header := map[string]string{"Content-Type": "application/json",}opts = http.CallOptions(opts).CombineHeader(header)err := c.cc.HttpInvoke(ctx, "GET", "/user/list", in, out, opts...)if err != nil {return nil, err}return out, nil
}

开发者侧代码:

 conn := prpc.NewClientConn()err := conn.NewHttpClientConn(context.Background(), "127.0.0.1:8000")if err != nil {log.Error(err)return}userClient := api.NewUserClient(conn)listReply, err := userClient.GetUserList(context.Background(), &api.GetUserListReq{Age: 18})if err != nil {log.Error(err)return}log.Info(listReply)

可以看出,开发者就像调用grpc方法一样简单的调用http接口,实现了对协议的无感,开发者只需要在protobuf中定义相关信息,其他的交给插件就行。

http和grpc调用随意切换

因为http和grpc客户端调用代码都是根据protobuf生成的,生成的是http还是grpc取决于rpc方法是否定义了http method option,如果定义了则生成http代码,否则生成grpc调用代码。

所以http切换成grpc protobuf只需要删除http method option 部分即可,同理,grpc切换成http则加上它就行。

上面GetUserList改成grpc调用的话protobuf rpc方法定义如下:

service User {//获取用户列表rpc GetUserList(GetUserListReq) returns (GetUserListReply) {}
}

服务发现和负载均衡

prpc还包含集群模式下的服务发现和负载均衡功能,一套服务发现和负载均衡机制同时兼容http和grpc,且都支持扩展。

开发者只需要实现resolver和balancer接口就可以自定义服务发现和负载均衡,目前prpc内置了基于consul的服务发现和轮训的负载均衡功能。

后续我们将增加基于zookeeper,etcd的服务发现和实现权重的负载均衡方式,也欢迎小伙伴积极参与进来,给我们贡献代码,共同完善prpc。

更多的细节请前往github prpc了解

相关链接

[prpc] https://github.com/classtorch/prpc
[prpc-examples] https://github.com/classtorch/prpc-examples


http://www.ppmy.cn/news/60025.html

相关文章

Java 多线程知识

参考链接:https://www.cnblogs.com/kingsleylam/p/6014441.html https://blog.csdn.net/ly0724ok/article/details/117030234/ https://blog.csdn.net/jiayibingdong/article/details/124674922 导致Java线程安全问题最主要的原因: (1&#…

Java基础(十七)File类与IO流

1. java.io.File类的使用 1.1 概述 File类及本章下的各种流,都定义在java.io包下。一个File对象代表硬盘或网络中可能存在的一个文件或者文件目录(俗称文件夹),与平台无关。(体会万事万物皆对象)File 能新…

WordPress网站如何开启Gzip压缩快速传输

最近无聊都没有使用Gzip压缩,是因为发现开启这个压缩也是有学问的。服务器上设置、WordPress站点上设置还是插件上设置让我有所疑惑。通过几天的研究学习,总结并分享下如何将 WordPress 站点开启 Gzip 压缩以达到加快传输的目的。 gzip on; gzip_min_length 1k; gzip_buffe…

linux_线程基础函数-pthread_self函数-pthread_create函数-pthread_exit函数-pthread_join函数

接上一篇:linux_线程概念-内核线程实现原理-线程共享资源-线程优缺点 今天来分享线程的代码函数了,主要是获得线程ID、创建线程函数、线程退出函数、等待线程结束函数,以及分享这些函数的例子,话不多说,开始上菜&#…

MySQL索引详解及如何使用

前言 MySQL 索引是 MySQL 数据库中的一项重要功能,它可以大大提高查询效率,加快数据检索速度。在本文中,我们将深入探讨 MySQL 索引的相关知识,包括索引的作用、常用索引类型、如何创建和使用索引等。我们将会从以下四个方面进行…

代码随想录算法训练营第四十八天| 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

文章目录 198.打家劫舍213.打家劫舍II337.打家劫舍III 198.打家劫舍 题目链接:代码随想录 解题思路: 1.dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i] 只是考虑,不一定偷 2.递推…

mobile代码打APK包

1、安装Android SDK Android SDK 下载地址: http://www.androiddevtools.cn/ 下载位置 下载后解压 打开解压文件,点击 SDK Manager.exe 进行安装 安装组件,这要选 Android 8.0.0 或者以上版本 再次安装,发现没什么可以安装了 2…

【在homeassistant的ONVIF中配置TP-Link】

【在homeassistant的ONVIF中配置TP-Link】 1. 配置2. 手动配置步骤3. 配置说明4. 集成的额外配置5. 支持的传感器6. SERVICE ONVIF.PTZ7. 支持的交换机欢迎大家阅读2345VOR的博客【在homeassistant的ONVIF中配置TP-Link】,本页是在homeassistant的ONVIF中配置TP-Link教程🥳�…