grpc与rpcx的区别
- 什么是微服务?
- rpc架构的主要区别
- rpcx与grpc的区别
- rpcx:
- grpc:
- 为什么grpc要使用http2,为什么不适应http1或者http3?
- 为什么grpc要使用proto而不是json或者其他数据格式?
- 为什么rpcx快,快多少?
- rpcx的具体性能指标与grpc比较:
什么是微服务?
整体功能通过多个程序实现,每个程序只关心特定的业务.
优点:
简化功能: 单个服务之需要关心部分业务,实现起来更容易
更灵活: 不同服务间互不影响,可以使用不同的语言与技术栈,以及交给不同的成员/团队实现,便于团队合作/外包
隔离: 部分服务出问题不影响其他服务的功能
拓展: 更容易针对借口的实际压力情况进行横向拓展.
rpc架构的主要区别
rpc架构的核心功能实际上是实现远程调用服务方法调用,客户端能像调用本地方法一样调用服务端和方法
那么核心问题就是如何实现接口的远程调用,选择什么网络协议,数据格式,这些决定了rpc架构是否跨语言,以及性能如何
可以写一个简单的rpc服务的demo去了解rpc是如何工作的
下面是一个很粗糙的demo;使用tcp进行通信,json进行编码的demo
public.go
package public
//公共的方法与类
import ("bytes""encoding/binary"
)func Encode(data []byte) []byte {l := len(data)lBytes := IntToBytes(l)return append(lBytes, data...)
}func IntToBytes(n int) []byte {data := int64(n)bytebuf := bytes.NewBuffer([]byte{})binary.Write(bytebuf, binary.BigEndian, data)return bytebuf.Bytes()
}func BytesToInt(bys []byte) int {bytebuff := bytes.NewBuffer(bys)var data int64binary.Read(bytebuff, binary.BigEndian, &data)return int(data)
}type ReqData struct {ServerName stringTag string //标记哪个线程调用的服务,返回的时候带上可以将数据传输到对应的县城Data []byte
}
type RspData struct {Tag string //标记哪个线程调用的服务,返回的时候带上可以将数据传输到对应的县城Data []byte
}type AddReq struct {NumA intNumB int
}type AddRsp struct {Sum int
}
server.go
package mainimport ("bufio""encoding/json""fmt""net""rpc_demo/public"
)type Server struct{}func (s *Server) Add(a *public.AddReq) *public.AddRsp {return &public.AddRsp{Sum: a.NumA + a.NumB}
}// 服务调用
// 服务名+方法名
// 封装对应的服务调用过程:根据方法名解析数据,并调用对应的方法
// 数据打包返回
// 这里做简化板手写处理:1. 没有实现自动化的服务方法注册;2. 我暂定使用uuid进行标识请求,以便于客户端可以将数据读取到对应的请求线程上,但事实上uuid过长,应该使用更为简单的标识方式
func serve(conn net.Conn) {defer conn.Close()reader := bufio.NewReader(conn)for {//解析长度lBytes := make([]byte, 8)_, err := reader.Read(lBytes[:])if err != nil {fmt.Printf("数据读取失败%v\n", err)return}l := public.BytesToInt(lBytes)reqBytes := make([]byte, l)_, err = reader.Read(reqBytes)if err != nil {fmt.Printf("数据读取失败%v\n", err)return}go func(reqData []byte) {req := new(public.ReqData)err = json.Unmarshal(reqData, req)if err != nil {fmt.Printf("json 解析失败%v\n", err)return}//解析处理(这里只注册了一个服务接口)switch req.ServerName {case "Server.Add":s := &Server{}data := new(public.AddReq)err := json.Unmarshal(req.Data, data)if err != nil {fmt.Printf("json 解析失败%v\n", err)return}rsp := s.Add(data)result, err := json.Marshal(rsp)if err != nil {fmt.Printf("数据编码失败%v\n", err)return}rspBytes, err := json.Marshal(&public.RspData{Tag: req.Tag, Data: result})if err != nil {fmt.Printf("数据编码失败%v\n", err)return}rspData := append(public.IntToBytes(len(rspBytes)), rspBytes...)conn.Write(rspData)default:conn.Write([]byte("该方法没有注册"))}}(reqBytes)}}func main() {listen, err := net.Listen("tcp", "127.0.0.1:9999")if err != nil {fmt.Println("Listen() failed, err: ", err)return}for {conn, err := listen.Accept() // 监听客户端的连接请求if err != nil {fmt.Println("Accept() failed, err: ", err)continue}go serve(conn) // 启动一个goroutine来处理客户端的连接请求}
}
client.go
package mainimport ("bufio""encoding/json""fmt""net""rpc_demo/public""time""github.com/google/uuid"
)type Client struct{ Conn net.Conn }func NewClient() *Client {conn, err := net.Dial("tcp", "127.0.0.1:9999")if err != nil {fmt.Println("err : ", err)return nil}return &Client{Conn: conn}
}// 每次调用都生成单独的uuid,并作为key,请求后select uuid对应的chan,直到有数据,读取数据,关闭通道,清除对应的map记录
var M map[string]chan ([]byte)// 启动客户端连接服务端并解析数据
func (c *Client) Run() {defer c.Conn.Close() // 关闭TCP连接reader := bufio.NewReader(c.Conn)for {lBytes := make([]byte, 8)_, err := reader.Read(lBytes[:])if err != nil {fmt.Printf("数据读取失败")return}l := public.BytesToInt(lBytes)reqBytes := make([]byte, l)_, err = reader.Read(reqBytes)if err != nil {fmt.Printf("数据读取失败")return}//解析数据体并写入对应的chango func(data []byte) {rspData := new(public.RspData)err := json.Unmarshal(data, rspData)if err != nil {fmt.Printf("数据解析失败")return}M[rspData.Tag] <- rspData.Data}(reqBytes)}
}// 我这边就不封装自动call了,直接手动call
func (c *Client) Call(serverAndfunc string, data []byte) []byte {//生成uuidtag := uuid.New().String()reqData := &public.ReqData{ServerName: serverAndfunc, Tag: tag, Data: data}r, err := json.Marshal(reqData)if err != nil {fmt.Println("编码错误")return nil}Ch := make(chan []byte)defer close(Ch)defer delete(M, tag)M[tag] = Chc.Conn.Write(append(public.IntToBytes(len(r)), r...))return <-Ch
}func main() {// 初始化mapM = make(map[string]chan []byte)//建立tcp连接服务端client := NewClient()// 启动处理go client.Run()//模拟调用call方法req1 := &public.AddReq{NumA: 1,NumB: 2,}reqdata1, err := json.Marshal(req1)if err != nil {fmt.Println("编码错误")return}req2 := &public.AddReq{NumA: 2,NumB: 2,}reqdata2, err := json.Marshal(req2)if err != nil {fmt.Println("编码错误")return}//模拟多线程调用服务端go fmt.Printf("线程1调用结果:%s\n", string(client.Call("Server.Add", reqdata1)))go fmt.Printf("线程2调用结果:%s\n", string(client.Call("Server.Add", reqdata2)))time.Sleep(10 * time.Second)
}
client运行结果:
线程1调用结果:{"Sum":3}
线程2调用结果:{"Sum":4}
- 当然这只是最简单的demo,模拟了使用tcp进行rpc远程调用,
- 是否跨语言就在于双方时候都支持相同时协议与数据格式,比如使用了tcp的通信协议,那么只要支持tcp的的语言就可以使用打包成相同的数据结构就可以被服务端解析,而那些跨语言的rpc(比如grpc)在这方面做得更好,他们隐式的生成了接口代码,你不需要知道他是如何编码与解码的.可以直接使用,这对使用者是非常友好的.
rpcx与grpc的区别
rpcx:
- 通信协议: 支持tcp,http,quic,kcp
- 数据格式: 支持json,proto等多种解码器
- 服务发现。支持 peer2peer、configured peers、zookeeper、etcd、consul 和 mDNS。
- 其他: 多功能支持 https://github.com/smallnest/rpcx?tab=readme-ov-file
- 性能优越
grpc:
- 通信协议:http2
- 数据格式: proto
- 服务发现: 支持etcd等多种组件.
- 其他:https://www.cnblogs.com/leijiangtao/p/4453914.html
- 自动生成photo文件规范,节省开发时间,方便快捷的部署微服务,跨语言开发等多种优势
为什么grpc要使用http2,为什么不适应http1或者http3?
- http1是一次请求一次响应的形式,要等上一次请求完成才能下一次请求,效率太低;而http2:每个请求都是一个双向流,一个连接可以包含多个流,等于是同时发起多个请求,效率更高
- 当时,http3技术不成熟,并且http3相对来讲比较复杂.并且http2对于grpc来讲已经够用了.
为什么grpc要使用proto而不是json或者其他数据格式?
- proto格式只包含数据,即T-(L)-V(TAG-LENGTH-VALUE)方式编码,没有额外不用的:与{,不像json那样包含字段名+数据的格式,数据结构更紧凑.数据体更小,传输的性能更好
- grpc作为一个跨语言的rpc架构,指定特定的数据类型可以更好的对接不同语言的接口
参考: https://segmentfault.com/a/1190000039158535
为什么rpcx快,快多少?
我翻阅了许多博客,他们都没有讲清楚为什么rpcx快.大多数都是在将rpcx与其他的比如grpc,阿里的Dubbo进行性能测试对比
rpcx的作者想做一个性能强大,服务治理的golang的rpc框架来补充golang rpc框架的空缺(虽然grpc与一些rpc架构开始支持go,但是他们都是走跨语言路线的.)
rpcx作者的发展历程介绍到开始的rpcx就是对标准库的rpc进行的封装,rpc标准库就是一个性能非常优秀的库;客户度通过tcp连接和服务器通讯,协议分为header和payload两部分,header很简单,包括服务名、方法和seq,payload包括序列化的数据。简单的数据格式,高效的网络通信使得他的性能非常的优秀.
rpcx开始的版本就是根据标准库进行封装的,封装了服务发现,各种fail处理以及丰富的路由支持.所以rpcx事实上继承了标准rpc库的性能优势,并且在后期重构了代码并且提供了更加丰富的功能.
参考: rpcx简史
rpcx的具体性能指标与grpc比较:
- 模拟0ms处理时间
| 客户端并发数 | 500 | 2000 | 5000 | ||
|---|---|---|---|---|---|
| 测试指标 | 吞吐量(call/s) | 平均延迟(ms) | p99延迟(ms) | 吞吐量(call/s) | 平均延迟(ms) |
| rpcx | 20万 | 25 | 20万 | ||
| grpc | 14万 | 25 | 14万 |
- 模拟10ms处理时间
| 客户端并发数 | 500 | 2000 | 5000 | ||
|---|---|---|---|---|---|
| 测试指标 | 吞吐量(call/s) | 平均延迟(ms) | p99延迟(ms) | 吞吐量(call/s) | 平均延迟(ms) |
| rpcx | 5万 | 10 | 25 | 15万 | 20 |
| grpc | 5万 | 10 | 25 | 9万 | 30 |
- 模拟30ms处理时间
| 客户端并发数 | 500 | 2000 | 5000 | ||
|---|---|---|---|---|---|
| 测试指标 | 吞吐量(call/s) | 平均延迟(ms) | p99延迟(ms) | 吞吐量(call/s) | 平均延迟(ms) |
| rpcx | 1.8万 | 10 | 25 | 7万 | 30 |
| grpc | 1.8万 | 10 | 25 | 6万 | 20 |
参考:rpcx- GitHub
总结: 在并发数量增加的情况下,rpcx相比grpc的吞吐量与与p99延迟(处理99%请求的平均延迟)要更加优秀.
相关文章:
grpc与rpcx的区别
什么是微服务?rpc架构的主要区别rpcx与grpc的区别rpcx:grpc:为什么grpc要使用http2,为什么不适应http1或者http3?为什么grpc要使用proto而不是json或者其他数据格式? 为什么rpcx快,快多少?rpcx的具体性能指标与grpc比较: 什么是微服务? 整体功能通过多个程序实现,每个程序…...
基于XML的AOP开发
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程。 AOP相关术语: 目标对象(Target): 你要去代理的对象,可以理解为之前很单纯的那个对象。 代理对象(Proxy): 你把你那个单纯的对象给我,…...
pdf也算是矢量图——pdf大小调整--福昕pdf
有时候需要把pdf作为矢量图放到latex论文中,有时候需要裁剪掉空白的部分,就需要用福昕pdf进行编辑, 参考文章:福昕高级PDF编辑器裁切工具怎么用?裁切工具使用方法介绍_福昕PDF软件工具集 (foxitsoftware.cn)...
Web应用程序文件包含-Server2233-解析
B-6 Web应用程序文件包含 任务环境说明:服务器场景名称:Server2233...
AI开发: 知识图谱的初识,学会制作知识图谱- Python 机器学习
一、知识图谱的概念 知识图谱是一个通过图结构来表示和组织知识的工具,它将事物、概念和它们之间的关系以图的形式呈现出来,图中的节点代表实体(比如人物、地点、事件等),而边代表这些实体之间的各种关系(…...
Ubuntu Linux用户与组的管理
Ubuntu Linux操作系统- 第一弹 由猪猪侠开启Linux操作系统的学习 文章目录 前言Linux操作系统的发展Linux版本 Linux用户账户及其类型超级用户系统用户普通用户 Ubuntu超级用户权限与管理员Linux的超级用户权限解决方案Ubuntu管理员sudo命令su命令Ubuntu启用root登录 组账户及其…...
算力100问☞第32问:密集计算的关键技术有哪些?
1、高性能处理器和图形处理器 高性能处理器和图形处理器作为计算系统中的核心组件,发挥着至关重要的作用。 高性能处理器是密集计算的基础。它们采用先进的制程技术和架构设计,能够提供更高的时钟频率和更多的核心数量,从而实现更快的计算速…...
Rust : 生成日历管理markdown文件的小工具
需求: 拟生成以下markdown管理小工具,这也是我日常工作日程表。 可以输入任意时间段,运行后就可以生成以上的markdown文件。 一、toml [package] name "rust-workfile" version "0.1.0" edition "2021"[d…...
【并集查询】.NET开源 ORM 框架 SqlSugar 系列
.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...
基于单片机的智能农田灌溉节水系统设计及应用
摘 要 : 针对传统的灌溉方法浪费水资源节水系统设计。该系统从节水角度出发,对传感器和主电路进行了设计,主要采集灌溉地的湿度与温度数据,根据测量土壤中的温度与湿度作为主要参数,对农田灌溉节水系统进行实时控制&am…...
jmeter如何导出中文版的测试报告?
文章目录 0、初始步骤:把报告模板换成中文形式1、首先添加一份聚合报告2、然后点开【聚合报告】3,生成报告3.1 选择【工具】-【generate HTML report】3.2 【generate HTML report】参数详解3.3 、最后点击 【generate report】直接生成。 声明ÿ…...
AIGC 与艺术创作:变革与机遇
在当今数字化时代,人工智能生成内容(AIGC)正以惊人的速度重塑着艺术创作的格局,为艺术家们带来了令人振奋的新机遇。 一.AIGC 的崛起与艺术领域的变革 随着人工智能技术的不断进步,AIGC 逐渐在艺术领域崭露头角。它依…...
【Axios】如何在Vue中使用Axios请求拦截器
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
element Plus中 el-table表头宽度自适应,不换行
在工作中,使用el-table表格进行开发后,遇到了小屏幕显示器上显示表头文字会出现换行展示,比较影响美观,因此需要让表头的宽度变为不换行,且由内容自动撑开。 以下是作为工作记录,用于demo演示教程 先贴个…...
【Android】从事件分发开始:原理解析如何解决滑动冲突
【Android】从事件分发开始:原理解析如何解决滑动冲突 文章目录 【Android】从事件分发开始:原理解析如何解决滑动冲突Activity层级结构浅析Activity的setContentView源码浅析AppCompatActivity的setContentView源码 触控三分显纷争,滑动冲突…...
如何使用JDBC向数据库中插入日期数据???
在学习JDBC 的过程中很多小明有疑问在IDEA编辑器是如何插入一个日期类型的数据的,此篇一些方法希望可以帮助到你。 示例: import java.text.ParseException; import java.text.SimpleDateFormat; import java.sql.Date; import java.util.Scanner;publi…...
高频面试题(含笔试高频算法整理)基本总结回顾29
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版和持续更新见高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言…...
Flink日志配置
所有Flink进程都会创建一个日志文本文件,其中包含进程中发生的各种事件的消息。这些日志可以深入了解Flink的内部工作原理,还可以用来检测问题(以警告/错误信息的形式),并帮助调试。 可以通过web界面的JobManager/TaskManager页面访问日志文件。使用的资源提供者(例如YA…...
论文 | EfficientRAG: Efficient Retriever for Multi-Hop Question Answering
1. 论文介绍与研究动机 本文提出了一个新的检索增强生成(RAG)方法——EfficientRAG,它专门用于解决复杂的多跳问题。在多跳问答中,问题的答案需要从多个信息源中检索并结合起来,远比单跳问题复杂,因此也更加…...
超越Hallo和AniPortrait?音频驱动肖像动画新方法LetsTalk
之前的文章中已经给大家介绍过许多关于音频驱动的肖像图像生成动画方法,感兴趣的小伙伴可以点击下面链接阅读~ 复旦开源Hallo:只需输入一段音频和一张照片就可以让人物说话。 开源EMO再升级!复旦|百度|南大推出Hallo2:可以生成4…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
