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…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...