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)
}
クライアントとサーバーが同じノードであるかどうかを確認します
rpc / context.go
func IsLocal(iface roachpb.InternalClient) bool {
_, ok := iface.(internalClientAdapter)
return ok // internalClientAdapter is used for local connections.
}
サーバー側で対応する関数を直接呼び出します。ネットワーク送信によるrpcの回避
func (a internalClientAdapter) Batch(
ctx context.Context, ba *roachpb.BatchRequest, _ ...grpc.CallOption,
) (*roachpb.BatchResponse, error) {
return a.InternalServer.Batch(ctx, ba)
}
InternalServerはノードクラスです
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()
}
つまり、クライアントとサーバーが同じノードの場合、gRPC呼び出しは使用されません。
Cockroach BatchRequestリクエストの
結論:
1)。gRpcを使用して要求を実行する場合、シリアル化と逆シリアル化は避けられません。
2)crdbは、クライアントとサーバーが同じノードであるというロジックを追加するため、gRPCは使用されず、node.goのBatchメソッドが直接呼び出されます。現時点では、pbのシリアル化と逆シリアル化はありません。
3)シリアル化と逆シリアル化にpbを使用すると、バイトタイプコーデックに対して2つのメモリコピー操作があるため、unsafe.Pointerポインタを使用してC層byte []をコピーするよりも多くのCPUリソースを消費します。