目錄git
本文是學習kratos warden第一節,kratos warden的直連方式client調用,我直接用demo項目作示例github
先建立一個用做grpc-servergolang
kratos new grpc-server
在建立一個調用grpc-server接口的call-serverredis
kratos new call-server
如今該目錄下有兩個服務sql
[I:\VSProject\kratos-note\warden\direct]$ tree 卷 辦公 的文件夾 PATH 列表 卷序列號爲 00650064 0007:32FD I:. ├─call-server │ ├─api │ ├─cmd │ ├─configs │ ├─internal │ │ ├─dao │ │ ├─di │ │ ├─model │ │ ├─server │ │ │ ├─grpc │ │ │ └─http │ │ └─service │ └─test └─grpc-server ├─api ├─cmd ├─configs ├─internal │ ├─dao │ ├─di │ ├─model │ ├─server │ │ ├─grpc │ │ └─http │ └─service └─test
咱們後面用call-server直連 grpc-server 調用grpc接口。api
配置裏面修改下端口,同時call-server裏面添加grpc-server的地址,我這是9003.app
[Server] addr = "0.0.0.0:9004" timeout = "1s" [Client] addr = "0.0.0.0:9003" timeout = "1s"
grpc-server的internal/server/grpc目錄打開server.go文件,能夠看到如下代碼,替換註釋內容就能夠啓動一個gRPC、咱們就是demo項目不須要替換。框架
package grpc import ( pb "grpc-server/api" "github.com/bilibili/kratos/pkg/conf/paladin" "github.com/bilibili/kratos/pkg/net/rpc/warden" ) // New new a grpc server. func New(svc pb.DemoServer) (ws *warden.Server, err error) { var ( cfg warden.ServerConfig ct paladin.TOML ) if err = paladin.Get("grpc.toml").Unmarshal(&ct); err != nil { return } if err = ct.Get("Server").UnmarshalTOML(&cfg); err != nil { return } ws = warden.NewServer(&cfg) // 注意替換這裏: // RegisterDemoServer方法是在"api"目錄下代碼生成的 // 對應proto文件內自定義的service名字,請使用正確方法名替換 pb.RegisterDemoServer(ws.Server(), svc) ws, err = ws.Start() return }
接着直接啓動grpc-serveride
kratos run I:/VSProject/go/pkg/mod/github.com/bilibili/kratos@v0.3.2-0.20191224125553-6e1180f53a8e/pkg/net/rpc/warden/server.go:329 warden: start grpc listen addr: [::]:9003
client端要調用grpc的接口必須有它生成的protobuf文件微服務
通常是下面兩種方式:
一、拷貝proto文件到本身項目下而且執行代碼生成
二、直接import服務端的api package
這裏由於demo服務api如出一轍,我就不作import了,直接取api裏面的pb.go文件
在internal/dao
裏面直接修改dao文件並添加一個direct_client.go
direct_client.go
其中,target爲gRPC用於服務發現的目標,使用標準url資源格式提供給resolver用於服務發現。warden默認使用direct直連方式,直接與server端進行鏈接。其餘服務發現方式下回見。
package dao import ( "context" "github.com/bilibili/kratos/pkg/net/rpc/warden" "google.golang.org/grpc" ) // target server addrs. const target = "direct://default/127.0.0.1:9003" // NOTE: example // NewClient new member grpc client func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (DemoClient, error) { client := warden.NewClient(cfg, opts...) conn, err := client.Dial(context.Background(), target) if err != nil { return nil, err } // 注意替換這裏: // NewDemoClient方法是在"api"目錄下代碼生成的 // 對應proto文件內自定義的service名字,請使用正確方法名替換 return NewDemoClient(conn), nil }
dao.go 改爲以下。
添加一個dao裏面直接demoClient,newDao裏面作democlient的初始化、並添加一個SayHello接口。
package dao import ( "context" "time" demoapi "call-server/api" "call-server/internal/model" "github.com/bilibili/kratos/pkg/cache/memcache" "github.com/bilibili/kratos/pkg/cache/redis" "github.com/bilibili/kratos/pkg/conf/paladin" "github.com/bilibili/kratos/pkg/database/sql" "github.com/bilibili/kratos/pkg/net/rpc/warden" "github.com/bilibili/kratos/pkg/sync/pipeline/fanout" xtime "github.com/bilibili/kratos/pkg/time" grpcempty "github.com/golang/protobuf/ptypes/empty" "github.com/pkg/errors" "github.com/google/wire" ) var Provider = wire.NewSet(New, NewDB, NewRedis, NewMC) //go:generate kratos tool genbts // Dao dao interface type Dao interface { Close() Ping(ctx context.Context) (err error) // bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1 Article(c context.Context, id int64) (*model.Article, error) SayHello(c context.Context, req *demoapi.HelloReq) (resp *grpcempty.Empty, err error) } // dao dao. type dao struct { db *sql.DB redis *redis.Redis mc *memcache.Memcache demoClient demoapi.DemoClient cache *fanout.Fanout demoExpire int32 } // New new a dao and return. func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, cf func(), err error) { return newDao(r, mc, db) } func newDao(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d *dao, cf func(), err error) { var cfg struct { DemoExpire xtime.Duration } if err = paladin.Get("application.toml").UnmarshalTOML(&cfg); err != nil { return } grpccfg := &warden.ClientConfig{} paladin.Get("grpc.toml").UnmarshalTOML(grpccfg) var grpcClient demoapi.DemoClient if grpcClient, err = NewClient(grpccfg); err != nil { return } d = &dao{ db: db, redis: r, mc: mc, demoClient: grpcClient, cache: fanout.New("cache"), demoExpire: int32(time.Duration(cfg.DemoExpire) / time.Second), } cf = d.Close return } // Close close the resource. func (d *dao) Close() { d.cache.Close() } // Ping ping the resource. func (d *dao) Ping(ctx context.Context) (err error) { return nil } // SayHello say hello. func (d *dao) SayHello(c context.Context, req *demoapi.HelloReq) (resp *grpcempty.Empty, err error) { if resp, err = d.demoClient.SayHello(c, req); err != nil { err = errors.Wrapf(err, "%v", req.Name) } return }
service.go
裏面調用dao.SayHello()
// SayHello grpc demo func. func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) { reply = new(empty.Empty) s.dao.SayHello(ctx, req) fmt.Printf("hello %s", req.Name) return }
最後調用call-server的http接口測試:
從grpc-server的日誌裏面能夠看到咱們的調用是成功的, 本節完(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤。
本例子源代碼 :https://github.com/ailumiyana/kratos-note