go语言的rpc机制 go实现rpc

GoLang -- gRPC框架四大服务 在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端 应用的方法,使得您能够更容易地创建分布式应用和服务 。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型) 。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用 。在客户端拥有一个存根能够像服务端一样的方法 。
gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写 。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端 。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里 。
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON) 。名叫 proto3 的新风格的 protocol buffers,它拥有轻量简化的语法、一些有用的新功能 , 并且支持更多新语言 。当前针对 Java 和 C发布了 beta 版本,针对 JavaNano(即 Android Java)发布 alpha 版本,在protocol buffers Github 源码库里有 Ruby 支持 , 在golang/protobuf Github 源码库里还有针对 Go 语言的生成器, 对更多语言的支持正在开发中 。
有了 gRPC , 我们可以一次性的在一个 .proto 文件中定义服务并使用任何支持它的语言去实现客户端和服务器,反过来 , 它们可以在各种环境中,从Google的服务器到你自己的平板电脑—— gRPC 帮你解决了不同语言及环境间通信的复杂性.使用 protocol buffers 还能获得其他好处,包括高效的序列号,简单的 IDL 以及容易进行接口更新 。
现在让我们来仔细了解一下当 gRPC 客户端调用 gRPC 服务端的方法时到底发生了什么 。我们不究其实现细节,关于实现细节的部分,你可以在我们的特定语言页面里找到更为详尽的内容 。
首先我们来了解一下最简单的 RPC 形式:客户端发出单个请求,获得单个响应 。
服务端流式 RPC 除了在得到客户端请求信息后发送回一个应答流之外,与我们的简单例子一样 。在发送完所有应答后,服务端的状态详情(状态码和可选的状态信息)和可选的跟踪元数据被发送回客户端,以此来完成服务端的工作 。客户端在接收到所有服务端的应答后也完成了工作 。
客户端流式 RPC 也基本与我们的简单例子一样 , 区别在于客户端通过发送一个请求流给服务端,取代了原先发送的单个请求 。服务端通常(但并不必须)会在接收到客户端所有的请求后发送回一个应答 , 其中附带有它的状态详情和可选的跟踪数据 。
双向流式 RPC,调用由客户端调用方法来初始化,而服务端则接收到客户端的元数据 , 方法名和截止时间 。服务端可以选择发送回它的初始元数据或等待客户端发送请求 。下一步怎样发展取决于应用 , 因为客户端和服务端能在任意顺序上读写 - 这些流的操作是完全独立的 。例如服务端可以一直等直到它接收到所有客户端的消息才写应答,或者服务端和客户端可以像"乒乓球"一样:服务端后得到一个请求就回送一个应答,接着客户端根据应答来发送另一个请求,以此类推 。
通过运行下面的命令克隆并安装grpc-go代码库:
下载protobuf源码包
安装golang-protobuf
第一步使用 protocol buffers去定义 gRPC service 和方法 request 以及 response 的类型 。
要定义一个服务,必须在.proto 文件中指定 service:
然后在服务中定义 rpc 方法,指定请求的和响应类型,gRPC 允许定义4种类型的 service 方法 。
服务.proto文件如下所示:
Go微服务--常见的微服务框架近几年诞生了很多微服务框架 , 比如JAVA的Spring Cloud、Dubbo;Golang的GoKit和GoMicro以及NodeJs的Seneca 。几乎每种主流语言都有其对应的微服务框架 。
Go在微服务框架中有其独特的优势 , 至于优势在哪 , 自行google 。
1、GoKit框架
这是一个工具包的集合 , 可以帮助攻城狮构建强大、可靠和可维护的微服务 。提供了用于实现系统监控和弹性模式组件的库 , 例如日志、跟踪、限流、熔断等 。
基于这个框架的应用程序架构由三个主要的部分组成:
传输层:用于网络通信,服务通常使用HTTP或者gRPC等网络传输协议,或者使用NATS等发布订阅系统相互通信 。
接口层:是服务器和客户端的基本构建块 。每个对外提供的接口方法都会定义为一个Endpoint,一遍在服务器和客户端之间进行网络通信,每个端点使用传输层通过HTTP或gRPC等具体通信模式对外提供服务
服务成:具体的业务逻辑实现
2、GoMicro框架
这是一个基于Go语言实现的插件化RPC微服务框架 。提供了服务发现、负载均衡、同步传输、异步通信以及事件驱动等机制,尝试简化分布式系统之间的通信,让开发者更专注于自身业务逻辑的开发 。
GoMicro的设计哲学是可插拔的架构理念,提供了可快速构建系统的组件,并且可以根据自身的需求对GoMicro提供的默认实现进行定制 。所有插件都可在仓库github.com/micro/go-plugins 中找到 。
go websocket 问题(Hijacker)在写websocket包的时候发现一个比较有趣问题!go 使用 TLS验证的时候发现 websocket 使用不了 。深入了解发现其中奥秘:go 在执行 TLS 验证时候默认是使用 http2 协议进行的!但是 websocket 是无法支持 http2 协议(暂时),导致这个问题所在的原因!
使用空 map 来使用 http1.x协议
因为默认支持h2,所有我们把降到http1.x 。
使用 http.Hijacker 对其进行劫持 net.Conn , 让程序员自己控制使用!其实这个时候已经脱离 http 协议规范!
发现使用 Hijacker 会脱离 http 协议范畴,可以解决h2与websocket的相关问题!
协议: 状态码:101 , Upgrade , Connection, Sec-WebSocket-Accept
实现最简单 websocket 连接!
websocket连接已经建立,有些 sec 是默认添加上去!
根据 http.Listen 进行向下追踪
在 func (srv *Server) Serve(l net.Listener) error 发现原由
对 c.setState 进入分析
发现当 case 是 Hijack【StateHijacked, StateClosed】状态时候执行 trackConn
add 为 false , 对其 delete(s.activeConn,c)。Hijacker是满足相关条件
所以在go c.serve(connCtx) 里面不在给 Hijacker 进行操作!导致 http header 无法设置!最后交给程序员自己操作!
go中自带的rpc可以直接复用http server处理请求的那一套流程去创建连接,连接创建完毕后再使用Hijack方法拿到连接 。
注: github.com/gorilla/websocket
这包就接入 HIjacker,直接使用现成包就香~~~~~
一学就会,手把手教你用Go语言调用智能合约智能合约调用是实现一个 DApp 的关键,一个完整的 DApp 包括前端、后端、智能合约及区块 链系统,智能合约的调用是连接区块链与前后端的关键 。
我们先来了解一下智能合约调用的基础原理 。智能合约运行在以太坊节点的 EVM 中 。因此要 想调用合约必须要访问某个节点 。
以后端程序为例,后端服务若想连接节点有两种可能,一种是双 方在同一主机,此时后端连接节点可以采用 本地 IPC(Inter-Process Communication,进 程间通信)机制,也可以采用 RPC(Remote Procedure Call , 远程过程调用)机制;另 一种情况是双方不在同一台主机 , 此时只能采用 RPC 机制进行通信 。
提到 RPC , 读者应该对 Geth 启动参数有点印象,Geth 启动时可以选择开启 RPC 服务,对应的 默认服务端口是 8545 。。
接着,我们来了解一下智能合约运行的过程 。
智能合约的运行过程是后端服务连接某节点,将 智能合约的调用(交易)发送给节点,节点在验证了交易的合法性后进行全网广播,被矿工打包到 区块中代表此交易得到确认,至此交易才算完成 。
就像数据库一样,每个区块链平台都会提供主流 开发语言的 SDK(Software Development Kit,软件开发工具包),由于 Geth 本身就是用 Go 语言 编写的 , 因此若想使用 Go 语言连接节点、发交易,直接在工程内导入 go-ethereum(Geth 源码) 包就可以了,剩下的问题就是流程和 API 的事情了 。
总结一下,智能合约被调用的两个关键点是节点和 SDK 。
由于 IPC 要求后端与节点必须在同一主机,所以很多时候开发者都会采用 RPC 模式 。除了 RPC,以太坊也为开发者提供了 json- rpc 接口,本文就不展开讨论了 。
接下来介绍如何使用 Go 语言,借助 go-ethereum 源码库来实现智能合约的调用 。这是有固定 步骤的 , 我们先来说一下总体步骤,以下面的合约为例 。
步骤 01:编译合约,获取合约 ABI(Application Binary Interface,应用二进制接口) 。单击【ABI】按钮拷贝合约 ABI 信息 , 将其粘贴到文件 calldemo.abi 中(可使用 Go 语言IDE 创建该文件 , 文件名可自定义,后缀最好使用 abi) 。
最好能将 calldemo.abi 单独保存在一个目录下,输入“ls”命令只能看到 calldemo.abi 文件 , 参 考效果如下:
步骤 02:获得合约地址 。注意要将合约部署到 Geth 节点 。因此 Environment 选择为 Web3 Provider 。
在【Environment】选项框中选择“Web3 Provider” , 然后单击【Deploy】按钮 。
部署后,获得合约地址为:0xa09209c28AEf59a4653b905792a9a910E78E7407 。
步骤 03:利用 abigen 工具(Geth 工具包内的可执行程序)编译智能合约为 Go 代码 。abigen 工具的作用是将 abi 文件转换为 Go 代码,命令如下:
其中各参数的含义如下 。(1)abi:是指定传入的 abi 文件 。(2)type:是指定输出文件中的基本结构类型 。(3)pkg:指定输出文件 package 名称 。(4)out:指定输出文件名 。执行后,将在代码目录下看到 funcdemo.go 文件,读者可以打开该文件欣赏一下 , 注意不要修改它 。
步骤 04:创建 main.go , 填入如下代码 。注意代码中 HexToAddress 函数内要传入该合约部署后的地址 , 此地址在步骤 01 中获得 。
步骤 04:设置 go mod,以便工程自动识别 。
【go语言的rpc机制 go实现rpc】前面有所提及,若要使用 Go 语言调用智能合约,需要下载 go-ethereum 工程,可以使用下面 的指令:
该指令会自动将 go-ethereum 下载到“$GOPATH/src/github.com/ethereum/go-ethereum” , 这样还算 不错 。不过,Go 语言自 1.11 版本后,增加了 module 管理工程的模式 。只要设置好了 go mod,下载 依赖工程的事情就不必关心了 。
接下来设置 module 生效和 GOPROXY,命令如下:
在项目工程内,执行初始化 , calldemo 可以自定义名称 。
步骤 05:运行代码 。执行代码 , 将看到下面的效果 , 以及最终输出的 2020 。
上述输出信息中 , 可以看到 Go 语言会自动下载依赖文件,这就是 go mod 的神奇之处 。看到 2020 , 相信读者也知道运行结果是正确的了 。
golang之大端序、小端序当分别处于大小端模式下go语言的rpc机制的内容存放如下
(1)大端模式存储(存储地址为16位)
地址数据
0x0004(高地址)0x44
0x00030x33
0x00020x22
0x0001(低地址)0x11
(2)小端模式存储(存储地址为16位)
地址数据
0x0004(高地址)0x11
0x00030x22
0x00020x33
0x0001(低地址)0x44
在前面也简单阐述go语言的rpc机制了大小端序的定义并结合简单实例来说明,接下来会给出详细实例来说明go语言的rpc机制:
1、大端序(Big-Endian):或称大尾序
一个类型: int32 的数 0X0A0B0C0D的内存存放情况
数据是以8bits为单位
2、小端序(little-endian):或称小尾序
比如0x00000001
大端序:内存低比特位 00000000 00000000 00000000 00000001 内存高比特位
小端序:内存低比特位 10000000 00000000 00000000 00000000 内存高比特位
其实在前面罗列出那么东西,最终是为go语言的rpc机制了接下来讲述的在golang中涉及到网络传输、文件存储时的选择 。一般来说网络传输的字节序 , 可能是大端序或者小端序,取决于软件开始时通讯双方的协议规定 。TCP/IP协议RFC1700规定使用“大端”字节序为网络字节序 , 开发的时候需要遵守这一规则 。默认golang是使用大端序 。详情见golang中包encoding/binary已提供了大、小端序的使用
输出结果:
16909060 use big endian:
int32 to bytes: [1 2 3 4]### [0001 0002 0003 0004]
bytes to int32: 16909060
16909060 use little endian:
int32 to bytes: [4 3 2 1]### [0004 0003 0002 0001]
bytes to int32: 16909060
在RPCX框架中关于RPC调用过程涉及的传递消息进行编码的,采用的就是大端序模式
为什么go语言适合开发网游服务器端个人觉得golang十分适合进行网游服务器端开发go语言的rpc机制,写下这篇文章总结一下 。从网游的角度看go语言的rpc机制:要成功的运营一款网游 , 很大程度上依赖于玩家自发形成的社区 。只有玩家自发形成一个稳定的生态系统,游戏才能持续下去 , 避免鬼城的出现 。而这就需要多次大量导入用户,在同时在线用户量达到某个临界点的时候,才有可能完成 。因此 , 多人同时在线十分有必要 。再来看网游的常见玩法,除go语言的rpc机制了排行榜这类统计和数据汇总的功能外,基本没有需要大量CPU时间的应用 。以前的项目里,即时战斗产生的各种伤害计算对CPU的消耗也不大 。玩家要完成一次操作,需要通过客户端-服务器端-客户端这样一个来回 , 为了获得高响应速度,满足玩家体验 , 服务器端的处理也不能占用太多时间 。所以,每次请求对应的CPU占用是比较小的 。网游的IO主要分两个方面,一个是网络IO,一个是磁盘IO 。网络IO方面,可以分成美术资源的IO和游戏逻辑指令的IO,这里主要分析游戏逻辑的IO 。游戏逻辑的IO跟CPU占用的情况相似,每次请求的字节数很?。捎诙嗳送痹谙? ,因此并发数相当高 。另外 , 地图信息的广播也会带来比较频繁的网络通信 。磁盘IO方面,主要是游戏数据的保存 。采用不同的数据库,会有比较大的区别 。以前的项目里,就经历了从MySQL转向MongoDB这种内存数据库的过程,磁盘IO不再是瓶颈 。总体来说,还是用内存做一级缓冲,避免大量小数据块读写的方案 。针对网游的这些特点,golang的语言特性十分适合开发游戏服务器端 。首先 , go语言提供goroutine机制作为原生的并发机制 。每个goroutine所需的内存很少,实际应用中可以启动大量的goroutine对并发连接进行响应 。goroutine与gevent中的greenlet很相像 , 遇到IO阻塞的时候,调度器就会自动切换到另一个goroutine执行,保证CPU不会因为IO而发生等待 。而goroutine与gevent相比,没有了python底层的GIL限制 , 就不需要利用多进程来榨取多核机器的性能了 。通过设置最大线程数,可以控制go所启动的线程,每个线程执行一个goroutine,让CPU满负载运行 。同时,go语言为goroutine提供了独到的通信机制channel 。channel发生读写的时候,也会挂起当前操作channel的goroutine , 是一种同步阻塞通信 。这样既达到了通信的目的,又实现同步 , 用CSP模型的观点看,并发模型就是通过一组进程和进程间的事件触发解决任务的 。虽然说,主流的编程语言之间 , 只要是图灵完备的,go语言的rpc机制他们就都能实现相同的功能 。但go语言提供的这种协程间通信机制,十分优雅地揭示了协程通信的本质,避免了以往锁的显式使用带给程序员的心理负担,确是一大优势 。进行网游开发的程序员,可以将游戏逻辑按照单线程阻塞式的写 , 不需要额外考虑线程调度的问题,以及线程间数据依赖的问题 。因为,线程间的channel通信 , 已经表达了线程间的数据依赖关系了 , 而go的调度器会给予妥善的处理 。另外,go语言提供的gc机制 , 以及对指针的保护式使用,可以大大减轻程序员的开发压力,提高开发效率 。展望未来,go语言的rpc机制我期待go语言社区能够提供更多的goroutine间的隔离机制 。个人十分推崇erlang社区的脆崩哲学,推动应用发生预期外行为时,尽早崩溃 , 再fork出新进程处理新的请求 。对于协程机制,需要由程序员保证执行的函数不会发生死循环 , 导致线程卡死 。
关于go语言的rpc机制和go实现rpc的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息 , 记得收藏关注本站 。

    推荐阅读