微服務中很重要的一個內(nèi)容就是「RPC」遠程過程調(diào)用(Remote Procedure Call,縮寫為 RPC)是一個計算機通信協(xié)議,他的主要作用是「允許運行于一臺計算機的程序調(diào)用另一臺計算機的子程序,而程序員無需額外地為這個交互作用編程」。


引言?
"微服務"這個概念想必不用我說大家都知道,就算沒接觸過也聽說過。簡單來說就是以前系統(tǒng)中的,用戶,搜索,內(nèi)容,等等模塊都在一起,這樣會導致代碼「越來越冗余,越來越難維護」,所以往往需要拆分這些服務,微服務在拆分的時候,會根據(jù)業(yè)務功能模塊把一個單體的應用拆分成許多個獨立的項目,每個項目完成一部分的業(yè)務功能,然后獨立開發(fā)和部署。這些獨立的項目就成為一個微服務。進而構(gòu)成一個「服務集群」。看下面兩張圖可能會對微服務的概念更加直觀。
單體服務

單體服務
微服務

微服務
RPC介紹?
微服務中很重要的一個內(nèi)容就是「RPC」遠程過程調(diào)用(Remote Procedure Call,縮寫為 RPC)是一個計算機通信協(xié)議,他的主要作用是「允許運行于一臺計算機的程序調(diào)用另一臺計算機的子程序,而程序員無需額外地為這個交互作用編程」。
那么RPC是如何實現(xiàn)的呢?今天咱們就以golang為工具,給大家實現(xiàn)一個簡單的用rpc輸出helloWorld。
RPC實現(xiàn)步驟?
其實RPC的實現(xiàn)和網(wǎng)絡編程有點像,A服務需要遠程調(diào)用B服務的某個方法,在這種情況下我們就把B服務稱為「服務端」,A稱為「客戶端」。

具體實現(xiàn)步驟如下圖:
RPC實現(xiàn)步驟
服務端?
1、注冊服務對象,綁定類方法
rpc.ResisterName("服務名","回調(diào)對象")
ResisterName函數(shù)解釋
func RegisterName(name string, rcvr interface{}) error
//參數(shù)解釋
//name 服務名(自己隨便取),字符串類型
//rcvr 對應的RPC對象,該對象綁定的方法需要滿足如下條件
1)方法必須是導出的(包外可見),在golang中的體現(xiàn)為,方法名首字母大寫
2)方法必須有兩個參數(shù),都是導出類型,內(nèi)建類型
3) 方法的第二個參數(shù)(也就是客戶端調(diào)用遠程函數(shù)中的傳出參數(shù)),必須指針(傳出參數(shù))
4) 該方法只有一個返回值,就是error接口類型的返回值
下面我們針對參數(shù)2舉個例子,比如下面這個方法TestMethod 就是符合條件的。type Test struct{
}
//這是符合RegisterName的參數(shù)2的方法名
func (this *Test) TestMethod(name string, resp *string)error{
return nil
}
rpc.RegisterName("test", new(Test)) //注冊rpc服務對象
2、創(chuàng)建監(jiān)聽器
listener, err := net.Listen()
3、啟動監(jiān)聽,建立鏈接
conn, err := listener.Accept()
4、將鏈接綁定RPC服務
ServerConn函數(shù)解釋
func (server *Server) ServeConn(conn io.ReadWriteCloser)
//參數(shù)conn為成功建立好連接的socket,也就是前面的conn
客戶端?
1、用RPC連接服務器(服務端)
2、調(diào)用遠程函數(shù)
conn.Call("服務名.方法名", "傳入?yún)?shù)", "傳出參數(shù)")
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
//參數(shù)含義
//serviceMethod "服務名"."方法名"
//args "傳入?yún)?shù)" 調(diào)用方法需要的參數(shù)
//reply "傳出參數(shù)" 定義一個變量,對變量名取地址 &變量,完成傳參
代碼示例?
服務端代碼?
server.go:
package main
import (
"fmt"
"net"
"net/rpc"
)
type Hello struct {
}
func (this *Hello) HelloWorld(name string, resp *string) (err error) {
*resp = name + "您好!"
return err
}
func main() {
//注冊rpc服務,指定對象和方法
err := rpc.RegisterName("hello", new(Hello))
if err != nil {
fmt.Println("注冊 err:", err)
return
}
//設置監(jiān)聽
listener, err := net.Listen("tcp", "127.0.0.1:8088")
if err != nil {
fmt.Println("listen err:", err)
return
}
defer listener.Close()
//建立連接
conn, err := listener.Accept()
if err != nil {
fmt.Println("accept err:", err)
return
}
defer conn.Close()
//綁定服務
rpc.ServeConn(conn)
}
客戶端代碼?
client.go:
package main
import (
"fmt"
"net/rpc"
)
func main() {
//用rpc鏈接服務器
conn, err := rpc.Dial("tcp", "127.0.0.1:8088")
if err != nil {
fmt.Println("Dial err:", err)
return
}
defer conn.Close()
var resp *string
conn.Call("hello.HelloWorld", "小飯", &resp)
fmt.Println(*resp)
}