github.com/polarismesh/polaris@v1.17.8/cache/client/client.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 cache_client 19 20 import ( 21 "sort" 22 "sync" 23 "time" 24 25 "go.uber.org/zap" 26 "golang.org/x/sync/singleflight" 27 28 types "github.com/polarismesh/polaris/cache/api" 29 "github.com/polarismesh/polaris/common/log" 30 "github.com/polarismesh/polaris/common/model" 31 "github.com/polarismesh/polaris/store" 32 ) 33 34 var ( 35 _ types.ClientCache = (*clientCache)(nil) 36 ) 37 38 // clientCache 客户端缓存的类 39 type clientCache struct { 40 *types.BaseCache 41 42 storage store.Store 43 lastMtimeLogged int64 44 clients map[string]*model.Client // instance id -> instance 45 lock sync.RWMutex 46 singleFlight *singleflight.Group 47 lastUpdateTime time.Time 48 } 49 50 // name 获取资源名称 51 func (c *clientCache) Name() string { 52 return types.ClientName 53 } 54 55 // LastMtime 最后一次更新时间 56 func (c *clientCache) LastMtime() time.Time { 57 return c.BaseCache.LastMtime(c.Name()) 58 } 59 60 // NewClientCache 新建一个clientCache 61 func NewClientCache(storage store.Store, cacheMgr types.CacheManager) types.ClientCache { 62 return &clientCache{ 63 BaseCache: types.NewBaseCache(storage, cacheMgr), 64 storage: storage, 65 clients: map[string]*model.Client{}, 66 } 67 } 68 69 // initialize 初始化函数 70 func (c *clientCache) Initialize(_ map[string]interface{}) error { 71 c.singleFlight = &singleflight.Group{} 72 c.lastUpdateTime = time.Unix(0, 0) 73 return nil 74 } 75 76 // update 更新缓存函数 77 func (c *clientCache) Update() error { 78 // 多个线程竞争,只有一个线程进行更新 79 _, err, _ := c.singleFlight.Do(c.Name(), func() (interface{}, error) { 80 defer func() { 81 c.lastMtimeLogged = types.LogLastMtime(c.lastMtimeLogged, c.LastMtime().Unix(), "Client") 82 c.reportMetricsInfo() 83 }() 84 return nil, c.DoCacheUpdate(c.Name(), c.realUpdate) 85 }) 86 87 return err 88 } 89 90 func (c *clientCache) realUpdate() (map[string]time.Time, int64, error) { 91 // 拉取diff前的所有数据 92 start := time.Now() 93 clients, err := c.storage.GetMoreClients(c.LastFetchTime(), c.IsFirstUpdate()) 94 if err != nil { 95 log.Errorf("[Cache][Client] update get storage more err: %s", err.Error()) 96 return nil, -1, err 97 } 98 timeDiff := time.Since(start) 99 lastMtimes, update, del := c.setClients(clients) 100 if timeDiff > 1*time.Second { 101 log.Info("[Cache][Client] get more clients", 102 zap.Int("update", update), zap.Int("delete", del), 103 zap.Time("last", c.LastMtime()), zap.Duration("used", time.Since(start))) 104 } 105 106 c.lastUpdateTime = time.Now() 107 return lastMtimes, int64(len(clients)), nil 108 } 109 110 func (c *clientCache) getClient(id string) (*model.Client, bool) { 111 c.lock.RLock() 112 defer c.lock.RUnlock() 113 114 client, ok := c.clients[id] 115 return client, ok 116 } 117 118 func (c *clientCache) deleteClient(id string) { 119 c.lock.Lock() 120 delete(c.clients, id) 121 c.lock.Unlock() 122 } 123 124 func (c *clientCache) storeClient(id string, client *model.Client) { 125 c.lock.Lock() 126 c.clients[id] = client 127 c.lock.Unlock() 128 } 129 130 // setClients 保存client到内存中 131 // 返回:更新个数,删除个数 132 func (c *clientCache) setClients(clients map[string]*model.Client) (map[string]time.Time, int, int) { 133 if len(clients) == 0 { 134 return nil, 0, 0 135 } 136 137 lastMtime := c.LastMtime().Unix() 138 update := 0 139 del := 0 140 progress := 0 141 for _, client := range clients { 142 progress++ 143 if progress%50000 == 0 { 144 log.Infof("[Cache][Client] set clients progress: %d / %d", progress, len(clients)) 145 } 146 147 modifyTime := client.ModifyTime().Unix() 148 if lastMtime < modifyTime { 149 lastMtime = modifyTime 150 } 151 152 id := client.Proto().GetId().GetValue() 153 _, itemExist := c.getClient(id) 154 // 待删除的instance 155 if !client.Valid() { 156 del++ 157 c.deleteClient(id) 158 if itemExist { 159 c.Manager.OnEvent(client, types.EventDeleted) 160 } 161 continue 162 } 163 164 // 有修改或者新增的数据 165 update++ 166 c.storeClient(id, client) 167 if !itemExist { 168 c.Manager.OnEvent(client, types.EventCreated) 169 } else { 170 c.Manager.OnEvent(client, types.EventUpdated) 171 } 172 } 173 174 return map[string]time.Time{ 175 c.Name(): time.Unix(lastMtime, 0), 176 }, update, del 177 } 178 179 // clear 180 // 181 // @return error 182 func (c *clientCache) Clear() error { 183 c.BaseCache.Clear() 184 c.lock.Lock() 185 c.clients = map[string]*model.Client{} 186 c.lock.Unlock() 187 return nil 188 } 189 190 // GetClient get client 191 // @param id 192 // @return *model.Client 193 func (c *clientCache) GetClient(id string) *model.Client { 194 if id == "" { 195 return nil 196 } 197 198 value, ok := c.getClient(id) 199 if !ok { 200 return nil 201 } 202 203 return value 204 } 205 206 // IteratorClients 迭代 207 func (c *clientCache) IteratorClients(iterProc types.ClientIterProc) { 208 c.lock.RLock() 209 defer c.lock.RUnlock() 210 211 for key := range c.clients { 212 if !iterProc(key, c.clients[key]) { 213 break 214 } 215 } 216 } 217 218 // GetClientsByFilter Query client information 219 func (c *clientCache) GetClientsByFilter(filters map[string]string, offset, limit uint32) (uint32, 220 []*model.Client, error) { 221 var ( 222 ret = make([]*model.Client, 0, 16) 223 host, hasHost = filters["host"] 224 clientType, hasType = filters["type"] 225 version, hasVer = filters["version"] 226 id, hasId = filters["id"] 227 ) 228 c.IteratorClients(func(_ string, value *model.Client) bool { 229 if hasHost && value.Proto().GetHost().GetValue() != host { 230 return true 231 } 232 if hasType && value.Proto().GetType().String() != clientType { 233 return true 234 } 235 if hasVer && value.Proto().GetVersion().GetValue() != version { 236 return true 237 } 238 if hasId && value.Proto().GetId().GetValue() != id { 239 return true 240 } 241 242 ret = append(ret, value) 243 return true 244 }) 245 246 return uint32(len(ret)), doClientPage(ret, offset, limit), nil 247 } 248 249 // doClientPage 进行分页, 仅用于控制台查询时的排序 250 func doClientPage(ret []*model.Client, offset, limit uint32) []*model.Client { 251 clients := make([]*model.Client, 0, len(ret)) 252 beginIndex := offset 253 endIndex := beginIndex + limit 254 totalCount := uint32(len(ret)) 255 if totalCount == 0 || beginIndex >= endIndex || beginIndex >= totalCount { 256 return clients 257 } 258 259 if endIndex > totalCount { 260 endIndex = totalCount 261 } 262 263 clients = append(clients, ret...) 264 sort.Slice(clients, func(i, j int) bool { 265 return clients[i].ModifyTime().After(clients[j].ModifyTime()) 266 }) 267 268 return clients[beginIndex:endIndex] 269 }