cockroach BatchRequest execution process

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)
}

Determine whether the client and server are the same node
rpc/context.go

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

Directly call the corresponding function on the Server side. Avoid rpc through network transmission

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

cockroach BatchRequest execution process
InternalServer is Node class

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()
}

That is, when the client and server are the same Node, gRPC calls are not used.

Cockroach BatchRequest request
conclusion:
1). If you use gRpc to execute the request, serialization and deserialization cannot be avoided. 
2). Since crdb adds the logic that the client and the server are the same node, gRPC is not used, and the Batch method in node.go is directly called. At this time, there is no serialization and deserialization of pb.

3). Using pb for serialization and deserialization, there are two memory copy operations for the bytes type codec, so it consumes more CPU resources than using unsafe.Pointer pointer to copy the C layer byte[].

Guess you like

Origin blog.51cto.com/1196740/2578072