milvus/internal/util/streamingutil/service/discoverer/channel_assignment_discoverer.go
chyezh fda720b880
enhance: streaming service grpc utilities (#34436)
issue: #33285

- add two grpc resolver (by session and by streaming coord assignment
service)
- add one grpc balancer (by serverID and roundrobin)
- add lazy conn to avoid block by first service discovery
- add some utility function for streaming service

Signed-off-by: chyezh <chyezh@outlook.com>
2024-07-15 20:49:38 +08:00

85 lines
3.0 KiB
Go

package discoverer
import (
"context"
"go.uber.org/zap"
"google.golang.org/grpc/resolver"
"github.com/milvus-io/milvus/internal/util/streamingutil/service/attributes"
"github.com/milvus-io/milvus/pkg/log"
"github.com/milvus-io/milvus/pkg/streaming/util/types"
"github.com/milvus-io/milvus/pkg/util/typeutil"
)
// NewChannelAssignmentDiscoverer returns a new Discoverer for the channel assignment registration.
func NewChannelAssignmentDiscoverer(logCoordManager types.AssignmentDiscoverWatcher) Discoverer {
return &channelAssignmentDiscoverer{
assignmentWatcher: logCoordManager,
lastDiscovery: nil,
}
}
// channelAssignmentDiscoverer is the discoverer for channel assignment.
type channelAssignmentDiscoverer struct {
assignmentWatcher types.AssignmentDiscoverWatcher // last discovered state and last version discovery.
lastDiscovery *types.VersionedStreamingNodeAssignments
}
// NewVersionedState returns a lowest versioned state.
func (d *channelAssignmentDiscoverer) NewVersionedState() VersionedState {
return VersionedState{
Version: typeutil.VersionInt64Pair{Global: -1, Local: -1},
State: resolver.State{},
}
}
// channelAssignmentDiscoverer implements the resolver.Discoverer interface.
func (d *channelAssignmentDiscoverer) Discover(ctx context.Context, cb func(VersionedState) error) error {
// Always send the current state first.
// Outside logic may lost the last state before retry Discover function.
if err := cb(d.parseState()); err != nil {
return err
}
return d.assignmentWatcher.AssignmentDiscover(ctx, func(assignments *types.VersionedStreamingNodeAssignments) error {
d.lastDiscovery = assignments
return cb(d.parseState())
})
}
// parseState parses the addresses from the discovery response.
// Always perform a copy here.
func (d *channelAssignmentDiscoverer) parseState() VersionedState {
if d.lastDiscovery == nil {
return d.NewVersionedState()
}
addrs := make([]resolver.Address, 0, len(d.lastDiscovery.Assignments))
for _, assignment := range d.lastDiscovery.Assignments {
assignment := assignment
addrs = append(addrs, resolver.Address{
Addr: assignment.NodeInfo.Address,
BalancerAttributes: attributes.WithChannelAssignmentInfo(new(attributes.Attributes), &assignment),
})
}
// TODO: service config should be sent by resolver in future to achieve dynamic configuration for grpc.
return VersionedState{
Version: d.lastDiscovery.Version,
State: resolver.State{Addresses: addrs},
}
}
// ChannelAssignmentInfo returns the channel assignment info from the resolver state.
func (s *VersionedState) ChannelAssignmentInfo() map[int64]types.StreamingNodeAssignment {
assignments := make(map[int64]types.StreamingNodeAssignment)
for _, v := range s.State.Addresses {
assignment := attributes.GetChannelAssignmentInfoFromAttributes(v.BalancerAttributes)
if assignment == nil {
log.Error("no assignment found in resolver state, skip it", zap.String("address", v.Addr))
continue
}
assignments[assignment.NodeInfo.ServerID] = *assignment
}
return assignments
}