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 }