mirror of
https://github.com/minio/minio.git
synced 2025-04-22 03:24:38 -04:00
resize replication worker pool dynamically after config update (#11737)
This commit is contained in:
parent
209fe61dcc
commit
2f29719e6b
@ -22,6 +22,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
minio "github.com/minio/minio-go/v7"
|
minio "github.com/minio/minio-go/v7"
|
||||||
@ -770,81 +771,102 @@ type DeletedObjectVersionInfo struct {
|
|||||||
DeletedObject
|
DeletedObject
|
||||||
Bucket string
|
Bucket string
|
||||||
}
|
}
|
||||||
type replicationState struct {
|
|
||||||
// add future metrics here
|
|
||||||
replicaCh chan ObjectInfo
|
|
||||||
replicaDeleteCh chan DeletedObjectVersionInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *replicationState) queueReplicaTask(oi ObjectInfo) {
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case r.replicaCh <- oi:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *replicationState) queueReplicaDeleteTask(doi DeletedObjectVersionInfo) {
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case r.replicaDeleteCh <- doi:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
globalReplicationState *replicationState
|
globalReplicationPool *ReplicationPool
|
||||||
)
|
)
|
||||||
|
|
||||||
func newReplicationState() *replicationState {
|
// ReplicationPool describes replication pool
|
||||||
rs := &replicationState{
|
type ReplicationPool struct {
|
||||||
replicaCh: make(chan ObjectInfo, 10000),
|
mu sync.Mutex
|
||||||
replicaDeleteCh: make(chan DeletedObjectVersionInfo, 10000),
|
size int
|
||||||
}
|
replicaCh chan ObjectInfo
|
||||||
go func() {
|
replicaDeleteCh chan DeletedObjectVersionInfo
|
||||||
<-GlobalContext.Done()
|
killCh chan struct{}
|
||||||
close(rs.replicaCh)
|
wg sync.WaitGroup
|
||||||
close(rs.replicaDeleteCh)
|
ctx context.Context
|
||||||
}()
|
objLayer ObjectLayer
|
||||||
return rs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// addWorker creates a new worker to process tasks
|
// NewReplicationPool creates a pool of replication workers of specified size
|
||||||
func (r *replicationState) addWorker(ctx context.Context, objectAPI ObjectLayer) {
|
func NewReplicationPool(ctx context.Context, o ObjectLayer, sz int) *ReplicationPool {
|
||||||
// Add a new worker.
|
pool := &ReplicationPool{
|
||||||
|
replicaCh: make(chan ObjectInfo, 10000),
|
||||||
|
replicaDeleteCh: make(chan DeletedObjectVersionInfo, 10000),
|
||||||
|
ctx: ctx,
|
||||||
|
objLayer: o,
|
||||||
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
<-ctx.Done()
|
||||||
select {
|
close(pool.replicaCh)
|
||||||
case <-ctx.Done():
|
close(pool.replicaDeleteCh)
|
||||||
return
|
|
||||||
case oi, ok := <-r.replicaCh:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
replicateObject(ctx, oi, objectAPI)
|
|
||||||
case doi, ok := <-r.replicaDeleteCh:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
replicateDelete(ctx, doi, objectAPI)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
pool.Resize(sz)
|
||||||
|
return pool
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWorker adds a replication worker to the pool
|
||||||
|
func (p *ReplicationPool) AddWorker() {
|
||||||
|
defer p.wg.Done()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-p.ctx.Done():
|
||||||
|
return
|
||||||
|
case oi, ok := <-p.replicaCh:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
replicateObject(p.ctx, oi, p.objLayer)
|
||||||
|
case doi, ok := <-p.replicaDeleteCh:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
replicateDelete(p.ctx, doi, p.objLayer)
|
||||||
|
case <-p.killCh:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resize replication pool to new size
|
||||||
|
func (p *ReplicationPool) Resize(n int) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
|
||||||
|
for p.size < n {
|
||||||
|
p.size++
|
||||||
|
p.wg.Add(1)
|
||||||
|
go p.AddWorker()
|
||||||
|
}
|
||||||
|
for p.size > n {
|
||||||
|
p.size--
|
||||||
|
go func() { p.killCh <- struct{}{} }()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReplicationPool) queueReplicaTask(oi ObjectInfo) {
|
||||||
|
if p == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case p.replicaCh <- oi:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReplicationPool) queueReplicaDeleteTask(doi DeletedObjectVersionInfo) {
|
||||||
|
if p == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case p.replicaDeleteCh <- doi:
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBackgroundReplication(ctx context.Context, objectAPI ObjectLayer) {
|
func initBackgroundReplication(ctx context.Context, objectAPI ObjectLayer) {
|
||||||
if globalReplicationState == nil {
|
globalReplicationPool = NewReplicationPool(ctx, objectAPI, globalAPIConfig.getReplicationWorkers())
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start replication workers per count set in api config or MINIO_API_REPLICATION_WORKERS.
|
|
||||||
for i := 0; i < globalAPIConfig.getReplicationWorkers(); i++ {
|
|
||||||
globalReplicationState.addWorker(ctx, objectAPI)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get Reader from replication target if active-active replication is in place and
|
// get Reader from replication target if active-active replication is in place and
|
||||||
@ -984,7 +1006,7 @@ func scheduleReplication(ctx context.Context, objInfo ObjectInfo, o ObjectLayer,
|
|||||||
if sync {
|
if sync {
|
||||||
replicateObject(ctx, objInfo, o)
|
replicateObject(ctx, objInfo, o)
|
||||||
} else {
|
} else {
|
||||||
globalReplicationState.queueReplicaTask(objInfo)
|
globalReplicationPool.queueReplicaTask(objInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -992,6 +1014,6 @@ func scheduleReplicationDelete(ctx context.Context, dv DeletedObjectVersionInfo,
|
|||||||
if sync {
|
if sync {
|
||||||
replicateDelete(ctx, dv, o)
|
replicateDelete(ctx, dv, o)
|
||||||
} else {
|
} else {
|
||||||
globalReplicationState.queueReplicaDeleteTask(dv)
|
globalReplicationPool.queueReplicaDeleteTask(dv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,6 @@ func init() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
globalReplicationState = newReplicationState()
|
|
||||||
globalTransitionState = newTransitionState()
|
globalTransitionState = newTransitionState()
|
||||||
|
|
||||||
console.SetColor("Debug", color.New())
|
console.SetColor("Debug", color.New())
|
||||||
|
@ -1076,10 +1076,10 @@ func (i *scannerItem) healReplication(ctx context.Context, o ObjectLayer, oi Obj
|
|||||||
switch oi.ReplicationStatus {
|
switch oi.ReplicationStatus {
|
||||||
case replication.Pending:
|
case replication.Pending:
|
||||||
sizeS.pendingSize += oi.Size
|
sizeS.pendingSize += oi.Size
|
||||||
globalReplicationState.queueReplicaTask(oi)
|
globalReplicationPool.queueReplicaTask(oi)
|
||||||
case replication.Failed:
|
case replication.Failed:
|
||||||
sizeS.failedSize += oi.Size
|
sizeS.failedSize += oi.Size
|
||||||
globalReplicationState.queueReplicaTask(oi)
|
globalReplicationPool.queueReplicaTask(oi)
|
||||||
case replication.Completed, "COMPLETE":
|
case replication.Completed, "COMPLETE":
|
||||||
sizeS.replicatedSize += oi.Size
|
sizeS.replicatedSize += oi.Size
|
||||||
case replication.Replica:
|
case replication.Replica:
|
||||||
@ -1098,7 +1098,7 @@ func (i *scannerItem) healReplicationDeletes(ctx context.Context, o ObjectLayer,
|
|||||||
} else {
|
} else {
|
||||||
versionID = oi.VersionID
|
versionID = oi.VersionID
|
||||||
}
|
}
|
||||||
globalReplicationState.queueReplicaDeleteTask(DeletedObjectVersionInfo{
|
globalReplicationPool.queueReplicaDeleteTask(DeletedObjectVersionInfo{
|
||||||
DeletedObject: DeletedObject{
|
DeletedObject: DeletedObject{
|
||||||
ObjectName: oi.Name,
|
ObjectName: oi.Name,
|
||||||
DeleteMarkerVersionID: dmVersionID,
|
DeleteMarkerVersionID: dmVersionID,
|
||||||
|
@ -80,6 +80,10 @@ func (t *apiConfig) init(cfg api.Config, setDriveCounts []int) {
|
|||||||
t.requestsDeadline = cfg.RequestsDeadline
|
t.requestsDeadline = cfg.RequestsDeadline
|
||||||
t.listQuorum = cfg.GetListQuorum()
|
t.listQuorum = cfg.GetListQuorum()
|
||||||
t.extendListLife = cfg.ExtendListLife
|
t.extendListLife = cfg.ExtendListLife
|
||||||
|
if globalReplicationPool != nil &&
|
||||||
|
cfg.ReplicationWorkers != t.replicationWorkers {
|
||||||
|
globalReplicationPool.Resize(cfg.ReplicationWorkers)
|
||||||
|
}
|
||||||
t.replicationWorkers = cfg.ReplicationWorkers
|
t.replicationWorkers = cfg.ReplicationWorkers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user