我的站点

一个系统软件工程师的随手涂鸦

Date: 八月 19, 2016

RPC和gRPC

关于RPC(Remote Procedure Call)的定义,可以参考这两篇文章:Remote procedure callRemote Procedure Call (RPC)。简单来讲,RPC指的就是一个进程(client)发起一个函数调用,但是实际用来执行这个函数调用是另一个进程(server)。这个函数调用会阻塞在那里,直到收到响应。Server进程可以与client进程可以位于同一台机器也可以是不同机器。Clientserver都有一个stub模块,clientstub负责发送request,并处理server返回的response;而serverstub则负责处理client发送的request,并返回response。 通常,我们使用Interface Description Language来定义RPC的消息格式。

gRPCgoogle实现的RPC,其默认使用protocol buffers,一个使用gRPC的例子如下(图出自Getting started):

grpc_concept_diagram_00

Go语言为例,搭建gPRC环境包括下列几步:

(1)安装gRPC runtime

go get google.golang.org/grpc

(2)安装protocol buffers支持(包含compilerruntime):从protocol buffers官网下载最新的源码包,解压缩:

./configure
make
make check
make install
ldconfig

(3)安装Go protoc plugin

go get -a github.com/golang/protobuf/protoc-gen-go

参考gRPC提供的例子,下载helloworld.proto文件,然后在当前目录执行“protoc --go_out=plugins=grpc:. *.proto”就会在当前目录下生成helloworld.pb.go文件。对于client来讲,发送request的函数已生成好,只需直接传入request内容以及option即可:

type GreeterClient interface {
    // Sends a greeting
    SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}

type greeterClient struct {
    cc *grpc.ClientConn
}

func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
    return &greeterClient{cc}
}

func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
    out := new(HelloReply)
    err := grpc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, c.cc, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
} 

对于server,定义好了interface,需要自己实现满足这个interface的结构体:

// Server API for Greeter service

type GreeterServer interface {
    // Sends a greeting
    SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

可以看出,SayHello()函数只要实现如何构造response即可,其它如何传输消息等等,均不用管。

为了熟悉这个流程,我自己做了一遍,代码在这里:https://github.com/NanXiao/helloworld

Swarmkit笔记(13)——swarmctl通过controlClient向swarm cluster发命令

swarmctl实质上是通过controlClientswarm cluster发命令。controlClient定义在api/control.pb.go

// Client API for Control service

type ControlClient interface {
    GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error)
    ListNodes(ctx context.Context, in *ListNodesRequest, opts ...grpc.CallOption) (*ListNodesResponse, error)
    ......
}

type controlClient struct {
    cc *grpc.ClientConn
}

func NewControlClient(cc *grpc.ClientConn) ControlClient {
    return &controlClient{cc}
}

func (c *controlClient) GetNode(ctx context.Context, in *GetNodeRequest, opts ...grpc.CallOption) (*GetNodeResponse, error) {
    out := new(GetNodeResponse)
    err := grpc.Invoke(ctx, "/docker.swarmkit.v1.Control/GetNode", in, out, c.cc, opts...)
    if err != nil {
        return nil, err
    }
    return out, nil
}

......

 

docker笔记(17)——为image,container和Docker daemon加label

可以通过为imagecontainerDocker daemonlabel的方式(key=value格式)来存储metadata:比如licensevendor等等:

(1)为imagelabel,在Dockerfile中使用LABEL指令(尽量把所有的label放在1LABEL指令中,因为每一个LABEL指令都会为image增加一层layer):

LABEL [<namespace>.]<key>=<value> ...

(2)为containerlabel

docker run \
   -d \
   --label com.example.group="webservers" \
   --label com.example.environment="production" \
   busybox \
   top

(3)为Docker daemonlabel

docker daemon \
  --dns 8.8.8.8 \
  --dns 8.8.4.4 \
  -H unix:///var/run/docker.sock \
  --label com.example.environment="production" \
  --label com.example.storage="ssd"

参考资料:
Apply custom metadata

 

FreeBSD kernel 笔记(9)——modeventtype_t定义

modeventtype_t定义如下:

typedef enum modeventtype {
    MOD_LOAD,
    MOD_UNLOAD,
    MOD_SHUTDOWN,
    MOD_QUIESCE
} modeventtype_t;
typedef int (*modeventhand_t)(module_t, int /* modeventtype_t */, void *);

MOD_LOADMOD_UNLOADMOD_SHUTDOWN都好理解。分别是在加载,卸载模块,还有关机时传入模块处理函数的值。而关于MOD_QUIESCE可以参考FreeBSD Device Drivers

When one issues the kldunload(8) command, MOD_QUIESCE is run before MOD_UNLOAD . If MOD_QUIESCE returns an error, MOD_UNLOAD does not get executed. In other words, MOD_QUIESCE verifies that it is safe to unload your module.

NOTE The kldunload -f command ignores every error returned by MOD_QUIESCE . So you can always unload a module, but it may not be the best idea.

另外,关于MOD_QUIESCEMOD_SHUTDOWN区别,也可参考FreeBSD Kernel Developer’s Manual

The difference between MOD_QUIESCE and MOD_UNLOAD is that the module should fail MOD_QUIESCE if it is currently in use, whereas MOD_UNLOAD should only fail if it is impossible to unload the module, for instance because there are memory references to the module which cannot be revoked.

Powered by WordPress & Theme by Anders Norén