cockroach BatchRequest执行流程

dist_sender.go

func (ds *DistSender) sendToReplicas(
    ctx context.Context,
    ba roachpb.BatchRequest,
    opts SendOptions,
    rangeID roachpb.RangeID,
    replicas ReplicaSlice,
    nodeDialer *nodedialer.Dialer,
    cachedLeaseHolder roachpb.ReplicaDescriptor,
    withCommit bool,
) (*roachpb.BatchResponse, error) {
    ...
    br, err := transport.SendNext(ctx, ba)
    ...
}

kv/transport.go

// SendNext invokes the specified RPC on the supplied client when the
// client is ready. On success, the reply is sent on the channel;
// otherwise an error is sent.
func (gt *grpcTransport) SendNext(
    ctx context.Context, ba roachpb.BatchRequest,
) (*roachpb.BatchResponse, error) {
  ...
    client := gt.orderedClients[gt.clientIndex]
    ctx, iface, err := gt.NextInternalClient(ctx)
    ...
    reply, err := gt.sendBatch(ctx, client.replica.NodeID, iface, ba)
    ...
}

rpc/context.go

func (a internalClientAdapter) Batch(
    ctx context.Context, ba *roachpb.BatchRequest, _ ...grpc.CallOption,
) (*roachpb.BatchResponse, error) {
    return a.InternalServer.Batch(ctx, ba)
}

server/node.go

func (n *Node) Batch(
    ctx context.Context, args *roachpb.BatchRequest,
) (*roachpb.BatchResponse, error) {
  ...
    br, err := n.batchInternal(ctx, args)
  ...
}

func (n *Node) batchInternal(
    ctx context.Context, args *roachpb.BatchRequest,
) (*roachpb.BatchResponse, error) {
    ...
      br, pErr = n.stores.Send(ctx, *args)
    ...
}

storage/stores.go

func (ls *Stores) Send(
    ctx context.Context, ba roachpb.BatchRequest,
) (*roachpb.BatchResponse, *roachpb.Error) {
    ...
    store, err := ls.GetStore(ba.Replica.StoreID)
    ...
    br, pErr := store.Send(ctx, ba)
    ...
}

storage/store.go

func (s *Store) Send(
    ctx context.Context, ba roachpb.BatchRequest,
) (br *roachpb.BatchResponse, pErr *roachpb.Error) {
 ...
 br, pErr = repl.Send(ctx, ba)
 ...
}

storage/replica.go

func (r *Replica) Send(
    ctx context.Context, ba roachpb.BatchRequest,
) (*roachpb.BatchResponse, *roachpb.Error) {
    return r.sendWithRangeID(ctx, r.RangeID, &ba)
}

判断客户端与Server端是否为同一个节点
rpc/context.go

func IsLocal(iface roachpb.InternalClient) bool {
    _, ok := iface.(internalClientAdapter)
    return ok // internalClientAdapter is used for local connections.
}

直接调用Server端的对应函数.避免rpc走网络传输

func (a internalClientAdapter) Batch(
    ctx context.Context, ba *roachpb.BatchRequest, _ ...grpc.CallOption,
) (*roachpb.BatchResponse, error) {
    return a.InternalServer.Batch(ctx, ba)
}

cockroach BatchRequest执行流程
InternalServer即Node类

context.go

// SetLocalInternalServer sets the context's local internal batch server.
func (ctx *Context) SetLocalInternalServer(internalServer roachpb.InternalServer) {
    ctx.localInternalClient = internalClientAdapter{internalServer}
}

server.go

func (s *Server) Start(ctx context.Context) error {
    ...
    s.rpcContext.SetLocalInternalServer(s.node)
    ...
}

dist_sender.go

ds.transportFactory = GRPCTransportFactory

transport_regular.go

// GRPCTransportFactory is the default TransportFactory, using GRPC.
func GRPCTransportFactory(
    opts SendOptions, nodeDialer *nodedialer.Dialer, replicas ReplicaSlice,
) (Transport, error) {
    return grpcTransportFactoryImpl(opts, nodeDialer, replicas)
}

transport.go

func grpcTransportFactoryImpl(
    opts SendOptions, nodeDialer *nodedialer.Dialer, replicas ReplicaSlice,
) (Transport, error) {
clients := make([]batchClient, 0, len(replicas))
    for _, replica := range replicas {
        healthy := nodeDialer.ConnHealth(replica.NodeID) == nil    // 核心代码
        clients = append(clients, batchClient{ 
            replica: replica.ReplicaDescriptor,
            healthy: healthy,
        })
    }
}

node_dialer.go

func (n *Dialer) ConnHealth(nodeID roachpb.NodeID) error {
    if n == nil || n.resolver == nil {
        return errors.New("no node dialer configured")
    }
    if !n.getBreaker(nodeID).Ready() {
        return circuit.ErrBreakerOpen
    }
    addr, err := n.resolver(nodeID)
    if err != nil {
        return err
    }
    // TODO(bdarnell): GRPCDial should detect local addresses and return
    // a dummy connection instead of requiring callers to do this check.
    if n.rpcContext.GetLocalInternalClientForAddr(addr.String()) != nil {  // 核心代码,本地
        // The local client is always considered healthy.
        return nil
    }
    conn := n.rpcContext.GRPCDial(addr.String())
    return conn.Health()
}

即客户端与Server端是同一个Node时,不走gRPC调用.

cockroach BatchRequest请求
结论:
1).如果使用gRpc执行请求,无法避免序列化和反序列化. 
2). 由于crdb增加了客户端与Server是同一节点的逻辑,不使用gRPC,直接调用node.go中的Batch方法,此时不存在pb的序列化和反序列化.

3). 采用pb进行序列化与反序列化,对于bytes类型编解码存在两次内存复制的操作,因此与使用unsafe.Pointer指针复制C层byte[]相比,更消耗CPU资源.

猜你喜欢

转载自blog.51cto.com/1196740/2578072