基于 go-micro 2.9.1 版本,
样例代码 example/greeter,git commit:3b3de68cded8879ca3dde5d81192f2881619aabd
一个微服务 server 的外围只有 3 步
service := micro.NewService()
service.Init()
service.Run()
先看 micro.NewService()
service := micro.NewService(micro.Name("greeter"),
micro.Version("latest"),
micro.Metadata(map[string]string{"type": "helloworld",}),
)
micro.NewService 的参数都会返回一个 Option
,
这些参数没有做任何事件,只是返回了一些设置用的函数,
这种写法是“函数选项模式”,可参考 https://segmentfault.com/a/11…
先看 NewService()
外面做了什么
// Name of the service
func Name(n string) Option {return func(o *Options) {o.Server.Init(server.Name(n))
}
}
//Option 函数在 micro.go 中定义
//Options 构造体在 options.go 中定义
type Option func(*Options)
// Options for micro service
type Options struct {
Auth auth.Auth
Broker broker.Broker
Cmd cmd.Cmd
Config config.Config
Client client.Client
Server server.Server
Store store.Store
Registry registry.Registry
Router router.Router
Runtime runtime.Runtime
Transport transport.Transport
Profile profile.Profile
// Before and After funcs
BeforeStart []func() error
BeforeStop []func() error
AfterStart []func() error
AfterStop []func() error
// Other options for implementations of the interface
// can be stored in a context
Context context.Context
Signal bool
}
server.Name(n)实现这样, 通过 micro 包提供的函数设置 micro.options
// Server name
func Name(n string) Option {return func(o *Options) {o.Name = n}
}
NewService 中调用了 service.go 中的 newService(opts…)
// NewService creates and returns a new Service based on the packages within.
func NewService(opts ...Option) Service {return newService(opts...)
}
type service struct {
opts Options
once sync.Once
}
func newService(opts ...Option) Service {service := new(service)
options := newOptions(opts...)
// service name
serviceName := options.Server.Options().Name
// we pass functions to the wrappers since the values can change during initialisation
authFn := func() auth.Auth { return options.Server.Options().Auth }
cacheFn := func() *client.Cache { return options.Client.Options().Cache }
// wrap client to inject From-Service header on any calls
options.Client = wrapper.FromService(serviceName, options.Client)
options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client)
options.Client = wrapper.CacheClient(cacheFn, options.Client)
options.Client = wrapper.AuthClient(authFn, options.Client)
// wrap the server to provide handler stats
options.Server.Init(server.WrapHandler(wrapper.HandlerStats(stats.DefaultStats)),
server.WrapHandler(wrapper.TraceHandler(trace.DefaultTracer)),
server.WrapHandler(wrapper.AuthHandler(authFn)),
)
// set opts
service.opts = options
return service
}
func newOptions(opts ...Option) Options {
opt := Options{
Auth: auth.DefaultAuth,
Broker: broker.DefaultBroker,
Cmd: cmd.DefaultCmd,
Config: config.DefaultConfig,
Client: client.DefaultClient,
Server: server.DefaultServer,
Store: store.DefaultStore,
Registry: registry.DefaultRegistry,
Router: router.DefaultRouter,
Runtime: runtime.DefaultRuntime,
Transport: transport.DefaultTransport,
Context: context.Background(),
Signal: true,
}
for _, o := range opts {o(&opt)
}
return opt
}
-
实例化 service 构造体,初始化参数并赋值到 opts
- 先初始化一些 Options 属性
- 再从 opts 中遍历执行 micro.NewService 的参数(理论就是函数),设置各种值
-
为 options.Client 减少几个 wrapper,ctx 中减少了 4 个键值对,在 client 发动申请的时候回放到 header 中
- wrapper.FromService()中,ctx 减少
Micro-From-Service
- wrapper.TraceHandler(trace.DefaultTracer) -> t.Start(ctx, req.Service()+”.”+req.Endpoint()) -> Tracer.start()(trace/memory/memory.go),ctx 减少
Micro-Trace-Id, Micro-Span-Id
- server.WrapHandler(wrapper.AuthHandler(authFn)), ctx 减少
Micro-Namespace
- wrapper.FromService()中,ctx 减少
- 为 options.Server 减少几个 wrapper
options.Server.Init(server.Name(n))
这里的 options.Server 是哪里来的呢, 后面没见有初始化这个属性的中央, 其实在 go-micro/defaults.go 的 init()中
func init() {
// default client
client.DefaultClient = gcli.NewClient()
// default server
server.DefaultServer = gsrv.NewServer()
// default store
store.DefaultStore = memoryStore.NewStore()
// set default trace
trace.DefaultTracer = memTrace.NewTracer()}
init()中定义了 4 个变量,server,client,store,trace
,须要留神的是这里的 server 是默认的 grpc,是 micro 包外部变量,在其余中央无奈间接拜访
o.Server.Init(server.Name(n)) 的 Init()
则是 server/grpc.go 中的 init(), 初始化 grpcServer.opts[类型是 server.Options]的一些属性,如 server.Name(n)设置的是 grpcServer.opts.Name
grpc.configure()中的其余局部这里暂不细看
func (g *grpcServer) Init(opts ...server.Option) error {g.configure(opts...)
return nil
}
func (g *grpcServer) configure(opts ...server.Option) {g.Lock()
defer g.Unlock()
// Don't reprocess where there's no config
if len(opts) == 0 && g.srv != nil {return}
for _, o := range opts {o(&g.opts)
}
maxMsgSize := g.getMaxMsgSize()
gopts := []grpc.ServerOption{grpc.MaxRecvMsgSize(maxMsgSize),
grpc.MaxSendMsgSize(maxMsgSize),
grpc.UnknownServiceHandler(g.handler),
}
if creds := g.getCredentials(); creds != nil {gopts = append(gopts, grpc.Creds(creds))
}
if opts := g.getGrpcOptions(); opts != nil {gopts = append(gopts, opts...)
}
g.rsvc = nil
g.srv = grpc.NewServer(gopts...)
}
上面再看service.Init()
// Init will parse the command line flags. Any flags set will
// override the above settings. Options defined here will
// override anything set on the command line.
service.Init(
// Add runtime action
// We could actually do this above
micro.Action(func(c *cli.Context) error {if c.Bool("run_client") {runClient(service)
os.Exit(0)
}
return nil
}),
)
// Init initialises options. Additionally it calls cmd.Init
// which parses command line flags. cmd.Init is only called
// on first Init.
func (s *service) Init(opts ...Option) {
// process options
for _, o := range opts {o(&s.opts)
}
s.once.Do(func() {
// setup the plugins
for _, p := range strings.Split(os.Getenv("MICRO_PLUGIN"), ",") {if len(p) == 0 {continue}
// load the plugin
c, err := plugin.Load(p)
if err != nil {logger.Fatal(err)
}
// initialise the plugin
if err := plugin.Init(c); err != nil {logger.Fatal(err)
}
}
// set cmd name
if len(s.opts.Cmd.App().Name) == 0 {s.opts.Cmd.App().Name = s.Server().Options().Name
}
// Initialise the command flags, overriding new service
if err := s.opts.Cmd.Init(cmd.Auth(&s.opts.Auth),
cmd.Broker(&s.opts.Broker),
cmd.Registry(&s.opts.Registry),
cmd.Runtime(&s.opts.Runtime),
cmd.Transport(&s.opts.Transport),
cmd.Client(&s.opts.Client),
cmd.Config(&s.opts.Config),
cmd.Server(&s.opts.Server),
cmd.Store(&s.opts.Store),
cmd.Profile(&s.opts.Profile),
); err != nil {logger.Fatal(err)
}
// Explicitly set the table name to the service name
name := s.opts.Cmd.App().Name
s.opts.Store.Init(store.Table(name))
})
}
- 和 micro.NewService 的参数解决一样,初始化参数
-
s.once.Do(),只执行一次
- 加载插件
- 设置 cmd 名字
- 初始化命令行参数,笼罩 service 中的属性
- 显式地将 cmd 名字设置为服务名
最初一步service.Run()
func (s *service) Run() error {
// register the debug handler
s.opts.Server.Handle(
s.opts.Server.NewHandler(handler.NewHandler(s.opts.Client),
server.InternalHandler(true),
),
)
// start the profiler
if s.opts.Profile != nil {
// to view mutex contention
rtime.SetMutexProfileFraction(5)
// to view blocking profile
rtime.SetBlockProfileRate(1)
if err := s.opts.Profile.Start(); err != nil {return err}
defer s.opts.Profile.Stop()}
if logger.V(logger.InfoLevel, logger.DefaultLogger) {logger.Infof("Starting [service] %s", s.Name())
}
if err := s.Start(); err != nil {return err}
ch := make(chan os.Signal, 1)
if s.opts.Signal {signal.Notify(ch, signalutil.Shutdown()...)
}
select {
// wait on kill signal
case <-ch:
// wait on context cancel
case <-s.opts.Context.Done():}
return s.Stop()}
- 注册 debug handler
- 启动 profiler,控制台输入启动信息
- s.start(), 前面再看
- 监听退出 Signal 和 ctx 勾销信号,收到信号后执行 s.stop()
func (s *service) Start() error {
for _, fn := range s.opts.BeforeStart {if err := fn(); err != nil {return err}
}
if err := s.opts.Server.Start(); err != nil {return err}
for _, fn := range s.opts.AfterStart {if err := fn(); err != nil {return err}
}
return nil
}
func (s *service) Stop() error {
var gerr error
for _, fn := range s.opts.BeforeStop {if err := fn(); err != nil {gerr = err}
}
if err := s.opts.Server.Stop(); err != nil {return err}
for _, fn := range s.opts.AfterStop {if err := fn(); err != nil {gerr = err}
}
return gerr
}
启动:
- 顺次执行
s.opts.BeforeStart
列表中的函数 - 启动服务
s.opts.Server.Start()
,具体就看用的什么服务了 - 顺次执行
s.opts.AfterStart
列表中的函数
退出:
退出流程与启动流程统一,顺次执行s.opts.BeforeStop,s.opts.Server.Stop(),s.opts.AfterStop
BeforeStart 的例子,其余的相似
func aa() error {fmt.Println("beforestart fmt")
return nil
}
service := micro.NewService(micro.BeforeStart(aa),
)
默认的 store.DefaultStore
应用 https://github.com/patrickmn/…
在 memory/memory.go 中做了一些封装
其余init()
,在 golang 中援用的包,会主动执行 init()
logger/default.go 初始化 logger
micro.NewService()中的所有设置选项见 go-micro/options.go,能够参见【Micro In Action(二):我的项目构造与启动过程】
https://medium.com/@dche423/m…
这就是 go micro 微服务的启动过程,肯定要先理解 函数选项模式
才有助于了解 go micro。