2021你必须懂的RPC--分布式微服务和云计算应用的核心技术
Posted gocloudcoder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021你必须懂的RPC--分布式微服务和云计算应用的核心技术相关的知识,希望对你有一定的参考价值。
大家好我是CloudCoder,云计算码农,专注分享linux/go/java等相关技术。
2021你必须懂的RPC--分布式、微服务和云计算应用的核心技术
随着分布式、微服务、云计算应用越来越火,对于程序猿来说,需要了解的东西也越来越多,概念也越来越多。今天就来聊聊这些热门技术背后的核心技术RPC--远程过程调用(Remote Procedure Call)。
http 与 rpc 的区别与联系
HTTP协议,以其中的Restful规范为代表,其优势很大。它可读性好,且可以得到防火墙的支持、跨语言的支持。但是HTTP也有其缺点,这是与其优点相对应的。首先是有用信息占比少,并且使用HTTP协议调用远程方法比较复杂,要封装各种参数名和参数值。
而良好的rpc调用是面向服务的封装,且RPC框架针对服务的可用性和效率等都做了优化。在目前推崇的分布式应用,微服务应用,云计算等面有着广泛的应用。可以理解为,远程的方法就和本地的方法无异,包括所有的过程都和本地是一样的。后面会使用代码进行讲解。
在分布式系统中,因为每个服务的边界都很小,很有可能调用别的服务提供的方法。这就出现了服务A调用服务B中方法的需求,即远程过程调用。要想让服务A调用服务B中的方法,最先想到的当然是通过http去实现,让服务B暴露接口,然后让A通过接口去调用对应的服务。
当然,基于接口的调用方式不仅可读性好,而且http请求可以通过各种防火墙,同时也很方便。但是基于这种方式存在一个明显的缺点,效率比较低,封装调用比较复杂,当前分布式,微服务比较热门,微服务就是将业务拆解为很多的小服务,那么这将存在大量的服务间调用,还使用基于接口的调用方式就不太适合了。
服务A调用服务B的过程是应用间的内部过程,牺牲可读性提升效率、易用性是可取的。基于这种思路,RPC产生了。调用方可以像调用内部接口一样调用远程的方法,而不用封装参数名和参数值等操作。
如何选择http 和 rpc呢?
根据业务场景,业务的大小进行灵活的运用。
与前端交互当然还是使用http的方式,在后端服务之间调用选择http 或者 rpc。
一般来讲中小厂多使用http方式。
大厂多使用http + rpc组合的方式。
通过代码分析两者的区别
我们实现一个简单的服务,两个整数相加,返回结果。
首先我们通过http方式实现。老样子使用Go语言做演示,技术栈为gin框架。
服务端代码:
package main
import (
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"net/http"
)
func main() {
r := gin.Default()
//使用POST,路由为http://localhost:8080/add
r.Handle("POST", "/add", add)
if err := r.Run(":8080"); err != nil {
panic("err")
}
}
func add(c *gin.Context) {
//获取参数a的值
a := c.PostForm("a")
//获取参数b的值
b := c.PostForm("b")
//将string类型转为int类型并相加
result := cast.ToInt(a) + cast.ToInt(b)
//返回json形式的结果,参数为result
c.IndentedJSON(http.StatusOK, gin.H{
"result" : result,
})
}
客户端代码:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
func main() {
//将a = 1, b = 2传到后端
params := url.Values{
"a": {"1"},
"b": {"2"},
}
//请求后端服务得到相应
resp, _ := http.PostForm("http://localhost:8080/add", params)
defer resp.Body.Close()
//获取结果
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
接下来我们通过rpc方式实现
服务端代码:
package main
import (
"log"
"net"
"net/http"
"net/rpc"
)
type NumbersTwo struct {
A int
B int
}
func main() {
Nt := new(NumbersTwo)
//注册服务对象
//该对象必须是结构体对象,通过对象所属的方法暴露给调用者从而提供服务
err := rpc.Register(Nt)
if err != nil {
log.Fatal(err)
}
//通过该函数把对象所属的方法的服务注册到http协议上,方便调用者可以利用http的方式进行数据传递
rpc.HandleHTTP()
//端口监听
listen, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err.Error())
}
err = http.Serve(listen, nil)
if err != nil {
panic(err.Error())
}
}
func (n *NumbersTwo) AddTwoNumbers(t map[string]int, result *int) error {
*result = t["A"] + t["B"]
return nil
}
客户端代码:
//client.go客户端
package main
import (
"fmt"
"net/rpc"
)
func main() {
//通过http的端口监听方式连接
client, err := rpc.DialHTTP("tcp", "localhost:8080")
if err != nil {
panic(err.Error())
}
var result *int
t := map[string]int{
"A":1,
"B":2,
}
//调用远端方法
err = client.Call("NumbersTwo.AddTwoNumbers", t, &result)
if err != nil {
panic(err.Error())
}
fmt.Println("远程调用程序, 结果为:", *result)
}
使用rpc的方式,就像是使用本地的方法一样。比http方式更加的高效,更加的适合分布式应用和微服务。
以上是关于2021你必须懂的RPC--分布式微服务和云计算应用的核心技术的主要内容,如果未能解决你的问题,请参考以下文章