chrislu
1 year ago
5 changed files with 157 additions and 5 deletions
-
5weed/mq/client/sub_client/subscribe.go
-
2weed/mq/client/sub_client/subscriber.go
-
92weed/mq/coordinator/consumer_group.go
-
36weed/mq/coordinator/coordinator.go
-
17weed/mq/topic/partition.go
@ -0,0 +1,92 @@ |
|||
package coordinator |
|||
|
|||
import ( |
|||
"github.com/seaweedfs/seaweedfs/weed/mq/topic" |
|||
"sync" |
|||
) |
|||
|
|||
func (cg *ConsumerGroup) SetMinMaxActiveInstances(min, max int32) { |
|||
cg.MinimumActiveInstances = min |
|||
cg.MaximumActiveInstances = max |
|||
} |
|||
|
|||
func (cg *ConsumerGroup) AddConsumerGroupInstance(clientId string) *ConsumerGroupInstance { |
|||
cgi := &ConsumerGroupInstance{ |
|||
ClientId: clientId, |
|||
} |
|||
cg.ConsumerGroupInstances.Set(clientId, cgi) |
|||
return cgi |
|||
} |
|||
|
|||
func (cg *ConsumerGroup) RemoveConsumerGroupInstance(clientId string) { |
|||
cg.ConsumerGroupInstances.Remove(clientId) |
|||
} |
|||
|
|||
func (cg *ConsumerGroup) CoordinateIfNeeded() { |
|||
emptyInstanceCount, activeInstanceCount := int32(0), int32(0) |
|||
for cgi := range cg.ConsumerGroupInstances.IterBuffered() { |
|||
if cgi.Val.Partition == nil { |
|||
// this consumer group instance is not assigned a partition
|
|||
// need to assign one
|
|||
emptyInstanceCount++ |
|||
} else { |
|||
activeInstanceCount++ |
|||
} |
|||
} |
|||
|
|||
var delta int32 |
|||
if emptyInstanceCount > 0 { |
|||
if cg.MinimumActiveInstances <= 0 { |
|||
// need to assign more partitions
|
|||
delta = emptyInstanceCount |
|||
} else if activeInstanceCount < cg.MinimumActiveInstances && activeInstanceCount+emptyInstanceCount >= cg.MinimumActiveInstances { |
|||
// need to assign more partitions
|
|||
delta = cg.MinimumActiveInstances - activeInstanceCount |
|||
} |
|||
} |
|||
|
|||
if cg.MaximumActiveInstances > 0 { |
|||
if activeInstanceCount > cg.MaximumActiveInstances { |
|||
// need to remove some partitions
|
|||
delta = cg.MaximumActiveInstances - activeInstanceCount |
|||
} |
|||
} |
|||
if delta == 0 { |
|||
return |
|||
} |
|||
cg.doCoordinate(activeInstanceCount + delta) |
|||
} |
|||
|
|||
func (cg *ConsumerGroup) doCoordinate(target int32) { |
|||
// stop existing instances from processing
|
|||
var wg sync.WaitGroup |
|||
for cgi := range cg.ConsumerGroupInstances.IterBuffered() { |
|||
if cgi.Val.Partition != nil { |
|||
wg.Add(1) |
|||
go func(cgi *ConsumerGroupInstance) { |
|||
defer wg.Done() |
|||
// stop processing
|
|||
// flush internal state
|
|||
// wait for all messages to be processed
|
|||
// close the connection
|
|||
}(cgi.Val) |
|||
} |
|||
} |
|||
wg.Wait() |
|||
|
|||
partitions := topic.SplitPartitions(target) |
|||
|
|||
// assign partitions to new instances
|
|||
i := 0 |
|||
for cgi := range cg.ConsumerGroupInstances.IterBuffered() { |
|||
cgi.Val.Partition = partitions[i] |
|||
i++ |
|||
wg.Add(1) |
|||
go func(cgi *ConsumerGroupInstance) { |
|||
defer wg.Done() |
|||
// start processing
|
|||
// start consuming from the last offset
|
|||
}(cgi.Val) |
|||
} |
|||
wg.Wait() |
|||
} |
@ -0,0 +1,36 @@ |
|||
package coordinator |
|||
|
|||
import ( |
|||
cmap "github.com/orcaman/concurrent-map/v2" |
|||
"github.com/seaweedfs/seaweedfs/weed/mq/topic" |
|||
) |
|||
|
|||
type ConsumerGroupInstance struct { |
|||
ClientId string |
|||
// the consumer group instance may not have an active partition
|
|||
Partition *topic.Partition |
|||
// processed message count
|
|||
ProcessedMessageCount int64 |
|||
} |
|||
type ConsumerGroup struct { |
|||
// map a client id to a consumer group instance
|
|||
ConsumerGroupInstances cmap.ConcurrentMap[string, *ConsumerGroupInstance] |
|||
MinimumActiveInstances int32 |
|||
MaximumActiveInstances int32 |
|||
} |
|||
type TopicConsumerGroups struct { |
|||
// map a consumer group name to a consumer group
|
|||
ConsumerGroups cmap.ConcurrentMap[string, *ConsumerGroup] |
|||
} |
|||
|
|||
// Coordinator coordinates the instances in the consumer group for one topic.
|
|||
// It is responsible for:
|
|||
// 1. Assigning partitions to consumer instances.
|
|||
// 2. Reassigning partitions when a consumer instance is down.
|
|||
// 3. Reassigning partitions when a consumer instance is up.
|
|||
type Coordinator struct { |
|||
// map client id to subscriber
|
|||
Subscribers cmap.ConcurrentMap[string, *ConsumerGroupInstance] |
|||
// map topic name to consumer groups
|
|||
TopicSubscribers cmap.ConcurrentMap[string, map[string]TopicConsumerGroups] |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue