1. micro server命令流程

1.1. makefile

micro的makefile很简单

build:
        go build -a -installsuffix cgo -ldflags "-s -w ${LDFLAGS}" -o $(NAME)

会展开成

$ make build
go build -a -installsuffix cgo -ldflags "-s -w -X github.com/micro/micro/v3/cmd.BuildDate=1624082635 -X github.com/micro/micro/v3/cmd.GitCommit=870f80e7 -X github.com/micro/micro/v3/cmd.GitTag=v3.3.0" -o micro

注:

  • -a是强制所有包都重编
  • -ldflags "-X ...这一堆是给包的"全局变量"赋值

1.2. main.go

main.go的思路和gshellos building很像 通过import的package的init函数来注册, main里面只调用cmd.Run()

package main

//go:generate ./scripts/generate.sh

import (
    "github.com/micro/micro/v3/cmd"

    // load packages so they can register commands
    _ "github.com/micro/micro/v3/cmd/cli"
    _ "github.com/micro/micro/v3/cmd/server"
    _ "github.com/micro/micro/v3/cmd/service"
    _ "github.com/micro/micro/v3/cmd/usage"
)

func main() {
    cmd.Run()
}

注:

  • go generate命令是独立的, go build不会默认先调用go generate. 之所以这里在makefile里面没有调用go generate命令, 可能是因为生成代码这个步骤是开发者手动完成的

1.3. cmd

使用了urfave的cli框架 urfave的cli框架里, 命令是以树的形式组织的:子命令先注册到上级命令, 然后顶层命令的run函数, 会找到合适的子命令来run; 如果没找到, 就调用本层命令的Action函数. cmd包全局变量DefaultCmd Cmd = New()之后, 就调用DefaultCmd.Run()来开始命令行解析.

1.3.1. 顶层Action

上面说过, 没有匹配的子命令的时候, 就调用本次的Action. 那么顶层的Action被调用到的时候, 说明用户输入的不是子命令, 按照micro的设计, 而是个自定义服务名. 这里的基本逻辑是查找这个服务名, 调用服务.

1.3.2. server子命令

按照教程, 所有micro都要依赖micro服务. ./micro server 这个server是个子命令, 被注册到DefaultCmd的子命令列表中

    command := &cli.Command{
        Name:  "server",
        Usage: "Run the micro server",
        Description: `Launching the micro server ('micro server') will enable one to connect to it by
        setting the appropriate Micro environment (see 'micro env' && 'micro env --help') commands.`,
        Flags: []cli.Flag{
            &cli.StringFlag{
                Name:    "address",
                Usage:   "Set the micro server address :10001",
                EnvVars: []string{"MICRO_SERVER_ADDRESS"},
            },
            &cli.StringFlag{
                Name:    "image",
                Usage:   "Set the micro server image",
                EnvVars: []string{"MICRO_SERVER_IMAGE"},
                Value:   "micro/micro:latest",
            },
        },
        Action: func(ctx *cli.Context) error {
            Run(ctx)
            return nil
        },
    }

server的Action动作是启动如下服务

    services = []string{
        "registry", // :8000
        "broker",   // :8003
        "network",  // :8443
        "runtime",  // :8088
        "config",   // :8001
        "store",    // :8002
        "events",   // :unset
        "auth",     // :8010
        "proxy",    // :8081
        "api",      // :8080
    }

按照micro service [name]的形式, 注意这里的命令的关键词是service

for 每个在上面services列表中的service {
        // all things run by the server are `micro service [name]`
        cmdArgs := []string{"service"}
        cmdArgs = append(cmdArgs, service)
        // runtime based on environment we run the service in
        args := []runtime.CreateOption{
            runtime.WithCommand(os.Args[0]),
            runtime.WithArgs(cmdArgs...),
            runtime.WithEnv(env),
            runtime.WithPort(port),
            runtime.WithRetries(10),
            runtime.WithServiceAccount("micro"),
            runtime.WithVolume("store-pvc", "/store"),
            runtime.CreateImage(context.String("image")),
            runtime.CreateNamespace("micro"),
            runtime.WithSecret("MICRO_AUTH_PUBLIC_KEY", auth.DefaultAuth.Options().PublicKey),
            runtime.WithSecret("MICRO_AUTH_PRIVATE_KEY", auth.DefaultAuth.Options().PrivateKey),
        }
        // NOTE: we use Version right now to check for the latest release
        muService := &runtime.Service{Name: service, Version: "latest"}
        //真正的启动内置service
        runtimeServer.Create(muService, args...)
}

这里有两种类型的runtime:

  • local
  • kubernetes

我们这里走的是local. local的Create函数在 service/runtime/local/local.go

func (r *localRuntime) Create(resource runtime.Resource, opts ...runtime.CreateOption) error {
    这个Create是个通用的接口, 可以新建比如namespace, NetworkPolicy, 也可以是Service
    // create new service
    service := newService(s, options)
    // 先建log文件, 一般在 /tmp/micro/logs/runtime.log
    f, err := os.OpenFile(logFile(service.Name), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    // start the service
    err := service.Start()
}

注意最后service.Start()是启动一个独立的进程, 这个进程运行了内置的service 这里执行的命令是:./micro service api

p, err := s.Process.Fork(s.Exec)
    cmd := exec.Command(exe.Package.Path, exe.Args...)
    err := cmd.Start()

1.3.3. log

micro的log都放在/tmp/micro/logs

var (
    // The directory for logs to be output
    LogDir = filepath.Join(os.TempDir(), "micro", "logs")
    // The source directory where code lives
    SourceDir = filepath.Join(os.TempDir(), "micro", "uploads")
)

比如我的实际例子:

$ ls /tmp/micro/logs/
api.log  auth.log  broker.log  config.log  events.log  network.log  proxy.log  registry.log  runtime.log  store.log

1.3.4. ./micro service api执行流程

service命令入口, 代码在cmd/service/service.go

命令行入口: 注意这个入口是在下级命令的情况下才会调用的. 所以我看了半天实际是执行不到的. : (

// Run starts a micro service sidecar to encapsulate any app
func Run(ctx *ccli.Context) {
    // new service
    srv := service.New(opts...)

    // create new muxer
    //    muxer := mux.New(name, p)

    // set the router
    srv.Server().Init(
        server.WithRouter(p),
    )

    // run service
    srv.Run()
}

1.3.5. api命令入口

api命令的入口实际上是

var srvCommands = []srvCommand{
    {
        Name:    "api",
        Command: api.Run,
        Flags:   api.Flags,
    },
    ...
}

对应代码: service/api/server/server.go 默认值就是这里的8080

var (
    Name                  = "api"
    Address               = ":8080"
    Handler               = "meta"
    Resolver              = "micro"
    APIPath               = "/"
    ProxyPath             = "/{service:[a-zA-Z0-9]+}"
    Namespace             = ""
    ACMEProvider          = "autocert"
    ACMEChallengeProvider = "cloudflare"
    ACMECA                = acme.LetsEncryptProductionCA
)

api命令的入口就是:

func Run(ctx *cli.Context) error {
    // initialise service
    srv := service.New(service.Name(Name))
    // create a new api server with wrappers
    api := httpapi.NewServer(Address)
    // initialise
    api.Init(opts...)
    // register the handler
    api.Handle("/", h)

    // Start API
    if err := api.Start(); err != nil {
        log.Fatal(err)
    }

    // Run server
    if err := srv.Run(); err != nil {
        log.Fatal(err)
    }

    // Stop API
    if err := api.Stop(); err != nil {
        log.Fatal(err)
    }
}

我这里./micro server总是出错, 看log是因为: api这个服务的8080端口被占用了.

2021-06-20 05:20:44  file=server/server.go:341 level=fatal service=api listen tcp :8080: bind: address already in use

这个端口是写死的. 虽然有命令行参数可以改, 但是这个命令行是micro server传入写死的... 这似乎是个死局, 初非直接改代码. 解决办法很简单, 直接改个port:

$ git diff
diff --git a/service/api/server/server.go b/service/api/server/server.go
index 2bcd7651..69f7f31a 100644
--- a/service/api/server/server.go
+++ b/service/api/server/server.go
@@ -39,7 +39,7 @@ import (

 var (
        Name                  = "api"
-       Address               = ":8080"
+       Address               = ":18080"
        Handler               = "meta"
        Resolver              = "micro"
        APIPath               = "/"

1.3.6. 总结

  • 每个service都使用了micro的框架, 都以独立进程的形式存在.

1.4. urfave的cli使用

注册的action会被调用: 比如

func Run(ctx *cli.Context) error {
    ...
}
  • ctx.String("server_name"): 获取命令行的string类型的flag值
  • ctx.Bool("enable_acme"): 类似的, 获取Bool类型的值

2. 新版micro搭建blog服务

2.1. 建立运行环境

先run micro server

micro server

看看当前环境

$ micro env
* local      127.0.0.1:8081         Local running micro server
  dev        proxy.m3o.dev          Cloud hosted development environment
  platform   proxy.m3o.com          Cloud hosted production environment

可能需要先运行micro env set local来建立local的环境

2.2. 新建posts 服务

$ micro new posts
$ ls posts
Dockerfile    Makefile    README.md    generate.go    go.mod        handler        main.go        proto

改proto先

syntax = "proto3";

package posts;

service Posts {
    rpc Save(SaveRequest) returns (SaveResponse) {}
    rpc Query(QueryRequest) returns (QueryResponse) {}
    rpc Delete(DeleteRequest) returns (DeleteResponse) {}
}

message SaveRequest {
    string id = 1;
    string title = 2;
    string slug = 3;
    string content = 4;
    int64 timestamp = 5;
    repeated string tags = 6;
}

message SaveResponse {
    string id = 1;
}

message Post {
    string id = 1;
    string title = 2;
    string slug = 3;
    string content = 4;
    int64 created = 5;
    int64 updated = 6;
    string author = 7;
    repeated string tags = 8;
}

proto文件有一定的修改, 目的是让命令访问更简单点 不改的话是这样 micro posts save --post_title=Title --post_content=Content 这里想整成这样: micro posts save --title=Title --content=Content

然后make proto就可以生成代码了

2.2.1. 写main.go

package main

import (
    "posts/handler"

    "github.com/micro/micro/v3/service"
    "github.com/micro/micro/v3/service/logger"
)

func main() {
    // Create the service
    srv := service.New(
        service.Name("posts"),
    )

    // Register Handler
    srv.Handle(handler.NewPosts())

    // Run service
    if err := srv.Run(); err != nil {
        logger.Fatal(err)
    }
}

2.2.2. 写handler.go

package handler

import (
    "context"
    "time"

    "github.com/micro/dev/model"
    "github.com/micro/go-micro/errors"
    "github.com/micro/micro/v3/service/logger"
    "github.com/micro/micro/v3/service/store"

    proto "posts/proto"

    "github.com/gosimple/slug"
)

type Posts struct {
    db           model.Model
    idIndex      model.Index
    createdIndex model.Index
    slugIndex    model.Index
}

func NewPosts() *Posts {
    createdIndex := model.ByEquality("created")
    createdIndex.Order.Type = model.OrderTypeDesc

    slugIndex := model.ByEquality("slug")

    idIndex := model.ByEquality("id")
    idIndex.Order.Type = model.OrderTypeUnordered

    return &Posts{
        db: model.New(
            store.DefaultStore,
            "posts",
            model.Indexes(slugIndex, createdIndex),
            &model.ModelOptions{
                IdIndex: idIndex,
            },
        ),
        createdIndex: createdIndex,
        slugIndex:    slugIndex,
        idIndex:      idIndex,
    }
}

现在run这个服务micro run ., 能得到初步的输出

$ micro logs posts
Starting [service] posts
Server [grpc] Listening on [::]:53031
Registry [service] Registering node: posts-b36361ae-f2ae-48b0-add5-a8d4797508be

2.2.3. 增加save功能

增加save函数

func (p *Posts) Save(ctx context.Context, req *proto.SaveRequest, rsp *proto.SaveResponse) error {
    logger.Info("Received Posts.Save request")
    post := &proto.Post{
        Id:      req.Id,
        Title:   req.Title,
        Content: req.Content,
        Slug:    req.Slug,
        Created: time.Now().Unix(),
    }
    if req.Slug == "" {
        post.Slug = slug.Make(req.Title)
    }
    return p.db.Save(post)
}

重新run micro update .

micro posts save --id=1 --title="Post one" --content="First saved post"
micro posts save --id=2 --title="Post two" --content="Second saved post"

3. 新版micro

3.1. 依赖

依赖protobuf go版本

# Download latest proto releaes
# https://github.com/protocolbuffers/protobuf/releases
go get github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro

3.2. 要先启动server, 再login上去

用户名密码是admin和micro

micro server

$ micro login
Enter username: admin
Enter password:
Successfully logged in.

3.3. micro server会默认启动一些服务

$ micro services
api
auth
broker
config
events
network
proxy
registry
runtime
server
store

3.4. run hello world service

github.com/micro/services库中, 有很多"官方"写好的服务 比如我们要run个hello world

micro run github.com/micro/services/helloworld

现在可以看看状态

$ micro status
NAME        VERSION    SOURCE                    STATUS    BUILD    UPDATED    METADATA
helloworld    latest    github.com/micro/services/helloworld    running    n/a    4s ago    owner=admin, group=micro

看看log

$ micro logs helloworld
2020-10-06 17:52:21  file=service/service.go:195 level=info Starting [service] helloworld
2020-10-06 17:52:21  file=grpc/grpc.go:902 level=info Server [grpc] Listening on [::]:33975
2020-10-06 17:52:21  file=grpc/grpc.go:732 level=info Registry [service] Registering node: helloworld-67627b23-3336-4b92-a032-09d8d13ecf95

3.5. 调用hello world服务

3.5.1. cli方式

还是使用micro命令来调用, 格式是micro [service] [method], 默认的method是call, 参数可以直接命令行传入

$ micro helloworld --name=Jane
{
    "msg": "Hello Jane"
}

查询这个服务能提供什么服务:

$ micro helloworld --help
NAME:
    micro helloworld

VERSION:
    latest

USAGE:
    micro helloworld [command]

COMMANDS:
    call

要看call命令的子命令call的使用

$ micro helloworld call --help
NAME:
    micro helloworld call

USAGE:
    micro helloworld call [flags]

FLAGS:
    --name string

3.5.2. rest API方式

curl "http://localhost:8080/helloworld?name=John"

3.5.3. 自己写个client

是个rpc模式的client 实际上这个client本身也是个"service"(使用service.New()得来)

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/micro/micro/v3/service"
    proto "github.com/micro/services/helloworld/proto"
)

func main() {
    // create and initialise a new service
    srv := service.New()

        // create the proto client for helloworld
        client := proto.NewHelloworldService("helloworld", srv.Client())

        // call an endpoint on the service
        rsp, err := client.Call(context.Background(), &proto.Request{
            Name: "John",
        })
        if err != nil {
            fmt.Println("Error calling helloworld: ", err)
            return
        }

        // print the response
        fmt.Println("Response: ", rsp.Msg)

        // let's delay the process for exiting for reasons you'll see below
        time.Sleep(time.Second * 5)
}

run这个client:

cd example && go mod init example
micro run .

run的时候不打印, 用status命令能看到

$ micro status
NAME        VERSION    SOURCE                                    STATUS    BUILD    UPDATED        METADATA
example        latest    example.tar.gz                            running    n/a     2s ago        owner=admin, group=micro
helloworld    latest    github.com/micro/services/helloworld    running    n/a        5m59s ago    owner=admin, group=micro

看log能够得到其output

$ micro logs example
# some go build output here
Response:  Hello John

3.5.4. 总结

  • 使用protobuf来封装message
  • client也是service

3.6. 新建service

3.6.1. 使用micro new新建个工程

配套目录, proto定义, Makefile自动生成

$ micro new helloworld
Creating service helloworld

.
├── main.go
├── generate.go
├── handler
│   └── helloworld.go
├── proto
│   └── helloworld.proto
├── Dockerfile
├── Makefile
├── README.md
├── .gitignore
└── go.mod


download protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:

visit https://github.com/protocolbuffers/protobuf/releases

download protobuf for micro:

go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro

compile the proto file helloworld.proto:

cd helloworld
make proto

根据提示, 改了proto后, make proto来生成go代码

3.7. storage服务

没错, 永久存储被内置成了服务, 并配套了专有命令

  • 写key value对
    $ micro store write key1 value1
    
  • 读key
    $ micro store read key1
    val1
    $ micro store read -v key1
    KEY    VALUE   EXPIRY
    key1   val1    None
    
  • pattern读, -p选项
    $ micro store read --prefix --verbose key
    KEY    VALUE   EXPIRY
    key1   val1    None
    key2   val2    None
    

3.7.1. 每个service都有自己的table

--table指定table micro store write --table=example mykey "Hi there" 可以在client代码里读key

package main

import (
    "fmt"
    "time"

    "github.com/micro/micro/v3/service"
    "github.com/micro/micro/v3/service/store"
)

func main() {
    srv := service.New(service.Name("example"))
    srv.Init()

    records, err := store.Read("mykey")
    if err != nil {
        fmt.Println("Error reading from store: ", err)
    }

    if len(records) == 0 {
        fmt.Println("No records")
    }
    for _, record := range records {
        fmt.Printf("key: %v, value: %v\n", record.Key, string(record.Value))
    }

    time.Sleep(1 * time.Hour)
}

3.8. 用update命令重新run一个服务

比如之前已经在run的example服务(实际是hello world的client), 改了代码要重新run, 用 micro update . 使用最近代码重run 也可以先kill, 再run

micro kill example
micro run .

3.9. 内置config命令

支持类似map式的set

$ micro config set key val
$ micro config get key
val

$ micro config set key.subkey val
$ micro config get key.subkey
val
$ micro config get key
{"subkey":"val"}

$ micro config set key.othersubkey val2
$ micro config get key
{"othersubkey":"val2","subkey":"val"}

用client代码来获取config

package main

import (
    "fmt"

    "github.com/micro/micro/v3/service"
    "github.com/micro/micro/v3/service/config"
)

func main() {
    // setup the service
    srv := service.New(service.Name("example"))
    srv.Init()

    // read config value
    val, _ := config.Get("key.subkey")
    fmt.Println("Value of key.subkey: ", val.String(""))
}

4. 更新2021.6.18

4.1. 分叉

分叉为两个分支:

4.2. v2-to-v3-upgrade-guide

  srv := micro.NewService(
    micro.Name("go.micro.service.foo")
  )

变为

  srv := service.New(
    service.Name("foo")
  )

4.3. v3版本也是搞micro run这一套

要先起个server: 使用命令micro server, 没有server的环境, 可以使用免费的M3O环境: micro env set platform

4.4. go micro的网络设计理念

Building a global services network using Go, QUIC and Micro看过来的.

5. 更新2020.11

go micro换了地址 老地址:github.com/micro/go-micro 新地址:https://github.com/asim/nitro

访问老地址会自动跳到新地址 FAQ中说

  • go-micro重命名为Nitro, 现在由个人维护; 原组织github.com/micro现在加倍下注(doubling down)在Micro项目, 这个项目会集大成
  • License从Apache 2.0换到了Polyform Noncommercial
  • go-plugins现在地址是github.com/asim/nitro-plugins, 虽然是Apache协议, 但用了Nitro, 所以也不能商用
  • Nitro的目标是不引入外部依赖, 外部依赖由Nitro Plugins解决. -- 纯框架
  • defualt的top level services初始化被移出了. 作者认为设置default初始化不好
  • cmd包也被移出了. 作者认为这部分代码引入了复杂的依赖代码.难于维护. 作者推荐使用google的生成依赖初始化项目wire 介绍见blog 不同于基于reflection的 Uber's dig and Facebook's inject, wire使用代码生成技术, 类似java的 Dagger 2 基本上是代码里声明依赖, 用go generate调用wire生成代码.
  • 作者认为micro和nitro的区别是, 前者现在是大一统的方案, 目标是云; 后者是作者自己维护的框架, 目标是edge, IOT, 嵌入式等.
  • 原来的go-micro开发怎么继续? 答: 使用Micro和m3o.com which starts as a purely free Dev environment in the cloud.
  • go-micro v2还能用吗? 答: 可以. v2还是Apache许可证. import github.com/micro/go-micro/v2 github会自动重定向到https://github.com/asim/nitro

补充: Micro项目的License也换了. 但同样的, 可以用v2版本

6. 介绍

本文介绍go的开源微服务框架https://github.com/micro/go-micro. 原文链接

Micro有两个库:

  • go-micro 核心库. 典型的是用gRPC
  • micro 辅助工具集, 比如工程模板生成, 运行状态检查, 微服务调用. 基于go-micro

还有一个重要库:

  • go-plugins 自定义扩展, 比如提供了transport protocols的扩展选择. go-micro是plugin的思路, 不同的扩展可以自由组合.

7. 框架

go-mirco对通用的分布式微服务做了interface抽象.

其中service是核心, 负责协调其他interfaces

7.1. 服务发现

服务发现定义为如下的interface, 只要实现了这些, 就能被框架使用. github.com/micro/go-micro/v2/registry/Registry

// The registry provides an interface for service discovery
// and an abstraction over varying implementations
// {consul, etcd, zookeeper, ...}
type Registry interface {
 Init(...Option) error
 Options() Options
 Register(*Service, ...RegisterOption) error
 Deregister(*Service) error
 GetService(string) ([]*Service, error)
 ListServices() ([]*Service, error)
 Watch(...WatchOption) (Watcher, error)
 String() string
}

实际上, go-plugin库已经有很多实现了, 比如etcd/consul/zookeeper, 默认是多播DNS(mDNS), 不需要配置, 开箱即用.

7.2. 异步消息

异步消息定义如下: github.com/micro/go-micro/v2/broker/Broker

// Broker is an interface used for asynchronous messaging.
type Broker interface {
 Init(...Option) error
 Options() Options
 Address() string
 Connect() error
 Disconnect() error
 Publish(topic string, m *Message, opts ...PublishOption) error
 Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error)
 String() string
}

已经实现的broker有: RabbitMQ, Kafka, NSQ, 默认的使用http.

7.3. 消息编码

github.com/micro/go-micro/v2/codec/Codec

// Codec encodes/decodes various types of messages used within go-micro.
// ReadHeader and ReadBody are called in pairs to read requests/responses
// from the connection. Close is called when finished with the
// connection. ReadBody may be called with a nil argument to force the
// body to be read and discarded.
type Codec interface {
 Reader
 Writer
 Close() error
 String() string
}

目前有json bson msgpack等实现.

7.4. 其他接口

  • Server, define the server of microservices
  • Transport, defines the transport protocol
  • Selector,abstracts logic of service selection. you can implement various load balancing strategies with this interface
  • Wrapper,defines middleware which can wrap server/client request

go-micro对微服务的抽象很"正交"(orthoganal), 比较全面.

8. 使用micro模板

8.1. 生成工程模板代码

下载micro工具 GO111MODULE=on go get github.com/micro/micro/v2@v2.4.0 创建一个模板工程 micro new --namespace=com.foo --gopath=false hello

  • micro new, create a gRPC service by running the new sub-command of the micro command-line tool
  • hello, specify the service name
  • --namespace=com.foo, provide a namespace to the service
  • --gopath=false, generate code into the current directory instead of $GOPATH (since Golang supports Go Module, new projects should be placed outside of $GOPATH)

命令执行完毕后, 在当前目录会创建工程代码:

Creating service com.foo.srv.hello in hello
.
├── main.go
├── generate.go
├── plugin.go
├── handler
│   └── hello.go
├── subscriber
│   └── hello.go
├── proto/hello
│   └── hello.proto
├── Dockerfile
├── Makefile
├── README.md
├── .gitignore
└── go.mod
download protobuf for micro:
brew install protobuf
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-micro/v2
compile the proto file hello.proto:
cd hello
protoc --proto_path=.:$GOPATH/src --go_out=. --micro_out=. proto/hello/hello.proto

注意到一个Makefile文件生成了

8.2. 安装依赖

主要是安装protobuf

# install protobuf
brew install protobuf
# install protoc-gen-go
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
# install protoc-gen-micro
GO111MODULE=on go get -u github.com/micro/protoc-gen-micro/v2

protoc-gen-micro是protobuf的micro插件

注: protobuf项目的go版本现在转到: https://github.com/protocolbuffers/protobuf-go 之前是golang team维护的 https://github.com/golang/protobuf

8.3. 运行工程

首先要get go-micro go get github.com/micro/go-micro/v2@v2.4.0 这样go.mod会是

module hello
go 1.14
require github.com/micro/go-micro/v2 v2.4.0

运行 make build && ./hello-service 得到如下输出

make build && ./hello-serviceprotoc --proto_path=. --micro_out=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v2/api/proto:. --go_out=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v2/api/proto:. proto/hello/hello.protogo build -o hello-service *.go2020-04-02 11:12:47  level=info Starting [service] go.micro.service.hello
2020-04-02 11:12:47  level=info Server [grpc] Listening on [::]:53451
2020-04-02 11:12:47  level=info Broker [eats] Connected to [::]:53453
2020-04-02 11:12:47  level=info Registry [mdns] Registering node: go.micro.service.hello-063d6dae-826b-49f5-9141-df525af8a6b1
2020-04-02 11:12:47  level=info Subscribing to topic: go.micro.service.hello

这里make build会先用protoc编译.proto文件, 然后go build, 生成hello-service可执行程序.

results matching ""

    No results matching ""