github.com/polarismesh/polaris@v1.17.8/cache/service/service.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 service
    19  
    20  import (
    21  	"context"
    22  	"crypto/sha1"
    23  	"sort"
    24  	"strconv"
    25  	"strings"
    26  	"sync"
    27  	"time"
    28  
    29  	"go.uber.org/zap"
    30  	"golang.org/x/sync/singleflight"
    31  
    32  	types "github.com/polarismesh/polaris/cache/api"
    33  	"github.com/polarismesh/polaris/common/model"
    34  	"github.com/polarismesh/polaris/common/utils"
    35  	"github.com/polarismesh/polaris/store"
    36  )
    37  
    38  // serviceCache Service data cache implementation class
    39  type serviceCache struct {
    40  	*types.BaseCache
    41  
    42  	storage store.Store
    43  	// service_id -> service
    44  	ids *utils.SyncMap[string, *model.Service]
    45  	// namespace -> [serviceName -> service]
    46  	names *utils.SyncMap[string, *utils.SyncMap[string, *model.Service]]
    47  	// 兼容Cl5,sid -> name
    48  	cl5Sid2Name *utils.SyncMap[string, string]
    49  	// 兼容Cl5,name -> service
    50  	cl5Names        *utils.SyncMap[string, *model.Service]
    51  	alias           *serviceAliasBucket
    52  	serviceList     *serviceNamespaceBucket
    53  	disableBusiness bool
    54  	needMeta        bool
    55  	singleFlight    *singleflight.Group
    56  	instCache       types.InstanceCache
    57  
    58  	plock sync.RWMutex
    59  	// service-id -> struct{}{}
    60  	pendingServices *utils.SyncMap[string, struct{}]
    61  	countLock       sync.Mutex
    62  	// namespace -> model.NamespaceServiceCount
    63  	namespaceServiceCnt *utils.SyncMap[string, *model.NamespaceServiceCount]
    64  
    65  	lastMtimeLogged int64
    66  
    67  	serviceCount     int64
    68  	lastCheckAllTime int64
    69  
    70  	revisionWorker *ServiceRevisionWorker
    71  
    72  	cancel context.CancelFunc
    73  }
    74  
    75  // NewServiceCache 返回一个serviceCache
    76  func NewServiceCache(storage store.Store, cacheMgr types.CacheManager) types.ServiceCache {
    77  	return &serviceCache{
    78  		BaseCache:   types.NewBaseCache(storage, cacheMgr),
    79  		storage:     storage,
    80  		alias:       newServiceAliasBucket(),
    81  		serviceList: newServiceNamespaceBucket(),
    82  	}
    83  }
    84  
    85  // initialize 缓存对象初始化
    86  func (sc *serviceCache) Initialize(opt map[string]interface{}) error {
    87  	sc.instCache = sc.BaseCache.CacheMgr.GetCacher(types.CacheInstance).(*instanceCache)
    88  	sc.singleFlight = new(singleflight.Group)
    89  	sc.ids = utils.NewSyncMap[string, *model.Service]()
    90  	sc.names = utils.NewSyncMap[string, *utils.SyncMap[string, *model.Service]]()
    91  	sc.cl5Sid2Name = utils.NewSyncMap[string, string]()
    92  	sc.cl5Names = utils.NewSyncMap[string, *model.Service]()
    93  	sc.pendingServices = utils.NewSyncMap[string, struct{}]()
    94  	sc.namespaceServiceCnt = utils.NewSyncMap[string, *model.NamespaceServiceCount]()
    95  	sc.revisionWorker = newRevisionWorker(sc, sc.instCache.(*instanceCache))
    96  
    97  	ctx, cancel := context.WithCancel(context.Background())
    98  	sc.cancel = cancel
    99  	// 先启动revision计算协程
   100  	go sc.revisionWorker.revisionWorker(ctx)
   101  	if opt == nil {
   102  		return nil
   103  	}
   104  	sc.disableBusiness, _ = opt["disableBusiness"].(bool)
   105  	sc.needMeta, _ = opt["needMeta"].(bool)
   106  	return nil
   107  }
   108  
   109  // LastMtime 最后一次更新时间
   110  func (sc *serviceCache) Close() error {
   111  	if err := sc.BaseCache.Close(); err != nil {
   112  		return err
   113  	}
   114  	if sc.cancel != nil {
   115  		sc.cancel()
   116  	}
   117  	return nil
   118  }
   119  
   120  // LastMtime 最后一次更新时间
   121  func (sc *serviceCache) LastMtime() time.Time {
   122  	return sc.BaseCache.LastMtime(sc.Name())
   123  }
   124  
   125  // update Service缓存更新函数
   126  // service + service_metadata作为一个整体获取
   127  func (sc *serviceCache) Update() error {
   128  	// 多个线程竞争,只有一个线程进行更新
   129  	_, err, _ := sc.singleFlight.Do(sc.Name(), func() (interface{}, error) {
   130  		defer func() {
   131  			sc.lastMtimeLogged = types.LogLastMtime(sc.lastMtimeLogged, sc.LastMtime().Unix(), "Service")
   132  			sc.checkAll()
   133  		}()
   134  		return nil, sc.DoCacheUpdate(sc.Name(), sc.realUpdate)
   135  	})
   136  	return err
   137  }
   138  
   139  func (sc *serviceCache) checkAll() {
   140  	curTimeSec := time.Now().Unix()
   141  	if curTimeSec-sc.lastCheckAllTime < checkAllIntervalSec {
   142  		return
   143  	}
   144  	defer func() {
   145  		sc.lastCheckAllTime = curTimeSec
   146  	}()
   147  	count, err := sc.storage.GetServicesCount()
   148  	if err != nil {
   149  		log.Errorf("[Cache][Service] get service count from storage err: %s", err.Error())
   150  		return
   151  	}
   152  	if sc.serviceCount == int64(count) {
   153  		return
   154  	}
   155  	log.Infof(
   156  		"[Cache][Service] service count not match, expect %d, actual %d, fallback to load all",
   157  		count, sc.serviceCount)
   158  	sc.ResetLastMtime(sc.Name())
   159  }
   160  
   161  func (sc *serviceCache) realUpdate() (map[string]time.Time, int64, error) {
   162  	// 获取几秒前的全部数据
   163  	start := time.Now()
   164  	services, err := sc.storage.GetMoreServices(sc.LastFetchTime(), sc.IsFirstUpdate(), sc.disableBusiness, sc.needMeta)
   165  	if err != nil {
   166  		log.Errorf("[Cache][Service] update services err: %s", err.Error())
   167  		return nil, -1, err
   168  	}
   169  
   170  	lastMtimes, update, del := sc.setServices(services)
   171  	costTime := time.Since(start)
   172  	log.Info("[Cache][Service] get more services", zap.Int("update", update), zap.Int("delete", del),
   173  		zap.Time("last", sc.LastMtime()), zap.Duration("used", costTime))
   174  	return lastMtimes, int64(len(services)), err
   175  }
   176  
   177  // clear 清理内部缓存数据
   178  func (sc *serviceCache) Clear() error {
   179  	sc.BaseCache.Clear()
   180  	sc.ids = utils.NewSyncMap[string, *model.Service]()
   181  	sc.names = utils.NewSyncMap[string, *utils.SyncMap[string, *model.Service]]()
   182  	sc.cl5Sid2Name = utils.NewSyncMap[string, string]()
   183  	sc.cl5Names = utils.NewSyncMap[string, *model.Service]()
   184  	sc.pendingServices = utils.NewSyncMap[string, struct{}]()
   185  	sc.namespaceServiceCnt = utils.NewSyncMap[string, *model.NamespaceServiceCount]()
   186  	sc.alias = newServiceAliasBucket()
   187  	sc.serviceList = newServiceNamespaceBucket()
   188  	return nil
   189  }
   190  
   191  // name 获取资源名称
   192  func (sc *serviceCache) Name() string {
   193  	return types.ServiceName
   194  }
   195  
   196  func (sc *serviceCache) GetAliasFor(name string, namespace string) *model.Service {
   197  	svc := sc.GetServiceByName(name, namespace)
   198  	if svc == nil {
   199  		return nil
   200  	}
   201  	if svc.Reference == "" {
   202  		return nil
   203  	}
   204  	return sc.GetServiceByID(svc.Reference)
   205  }
   206  
   207  // GetServiceByID 根据服务ID获取服务数据
   208  func (sc *serviceCache) GetServiceByID(id string) *model.Service {
   209  	if id == "" {
   210  		return nil
   211  	}
   212  	svc, ok := sc.ids.Load(id)
   213  	if !ok {
   214  		return nil
   215  	}
   216  	sc.fillServicePorts(svc)
   217  	return svc
   218  }
   219  
   220  // GetOrLoadServiceByID 先从缓存获取服务,如果没有的话,再从存储层获取,并设置到 Cache 中
   221  func (sc *serviceCache) GetOrLoadServiceByID(id string) *model.Service {
   222  	if id == "" {
   223  		return nil
   224  	}
   225  	value, ok := sc.ids.Load(id)
   226  	if !ok {
   227  		_, _, _ = sc.singleFlight.Do(id, func() (interface{}, error) {
   228  			svc, err := sc.storage.GetServiceByID(id)
   229  			if err == nil && svc != nil {
   230  				sc.ids.Store(svc.ID, svc)
   231  			}
   232  			return svc, err
   233  		})
   234  
   235  		value, ok = sc.ids.Load(id)
   236  		if !ok {
   237  			return nil
   238  		}
   239  	}
   240  	svc := value
   241  	sc.fillServicePorts(svc)
   242  	return svc
   243  }
   244  
   245  // GetServiceByName 根据服务名获取服务数据
   246  func (sc *serviceCache) GetServiceByName(name string, namespace string) *model.Service {
   247  	if name == "" || namespace == "" {
   248  		return nil
   249  	}
   250  
   251  	spaces, ok := sc.names.Load(namespace)
   252  	if !ok {
   253  		return nil
   254  	}
   255  	value, ok := spaces.Load(name)
   256  	if !ok {
   257  		return nil
   258  	}
   259  	svc := value
   260  	sc.fillServicePorts(svc)
   261  	return svc
   262  }
   263  
   264  func (sc *serviceCache) fillServicePorts(svc *model.Service) {
   265  	if svc.Ports != "" {
   266  		return
   267  	}
   268  	if sc.instCache == nil {
   269  		return
   270  	}
   271  	ports := sc.instCache.GetServicePorts(svc.ID)
   272  	if len(ports) == 0 {
   273  		return
   274  	}
   275  	item := make([]string, 0, len(ports))
   276  	for i := range ports {
   277  		item = append(item, strconv.FormatUint(uint64(ports[i].Port), 10))
   278  	}
   279  	svc.ServicePorts = ports
   280  	svc.Ports = strings.Join(item, ",")
   281  }
   282  
   283  // CleanNamespace 清除Namespace对应的服务缓存
   284  func (sc *serviceCache) CleanNamespace(namespace string) {
   285  	sc.names.Delete(namespace)
   286  }
   287  
   288  // IteratorServices 对缓存中的服务进行迭代
   289  func (sc *serviceCache) IteratorServices(iterProc types.ServiceIterProc) error {
   290  	var (
   291  		cont bool
   292  		err  error
   293  	)
   294  
   295  	proc := func(k string, svc *model.Service) bool {
   296  		sc.fillServicePorts(svc)
   297  		cont, err = iterProc(k, svc)
   298  		if err != nil {
   299  			return false
   300  		}
   301  		return cont
   302  	}
   303  	sc.ids.Range(proc)
   304  	return err
   305  }
   306  
   307  // GetNamespaceCntInfo Return to the service statistics according to the namespace,
   308  //
   309  //	the count statistics and health instance statistics
   310  func (sc *serviceCache) GetNamespaceCntInfo(namespace string) model.NamespaceServiceCount {
   311  	val, _ := sc.namespaceServiceCnt.Load(namespace)
   312  	if val == nil {
   313  		return model.NamespaceServiceCount{
   314  			InstanceCnt: &model.InstanceCount{},
   315  		}
   316  	}
   317  
   318  	return *val
   319  }
   320  
   321  // GetServicesCount 获取缓存中服务的个数
   322  func (sc *serviceCache) GetServicesCount() int {
   323  	count := 0
   324  	sc.ids.Range(func(key string, value *model.Service) bool {
   325  		count++
   326  		return true
   327  	})
   328  
   329  	return count
   330  }
   331  
   332  // ListServices get service list and revision by namespace
   333  func (sc *serviceCache) ListServices(ns string) (string, []*model.Service) {
   334  	return sc.serviceList.ListServices(ns)
   335  }
   336  
   337  // ListAllServices get all service and revision
   338  func (sc *serviceCache) ListAllServices() (string, []*model.Service) {
   339  	return sc.serviceList.ListAllServices()
   340  }
   341  
   342  // ListServiceAlias get all service alias by target service
   343  func (sc *serviceCache) ListServiceAlias(namespace, name string) []*model.Service {
   344  	return sc.alias.getServiceAliases(&model.Service{
   345  		Namespace: namespace,
   346  		Name:      name,
   347  	})
   348  }
   349  
   350  // GetServiceByCl5Name obtains the corresponding SID according to cl5Name
   351  func (sc *serviceCache) GetServiceByCl5Name(cl5Name string) *model.Service {
   352  	value, ok := sc.cl5Names.Load(genCl5Name(cl5Name))
   353  	if !ok {
   354  		return nil
   355  	}
   356  
   357  	return value
   358  }
   359  
   360  // removeServices Delete the service data from the cache
   361  func (sc *serviceCache) removeServices(service *model.Service) {
   362  	// Delete the index of serviceid
   363  	sc.ids.Delete(service.ID)
   364  	// delete service item from name list
   365  	sc.serviceList.removeService(service)
   366  	// delete service all link alias info
   367  	sc.alias.cleanServiceAlias(service)
   368  	// delete pending count service task
   369  	sc.pendingServices.Delete(service.ID)
   370  
   371  	// Delete the index of servicename
   372  	spaceName := service.Namespace
   373  	if spaces, ok := sc.names.Load(spaceName); ok {
   374  		spaces.Delete(service.Name)
   375  	}
   376  
   377  	/******Compatible CL5******/
   378  	if cl5Name, ok := sc.cl5Sid2Name.Load(service.Name); ok {
   379  		sc.cl5Sid2Name.Delete(service.Name)
   380  		sc.cl5Names.Delete(cl5Name)
   381  	}
   382  	/******Compatible CL5******/
   383  }
   384  
   385  // setServices 服务缓存更新
   386  // 返回:更新数量,删除数量
   387  func (sc *serviceCache) setServices(services map[string]*model.Service) (map[string]time.Time, int, int) {
   388  	if len(services) == 0 {
   389  		return nil, 0, 0
   390  	}
   391  
   392  	lastMtime := sc.LastMtime().Unix()
   393  
   394  	progress := 0
   395  	update := 0
   396  	del := 0
   397  
   398  	// 这里要记录 ns 的变动情况,避免由于 svc delete 之后,命名空间的服务计数无法更新
   399  	changeNs := make(map[string]struct{})
   400  	svcCount := sc.serviceCount
   401  
   402  	aliases := make([]*model.Service, 0, 32)
   403  
   404  	for _, service := range services {
   405  		progress++
   406  		if progress%20000 == 0 {
   407  			log.Infof(
   408  				"[Cache][Service] update service item progress(%d / %d)", progress, len(services))
   409  		}
   410  		serviceMtime := service.ModifyTime.Unix()
   411  		if lastMtime < serviceMtime {
   412  			lastMtime = serviceMtime
   413  		}
   414  
   415  		if service.IsAlias() {
   416  			aliases = append(aliases, service)
   417  		}
   418  
   419  		spaceName := service.Namespace
   420  		changeNs[spaceName] = struct{}{}
   421  		// 发现有删除操作
   422  		if !service.Valid {
   423  			sc.removeServices(service)
   424  			sc.revisionWorker.Notify(service.ID, false)
   425  			del++
   426  			svcCount--
   427  			continue
   428  		}
   429  
   430  		update++
   431  		_, exist := sc.ids.Load(service.ID)
   432  		if !exist {
   433  			svcCount++
   434  		}
   435  
   436  		sc.ids.Store(service.ID, service)
   437  		sc.serviceList.addService(service)
   438  		sc.revisionWorker.Notify(service.ID, true)
   439  
   440  		spaces, ok := sc.names.Load(spaceName)
   441  		if !ok {
   442  			spaces = utils.NewSyncMap[string, *model.Service]()
   443  			sc.names.Store(spaceName, spaces)
   444  		}
   445  		spaces.Store(service.Name, service)
   446  
   447  		/******兼容cl5******/
   448  		sc.updateCl5SidAndNames(service)
   449  		/******兼容cl5******/
   450  	}
   451  
   452  	if sc.serviceCount != svcCount {
   453  		log.Infof("[Cache][Service] service count update from %d to %d",
   454  			sc.serviceCount, svcCount)
   455  		sc.serviceCount = svcCount
   456  	}
   457  
   458  	sc.postProcessServiceAlias(aliases)
   459  	sc.postProcessUpdatedServices(changeNs)
   460  	sc.serviceList.reloadRevision()
   461  	return map[string]time.Time{
   462  		sc.Name(): time.Unix(lastMtime, 0),
   463  	}, update, del
   464  }
   465  
   466  func (sc *serviceCache) notifyServiceCountReload(svcIds map[string]bool) {
   467  	sc.plock.RLock()
   468  	defer sc.plock.RUnlock()
   469  	for k := range svcIds {
   470  		sc.pendingServices.Store(k, struct{}{})
   471  	}
   472  }
   473  
   474  // appendServiceCountChangeNamespace
   475  // Two Case
   476  // Case ONE:
   477  //  1. T1, ServiceCache pulls all of the service information
   478  //  2. T2 time, instanecache pulls and updates the instance count information, and notify ServiceCache to
   479  //     count the namespace count Reload
   480  //
   481  // - In this case, the instancecache notifies the servicecache, ServiceCache is a fixed count update.
   482  // Case TWO:
   483  //  1. T1, instanecache pulls and updates the instance count information, and notify ServiceCache to
   484  //     make a namespace count Reload
   485  //  2. T2 moments, ServiceCache pulls all of the service information
   486  //
   487  // - This situation, ServiceCache does not update the count, because the corresponding service object
   488  // has not been cached, you need to put it in a PendingService waiting
   489  // - Because under this case, WatchCountChangech is the first RELOAD notification from Instanecache,
   490  // handled the reload notification of ServiceCache.
   491  // - Therefore, for the reload notification of instancecache, you need to record the non-existing SVCID
   492  // record in the Pending list; wait for the servicecache's Reload notification. after arriving,
   493  // need to handle the last legacy PENDING calculation task.
   494  func (sc *serviceCache) appendServiceCountChangeNamespace(changeNs map[string]struct{}) map[string]struct{} {
   495  	sc.plock.Lock()
   496  	defer sc.plock.Unlock()
   497  	waitDel := map[string]struct{}{}
   498  	sc.pendingServices.Range(func(svcId string, _ struct{}) bool {
   499  		svc, ok := sc.ids.Load(svcId)
   500  		if !ok {
   501  			return true
   502  		}
   503  		changeNs[svc.Namespace] = struct{}{}
   504  		waitDel[svcId] = struct{}{}
   505  		return true
   506  	})
   507  	for svcId := range waitDel {
   508  		sc.pendingServices.Delete(svcId)
   509  	}
   510  	return changeNs
   511  }
   512  
   513  func (sc *serviceCache) postProcessServiceAlias(aliases []*model.Service) {
   514  	for i := range aliases {
   515  		alias := aliases[i]
   516  
   517  		_, aliasExist := sc.ids.Load(alias.ID)
   518  		aliasFor, aliasForExist := sc.ids.Load(alias.Reference)
   519  		if !aliasForExist {
   520  			continue
   521  		}
   522  
   523  		if aliasExist {
   524  			sc.alias.addServiceAlias(alias, aliasFor)
   525  		} else {
   526  			sc.alias.delServiceAlias(alias, aliasFor)
   527  		}
   528  	}
   529  }
   530  
   531  func (sc *serviceCache) postProcessUpdatedServices(affect map[string]struct{}) {
   532  	affect = sc.appendServiceCountChangeNamespace(affect)
   533  	sc.countLock.Lock()
   534  	defer sc.countLock.Unlock()
   535  	progress := 0
   536  	for namespace := range affect {
   537  		progress++
   538  		if progress%10000 == 0 {
   539  			log.Infof("[Cache][Service] namespace service detail count progress(%d / %d)", progress, len(affect))
   540  		}
   541  		// Construction of service quantity statistics
   542  		value, ok := sc.names.Load(namespace)
   543  		if !ok {
   544  			sc.namespaceServiceCnt.Delete(namespace)
   545  			continue
   546  		}
   547  
   548  		count, _ := sc.namespaceServiceCnt.LoadOrStore(namespace, &model.NamespaceServiceCount{})
   549  
   550  		// For count information under the Namespace involved in the change, it is necessary to re-come over.
   551  		count.ServiceCount = 0
   552  		count.InstanceCnt = &model.InstanceCount{}
   553  
   554  		value.Range(func(key string, svc *model.Service) bool {
   555  			count.ServiceCount++
   556  			insCnt := sc.instCache.GetInstancesCountByServiceID(svc.ID)
   557  			count.InstanceCnt.TotalInstanceCount += insCnt.TotalInstanceCount
   558  			count.InstanceCnt.HealthyInstanceCount += insCnt.HealthyInstanceCount
   559  			return true
   560  		})
   561  	}
   562  }
   563  
   564  // updateCl5SidAndNames 更新cl5的服务数据
   565  func (sc *serviceCache) updateCl5SidAndNames(service *model.Service) {
   566  	// 不是cl5服务的,不需要更新
   567  	if _, ok := service.Meta["internal-cl5-sid"]; !ok {
   568  		return
   569  	}
   570  
   571  	// service更新
   572  	// service中不存在cl5Name,可以认为是该sid删除了cl5Name,删除缓存
   573  	// service中存在cl5Name,则更新缓存
   574  	cl5NameMeta, ok := service.Meta["internal-cl5-name"]
   575  	sid := service.Name
   576  	if !ok {
   577  		if oldCl5Name, exist := sc.cl5Sid2Name.Load(sid); exist {
   578  			sc.cl5Sid2Name.Delete(sid)
   579  			sc.cl5Names.Delete(oldCl5Name)
   580  		}
   581  		return
   582  	}
   583  
   584  	// 更新的service,有cl5Name
   585  	cl5Name := genCl5Name(cl5NameMeta)
   586  	sc.cl5Sid2Name.Store(sid, cl5Name)
   587  	sc.cl5Names.Store(cl5Name, service)
   588  }
   589  
   590  // GetRevisionWorker
   591  func (sc *serviceCache) GetRevisionWorker() types.ServiceRevisionWorker {
   592  	return sc.revisionWorker
   593  }
   594  
   595  // genCl5Name 兼容cl5Name
   596  // 部分cl5Name与已有服务名存在冲突,因此给cl5Name加上一个前缀
   597  func genCl5Name(name string) string {
   598  	return "cl5." + name
   599  }
   600  
   601  // ComputeRevision 计算唯一的版本标识
   602  func ComputeRevision(serviceRevision string, instances []*model.Instance) (string, error) {
   603  	h := sha1.New()
   604  	if _, err := h.Write([]byte(serviceRevision)); err != nil {
   605  		return "", err
   606  	}
   607  
   608  	var slice sort.StringSlice
   609  	for _, item := range instances {
   610  		slice = append(slice, item.Revision())
   611  	}
   612  	if len(slice) > 0 {
   613  		slice.Sort()
   614  	}
   615  	return types.ComputeRevisionBySlice(h, slice)
   616  }
   617  
   618  const (
   619  	// RevisionConcurrenceCount Revision计算的并发线程数
   620  	RevisionConcurrenceCount = 64
   621  	// RevisionChanCount 存储revision计算的通知管道,可以稍微设置大一点
   622  	RevisionChanCount = 102400
   623  )
   624  
   625  // 更新revision的结构体
   626  type revisionNotify struct {
   627  	serviceID string
   628  	valid     bool
   629  }
   630  
   631  // create new revision notify
   632  func newRevisionNotify(serviceID string, valid bool) *revisionNotify {
   633  	return &revisionNotify{
   634  		serviceID: serviceID,
   635  		valid:     valid,
   636  	}
   637  }
   638  
   639  func newRevisionWorker(svcCache *serviceCache, instCache *instanceCache) *ServiceRevisionWorker {
   640  	return &ServiceRevisionWorker{
   641  		svcCache:      svcCache,
   642  		instCache:     instCache,
   643  		comRevisionCh: make(chan *revisionNotify, RevisionChanCount),
   644  		revisions:     map[string]string{},
   645  	}
   646  }
   647  
   648  type ServiceRevisionWorker struct {
   649  	svcCache  *serviceCache
   650  	instCache *instanceCache
   651  
   652  	comRevisionCh chan *revisionNotify
   653  	revisions     map[string]string // service id -> reversion (所有instance reversion 的累计计算值)
   654  	lock          sync.RWMutex      // for revisions rw lock
   655  }
   656  
   657  func (sc *ServiceRevisionWorker) Notify(serviceID string, valid bool) {
   658  	sc.comRevisionCh <- newRevisionNotify(serviceID, valid)
   659  }
   660  
   661  // GetServiceInstanceRevision 获取服务实例计算之后的revision
   662  func (sc *ServiceRevisionWorker) GetServiceInstanceRevision(serviceID string) string {
   663  	value, ok := sc.readRevisions(serviceID)
   664  	if !ok {
   665  		return ""
   666  	}
   667  	return value
   668  }
   669  
   670  // GetServiceRevisionCount 计算一下缓存中的revision的个数
   671  func (sc *ServiceRevisionWorker) GetServiceRevisionCount() int {
   672  	sc.lock.RLock()
   673  	defer sc.lock.RUnlock()
   674  
   675  	return len(sc.revisions)
   676  }
   677  
   678  // revisionWorker Cache中计算服务实例revision的worker
   679  func (sc *ServiceRevisionWorker) revisionWorker(ctx context.Context) {
   680  	log.Infof("[Cache] compute revision worker start")
   681  	defer log.Infof("[Cache] compute revision worker done")
   682  
   683  	// 启动多个协程来计算revision,后续可以通过启动参数控制
   684  	for i := 0; i < RevisionConcurrenceCount; i++ {
   685  		go func() {
   686  			for {
   687  				select {
   688  				case req := <-sc.comRevisionCh:
   689  					if ok := sc.processRevisionWorker(req); !ok {
   690  						continue
   691  					}
   692  
   693  					// 每个计算完,等待2ms
   694  					time.Sleep(2 * time.Millisecond)
   695  				case <-ctx.Done():
   696  					return
   697  				}
   698  			}
   699  		}()
   700  	}
   701  }
   702  
   703  // processRevisionWorker 处理revision计算的函数
   704  func (sc *ServiceRevisionWorker) processRevisionWorker(req *revisionNotify) bool {
   705  	if req == nil {
   706  		log.Errorf("[Cache][Revision] get null revision request")
   707  		return false
   708  	}
   709  
   710  	if req.serviceID == "" {
   711  		log.Errorf("[Cache][Revision] get request service ID is empty")
   712  		return false
   713  	}
   714  
   715  	if !req.valid {
   716  		log.Infof("[Cache][Revision] service(%s) revision has all been removed", req.serviceID)
   717  		sc.deleteRevisions(req.serviceID)
   718  		return true
   719  	}
   720  
   721  	service := sc.svcCache.GetServiceByID(req.serviceID)
   722  	if service == nil {
   723  		// log.Errorf("[Cache][Revision] can not found service id(%s)", req.serviceID)
   724  		return false
   725  	}
   726  
   727  	instances := sc.instCache.GetInstancesByServiceID(req.serviceID)
   728  	revision, err := ComputeRevision(service.Revision, instances)
   729  	if err != nil {
   730  		log.Errorf(
   731  			"[Cache] compute service id(%s) instances revision err: %s", req.serviceID, err.Error())
   732  		return false
   733  	}
   734  
   735  	sc.setRevisions(req.serviceID, revision) // string -> string
   736  	log.Debugf("[Cache] compute service id(%s) instances revision : %s", req.serviceID, revision)
   737  	return true
   738  }
   739  
   740  func (sc *ServiceRevisionWorker) deleteRevisions(id string) {
   741  	sc.lock.Lock()
   742  	delete(sc.revisions, id)
   743  	sc.lock.Unlock()
   744  }
   745  
   746  func (sc *ServiceRevisionWorker) setRevisions(key string, val string) {
   747  	sc.lock.Lock()
   748  	sc.revisions[key] = val
   749  	sc.lock.Unlock()
   750  }
   751  
   752  func (sc *ServiceRevisionWorker) readRevisions(key string) (string, bool) {
   753  	sc.lock.RLock()
   754  	defer sc.lock.RUnlock()
   755  
   756  	id, ok := sc.revisions[key]
   757  	return id, ok
   758  }