接上篇继续,从第117行开始分析:
进入StartBootstrapInOrder(s, cfg)
,先贴出整个方法的代码:
开始分析:
再次查看下启动配置文件内容:这2配置作者也说了,是为了不让db崩掉…
进入下面代码:
如果是boltdb:
// CreateTransaction create store transaction
func (m *boltStore) CreateTransaction() (store.Transaction, error) {
return &transaction{handler: m.handler}, nil
}
type transaction struct {
handler BoltHandler
}
如果是mysql: 创建开启事务…
这里我们只分析boltdb.
进入428行:
至此StartBootstrapInOrder(s, cfg)
介绍完毕,对boltdb来说,似乎…只创建了一个transaction对象…
开始进入第123行 StartComponents(ctx, cfg)
中:
先贴出整个方法代码:
开始分析:
// Initialize 初始化
func Initialize(ctx context.Context, cacheOpt *Config, storage store.Store) error {
var err error
once.Do(func() {
// 进入这看看:
err = initialize(ctx, cacheOpt, storage)
})
if err != nil {
return err
}
finishInit = true
return nil
}
// initialize cache 初始化
func initialize(ctx context.Context, cacheOpt *Config, storage store.Store) error {
var err error
cacheMgn, err = newCacheManager(ctx, cacheOpt, storage)
return err
}
整个newCacheManager(ctx, cacheOpt, storage)
代码如下:
初始化CacheManager
, 它管理着16个配置项(通过数组切片管理)
即CacheManager
管理着这些配置项,下面就看这些配置项如何注册(被管理)上的:
先看mgr.RegisterCacher
方法:
一个萝卜一个坑:每个配置项占位一个数组下标
func (nc *CacheManager) RegisterCacher(cacheType types.CacheIndex, item types.Cache) {
nc.caches[cacheType] = item
}
下面说缓存模块初始化,因为模块比较多,我们挑几个来看看:
1.第92行:cachens.NewNamespaceCache(storage, mgr)
func NewNamespaceCache(storage store.Store, cacheMgr types.CacheManager) types.NamespaceCache {
return &namespaceCache{
BaseCache: types.NewBaseCache(storage, cacheMgr), // 看这里
storage: storage,
}
}
type namespaceCache struct {
*types.BaseCache // 基类
storage store.Store // 持有存储的引用
ids *utils.SyncMap[string, *model.Namespace]
updater *singleflight.Group // 达到串行化操作目的
// exportNamespace 某个命名空间下的所有服务的可见性
exportNamespace *utils.SyncMap[string, *utils.SyncSet[string]]
}
namespace模块从字段数量来看,算比较少的,我们需要关注里面几个点:
- 几乎每个模块都持有
store.Store
的引用 - 每个模块都持有缓存管理器
CacheManager
的引用 - 里面有很多
*utils.SyncMap[...]
使用(读写锁 + 普通map) - 它们都有一个基类:
types.BaseCache
我们看看 基类:types.BaseCache
:
func NewBaseCache(s store.Store, cacheMgr CacheManager) *BaseCache {
c := &BaseCache{
s: s,
CacheMgr: cacheMgr,
}
c.initialize() // 我们看看如何初始化
return c
}
// BaseCache 对于 Cache 中的一些 func 做统一实现,避免重复逻辑
type BaseCache struct {
lock sync.RWMutex // 操作保护锁
// firstUpdate Whether the cache is loaded for the first time
// this field can only make value on exec initialize/clean, and set it to false on exec update
firstUpdate bool
s store.Store // boltdb存储dao引用
lastFetchTime int64
lastMtimes map[string]time.Time
CacheMgr CacheManager // 缓存管理器
reportMetrics func() // prometheus度量/logger/其它统计 相关
lastReportMetricsTime time.Time
}
// 只是初始化几个字段
func (bc *BaseCache) initialize() {
bc.lock.Lock()
defer bc.lock.Unlock()
bc.lastFetchTime = 1
bc.firstUpdate = true
bc.lastMtimes = map[string]time.Time{}
}
2.第94行:cachesvc.NewServiceCache(storage, mgr)
:
// NewServiceCache 返回一个serviceCache
func NewServiceCache(storage store.Store, cacheMgr types.CacheManager) types.ServiceCache {
return &serviceCache{
BaseCache: types.NewBaseCache(storage, cacheMgr),
storage: storage,
alias: newServiceAliasBucket(), // 看这里
serviceList: newServiceNamespaceBucket(), // 看这里
}
}
func newServiceAliasBucket() *serviceAliasBucket {
return &serviceAliasBucket{
alias: make(map[string]map[string]map[string]*model.Service),
}
}
type serviceAliasBucket struct {
lock sync.RWMutex
// aliase namespace->service->alias_id
alias map[string]map[string]map[string]*model.Service
}
func newServiceNamespaceBucket() *serviceNamespaceBucket {
return &serviceNamespaceBucket{
names: map[string]*serviceNameBucket{},
}
}
type serviceNamespaceBucket struct {
lock sync.RWMutex
revision string
names map[string]*serviceNameBucket
}
因为serviceCache
属性字段比较多,先不一一介绍,先关注代码中显式初始化的字段,从上面代码可以看到 别名的组织方式:
// aliase namespace->service->alias_id
一个命名空间下的服务:
names map[string]*serviceNameBucket
3.第104行:cacheconfig.NewConfigFileCache(storage, mgr)
// NewConfigFileCache 创建文件缓存
func NewConfigFileCache(storage store.Store, cacheMgr types.CacheManager) types.ConfigFileCache {
fc := &fileCache{
storage: storage,
}
// 新的一种初始化形式
fc.BaseCache = types.NewBaseCacheWithRepoerMetrics(storage, cacheMgr, fc.reportMetricsInfo)
return fc
}
func NewBaseCacheWithRepoerMetrics(s store.Store, cacheMgr CacheManager, reportMetrics func()) *BaseCache {
c := &BaseCache{
s: s,
CacheMgr: cacheMgr,
reportMetrics: reportMetrics, // 多了度量方法
}
c.initialize()
return c
}
4.最后举例,再看第110行:cacheclient.NewClientCache(storage, mgr)
北极星SDK Client
// NewClientCache 新建一个clientCache
func NewClientCache(storage store.Store, cacheMgr types.CacheManager) types.ClientCache {
return &clientCache{
BaseCache: types.NewBaseCache(storage, cacheMgr),
storage: storage,
clients: map[string]*model.Client{},
}
}
// clientCache 客户端缓存的类
type clientCache struct {
*types.BaseCache
storage store.Store
lastMtimeLogged int64
clients map[string]*model.Client // instance id -> instance
lock sync.RWMutex
singleFlight *singleflight.Group
lastUpdateTime time.Time
}
// Client 客户端上报信息表
type Client struct {
proto *apiservice.Client
valid bool
modifyTime time.Time
}
type Client struct {
Host *wrapperspb.StringValue `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
Type Client_ClientType `protobuf:"varint,2,opt,name=type,proto3,enum=v1.Client_ClientType" json:"type,omitempty"`
Version *wrapperspb.StringValue `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
Location *model.Location `protobuf:"bytes,4,opt,name=location,proto3" json:"location,omitempty"`
Id *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=id,proto3" json:"id,omitempty"`
Stat []*StatInfo `protobuf:"bytes,6,rep,name=stat,proto3" json:"stat,omitempty"`
Ctime *wrapperspb.StringValue `protobuf:"bytes,7,opt,name=ctime,proto3" json:"ctime,omitempty"`
Mtime *wrapperspb.StringValue `protobuf:"bytes,8,opt,name=mtime,proto3" json:"mtime,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
client 和 server端通过grpc协议交互,protobuf序列化传输,实锤了。
最后注册上的灰色发布:
type grayCache struct {
*types.BaseCache
storage store.Store
grayResources *utils.SyncMap[string, []*apimodel.ClientLabel]
updater *singleflight.Group
}
type ClientLabel struct {
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value *MatchString `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
也证实了确实是通过标签Label去实现的。
注册上了16个缓存模块后,最后是cacheManager
的初始化:
// Initialize 缓存对象初始化
func (nc *CacheManager) Initialize() error {
if config.DiffTime != 0 {
types.DefaultTimeDiff = -1 * (config.DiffTime.Abs())
}
if types.DefaultTimeDiff > 0 {
return fmt.Errorf("cache diff time to pull store must negative number: %+v", types.DefaultTimeDiff)
}
return nil
}
时间单位是:纳秒
这个值是我们配置的,不配置的默认值也是 5s (-5s), 取绝对值就没区别了:
至此,缓存初始化完毕。我们代码往下到了:
func StartComponents(ctx context.Context, cfg *boot_config.Config) error
方法比较复杂,还没完,下篇继续…
总结,本篇 缓存初始化 介绍了:
- 创建缓存管理器
cacheManager
- 给
cacheManager
注册了16个缓存配置项并初始化 cachemanager
初始化