It took a week to tidy up the use of RPCX, the general process is as follows:
Server-Side development
First of all, we need to implement our own services, which is very simple, that is to define a common method:
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}
I. Point-to-point
Point-to-point is the simplest way to register a hub, in fact there is no registry, and the client directly gets the unique server address.
Server
Instead of configuring the registry, the server starts directly.
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 {}}
Client
The client directly configures the address of the server, formatted as a network@ipaddress:port
format, and is not found through third-party components.
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)}
Two. Point-to-multiple
Multipleservers
The above method can only access one server, assuming we have a fixed number of servers to provide the same service, we can use this way.
Server
The server is still the same as the code above, just start your own service, no additional configuration is required. The following example launches two services:
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)}
Client
The client needs MultipleServersDiscovery
to use to configure multiple server addresses for the same service so that the client can select one of the calls based on the rule.
As you can see, the actual invocation of the service is the same in addition to the initialization, and the same is true for the registry that is described later, except that XClient
the initialization client is different and subsequent calls are the same.
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 is an open source tool launched by Hashicorp to implement service discovery and configuration for distributed systems. The consul is distributed, highly available, and horizontally scalable. It has the following features:
- Service Discovery: Consul provides a way to register services and discovery services through DNS or HTTP interfaces. Some external services can easily find the services it relies on by consul.
- Health testing: Consul's client provides a mechanism for health checks that can be used to prevent traffic from being forwarded to a faulty service.
- Key/value Storage: Applications can use Key/value storage provided by Consul as needed. Consul provides an easy-to-use HTTP interface with other tools to enable dynamic configuration, function tagging, leader election, and more.
- Multi-Datacenter: Consul supports out-of-the-box multi-data centers. This means that the user does not need to worry about the need to create an additional abstraction layer to extend the business to multiple regions.
Consul is also developed using go, and is widely used in the go ecosystem.
Server
Server-side development is similar to zookeeper, Etcd, and consul.
It mainly configures several parameters:
- Serviceaddress: This machine's listening address, this externally exposed listening address, in the form of
tcp@ipaddress:port
- Consulservers:consul the address of the cluster
- BasePath: Service prefix. If you have multiple projects that use Consul at the same time to avoid naming conflicts, you can set this parameter to set the namespace for the current service
- Metrics: TPS for updating services
- UpdateInterval: Service Refresh interval, if there is no refresh within a certain interval (currently set to 2 * updateinterval), the service will be removed from consul
Before you start, you have to make sure that you have installed the consul using instructions Consul Agent-dev Open, more consul use the way please get it yourself
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)}
Client
Configure ConsulDiscovery
, use, basepath
and consul addresses.
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 Reads