花了一個禮拜整理了一下 RPCX的使用方法,大致過程如下:
伺服器端開發
首先,我們需要實現自己的服務,這很簡單,就是定義普通的方法即可:
package exampleimport ("context""fmt")type Args struct {A intB int}type Reply struct {C int}type Arith intfunc (t *Arith) Mul(ctx context.Context, args *Args, reply *Reply) error {reply.C = args.A * args.Bfmt.Printf("call: %d * %d = %d\n", args.A, args.B, reply.C)return nil}func (t *Arith) Add(ctx context.Context, args *Args, reply *Reply) error {reply.C = args.A + args.Bfmt.Printf("call: %d + %d = %d\n", args.A, args.B, reply.C)return nil}func (t *Arith) Say(ctx context.Context, args *string, reply *string) error {*reply = "hello " + *argsreturn nil}
一.點對點
點對點是最簡單的一種註冊中心的方式,事實上沒有註冊中心,用戶端直接得到唯一的伺服器的地址。
伺服器
伺服器並沒有配置註冊中心,而是直接啟動。
package mainimport ("flag""github.com/smallnest/rpcx/server""github.com/rpcx-ecosystem/rpcx-examples3")var (addr = flag.String("addr", "localhost:8972", "server address"))func main() {flag.Parse()s := server.Server{}s.RegisterName("Arith", new(example.Arith), "")go s.Serve("tcp", *addr)select {}}
用戶端
用戶端直接配置了伺服器的地址,格式是network@ipaddress:port
的格式,並沒有通過第三方組件來尋找。
package mainimport ("github.com/smallnest/rpcx/client""log""service""context""flag")var (addr = flag.String("addr", "127.0.0.1:8972", "server address"))func main() {Peer2Peer()}func Peer2Peer() {flag.Parse()d := client.NewPeer2PeerDiscovery("tcp@" + *addr, "")xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption)defer xclient.Close()args := &service.Args{A: 10,B: 20,}reply := &service.Reply{}err := xclient.Call(context.Background(), "Mul", args, reply)if err != nil {log.Fatalf("failed to call: %v", err)}log.Printf("%d * %d = %d", args.A, args.B, reply.C)}
二.點對多
MultipleServers
上面的方式只能訪問一台伺服器,假設我們有固定的幾台伺服器提供相同的服務,我們可以採用這種方式。
伺服器
伺服器還是和上面的代碼一樣,只需啟動自己的服務,不需要做額外的配置。下面這個例子啟動了兩個服務:
package mainimport ("flag""github.com/smallnest/rpcx/server""github.com/rpcx-ecosystem/rpcx-examples3")var (addr1 = flag.String("addr1", "localhost:8972", "server1 address")addr2 = flag.String("addr2", "localhost:8973", "server2 address"))func main() {flag.Parse()go createServer(*addr1)go createServer(*addr2)select {}}func createServer(addr string) {s := server.NewServer()s.RegisterName("Arith", new(example.Arith), "")s.Serve("tcp", addr)}
用戶端
用戶端需要使用MultipleServersDiscovery
來配置同一個服務的多個伺服器位址,這樣用戶端就能基於規則從中選擇一個進行調用。
可以看到,除了初始化XClient
有所不同外,實際調用服務是一樣的, 後面介紹的註冊中心也是一樣,只有初始化用戶端有所不同,後續的調用都一樣。
package mainimport ("github.com/smallnest/rpcx/client""log""service""context""flag""github.com/rpcx-ecosystem/rpcx-examples3")var (addr1 = flag.String("addr1", "localhost:8972", "server1 address")addr2 = flag.String("addr2", "localhost:8973", "server2 address"))func main() {Peer2Many()}func Peer2Many(){flag.Parse()d := client.NewMultipleServersDiscovery([]*client.KVPair{{Key:*addr1}, {Key:*addr2}})xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption)defer xclient.Close()args := &example.Args{A: 10,B: 20,}reply := &example.Reply{}err := xclient.Call(context.Background(), "Mul",args, reply)if err != nil {log.Fatalf("failed to call: %v", err)}log.Printf("%d * %d = %d", args.A, args.B, reply.C)}
Consul
Consul是HashiCorp公司推出的開源工具,用於實現分布式系統的服務發現與配置。Consul是分布式的、高可用的、 可橫向擴充的。它具備以下特性:
- 服務發現: Consul提供了通過DNS或者HTTP介面的方式來註冊服務和探索服務。一些外部的服務通過Consul很容易的找到它所依賴的服務。
- 健康檢測: Consul的Client提供了健全狀態檢查的機制,可以通過用來避免流量被轉寄到有故障的服務上。
- Key/Value儲存: 應用程式可以根據自己的需要使用Consul提供的Key/Value儲存。 Consul提供了簡單易用的HTTP介面,結合其他工具可以實現動態配置、功能標記、領袖選舉等等功能。
- 多資料中心: Consul支援開箱即用的多資料中心. 這意味著使用者不需要擔心需要建立額外的抽象層讓業務擴充到多個地區。
Consul也是使用Go開發的,在Go生態圈也被廣泛應用。
伺服器
伺服器端的開發和zookeeper、etcd和consul類似。
它主要配置幾個參數:
- ServiceAddress: 原生監聽地址, 這個對外暴露的監聽地址, 格式為
tcp@ipaddress:port
- ConsulServers: consul叢集的地址
- BasePath: 服務首碼。 如果有多重專案同時使用consul,避免命名衝突,可以設定這個參數,為當前的服務設定命名空間
- Metrics: 用來更新服務的TPS
- UpdateInterval: 服務的重新整理間隔, 如果在一定間隔內(當前設為2 * UpdateInterval)沒有重新整理,服務就會從consul中刪除
在開始之前,你得確保已經裝上了Consul 使用指令 consul agent -dev 開啟,更多consul使用方式請自行get
package mainimport ("flag""github.com/smallnest/rpcx/server""github.com/smallnest/rpcx/serverplugin""time""github.com/rcrowley/go-metrics""log""github.com/rpcx-ecosystem/rpcx-examples3")var (addr = flag.String("addr", "localhost:8972", "server address")consulAddr = flag.String("consulAddr", "localhost:8500", "consul address")basePath = flag.String("base", "/rpcx_test", "prefix path"))func main() {flag.Parse()s := server.NewServer()addRegistryPlugin(s)s.RegisterName("Arith", new(example.Arith), "")s.Serve("tcp", *addr)}func addRegistryPlugin(s *server.Server) {r := &serverplugin.ConsulRegisterPlugin{ServiceAddress: "tcp@" + *addr,ConsulServers: []string{*consulAddr},BasePath: *basePath,Metrics: metrics.NewRegistry(),UpdateInterval: time.Minute,}err := r.Start()if err != nil {log.Fatal(err)}s.Plugins.Add(r)}
用戶端
配置ConsulDiscovery
,使用basepath
和consul的地址。
package mainimport ("github.com/smallnest/rpcx/client""log""context""flag""github.com/rpcx-ecosystem/rpcx-examples3")var (consulAddr = flag.String("consulAddr", "localhost:8500", "consul address")basePath = flag.String("base", "/rpcx_test/Arith", "prefix path"))func ConsulServer() {flag.Parse()d := client.NewConsulDiscovery(*basePath, "", []string{*consulAddr}, nil)xclient := client.NewXClient("Arith", client.Failtry, client.RandomSelect, d, client.DefaultOption)defer xclient.Close()args := &example.Args{A: 10,B: 20,}reply := &example.Reply{}err := xclient.Call(context.Background(), "Mul", args, reply)if err != nil {log.Fatalf("failed to call: %v", err)}log.Printf("%d * %d = %d", args.A, args.B, reply.C)}func main() {ConsulServer()}
176 次點擊