github.com/polarismesh/polaris@v1.17.8/apiserver/eurekaserver/delta_worker.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package eurekaserver
    19  
    20  import (
    21  	"context"
    22  	"crypto/sha1"
    23  	"encoding/hex"
    24  	"sync"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	commontime "github.com/polarismesh/polaris/common/time"
    29  	"github.com/polarismesh/polaris/service"
    30  	"github.com/polarismesh/polaris/service/healthcheck"
    31  )
    32  
    33  func sha1s(bytes []byte) string {
    34  	r := sha1.Sum(bytes)
    35  	return hex.EncodeToString(r[:])
    36  }
    37  
    38  type Lease struct {
    39  	instance          *InstanceInfo
    40  	lastUpdateTimeSec int64
    41  }
    42  
    43  // Expired check lease expired
    44  func (l *Lease) Expired(curTimeSec int64, deltaExpireInterval time.Duration) bool {
    45  	return curTimeSec-l.lastUpdateTimeSec >= deltaExpireInterval.Milliseconds()/1000
    46  }
    47  
    48  type ApplicationsWorkers struct {
    49  	interval               time.Duration
    50  	deltaExpireInterval    time.Duration
    51  	enableSelfPreservation bool
    52  	namingServer           service.DiscoverServer
    53  	healthCheckServer      *healthcheck.Server
    54  	workers                map[string]*ApplicationsWorker
    55  	rwMutex                *sync.RWMutex
    56  }
    57  
    58  func NewApplicationsWorkers(interval time.Duration,
    59  	deltaExpireInterval time.Duration, enableSelfPreservation bool,
    60  	namingServer service.DiscoverServer, healthCheckServer *healthcheck.Server,
    61  	namespaces ...string) *ApplicationsWorkers {
    62  	workers := make(map[string]*ApplicationsWorker)
    63  	for _, namespace := range namespaces {
    64  		work := NewApplicationsWorker(interval, deltaExpireInterval, enableSelfPreservation,
    65  			namingServer, healthCheckServer, namespace)
    66  		workers[namespace] = work
    67  	}
    68  	return &ApplicationsWorkers{
    69  		interval:               interval,
    70  		deltaExpireInterval:    deltaExpireInterval,
    71  		enableSelfPreservation: enableSelfPreservation,
    72  		namingServer:           namingServer,
    73  		healthCheckServer:      healthCheckServer,
    74  		workers:                workers,
    75  		rwMutex:                &sync.RWMutex{},
    76  	}
    77  }
    78  
    79  func (a *ApplicationsWorkers) Get(namespace string) *ApplicationsWorker {
    80  	a.rwMutex.RLock()
    81  	work, exist := a.workers[namespace]
    82  	a.rwMutex.RUnlock()
    83  	if exist {
    84  		return work
    85  	}
    86  	a.rwMutex.Lock()
    87  	defer a.rwMutex.Unlock()
    88  
    89  	work, exist = a.workers[namespace]
    90  	if exist {
    91  		return work
    92  	}
    93  
    94  	work = NewApplicationsWorker(a.interval, a.deltaExpireInterval, a.enableSelfPreservation,
    95  		a.namingServer, a.healthCheckServer, namespace)
    96  	a.workers[namespace] = work
    97  	return work
    98  
    99  }
   100  
   101  func (a *ApplicationsWorkers) Stop() {
   102  	for _, v := range a.workers {
   103  		v.Stop()
   104  	}
   105  }
   106  
   107  // ApplicationsWorker 应用缓存协程
   108  type ApplicationsWorker struct {
   109  	mutex *sync.Mutex
   110  
   111  	started uint32
   112  
   113  	waitCtx context.Context
   114  
   115  	workerCancel context.CancelFunc
   116  
   117  	interval time.Duration
   118  
   119  	deltaExpireInterval time.Duration
   120  
   121  	unhealthyExpireInterval time.Duration
   122  	// 全量服务的缓存,数据结构为ApplicationsRespCache
   123  	appsCache *atomic.Value
   124  	// 增量数据缓存,数据结构为ApplicationsRespCache
   125  	deltaCache *atomic.Value
   126  	// vip缓存同步
   127  	vipCacheMutex *sync.RWMutex
   128  	// vip数据缓存,数据格式为VipCacheKey:ApplicationsRespCache
   129  	vipCache map[VipCacheKey]*ApplicationsRespCache
   130  
   131  	appBuilder *ApplicationsBuilder
   132  
   133  	healthCheckServer *healthcheck.Server
   134  
   135  	// 增量缓存
   136  	leases []*Lease
   137  }
   138  
   139  // NewApplicationsWorker 构造函数
   140  func NewApplicationsWorker(interval time.Duration,
   141  	deltaExpireInterval time.Duration, enableSelfPreservation bool,
   142  	namingServer service.DiscoverServer, healthCheckServer *healthcheck.Server, namespace string) *ApplicationsWorker {
   143  	appBuilder := &ApplicationsBuilder{
   144  		namingServer:           namingServer,
   145  		namespace:              namespace,
   146  		enableSelfPreservation: enableSelfPreservation,
   147  	}
   148  	return &ApplicationsWorker{
   149  		mutex:               &sync.Mutex{},
   150  		interval:            interval,
   151  		deltaExpireInterval: deltaExpireInterval,
   152  		appsCache:           &atomic.Value{},
   153  		deltaCache:          &atomic.Value{},
   154  		vipCacheMutex:       &sync.RWMutex{},
   155  		vipCache:            make(map[VipCacheKey]*ApplicationsRespCache),
   156  		healthCheckServer:   healthCheckServer,
   157  		appBuilder:          appBuilder,
   158  		leases:              make([]*Lease, 0),
   159  	}
   160  }
   161  
   162  // IsStarted 是否已经启动
   163  func (a *ApplicationsWorker) IsStarted() bool {
   164  	return atomic.LoadUint32(&a.started) > 0
   165  }
   166  
   167  // getCachedApps 从缓存获取全量服务数据
   168  func (a *ApplicationsWorker) getCachedApps() *ApplicationsRespCache {
   169  	appsValue := a.appsCache.Load()
   170  	if appsValue != nil {
   171  		return appsValue.(*ApplicationsRespCache)
   172  	}
   173  	return nil
   174  }
   175  
   176  func (a *ApplicationsWorker) cleanupExpiredLeases() {
   177  	curTimeSec := commontime.CurrentMillisecond() / 1000
   178  	var startIndex = -1
   179  	for i, lease := range a.leases {
   180  		if !lease.Expired(curTimeSec, a.deltaExpireInterval) {
   181  			startIndex = i
   182  			break
   183  		}
   184  		eurekalog.Infof("[Eureka]lease %s(%s) has expired, lastUpdateTime %d, curTimeSec %d",
   185  			lease.instance.InstanceId, lease.instance.ActionType, lease.lastUpdateTimeSec, curTimeSec)
   186  	}
   187  	if startIndex == -1 && len(a.leases) > 0 {
   188  		// all expired
   189  		a.leases = make([]*Lease, 0)
   190  	} else if startIndex > -1 {
   191  		a.leases = a.leases[startIndex:]
   192  	}
   193  }
   194  
   195  // GetCachedAppsWithLoad 从缓存中获取全量服务信息,如果不存在就读取
   196  func (a *ApplicationsWorker) GetCachedAppsWithLoad() *ApplicationsRespCache {
   197  	appsRespCache := a.getCachedApps()
   198  	if appsRespCache == nil {
   199  		ctx := a.StartWorker()
   200  		if ctx != nil {
   201  			<-ctx.Done()
   202  		}
   203  		appsRespCache = a.getCachedApps()
   204  	}
   205  	return appsRespCache
   206  }
   207  
   208  // GetDeltaApps 从缓存获取增量服务数据
   209  func (a *ApplicationsWorker) GetDeltaApps() *ApplicationsRespCache {
   210  	appsValue := a.deltaCache.Load()
   211  	if appsValue != nil {
   212  		return appsValue.(*ApplicationsRespCache)
   213  	}
   214  	return nil
   215  }
   216  
   217  // GetVipApps 从缓存中读取VIP资源
   218  func (a *ApplicationsWorker) GetVipApps(key VipCacheKey) *ApplicationsRespCache {
   219  	a.vipCacheMutex.RLock()
   220  	res, ok := a.vipCache[key]
   221  	a.vipCacheMutex.RUnlock()
   222  	if ok {
   223  		return res
   224  	}
   225  	cachedApps := a.GetCachedAppsWithLoad()
   226  	a.vipCacheMutex.Lock()
   227  	defer a.vipCacheMutex.Unlock()
   228  	res, ok = a.vipCache[key]
   229  	if ok {
   230  		return res
   231  	}
   232  	res = BuildApplicationsForVip(&key, cachedApps)
   233  	a.vipCache[key] = res
   234  	return res
   235  }
   236  
   237  func (a *ApplicationsWorker) timingReloadAppsCache(workerCtx context.Context) {
   238  	ticker := time.NewTicker(a.interval)
   239  	defer ticker.Stop()
   240  	for {
   241  		select {
   242  		case <-workerCtx.Done():
   243  			return
   244  		case <-ticker.C:
   245  			oldApps := a.getCachedApps()
   246  			newApps := a.appBuilder.BuildApplications(oldApps)
   247  			newDeltaApps := a.buildDeltaApps(oldApps, newApps)
   248  			a.appsCache.Store(newApps)
   249  			a.deltaCache.Store(newDeltaApps)
   250  			a.clearExpiredVipResources()
   251  		}
   252  	}
   253  }
   254  
   255  func (a *ApplicationsWorker) clearExpiredVipResources() {
   256  	expireIntervalSec := int64(a.interval / time.Second)
   257  	a.vipCacheMutex.Lock()
   258  	defer a.vipCacheMutex.Unlock()
   259  	for key, respCache := range a.vipCache {
   260  		curTimeSec := time.Now().Unix()
   261  		if curTimeSec-respCache.createTimeSec >= expireIntervalSec {
   262  			delete(a.vipCache, key)
   263  		}
   264  	}
   265  }
   266  
   267  func diffApplicationInstances(curTimeSec int64, oldApplication *Application, newApplication *Application) []*Lease {
   268  	var out []*Lease
   269  	oldRevision := oldApplication.Revision
   270  	newRevision := newApplication.Revision
   271  	if len(oldRevision) > 0 && len(newRevision) > 0 && oldRevision == newRevision {
   272  		// 完全相同,没有变更
   273  		return out
   274  	}
   275  	// 获取新增和修改
   276  	newInstances := newApplication.Instance
   277  	if len(newInstances) > 0 {
   278  		for _, instance := range newInstances {
   279  			oldInstance := oldApplication.GetInstance(instance.InstanceId)
   280  			if oldInstance == nil {
   281  				// 新增实例
   282  				out = addLease(out, &Lease{instance: instance.Clone(ActionAdded), lastUpdateTimeSec: curTimeSec})
   283  				continue
   284  			}
   285  			// 比较实际的实例是否发生了变更
   286  			if oldInstance.Equals(instance) {
   287  				continue
   288  			}
   289  			// 新创建一个instance
   290  			out = addLease(out, &Lease{instance: instance.Clone(ActionModified), lastUpdateTimeSec: curTimeSec})
   291  		}
   292  	}
   293  	// 获取删除
   294  	oldInstances := oldApplication.Instance
   295  	if len(oldInstances) > 0 {
   296  		for _, instance := range oldInstances {
   297  			newInstance := newApplication.GetInstance(instance.InstanceId)
   298  			if newInstance == nil {
   299  				// 被删除了
   300  				out = addLease(out, &Lease{instance: instance.Clone(ActionDeleted), lastUpdateTimeSec: curTimeSec})
   301  			}
   302  		}
   303  	}
   304  	return out
   305  }
   306  
   307  func addLease(out []*Lease, lease *Lease) []*Lease {
   308  	eurekalog.Infof("[EUREKA] add delta instance %s(%s)", lease.instance.InstanceId, lease.instance.ActionType)
   309  	out = append(out, lease)
   310  	return out
   311  }
   312  
   313  func calculateDeltaInstances(oldAppsCache *ApplicationsRespCache, newAppsCache *ApplicationsRespCache) []*Lease {
   314  	var out []*Lease
   315  	newApps := newAppsCache.AppsResp.Applications
   316  	curTimeSec := commontime.CurrentMillisecond() / 1000
   317  	// 1. 处理服务新增场景
   318  	if nil == oldAppsCache {
   319  		applications := newApps.Application
   320  		for _, app := range applications {
   321  			for _, instance := range app.Instance {
   322  				out = addLease(out, &Lease{instance: instance.Clone(ActionAdded), lastUpdateTimeSec: curTimeSec})
   323  			}
   324  		}
   325  		return out
   326  	}
   327  	// 2. 处理服务变更场景
   328  	if oldAppsCache.Revision != newAppsCache.Revision {
   329  		oldApps := oldAppsCache.AppsResp.Applications
   330  		applications := newApps.Application
   331  		for _, application := range applications {
   332  			var oldApplication = oldApps.GetApplication(application.Name)
   333  			if oldApplication == nil {
   334  				// 新增,全部加入
   335  				for _, instance := range application.Instance {
   336  					out = addLease(out, &Lease{instance: instance.Clone(ActionAdded), lastUpdateTimeSec: curTimeSec})
   337  				}
   338  				continue
   339  			}
   340  			// 修改,需要比较实例的变更
   341  			leases := diffApplicationInstances(curTimeSec, oldApplication, application)
   342  			if len(leases) > 0 {
   343  				out = append(out, leases...)
   344  			}
   345  		}
   346  		// 3. 处理服务删除场景
   347  		oldApplications := oldApps.Application
   348  		if len(oldApplications) > 0 {
   349  			for _, application := range oldApplications {
   350  				var newApplication = newApps.GetApplication(application.Name)
   351  				if newApplication == nil {
   352  					// 删除
   353  					for _, instance := range application.Instance {
   354  						out = addLease(out, &Lease{instance: instance.Clone(ActionDeleted), lastUpdateTimeSec: curTimeSec})
   355  					}
   356  				}
   357  			}
   358  		}
   359  	}
   360  	return out
   361  }
   362  
   363  func (a *ApplicationsWorker) buildDeltaApps(
   364  	oldAppsCache *ApplicationsRespCache, newAppsCache *ApplicationsRespCache) *ApplicationsRespCache {
   365  	// 1. 清理过期的增量缓存
   366  	a.cleanupExpiredLeases()
   367  	// 2. 构建新增的增量缓存
   368  	leases := calculateDeltaInstances(oldAppsCache, newAppsCache)
   369  	a.leases = append(a.leases, leases...)
   370  	// 3. 创建新的delta对象
   371  	var instCount int
   372  	newApps := newAppsCache.AppsResp.Applications
   373  	newDeltaApps := &Applications{
   374  		VersionsDelta:  newApps.VersionsDelta,
   375  		AppsHashCode:   newApps.AppsHashCode,
   376  		Application:    make([]*Application, 0),
   377  		ApplicationMap: make(map[string]*Application, 0),
   378  	}
   379  	// 4. 拷贝lease对象
   380  	for _, lease := range a.leases {
   381  		instance := lease.instance
   382  		appName := instance.AppName
   383  		var app *Application
   384  		var ok bool
   385  		if app, ok = newDeltaApps.ApplicationMap[appName]; !ok {
   386  			app = &Application{
   387  				Name: appName,
   388  			}
   389  			newDeltaApps.Application = append(newDeltaApps.Application, app)
   390  			newDeltaApps.ApplicationMap[appName] = app
   391  		}
   392  		app.Instance = append(app.Instance, instance)
   393  		instCount++
   394  	}
   395  	return constructResponseCache(newDeltaApps, instCount, true)
   396  }
   397  
   398  // StartWorker 启动缓存构建器
   399  func (a *ApplicationsWorker) StartWorker() context.Context {
   400  	if a.getCachedApps() != nil {
   401  		return nil
   402  	}
   403  	a.mutex.Lock()
   404  	defer a.mutex.Unlock()
   405  	if !atomic.CompareAndSwapUint32(&a.started, 0, 1) {
   406  		return a.waitCtx
   407  	}
   408  	var waitCancel context.CancelFunc
   409  	// 进行首次缓存构建
   410  	a.waitCtx, waitCancel = context.WithCancel(context.Background())
   411  	defer waitCancel()
   412  	apps := a.appBuilder.BuildApplications(nil)
   413  	a.appsCache.Store(apps)
   414  	a.deltaCache.Store(a.buildDeltaApps(nil, apps))
   415  	// 开启定时任务构建
   416  	var workerCtx context.Context
   417  	workerCtx, a.workerCancel = context.WithCancel(context.Background())
   418  	go a.timingReloadAppsCache(workerCtx)
   419  	return nil
   420  }
   421  
   422  // Stop 结束任务
   423  func (a *ApplicationsWorker) Stop() {
   424  	a.mutex.Lock()
   425  	defer a.mutex.Unlock()
   426  	if atomic.CompareAndSwapUint32(&a.started, 1, 0) {
   427  		a.workerCancel()
   428  	}
   429  }